提交 76b9a3fc 编写于 作者: 张磊's avatar 张磊

Merge branch 'develop' into 'release'

Develop

See merge request !83
......@@ -44,6 +44,11 @@
"integrity": "sha1-ReN/s56No/JbruP/U2niu18iAXo=",
"dev": true
},
"after": {
"version": "0.8.2",
"resolved": "http://192.168.110.93:4873/after/-/after-0.8.2.tgz",
"integrity": "sha1-/ts5T58OAqqXaOcCvaI7UF+ufh8="
},
"ajv": {
"version": "4.11.8",
"resolved": "http://192.168.110.93:4873/ajv/-/ajv-4.11.8.tgz",
......@@ -197,6 +202,11 @@
"integrity": "sha1-odl8yvy8JiXMcPrc6zalDFiwGlM=",
"dev": true
},
"arraybuffer.slice": {
"version": "0.0.7",
"resolved": "http://192.168.110.93:4873/arraybuffer.slice/-/arraybuffer.slice-0.0.7.tgz",
"integrity": "sha1-O7xCdd1YTMGxCAm4nU6LY6aednU="
},
"asap": {
"version": "2.0.6",
"resolved": "http://192.168.110.93:4873/asap/-/asap-2.0.6.tgz",
......@@ -271,6 +281,11 @@
"integrity": "sha1-NhIfhFwFeBct5Bmpfb6x0W7DRUI=",
"dev": true
},
"async-limiter": {
"version": "1.0.1",
"resolved": "http://192.168.110.93:4873/async-limiter/-/async-limiter-1.0.1.tgz",
"integrity": "sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ=="
},
"async-validator": {
"version": "1.8.5",
"resolved": "http://192.168.110.93:4873/async-validator/-/async-validator-1.8.5.tgz",
......@@ -1102,6 +1117,11 @@
"integrity": "sha512-q/UEjfGJ2Cm3oKV71DJz9d25TPnq5rhBVL2Q4fA5wcC3jcrdn7+SssEybFIxwAvvP+YCsCYNKughoF33GxgycQ==",
"dev": true
},
"backo2": {
"version": "1.0.2",
"resolved": "http://192.168.110.93:4873/backo2/-/backo2-1.0.2.tgz",
"integrity": "sha1-MasayLEpNjRj41s+u2n038+6eUc="
},
"balanced-match": {
"version": "1.0.0",
"resolved": "http://192.168.110.93:4873/balanced-match/-/balanced-match-1.0.0.tgz",
......@@ -1175,6 +1195,11 @@
}
}
},
"base64-arraybuffer": {
"version": "0.1.5",
"resolved": "http://192.168.110.93:4873/base64-arraybuffer/-/base64-arraybuffer-0.1.5.tgz",
"integrity": "sha1-c5JncZI7Whl0etZmqlzUv5xunOg="
},
"base64-js": {
"version": "1.5.1",
"resolved": "http://192.168.110.93:4873/base64-js/-/base64-js-1.5.1.tgz",
......@@ -1196,6 +1221,14 @@
"tweetnacl": "^0.14.3"
}
},
"better-assert": {
"version": "1.0.2",
"resolved": "http://192.168.110.93:4873/better-assert/-/better-assert-1.0.2.tgz",
"integrity": "sha1-QIZrnhueC1W0gYlDEeaPr/rrxSI=",
"requires": {
"callsite": "1.0.0"
}
},
"better-scroll": {
"version": "0.1.15",
"resolved": "http://192.168.110.93:4873/better-scroll/-/better-scroll-0.1.15.tgz",
......@@ -1226,6 +1259,11 @@
"file-uri-to-path": "1.0.0"
}
},
"blob": {
"version": "0.0.5",
"resolved": "http://192.168.110.93:4873/blob/-/blob-0.0.5.tgz",
"integrity": "sha1-1oDu7yX4zZGtUz9bAe7UjmTK9oM="
},
"block-stream": {
"version": "0.0.9",
"resolved": "http://192.168.110.93:4873/block-stream/-/block-stream-0.0.9.tgz",
......@@ -1371,6 +1409,11 @@
}
}
},
"callsite": {
"version": "1.0.0",
"resolved": "http://192.168.110.93:4873/callsite/-/callsite-1.0.0.tgz",
"integrity": "sha1-KAOY5dZkvXQDi28JBRU+borxvCA="
},
"camel-case": {
"version": "3.0.0",
"resolved": "http://192.168.110.93:4873/camel-case/-/camel-case-3.0.0.tgz",
......@@ -1713,11 +1756,20 @@
"integrity": "sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs=",
"dev": true
},
"component-bind": {
"version": "1.0.0",
"resolved": "http://192.168.110.93:4873/component-bind/-/component-bind-1.0.0.tgz",
"integrity": "sha1-AMYIq33Nk4l8AAllGx06jh5zu9E="
},
"component-emitter": {
"version": "1.3.0",
"resolved": "http://192.168.110.93:4873/component-emitter/-/component-emitter-1.3.0.tgz",
"integrity": "sha1-FuQHD7qK4ptnnyIVhT7hgasuq8A=",
"dev": true
"integrity": "sha1-FuQHD7qK4ptnnyIVhT7hgasuq8A="
},
"component-inherit": {
"version": "0.0.3",
"resolved": "http://192.168.110.93:4873/component-inherit/-/component-inherit-0.0.3.tgz",
"integrity": "sha1-ZF/ErfWLcrZJ1crmUTVhnbJv8UM="
},
"compressible": {
"version": "2.0.18",
......@@ -2313,6 +2365,51 @@
"integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=",
"dev": true
},
"engine.io-client": {
"version": "3.3.3",
"resolved": "http://192.168.110.93:4873/engine.io-client/-/engine.io-client-3.3.3.tgz",
"integrity": "sha1-rrRWlc7YG3h6ihDJKwvCJrHLPFM=",
"requires": {
"component-emitter": "1.2.1",
"component-inherit": "0.0.3",
"debug": "~3.1.0",
"engine.io-parser": "~2.1.1",
"has-cors": "1.1.0",
"indexof": "0.0.1",
"parseqs": "0.0.5",
"parseuri": "0.0.5",
"ws": "~6.1.0",
"xmlhttprequest-ssl": "~1.6.3",
"yeast": "0.1.2"
},
"dependencies": {
"component-emitter": {
"version": "1.2.1",
"resolved": "http://192.168.110.93:4873/component-emitter/-/component-emitter-1.2.1.tgz",
"integrity": "sha1-E3kY1teCg/ffemt8WmPhQOaUJeY="
},
"debug": {
"version": "3.1.0",
"resolved": "http://192.168.110.93:4873/debug/-/debug-3.1.0.tgz",
"integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==",
"requires": {
"ms": "2.0.0"
}
}
}
},
"engine.io-parser": {
"version": "2.1.3",
"resolved": "http://192.168.110.93:4873/engine.io-parser/-/engine.io-parser-2.1.3.tgz",
"integrity": "sha1-dXq5cPvy37Mse3SwMyFtVznveaY=",
"requires": {
"after": "0.8.2",
"arraybuffer.slice": "~0.0.7",
"base64-arraybuffer": "0.1.5",
"blob": "0.0.5",
"has-binary2": "~1.0.2"
}
},
"enhanced-resolve": {
"version": "0.9.1",
"resolved": "http://192.168.110.93:4873/enhanced-resolve/-/enhanced-resolve-0.9.1.tgz",
......@@ -2734,8 +2831,7 @@
"ansi-regex": {
"version": "2.1.1",
"bundled": true,
"dev": true,
"optional": true
"dev": true
},
"aproba": {
"version": "1.2.0",
......@@ -2756,14 +2852,12 @@
"balanced-match": {
"version": "1.0.0",
"bundled": true,
"dev": true,
"optional": true
"dev": true
},
"brace-expansion": {
"version": "1.1.11",
"bundled": true,
"dev": true,
"optional": true,
"requires": {
"balanced-match": "^1.0.0",
"concat-map": "0.0.1"
......@@ -2778,20 +2872,17 @@
"code-point-at": {
"version": "1.1.0",
"bundled": true,
"dev": true,
"optional": true
"dev": true
},
"concat-map": {
"version": "0.0.1",
"bundled": true,
"dev": true,
"optional": true
"dev": true
},
"console-control-strings": {
"version": "1.1.0",
"bundled": true,
"dev": true,
"optional": true
"dev": true
},
"core-util-is": {
"version": "1.0.2",
......@@ -2908,8 +2999,7 @@
"inherits": {
"version": "2.0.4",
"bundled": true,
"dev": true,
"optional": true
"dev": true
},
"ini": {
"version": "1.3.5",
......@@ -2921,7 +3011,6 @@
"version": "1.0.0",
"bundled": true,
"dev": true,
"optional": true,
"requires": {
"number-is-nan": "^1.0.0"
}
......@@ -2936,7 +3025,6 @@
"version": "3.0.4",
"bundled": true,
"dev": true,
"optional": true,
"requires": {
"brace-expansion": "^1.1.7"
}
......@@ -2944,14 +3032,12 @@
"minimist": {
"version": "1.2.5",
"bundled": true,
"dev": true,
"optional": true
"dev": true
},
"minipass": {
"version": "2.9.0",
"bundled": true,
"dev": true,
"optional": true,
"requires": {
"safe-buffer": "^5.1.2",
"yallist": "^3.0.0"
......@@ -2970,7 +3056,6 @@
"version": "0.5.3",
"bundled": true,
"dev": true,
"optional": true,
"requires": {
"minimist": "^1.2.5"
}
......@@ -3032,8 +3117,7 @@
"npm-normalize-package-bin": {
"version": "1.0.1",
"bundled": true,
"dev": true,
"optional": true
"dev": true
},
"npm-packlist": {
"version": "1.4.8",
......@@ -3061,8 +3145,7 @@
"number-is-nan": {
"version": "1.0.1",
"bundled": true,
"dev": true,
"optional": true
"dev": true
},
"object-assign": {
"version": "4.1.1",
......@@ -3074,7 +3157,6 @@
"version": "1.4.0",
"bundled": true,
"dev": true,
"optional": true,
"requires": {
"wrappy": "1"
}
......@@ -3152,8 +3234,7 @@
"safe-buffer": {
"version": "5.1.2",
"bundled": true,
"dev": true,
"optional": true
"dev": true
},
"safer-buffer": {
"version": "2.1.2",
......@@ -3189,7 +3270,6 @@
"version": "1.0.2",
"bundled": true,
"dev": true,
"optional": true,
"requires": {
"code-point-at": "^1.0.0",
"is-fullwidth-code-point": "^1.0.0",
......@@ -3209,7 +3289,6 @@
"version": "3.0.1",
"bundled": true,
"dev": true,
"optional": true,
"requires": {
"ansi-regex": "^2.0.0"
}
......@@ -3253,14 +3332,12 @@
"wrappy": {
"version": "1.0.2",
"bundled": true,
"dev": true,
"optional": true
"dev": true
},
"yallist": {
"version": "3.1.1",
"bundled": true,
"dev": true,
"optional": true
"dev": true
}
}
},
......@@ -3520,6 +3597,26 @@
}
}
},
"has-binary2": {
"version": "1.0.3",
"resolved": "http://192.168.110.93:4873/has-binary2/-/has-binary2-1.0.3.tgz",
"integrity": "sha1-d3asYn8+p3JQz8My2rfd9eT10R0=",
"requires": {
"isarray": "2.0.1"
},
"dependencies": {
"isarray": {
"version": "2.0.1",
"resolved": "http://192.168.110.93:4873/isarray/-/isarray-2.0.1.tgz",
"integrity": "sha1-o32U7ZzaLVmGXJ92/llu4fM4dB4="
}
}
},
"has-cors": {
"version": "1.1.0",
"resolved": "http://192.168.110.93:4873/has-cors/-/has-cors-1.1.0.tgz",
"integrity": "sha1-XkdHk/fqmEPRu5nCPu9J/xJv/zk="
},
"has-flag": {
"version": "1.0.0",
"resolved": "http://192.168.110.93:4873/has-flag/-/has-flag-1.0.0.tgz",
......@@ -3814,8 +3911,7 @@
"indexof": {
"version": "0.0.1",
"resolved": "http://192.168.110.93:4873/indexof/-/indexof-0.0.1.tgz",
"integrity": "sha1-gtwzbSMrkGIXnQWrMpOmYFn9Q10=",
"dev": true
"integrity": "sha1-gtwzbSMrkGIXnQWrMpOmYFn9Q10="
},
"inflight": {
"version": "1.0.6",
......@@ -4832,8 +4928,7 @@
"ms": {
"version": "2.0.0",
"resolved": "http://192.168.110.93:4873/ms/-/ms-2.0.0.tgz",
"integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=",
"dev": true
"integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
},
"nan": {
"version": "2.14.2",
......@@ -5378,6 +5473,11 @@
"integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=",
"dev": true
},
"object-component": {
"version": "0.0.3",
"resolved": "http://192.168.110.93:4873/object-component/-/object-component-0.0.3.tgz",
"integrity": "sha1-8MaapQ78lbhmwYb0AKM3acsvEpE="
},
"object-copy": {
"version": "0.1.0",
"resolved": "http://192.168.110.93:4873/object-copy/-/object-copy-0.1.0.tgz",
......@@ -5637,6 +5737,22 @@
"error-ex": "^1.2.0"
}
},
"parseqs": {
"version": "0.0.5",
"resolved": "http://192.168.110.93:4873/parseqs/-/parseqs-0.0.5.tgz",
"integrity": "sha1-1SCKNzjkZ2bikbouoXNoSSGouJ0=",
"requires": {
"better-assert": "~1.0.0"
}
},
"parseuri": {
"version": "0.0.5",
"resolved": "http://192.168.110.93:4873/parseuri/-/parseuri-0.0.5.tgz",
"integrity": "sha1-gCBKUNTbt3m/3G6+J3jZDkvOMgo=",
"requires": {
"better-assert": "~1.0.0"
}
},
"parseurl": {
"version": "1.3.3",
"resolved": "http://192.168.110.93:4873/parseurl/-/parseurl-1.3.3.tgz",
......@@ -7605,6 +7721,67 @@
"hoek": "2.x.x"
}
},
"socket.io-client": {
"version": "2.2.0",
"resolved": "http://192.168.110.93:4873/socket.io-client/-/socket.io-client-2.2.0.tgz",
"integrity": "sha1-hOc+48Q9UCDMwaJY+u65rsJyOvc=",
"requires": {
"backo2": "1.0.2",
"base64-arraybuffer": "0.1.5",
"component-bind": "1.0.0",
"component-emitter": "1.2.1",
"debug": "~3.1.0",
"engine.io-client": "~3.3.1",
"has-binary2": "~1.0.2",
"has-cors": "1.1.0",
"indexof": "0.0.1",
"object-component": "0.0.3",
"parseqs": "0.0.5",
"parseuri": "0.0.5",
"socket.io-parser": "~3.3.0",
"to-array": "0.1.4"
},
"dependencies": {
"component-emitter": {
"version": "1.2.1",
"resolved": "http://192.168.110.93:4873/component-emitter/-/component-emitter-1.2.1.tgz",
"integrity": "sha1-E3kY1teCg/ffemt8WmPhQOaUJeY="
},
"debug": {
"version": "3.1.0",
"resolved": "http://192.168.110.93:4873/debug/-/debug-3.1.0.tgz",
"integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==",
"requires": {
"ms": "2.0.0"
}
}
}
},
"socket.io-parser": {
"version": "3.3.2",
"resolved": "http://192.168.110.93:4873/socket.io-parser/-/socket.io-parser-3.3.2.tgz",
"integrity": "sha1-74cgCdCtz3BPL76DAZGhR1KtULY=",
"requires": {
"component-emitter": "~1.3.0",
"debug": "~3.1.0",
"isarray": "2.0.1"
},
"dependencies": {
"debug": {
"version": "3.1.0",
"resolved": "http://192.168.110.93:4873/debug/-/debug-3.1.0.tgz",
"integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==",
"requires": {
"ms": "2.0.0"
}
},
"isarray": {
"version": "2.0.1",
"resolved": "http://192.168.110.93:4873/isarray/-/isarray-2.0.1.tgz",
"integrity": "sha1-o32U7ZzaLVmGXJ92/llu4fM4dB4="
}
}
},
"sockjs": {
"version": "0.3.21",
"resolved": "http://192.168.110.93:4873/sockjs/-/sockjs-0.3.21.tgz",
......@@ -7841,6 +8018,11 @@
}
}
},
"storejs": {
"version": "1.1.0",
"resolved": "http://192.168.110.93:4873/storejs/-/storejs-1.1.0.tgz",
"integrity": "sha1-9jvkPHR8FL46excBg5KTgJHWRnk="
},
"stream-browserify": {
"version": "2.0.2",
"resolved": "http://192.168.110.93:4873/stream-browserify/-/stream-browserify-2.0.2.tgz",
......@@ -8103,6 +8285,11 @@
"resolved": "http://192.168.110.93:4873/tiny-emitter/-/tiny-emitter-2.1.0.tgz",
"integrity": "sha512-NB6Dk1A9xgQPMoGqC5CVXn123gWyte215ONT5Pp5a0yt4nlEoO1ZWeCwpncaekPHXO60i47ihFnZPiRPjRMq4Q=="
},
"to-array": {
"version": "0.1.4",
"resolved": "http://192.168.110.93:4873/to-array/-/to-array-0.1.4.tgz",
"integrity": "sha1-F+bBH3PdTz10zaek/zI46a2b+JA="
},
"to-arraybuffer": {
"version": "1.0.1",
"resolved": "http://192.168.110.93:4873/to-arraybuffer/-/to-arraybuffer-1.0.1.tgz",
......@@ -9045,6 +9232,19 @@
"integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=",
"dev": true
},
"ws": {
"version": "6.1.4",
"resolved": "http://192.168.110.93:4873/ws/-/ws-6.1.4.tgz",
"integrity": "sha512-eqZfL+NE/YQc1/ZynhojeV8q+H050oR8AZ2uIev7RU10svA9ZnJUddHcOUZTJLinZ9yEfdA2kSATS2qZK5fhJA==",
"requires": {
"async-limiter": "~1.0.0"
}
},
"xmlhttprequest-ssl": {
"version": "1.6.3",
"resolved": "http://192.168.110.93:4873/xmlhttprequest-ssl/-/xmlhttprequest-ssl-1.6.3.tgz",
"integrity": "sha1-A7cThzsBZZ36LBxdBWBlsn3cLeY="
},
"xtend": {
"version": "4.0.2",
"resolved": "http://192.168.110.93:4873/xtend/-/xtend-4.0.2.tgz",
......@@ -9089,6 +9289,11 @@
"decamelize": "^1.2.0"
}
},
"yeast": {
"version": "0.1.2",
"resolved": "http://192.168.110.93:4873/yeast/-/yeast-0.1.2.tgz",
"integrity": "sha1-AI4G2AlDIMNy28L47XagymyKxBk="
},
"zrender": {
"version": "4.3.2",
"resolved": "http://192.168.110.93:4873/zrender/-/zrender-4.3.2.tgz",
......
......@@ -15,26 +15,33 @@
<v-footer></v-footer>
</div>
</el-container>
<chat :showChat="showChat" :currentChat="currentChat"></chat>
<diagnoseAdvice :showAdvice="showAdvice"></diagnoseAdvice>
</div>
</template>
<script>
import VHeader from "./views/layout/header.vue";
import VSlidebar from "./views/layout/slidebar.vue";
import VFooter from "./views/layout/footer.vue";
import chat from './components/IM/chat'
import DiagnoseAdvice from '@/components/common/diagnoseAdvice.vue'
import {
base64decode,
isNotEmptyUtils,
getUrlParamsMap,
ssoLogin
ssoLogin,
bindDragHeader
} from "./utils/utils.js";
import { mapActions, mapGetters } from "vuex";
import { getLoginUrl, getInnerLoginUrl } from "./utils/index.js";
import { mapActions, mapGetters, mapState } from "vuex";
import { getInnerLoginUrl } from "./utils/index";
let vm = null;
export default {
components: {
VHeader,
VSlidebar,
VFooter
VFooter,
chat,
DiagnoseAdvice
},
data() {
return {
......@@ -45,14 +52,26 @@ export default {
};
},
computed: {
...mapState({
showChat: 'showChat',
currentChat: 'currentChat',
showAdvice:'showAdvice'
}),
...mapGetters(["_token"])
},
created() {
vm = this;
vm.getToken();
window._VM = vm;
},
mounted() {
setTimeout( function () {
bindDragHeader('.c-header', '.chat-wrap');
}, 1000)
},
mounted() {},
methods: {
// 修改token
...mapActions(["changeToken"]),
// 解密token
getToken() {
let href = window.location.href;
......@@ -85,8 +104,7 @@ export default {
vm.changeToken(vm.token);
vm.getUserAuth();
},
// 修改token
...mapActions(["changeToken"]),
// 获取用户权限
getUserAuth(token) {
let req = null;
......@@ -104,11 +122,13 @@ export default {
}
this.systemType = systemType;
this.showSlidebar = true;
console.log(res,111);
vm.userName = res.data.userName;
vm.authList = authList;
}
});
}
},
closeGlobalMsgNotice () {}
}
};
</script>
......@@ -130,7 +150,7 @@ export default {
.content {
background: #f0f2f5;
position: absolute;
left: 255px;
left: 215px;
right: 0;
top: 64px;
bottom: 0;
......
.chat-wrap {
position: absolute;
top: 20px;
right: 20px;
z-index: 1000;
width: 640px;
min-height: 700px;
background: #ffffff;
box-shadow: 10px 10px 50px 0px #d9d9d9;
overflow: visible;
border-radius: 18px;
.component-content {
.center {
//margin-left: 10%;
//margin-right: 10%;
flex: 1;
background: #fff;
.c-header {
//height: 40px;
padding: 15px 24px;
.header-line {
display: flex;
flex-direction: row;
justify-content: space-between;
align-items: center;
}
.c-header-l {
color: #063948;
.num {
font-size: 28px;
}
.dep {
font-size: 20px;
}
}
.c-header-edit {
display: flex;
min-width: 140px;
justify-content: space-around;
.edit-img {
width: 24px;
height: 24px;
img {
width: 100%;
height: 100%;
}
}
.edit-imgclose {
width: 70px;
height: 24px;
background: #ff5e57;
border-radius: 12px;
font-size: 13px;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
color: #ffffff;
line-height: 24px;
user-select: none;
}
}
}
.msg-content {
height: 400px;
background: #f0f2f5;
word-break: break-all;
overflow: scroll;
display: flex;
flex-direction: column;
margin-top: 10px;
.msg-item {
display: flex;
flex-direction: row;
margin: 12px 0;
.msg-item-img {
width: 36px;
height: 36px;
margin-right: 12px;
& > img {
width: 100%;
height: 100%;
border-radius: 22px;
}
}
.msg-item-detail {
display: flex;
flex-direction: column;
text-align: left;
font-size: 13px;
& > :first-child {
color: #999999;
margin-bottom: 8px;
}
.send-warpper {
// display: flex;
// flex-direction: row;
// align-items: center;
& > .icon {
float: left;
width: 20px;
height: 20px;
margin-right: 10px;
margin-top: 10px;
}
.mid-text-wrapper {
display: inline-block;
// display: flex;
// flex-direction: row;
// align-items: center;
// & > img {
// width: 18px;
// height: 18px;
// margin-right: 8px;
// cursor: pointer;
// }
}
.mid-text {
padding: 12px 16px;
display: inline-block;
max-width: 520px;
border-radius: 8px;
text-align: justify;
&.no-support {
display: flex;
align-items: center;
& > img {
width: 14px;
height: 14px;
margin-right: 3px;
}
}
}
.link {
color: #ffffff;
}
& > .mid-pdf {
width: 260px;
display: flex;
flex-direction: row;
justify-content: space-between;
text-align: left;
padding: 10px 15px;
//background: #f0f1f2;
border-radius: 8px;
min-height: 80px;
cursor: pointer;
.midp-left {
display: flex;
flex-direction: column;
justify-content: space-around;
margin-right: 10px;
.name {
font-size: 13px;
color: #333333;
word-break: break-word;
}
.size {
font-size: 12px;
color: #999999;
}
}
.midp-icon {
width: 36px;
height: 44px;
& > img {
width: 36px;
height: 100%;
border-radius: 3px;
}
}
}
& > .mid-img {
display: flex;
flex-direction: row;
align-items: center;
cursor: pointer;
// & > .icon {
// width: 20px;
// height: 20px;
// }
// & > .img {
// width: 170px;
// height: 108px;
// border-radius: 8px;
// }
.img-box {
max-width: 192px;
max-height: 320px;
overflow: hidden;
}
}
& > .diagnosis-box {
width: 260px;
text-align: left;
padding: 10px 15px;
//background: #ffffff;
border-radius: 8px;
min-height: 80px;
.title {
padding-bottom: 10px;
font-size: 14px;
font-weight: 700;
}
.dia-text {
font-size: 12px;
.label {
color: #ffffff;
}
}
}
& > .time-box {
width: 260px;
text-align: left;
padding: 10px 15px;
//background: #ffffff;
border-radius: 8px;
min-height: 80px;
.title {
padding-bottom: 10px;
font-size: 14px;
font-weight: 700;
}
.time {
padding-bottom: 10px;
font-size: 12px;
font-weight: 700;
}
.time-text {
font-size: 12px;
}
}
& > .suggession-box {
width: 260px;
text-align: left;
padding: 10px 15px;
//background: #f0f1f2;
border-radius: 8px;
min-height: 80px;
.title {
padding-bottom: 10px;
font-size: 14px;
font-weight: 700;
}
.suggession-text {
font-size: 12px;
.label {
}
}
}
& > .audio-box audio {
width: 242px;
height: 44px;
//background: #EBF5FC;
border-radius: 20px;
}
& > .live-box {
width: 202px;
height: 44px;
line-height: 44px;
background: #ffffff;
border-radius: 8px;
text-align: center;
}
& > .diagnosis-end {
width: 100%;
.split-line {
width: 100%;
display: flex;
flex-direction: row;
align-items: center;
margin: 15px 0;
font-size: 14px;
&::before {
flex: 1;
content: "";
height: 1px;
margin-right: 18px;
//background: #f0f1f2;
}
&::after {
flex: 1;
content: "";
height: 1px;
margin-left: 18px;
//background: #f0f1f2;
}
}
}
}
}
.msg-item-detail.line {
width: 100%;
}
&.cr {
flex-direction: row-reverse;
//justify-content: flex-end;
.msg-item-img {
margin-right: 0;
margin-left: 8px;
}
.msg-item-detail {
text-align: right;
& > .mid-text {
background: #449284;
}
}
}
}
.msg-item {
color: #063948;
.mid-text {
background: #ffffff;
}
}
.cr {
color: #ffffff;
.mid-text,
.live-notice,
.time-box,
.diagnosis-box,
.suggession-box {
background: #449284;
.time {
color: #ffffff;
}
}
}
.split-line {
width: 100%;
display: flex;
flex-direction: row;
align-items: center;
margin: 15px 0;
font-size: 14px;
color: #999999;
&::before {
flex: 1;
content: "";
height: 1px;
margin-right: 18px;
background: #f0f1f2;
}
&::after {
flex: 1;
content: "";
height: 1px;
margin-left: 18px;
background: #f0f1f2;
}
}
.error-mg {
display: inline-block;
max-width: 520px;
// height: 24px;
max-width: 520px;
line-height: 16px;
text-align: left;
border-radius: 20px;
opacity: 0.45;
margin: -2px 0 10px;
padding: 4px 12px;
color: #ffffff;
background: #000000;
margin-left: 50px;
&.mr {
margin-left: 0;
margin-right: 50px;
}
}
}
.msg-content::-webkit-scrollbar {
width: 0px;
height: 0px;
background-color: #fff;
}
.c-bottom {
position: relative;
top: -8px;
left: 0;
display: flex;
align-items: center;
flex-direction: row;
margin: 16px 12px 16px 25px;
.cb-icon-wrapper {
display: flex;
align-items: center;
height: 44px;
img {
width: 20px;
height: 20px;
margin-right: 16px;
cursor: pointer;
}
}
.send-btn {
width: 86px;
height: 33px;
background: #449284;
border-radius: 23px;
color: #ffffff;
border: none;
font-size: 14px;
font-weight: bold;
}
::v-deep.el-textarea {
.el-textarea__inner {
border: none;
}
}
::v-deep.c-bottom-input {
//border: 4px solid #0d9078 !important;
::v-deep textarea {
border: none !important ;
}
}
}
&.no-content {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
img {
display: block;
width: 120px;
height: 100px;
}
p {
margin-top: 10px;
font-size: 14px;
color: rgba(0, 0, 0, 0.65);
}
}
}
background: #fff;
.time {
color: #999999;
}
.small {
font-size: 12px;
}
.ld {
-webkit-transition-property: -webkit-transform;
-webkit-transition-duration: 1s;
-moz-transition-property: -moz-transform;
-moz-transition-duration: 1s;
-webkit-animation: rotate 3s linear infinite;
-moz-animation: rotate 3s linear infinite;
-o-animation: rotate 3s linear infinite;
animation: rotate 3s linear infinite;
}
@-webkit-keyframes rotate {
from {
-webkit-transform: rotate(0deg);
}
to {
-webkit-transform: rotate(360deg);
}
}
@-moz-keyframes rotate {
from {
-moz-transform: rotate(0deg);
}
to {
-moz-transform: rotate(359deg);
}
}
@-o-keyframes rotate {
from {
-o-transform: rotate(0deg);
}
to {
-o-transform: rotate(359deg);
}
}
@keyframes rotate {
from {
transform: rotate(0deg);
}
to {
transform: rotate(359deg);
}
}
}
}
.wenzenbox {
position: absolute;
top: 20px;
right: 20px;
width: 120px;
height: 120px;
img{
width: 100%;
height: 100%;
}
}
.shrink64 {
height: 120px;
width: 120px;
background-color: transparent;
box-shadow:none;
overflow: visible;
border-radius: 18px;
}
<template>
<div
class="chat-wrap"
:class="!toggleChatSize ? 'shrink64' : ''"
v-show="showChat"
>
<section v-show="toggleChatSize" class="component-content" id="screenSet">
<article class="center" v-loadmore="getOldMSGHistory">
<section class="c-header">
<div class="header-line">
<div class="c-header-l">
<span class="num">{{ currentChat.diagnoseLogId }}</span>
<span class="dep">&nbsp;{{ currentChat.department }}</span>
</div>
<div class="c-header-edit">
<span class="edit-imgclose" @click="overFn"> 结束问诊 </span>
<span class="edit-img" @click="closeChat">
<img src="../../assets/image/IM/im_close2.png" alt />
</span>
<span class="edit-img" @click="toggleChatModal">
<img src="../../assets/image/IM/im_small.png" alt />
</span>
</div>
</div>
<div class="header-line"></div>
</section>
<diagnosis-Live :doctorImg="doctorImg"></diagnosis-Live>
<section id="msgContentId" class="msg-content scroll-box">
<article v-for="(item, index) in messageList" :key="index">
<!-- sendOrReceive 为true在右边 -->
<div class="msg-item" :class="{ cr: item.sendOrReceive }">
<div v-if="item.showType != 10" class="msg-item-img">
<img :src="item.avatarImg" alt />
</div>
<div
class="msg-item-detail"
:class="{ line: item.showType == 10 }"
>
<span v-if="item.showType != 10" class="mid-time"
>{{ item.name }} {{ item.timestampStr }}</span
>
<div class="send-warpper">
<img
v-if="item.sendOrReceive && item.isShowErrorIcon"
class="icon"
src="../../assets/image/IM/icon-no-send.png"
alt
/>
<img
v-if="item.sendOrReceive && item.isShowLoadingIcon"
class="icon ld"
src="../../assets/image/IM/loading-icon-new.png"
alt
/>
<div
v-if="item.showType == 1"
class="mid-text-wrapper"
style="max-width: 520px"
>
<div class="mid-text">{{ item.text }}</div>
</div>
<div v-if="item.showType == 2" class="mid-img" v-viewer>
<div class="img-box">
<img
class="img"
:src="item.url"
:style="{
width: item.newW + 'px',
height: item.newH + 'px',
}"
alt
/>
</div>
</div>
<div
v-if="item.showType == 3"
class="mid-pdf"
@click="openPDF(item)"
>
<div class="midp-left">
<span class="name">{{ item.text | shortName(23) }}</span>
<span class="size">{{ fileSizeChange(item.size) }}</span>
</div>
<div class="midp-icon">
<img src="../../assets/image/IM/icon-pdf.png" alt />
</div>
</div>
<div v-if="item.showType == 4" class="mid-text">
{{ item.text }}
<span class="link">{{ item.suffix }}</span>
</div>
<div v-if="item.showType == 5" class="mid-text no-support">
<img
src="../../assets/image/IM/icon-warning-circle.png"
alt
/>
<span>该消息类型PC端暂不支持</span>
</div>
<!-- 语音消息 -->
<div v-if="item.showType == 6" class="audio-box">
<audio controls>
<source :src="item.url" type="audio/mpeg" />
</audio>
</div>
<!-- 问诊开始与病例模块 -->
<div v-if="item.showType == 7" class="diagnosis-box">
<div class="title">{{ item.title }}</div>
<div class="dia-text">
<span class="label">患者:</span>
<span
>{{ item.text.patientName }}
{{ item.text.sex == 1 ? "男" : "女" }}
{{ item.text.age }}</span
>
</div>
<div class="dia-text">
<span class="label">病情描述:</span>
<span>{{ item.text.illnessDetail }}</span>
</div>
</div>
<!-- 预约时间模块 -->
<div v-if="item.showType == 8" class="time-box">
<div class="title">{{ item.title }}</div>
<div class="time">{{ item.text.timeStr }}</div>
<div class="time-text">{{ item.text.tips }}</div>
</div>
<!-- 音视频与IM的交互 -->
<div v-if="item.showType == 9" class="live-box">
<div class="live-notice">{{ item.text }}</div>
</div>
<!-- 问诊结束 -->
<div v-if="item.showType == 10" class="diagnosis-end">
<div class="split-line">{{ item.text }}</div>
</div>
<!-- 医生建议模块 -->
<div v-if="item.showType == 11" class="suggession-box">
<div class="title">{{ item.title }}</div>
<div class="suggession-text">{{ item.text }}</div>
</div>
</div>
</div>
</div>
<span
v-if="item.sendOrReceive && item.isShowErrorMsg"
class="error-mg"
:class="{ mr: item.sendOrReceive }"
>{{ item.errorMsg }}</span
>
</article>
</section>
<section class="c-bottom">
<el-input
type="textarea"
class="c-bottom-input"
placeholder="请输入内容"
v-model="sendText"
maxlength="499"
></el-input>
<div class="cb-icon-wrapper">
<el-upload
class="bg-uploader"
action="#"
accept=".jpg, .png, .pdf"
:show-file-list="false"
:before-upload="beforeUploadFile"
>
<img src="../../assets/image/IM/im_sendfile.png" alt />
</el-upload>
<img
src="../../assets/image/IM/im_sendvedio.png"
@click="preSendLinkMsg"
alt
/>
</div>
<el-button
size="small"
class="send-btn"
:class="{ active: canSend }"
@click="sendTextMsg"
>
发送
</el-button>
</section>
</article>
</section>
<div v-show="!toggleChatSize" class="wenzenbox" @click="toggleChatModal">
<div class="wenzenbox-header">
<img src="../../assets/image/IM/wenzhenicon.png" alt="" />
</div>
</div>
<!-- 选择链接弹窗 -->
<el-dialog
title="选择链接"
:modal="false"
:show-close="true"
:visible.sync="showSelectDialog"
:close-on-click-modal="false"
width="500px"
class="link-form"
>
<el-form
ref="linkFormRef"
:rules="rules"
:model="linkForm"
label-width="100px"
>
<el-form-item label="普通文本">
<el-col :span="20">
<el-input
v-model="linkForm.remark"
size="small"
maxlength="300"
></el-input>
</el-col>
</el-form-item>
<el-form-item label="链接文案" prop="info">
<el-col :span="20">
<el-input
v-model="linkForm.info"
size="small"
maxlength="100"
></el-input>
</el-col>
</el-form-item>
<el-form-item label="链接地址" prop="url">
<el-col :span="20">
<el-select
size="small"
style="width: 300px"
clearable
filterable
v-model="linkForm.url"
placeholder="请选择"
>
<el-option
v-for="item in linkList"
:key="item.id"
:label="item.title"
:value="item.id"
></el-option>
</el-select>
</el-col>
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer" style="text-align: right">
<el-button size="small" @click="showSelectDialog = false"
>取 消</el-button
>
<el-button size="small" type="primary" @click="sendLinkMsg"
>确 定</el-button
>
</div>
</el-dialog>
<alert ref="alert"></alert>
</div>
</template>
<script>
import BreadCrumb from "@/components/breadcrumb.vue";
import alert from "@/components/common/alert.vue";
import diagnosisLive from "./diagnosis-live";
import { doUpload, getFilePath } from "@/utils/qiniu-util";
import { openLoading, closeLoading, betaHandle } from "@/utils/utils";
import { getPicaKFAccid, getPhomeDemain } from "@/utils";
import { mapState } from "vuex";
const CONTAINER_HEIGHT = 700;
let forwardMsgIntervalId = null,
continueIntervalId = null,
autoCompletionIntervalId = null,
cacheMap = {};
let _this = null;
export default {
components: {
BreadCrumb,
diagnosisLive,
alert,
},
props: {
showChat: {
type: Boolean,
default: false,
},
},
data() {
return {
curmbFirst: "云鹊客服",
curmbSecond: "当前会话",
sendText: "",
sessionListData: {
currentTimestamp: 0,
myTaskCount: 0,
sessionList: [],
waitingTaskCount: 0,
},
currentContinueTimes: 0,
currentSessionIndex: 0, // 当前会话序号
currentSession: {},
currentTaskLogId: "", // 当前会话ID
picakfAccId: "",
historyTimestamp: 0,
realTimestamp: 0,
containerHeight: CONTAINER_HEIGHT,
showSelectDialog: false,
linkForm: {
remark: "",
info: "",
url: "",
},
linkList: [], // 消息列表 showType 1: 文本; 2: 图片; 3: PDF; 4: 链接; 5: 不支持类型; 6: 语音;7: 病例;
messageList: [],
rules: {
info: [
{ required: true, message: "请填写链接显示文案", trigger: "blur" },
],
url: [{ required: true, message: "请选择链接", trigger: "change" }],
},
imgWidth: 0,
imgHeight: 0,
imgProportion: 0,
hasNoHistoryData: false,
tid: "",
teamMemberList: [],
doctorName: "",
doctorImg: "",
toggleChatSize: true,
};
},
computed: {
...mapState({
currentChat: "currentChat",
}),
canSend() {
return !!this.sendText;
},
},
watch: {
// 监听消息列表的变化,添加sessionFlag(会话结束标志)
messageList: {
handler(newMsgList) {
let l = newMsgList.length;
if (l >= 2) {
for (let i = 1; i < l; i++) {
if (newMsgList[i - 1].taskLogId !== newMsgList[i].taskLogId) {
newMsgList[i].sessionFlag = true;
}
}
}
},
deep: true,
},
// 监听到有变化,就缓存一下
sendText(newText) {
cacheMap[this.currentSession.id] = newText || "";
},
currentChat(newVal, oldVal) {
if (newVal !== oldVal && newVal.imTeamId) {
this.chatInit();
}
},
},
created() {},
mounted() {
cacheMap = {};
this.$nextTick(() => {
// _this.containerHeight = document.body.clientHeight - 80;
// _this.getElmByID("msgContentId").style.height = "400px";
});
},
methods: {
chatInit() {
_this = this;
this.picakfAccId = getPicaKFAccid();
const { imTeamId } = this.currentChat;
this.tid = imTeamId;
this.getFiveContentList();
autoCompletionIntervalId && clearInterval(autoCompletionIntervalId);
autoCompletionIntervalId = setInterval(() => {
this.autoCompletionInterval();
}, 2000);
// 监听键盘的回车按键(回车时发送消息,并阻止其在textarea中的回车换行行为)
document.onkeydown = function (ev) {
var event = ev || event;
if (event.keyCode == 13) {
_this.sendTextMsg();
event.preventDefault();
}
};
this.getMembersList(); // 获取群聊成员信息
},
// 含有敏感信息的消息,自行补全提示文案
// 每30秒监测敏感信息
autoCompletionInterval() {
if (!this.messageList.length) return;
// 将带有loading的消息转成失败的
this.messageList.forEach((item) => {
if (item.isShowLoadingIcon) {
item.isShowLoadingIcon = false;
item.isShowErrorIcon = true;
}
});
let flag = false,
msg;
for (let i = 0; i < this.messageList.length; i++) {
msg = this.messageList[i];
if (msg.isShowErrorIcon && !msg.isShowErrorMsg) {
flag = true;
break;
}
}
if (flag) {
this.getMSGForwardForAC(msg);
}
},
// 查询群组成员列表
getMembersList() {
this.GET("/im/team/member/list", { tid: this.tid }).then((res) => {
if (res.code === "000000") {
this.teamMemberList = res.data; // 1 问诊医生 2接诊医生 3居民 4其他
this.doctorName = this.teamMemberList[0].name;
this.doctorImg = this.teamMemberList[0].avatarImageUrl;
this.getMSGHistory(); // 查询群聊历史消息
}
});
},
// 查询医生和居民的消息 - 向前查找
getMSGForwardForAC(msg) {
let params = {
includeFlag: 0,
lastMsgTimestamp: msg.realTimestamp,
limit: 50,
tid: this.tid,
};
this.POST("/im/team/message/forward", params).then((res) => {
if (res.code === "000000") {
this.contactForwardMessage(res.data, false);
}
});
},
// 获取元素
getElmByID(elmId) {
return document.getElementById(elmId);
},
// 查询医生和居民的消息历史(下拉刷新时调用)
getOldMSGHistory() {
if (this.hasNoHistoryData) return;
let params = {
includeFlag: 0, // 不带本条消息
lastMsgTimestamp: this.historyTimestamp,
limit: 20,
tid: this.tid,
};
this.POST("/im/team/message/history", params).then((res) => {
if (res.code === "000000") {
// 将新消息合并到之前的消息中, 并且重置最后一条消息
if (res.data && res.data.length > 0) {
this.convertMessageList(res.data, 3);
} else {
this.hasNoHistoryData = true;
}
} else {
this.$message({
message: res.message,
type: "error",
});
}
});
},
// 查询医生和居民的消息历史(第一次进来时就调用)
getMSGHistory(session) {
let params = {
includeFlag: 1, // 带本条消息
limit: 20,
tid: this.tid,
};
this.POST("/im/team/message/history", params).then((res) => {
if (res.code === "000000") {
this.convertMessageList(res.data, 1);
} else {
this.$message({
message: res.message,
type: "error",
});
}
});
},
// 查询医生和居民的消息 - 向前查找
// 将获取消息列表插入到当前消息列表的最后
getMSGForward() {
let params = {
includeFlag: 0,
lastMsgTimestamp: this.realTimestamp,
limit: 20,
tid: this.tid,
};
this.POST("/im/team/message/forward", params).then((res) => {
if (res.code === "000000") {
this.convertMessageList(res.data, 2);
} else {
this.$message({
message: res.message,
type: "error",
});
}
});
},
/* 转换消息格式
处理的消息类型只有5种:
type == TEXT(showType:1)
type == image 或 picture(showType:2)
type == custom时,18: PDF文件(showType:3); 19: 链接信息(showType:4); 1 ~ 17: 不支持的消息类型(showType:5);
directFlag 1: 第一次取数据; 2: 拼接实时消息(push); 3: 拼接历史消息(unshift);
*/
convertMessageList(messageList, directFlag = 1) {
messageList.sort((a, b) => {
return a.timestamp - b.timestamp;
});
let msg = null,
content = null,
text = "",
suffix = "",
showType = 1,
size = 0,
url = "",
title = "",
cMessageList = [];
messageList.forEach((rawMsg, index) => {
text = "";
suffix = "";
showType = 1;
size = 0;
url = "";
title = "";
msg = Object.assign({}, rawMsg);
msg.sendOrReceive = rawMsg.fromAccId === this.picakfAccId; // 判断消息是显示在左边还是右边, true 右
//msg.avatarImg = msg.sendOrReceive ? this.kfAvatar : this.currentSession.avatarImageUrl;
for (let i = 0; i < this.teamMemberList.length; i++) {
if (rawMsg.fromAccId == this.teamMemberList[i].accId) {
msg.avatarImg = this.teamMemberList[i].avatarImageUrl;
msg.name = this.teamMemberList[i].name;
break;
}
}
if (msg.type.toLowerCase() == "custom") {
content = JSON.parse(msg.content);
text = content.content;
if (content.bizType == -1||content.bizType == 27) {
// 系统消息:消息由于违规未发送成功(可以不处理)
showType = -1;
text = content.content;
} else if (content.bizType == 18) {
// PDF
showType = 3;
text = content.name;
size = content.size;
url = content.url;
} else if (content.bizType == 19) {
// 链接
showType = 4;
text = content.content;
suffix = content.suffix;
} else if (content.bizType == 22) {
// 病例
showType = 7;
title = content.title;
text = JSON.parse(content.content);
} else if (content.bizType == 23) {
// 预约时间
showType = 8;
title = content.title;
text = JSON.parse(content.content);
} else if (content.bizType == 24) {
// 音视频与IM交互
showType = 9;
text = content.content;
} else if (content.bizType == 25) {
// 本次问诊结束
showType = 10;
text = content.content;
} else if (content.bizType == 26) {
// 医生建议
showType = 11;
title = content.title;
text = content.content;
} else {
showType = 5;
}
} else if (
msg.type.toLowerCase() == "image" ||
msg.type.toLowerCase() == "picture"
) {
// 图片
content = JSON.parse(msg.content);
url = content.url;
text = content.name;
showType = 2;
this.imgSizeHandleNew(msg, content.w, content.h);
} else if (msg.type.toLowerCase() == "audio") {
// 语音
content = JSON.parse(msg.content);
url = content.url;
showType = 6;
} else {
showType = 1; // 文本
text = msg.content;
}
msg.title = title;
msg.text = text;
msg.showType = showType;
msg.suffix = suffix;
msg.size = size;
msg.url = url;
msg.sessionFlag = false;
cMessageList.push(msg);
});
if (directFlag === 1) {
this.messageList = [];
this.$forceUpdate();
forwardMsgIntervalId && clearInterval(forwardMsgIntervalId);
this.messageList = cMessageList;
this.$forceUpdate();
setTimeout(() => {
this.$nextTick(() => {
const scrollBoxDom = document.querySelector(".scroll-box");
scrollBoxDom.scrollTop = scrollBoxDom.scrollHeight;
});
}, 100);
this.currentContinueTimes =
this.sessionListData.currentTimestamp -
this.currentSession.handleStartTime;
continueIntervalId && clearInterval(continueIntervalId);
continueIntervalId = setInterval(() => {
this.currentContinueTimes += 1000;
}, 1000);
// 最新消息,要合并CUSTOM类型中,bizType是-1的数据(系统消息)
} else if (directFlag === 2) {
this.contactForwardMessage(cMessageList);
} else {
if (cMessageList.length) {
this.messageList.unshift(...cMessageList);
this.$nextTick(() => {
const scrollBoxDom = document.querySelector(".scroll-box");
scrollBoxDom.scrollTop = 1000;
});
}
}
// 重新设置历史与实时的时间戳
if (this.messageList.length) {
this.historyTimestamp = this.messageList[0].timestamp;
let timestamp = this.messageList[this.messageList.length - 1].timestamp;
if (timestamp) {
this.realTimestamp = timestamp;
}
}
// 自己发送消息时,暂时不刷新消息
if (directFlag == 1) {
forwardMsgIntervalId = setInterval(() => {
this.getMSGForward();
}, 3000);
}
this.$forceUpdate();
},
// 接接数据
contactForwardMessage(cMessageList, canPush = true) {
let content = {},
signature = "",
msgIndex = -1,
newMsgList = [],
flag = false;
cMessageList.forEach((item) => {
content = {};
signature = "";
msgIndex = -1;
newMsgList = [];
if (item.type.toLowerCase() == "custom") {
content = JSON.parse(item.content);
if (content.bizType == -1||content.bizType == 27) {
signature = content.signature;
msgIndex = this.messageList.findIndex((m) => {
return m.signature == signature && !m.isShowErrorMsg;
});
if (msgIndex > -1) {
flag = true;
this.messageList[msgIndex].errorMsg = content.content;
this.messageList[msgIndex].isShowErrorMsg = true;
}
this.$forceUpdate();
} else {
flag = true;
canPush && this.messageList.push(item);
}
} else {
flag = true;
canPush && this.messageList.push(item);
}
});
if (flag) {
this.$nextTick(() => {
var element = document.querySelector(".scroll-box");
if (
element.scrollTop >=
element.scrollHeight - element.offsetHeight - 400
) {
element.scrollTop = element.scrollHeight - element.offsetHeight;
}
});
}
},
// 打开PDF
openPDF(item) {
window.open(item.url, "__blank");
},
// 根据字段名及其值,从数组中查找对象
findItemByKeyAndVal(arr, key, value, flag = 0) {
if (flag == 0) {
return arr.find((item) => {
return item[key] == value;
});
} else if (flag == 1) {
return arr.findIndex((item) => {
return item[key] == value;
});
}
},
// 获取积木列表
getFiveContentList() {
this.GET(
"/contents/admin/template/queryTemplate?publishFlag=5&pageNo=1&pageSize=99999"
).then((res) => {
if (res.code === "000000") {
this.linkList = res.data.templateList || [];
} else {
this.$message({
message: res.message,
type: "error",
});
}
});
},
// 上传文件
beforeUploadFile(file) {
console.log("file", file);
let fileSize = file.size / (1024 * 1024);
if (fileSize > 5) {
this.$message({
message: "请上传小于5M的文件",
type: "warning",
});
return;
}
openLoading(_this);
doUpload(
_this,
file,
getFilePath(file, null),
"preview4",
"progress",
""
).then(function (resData) {
closeLoading(_this);
let params = {};
params.fileSize = resData.size;
params.fileExt = resData.ext;
params.url = resData.fullPath;
params.info = resData.name;
params.type = 2;
// 如果是图片,则要获取其宽与高
if (
params.fileExt.toLowerCase() === ".jpg" ||
params.fileExt.toLowerCase() === ".jpeg" ||
params.fileExt.toLowerCase() === ".png"
) {
params.type = 1;
let image = new Image();
image.src = params.url;
image.onload = function () {
let _img = this;
params.width = _img.width;
params.height = _img.height;
_this.sendCommonMsg(params);
};
} else {
_this.sendCommonMsg(params);
}
});
},
// 打开发送链接弹框
preSendLinkMsg() {
this.linkForm = {
remark: "",
info: "",
url: "",
};
this.showSelectDialog = true;
},
// 发送带链接消息
sendLinkMsg() {
this.$refs["linkFormRef"].validate((valid) => {
if (valid) {
let params = Object.assign({}, this.linkForm);
params.url = getPhomeDemain() + `/template_v2/?id=${params.url}`;
params.type = 3;
this.sendCommonMsg(params);
this.showSelectDialog = false;
}
});
},
// 发送文本消息
sendTextMsg() {
if (!this.canSend) return;
this.sendCommonMsg({ info: this.sendText });
this.sendText = "";
},
/* 处理发送消息
1: 先将消息体直接显示在对话框中
2: 设置一个时间戳,以便再次找回
3: 保存再次发送的数据
4: 设置各种状态(1:isShowErrorIcon; 2:isShowLoadingIcon; 3:isShowErrorMsg)
*/
handleSendMsg(params, sendId) {
let text = "";
let msg = Object.assign({}, params);
msg.fromAccount = this.tid;
msg.toAccount = this.picakfAccId;
// type: 0, // 类型 0文本 1图片 2pdf 3链接
msg.text = params.info || "";
msg.suffix = params.remark || "";
if (msg.type == 3) {
msg.suffix = params.info;
msg.text = params.remark || "";
}
msg.size = params.fileSize;
msg.url = params.url;
msg.showType = params.type - 0 + 1;
msg.sessionFlag = false;
msg.isShowLoadingIcon = true;
msg.isShowErrorIcon = false;
msg.isShowErrorMsg = false; // 只有在下次拉取新数据时才有可能是为ture
msg.extData = Object.assign({}, params); // 再将发送时的数据
msg.sendId = sendId;
msg.sendOrReceive = true;
msg.timestampStr = new Date().format("hh:mm");
msg.realTimestamp = this.realTimestamp;
msg.taskLogId = this.currentTaskLogId;
this.teamMemberList.forEach((item) => {
if ((this.picakfAccId = item.accId)) {
msg.avatarImg = item.avatarImageUrl; // 运营头像
}
});
if (msg.type == 1) {
this.imgSizeHandleNew(msg, msg.width, msg.height);
}
this.messageList.push(msg);
this.$nextTick(() => {
var element = document.querySelector(".scroll-box");
element.scrollTop = element.scrollHeight;
});
},
// 发送通用消息
async sendCommonMsg(params) {
let sendMsgParams = {
fromAccount: this.picakfAccId,
toAccount: this.tid,
fileExt: "", // 文件扩展名称图片或PDF文件)
fileSize: 0, // 文件大小(图片或PDF文件)
height: 0, // 图片高度(仅图片)
width: 0, // 图片宽度(仅图片)
info: "", // 文本内容,图片的名称,pdf的名称,链接显示内容
md5: "", // 图片或文件MD5 暂时由后台生成
remark: "", // 其他信息(链接中的前缀文案)
type: 0, // 类型 0文本 1图片 2pdf 3链接
url: "", // url地址(图片、pdf,链接)
};
params = Object.assign(sendMsgParams, params);
// 将获取新数据的定时器关闭
forwardMsgIntervalId && clearInterval(forwardMsgIntervalId);
let sendId = new Date().getTime();
this.handleSendMsg(params, sendId);
await this.POST("/im/team/op/message/send", params)
.then((res) => {
if (res.code === "000000") {
// 校验结果:1校验通过 2校验不通过
let msg = this.messageList[this.messageList.length - 1];
if (msg.sendId !== sendId) {
msg = this.getMsgBySendId(sendId);
}
if (res.data.checkFlag == 1) {
this.realTimestamp = res.data.timetag;
msg.isShowLoadingIcon = false;
msg.isShowErrorIcon = false;
msg.isShowErrorMsg = false; // 只有在下次拉取新数据时才有可能是为ture
} else {
msg.signature = res.data.signature;
msg.isShowLoadingIcon = false;
msg.isShowErrorIcon = true;
msg.isShowErrorMsg = false; // 只有在下次拉取新数据时才有可能是为ture
}
this.teamMemberList.forEach((item, index) => {
if (params.fromAccount == item.accId) {
msg.name = item.name;
}
});
} else {
this.$message({
message: res.message,
type: "error",
});
}
})
.catch((error) => {
let msg = this.messageList[this.messageList.length - 1];
if (msg.sendId !== sendId) {
msg = this.getMsgBySendId(sendId);
}
msg.isShowLoadingIcon = false;
msg.isShowErrorIcon = true;
msg.isShowErrorMsg = false; // 只有在下次拉取新数据时才有可能是为ture
msg.canRepeatSend = true;
});
this.$forceUpdate();
// 重新开启定时器
forwardMsgIntervalId = setInterval(() => {
this.getMSGForward();
}, 3000);
},
// 根据sendId,查找到对应的消息
getMsgBySendId(sendId) {
console.log("------------getMsgBySendId------------");
let l = this.messageList.length,
i = l - 1;
for (; i > 0; i--) {
if (this.messageList[i].sendId == sendId) {
break;
}
}
return this.messageList[i];
},
// 文件大小单位转换
fileSizeChange(val) {
return betaHandle(val);
},
closeChat() {
window.rtc.leave();
this.clearSession();
this.$store.commit("updateShowChat", false);
this.$store.commit("updateCurrentChat", {});
},
clearSession() {
sessionStorage.removeItem("TIME_askTime");
sessionStorage.removeItem("TIME_answerTime");
sessionStorage.removeItem("TIME_useTime");
sessionStorage.removeItem("TIME_loseTime");
},
// 结束会话
overFn() {
this.$refs.alert
.init({
cancleTxt: "取消",
confirmTxt: "确定",
title: `确定要结束会话吗?`,
content:`结束会话后,APP端问诊室将关闭`
})
.then(() => {
this.out();
})
.catch((err) => {});
},
out() {
const { diagnoseLogId } = this.currentChat;
let url = `/diagnose/admin/diagnose/endCall/${diagnoseLogId}`;
let params = {};
this.POST(url, params)
.then((res) => {
if (res.code == "000000") {
this.closeChat();
} else {
this.$refs.alert
.init({
confirmTxt: "我知道了",
title: `操作失败,请稍后重试`,
})
.then(() => {})
.catch((err) => {});
}
})
.catch(() => {
this.$refs.alert
.init({
confirmTxt: "我知道了",
title: `操作失败,请稍后重试`,
})
.then(() => {})
.catch((err) => {});
});
},
toggleChatModal() {
this.toggleChatSize = !this.toggleChatSize;
},
},
beforeDestroy() {
forwardMsgIntervalId && clearInterval(forwardMsgIntervalId);
autoCompletionIntervalId && clearInterval(autoCompletionIntervalId);
},
};
</script>
<style lang="scss" scoped>
@import "./chat.scss";
</style>
<template>
<div class="livebox">
<div class="top">
<div class="top-left">
<div class="time-message ">
<p class="msg-img">
<img :src="currentChat.diagnoseType == 2 ? im_text : im_video" />
</p>
<span>{{ diagnoseType }}</span>
</div>
<div class="time-message ml10">
<p class="msg-img"> <img :src="im_time" alt /></p>
<p>设定时长: {{ time }}分钟 &nbsp;&nbsp;</p>
<p v-if="startTime && endTime">总时长: {{ useTime }}&nbsp;&nbsp;</p>
<p v-if="startTime && endTime">剩余时长: {{ loseTime }}</p>
</div>
</div>
</div>
<div class="main" v-if="currentChat.diagnoseType == 1 || currentChat.diagnoseType == 2">
<div
class="viedo-wrapper"
v-for="(item, index) of memberList"
:key="index"
>
<div class="text">
<div class="text-left">
<img :src="item && item.avatarImageUrl" alt />
</div>
<div class="text-right">
<p>
<span class="text-name">{{ item.name }}</span>
<span class="text-dep">{{ item.role == 1 ? "助诊医生" : "接诊医生" }}</span>
</p>
<p class="text-num">{{item.role == 1 ? currentChat.userMobile:currentChat.doctorMobile }}</p>
</div>
</div>
<div :class="{viedowrap:currentChat.diagnoseType == 2}" :id="rtc.viewslist[index] ? rtc.viewslist[index].id : ''">
</div>
<div class="viedo-btn-wrap" :id="rtc.viewslist[index] ? rtc.viewslist[index].id : ''">
<el-button class="call-btn"
:class="{calling1: item.role == 1 && doctorTrtcEntryStatus != 2, calling2: item.role == 2 && userTrtcEntryStatus != 2}"
@click="drivingCall(item)">
{{ item.role == 1 ? showText(doctorTrtcEntryStatus) : showText(userTrtcEntryStatus)}}
</el-button>
</div>
</div>
<div class="vedio-man">
<p class="man-img" @click="toggleVol">
<img :src="isMuted ? im_man2: im_man1" alt />
</p>
<p class="man-txt">
{{isMuted ? '已静音' : '已接入'}}
</p>
</div>
</div>
<alert ref="alert"></alert>
</div>
</template>
<script>
import {
getLiveTimeText,
countDown,
getBroswer,
laseTime,
lastm,
} from "@/utils/live";
import RtcClient from "../../utils/RtcClient.js";
import { openLoading, closeLoading } from "@/utils/utils";
import alert from "@/components/common/alert.vue";
import timeLeft from "@/components/timeLeft";
import {mapState} from "vuex";
export default {
components: {
alert,
timeLeft,
},
props: {
doctorImg: {
type: String | Number,
default: ''
}
},
watch: {
currentChat(newVal, oldVal) {
if(newVal !== oldVal && newVal.imTeamId){
const {imTeamId, diagnoseLogId,} = this.currentChat;
this.tid = imTeamId;
this.diagnoseLogId = diagnoseLogId;
this.init();
}
}
},
data() {
return {
closeCallImg: require("../../assets/image/live/close-call.png"),
voiceCloseImg: require("../../assets/image/live/voice-close.png"),
voiceSmallImg: require("../../assets/image/live/voice-small.png"),
voiceImg: require("../../assets/image/live/voice.png"),
waitingCallImg: require("../../assets/image/live/waiting-call.png"),
noCameraImg: require("../../assets/image/live/no-camera.png"),
im_text: require("../../assets/image/IM/im_text.png"),
im_video: require("../../assets/image/IM/im_video.png"),
im_time: require("../../assets/image/IM/im_time.png"),
im_man1: require("../../assets/image/IM/im_man1.png"),
im_man2: require("../../assets/image/IM/im_man2.png"),
roleAnchor: "anchor", // 主播
rtc: null,
roomId: "",
sdkAppId: "",
userSig: "",
userId: "",
viedoParams: null,
askTime: 0, // 问诊医生接入时长
answerTime: 0, // 接诊医生接入时长
useTime: 0, // 问诊时长
loseTime: 0, // 问诊剩余时长
askTimeFn: null,
answerTimeFn: null,
useTimeFn: null,
loseTimeFn: null,
type: 1, // 1: 语音 2: 视频
startTime: 0,
endTime: 0,
time: 30, //总时长
memberList: [],
tid: "", // 群id
diagnoseLogId: "", //问诊id
isMuted: true,
liveInfoSave: {},
userTrtcEntryStatus:2,
doctorTrtcEntryStatus:2
};
},
created() {
},
computed: {
...mapState({
currentChat: 'currentChat',
}),
diagnoseType() {
switch(this.currentChat.diagnoseType) {
case 1:
return '语音问诊'
case 2:
return '视频问诊'
break;
case 3:
return '图文问诊'
break;
default:
return''
}
},
},
methods: {
async init() {
if(!this.checkChrome()){
this.$nextTick(() => {
this.$refs.alert.init({
confirmTxt: "我知道了",
title: `请下载新版Chrome浏览器`,
});
});
return false;
}
// 获取视频参数
this.getViedoParams();
this.getInfo(); // 获取用户信息列表
},
toggleVol () {
if(this.isMuted){
this.rtc.unmuteLocalAudio();
}else{
this.rtc.muteLocalAudio();
}
this.isMuted = !this.isMuted;
},
// 主动呼叫
drivingCall(data) {
if(data.role == 1 && this.doctorTrtcEntryStatus != 2){
return false;
}
if(data.role == 2 && this.userTrtcEntryStatus != 2){
return false;
}
console.log('--this.roomId',this.currentChat, data, this.roomId);
let url = `/im/team/call/direct/`;
let params = {
imAccId: data.accId,
imTeamId: this.currentChat.imTeamId,
liveRoomId: this.roomId
};
this.POST(url, params).then((res) => {
if (res.code === "000000") {
// this.getInfo(data);
// this.rtc.join()
this.$message({
message: '呼叫成功',
type: "success",
});
if(data.role == 1){
this.doctorTrtcEntryStatus = 3;
}
if(data.role == 2){
this.userTrtcEntryStatus = 3;
}
} else {
this.$message({
message: res.message,
type: "warning",
});
}
});
},
// 获取相关信息
getInfo() {
let url = `/im/team/detail?tid=${this.tid}`;
this.GET(url)
.then((res) => {
if (res.code == "000000") {
let { liveInfo, memberList } = res.data;
console.log('---liveInfo', liveInfo, memberList);
if (liveInfo) {
this.startTime = liveInfo.startTimestamp;
this.endTime = liveInfo.endTimestamp;
this.time = lastm(this.startTime, this.endTime);
this.roomId = Number(liveInfo.roomId);
this.type = liveInfo.liveType;
}
if (memberList && memberList.length) {
memberList.forEach((item) => {
if (item.role == 4) {
this.userId = item.liveUserId;
}
//在当前群组中的角色 1: 问诊医生 2: 接诊医生 3: 居民 4: 其他
if(item.role == 1){
this.memberList[0] = item;
}
if(item.role == 2){
this.memberList[1] = item;
}
});
}
this.getAppId();
}
})
.catch(() => {
this.getErr();
});
},
// 获取AppId
getAppId() {
let req = {};
this.GET("/coupler/app/trtc/sdkappid", req)
.then((res) => {
if (res.code == "000000") {
this.sdkAppId = res.data.sdkAppId;
this.getSing();
} else if (res.code == "200006" || res.code == "200000") {
if (this.rtc) {
this.leave();
}
this.getErr();
}
})
.catch((err) => {
this.getErr();
});
},
// 获取签名
getSing() {
let req = {
sdkAppId: this.sdkAppId,
userId: this.userId,
};
this.POST("/coupler/usersig/trtc", req)
.then((res) => {
if (res.code == "000000") {
this.userSig = res.data.userSig;
this.clientLogin();
} else if (res.code == "200006" || res.code == "200000") {
if (this.rtc) {
this.leave();
}
this.getErr();
return false;
}
})
.catch((err) => {
this.getErr();
});
},
// 创建trtcClient
clientLogin() {
let obj = {
roomId: this.roomId,
role: this.roleAnchor,
sdkAppId: this.sdkAppId,
userId: this.userId,
userSig: this.userSig,
vueInstance: this,
};
console.log('---obj', obj);
this.rtc = new RtcClient(obj);
window.rtc = this.rtc;
this.$nextTick(() => {
this.$refs.alert
.init({
confirmTxt: "我知道了",
title: `为了更好的体验,请保证您输出设备的正常使用`,
})
.then(() => {
Promise.all([this.rtc.join()]).then((res) => {
this.ispending();
let t = setTimeout(() => {
closeLoading(this);
this.muteLocalAudio();
clearTimeout(t);
}, 1000);
});
})
.catch((err) => {
Promise.all([this.rtc.join()]).then((res) => {
this.ispending();
let t = setTimeout(() => {
closeLoading(this);
this.muteLocalAudio();
clearTimeout(t);
}, 1000);
});
});
});
},
// 获取视频参数
getViedoParams() {
this.GET("/coupler/app/config/push/stream/params")
.then((res) => {
if (res.code == "000000") {
this.viedoParams = res.data;
} else if (res.code == "200006" || res.code == "200000") {
closeLoading(this);
if (this.rtc) {
this.leave();
}
}
})
.catch((err) => {
console.log("获取视频参数数据失败");
});
},
// 关闭mc
muteLocalAudio() {
this.rtc.muteLocalAudio();
},
// 打开mc
unmuteLocalAudio() {
this.rtc.unmuteLocalAudio();
},
// 显示文案
showText(status) {
let text = "";
switch (status) {
case 1:
text = "已接入";
break;
case 2:
text = "呼叫医生";
break;
case 3:
text = "呼叫中";
break;
default:
text = `呼叫医生`;
break;
}
return text;
},
//设置图像 1为等待 2为进行中 3为下麦
setImg(status) {
let img = null;
switch (status) {
case 1:
img = this.waitingCallImg;
break;
case 3:
img = this.closeCallImg;
break;
default:
img = this.closeCallImg;
break;
}
return img;
},
// 用户上线
addNewMember(id) {
this.memberList.forEach((item) => {
if (item.liveUserId == id) {
item.status = 2;
this.setTime(item.role);
if(item.role == 1){
this.doctorTrtcEntryStatus = 1;
}
if(item.role == 2){
this.userTrtcEntryStatus = 1;
}
}
});
console.log('---this.addNewMember', this.memberList, id);
},
// 用户下线
removeMember(id) {
this.memberList.forEach((item) => {
if (item.liveUserId == id) {
item.status = 3;
if(item.role == 1){
this.doctorTrtcEntryStatus = 2;
}
if(item.role == 2){
this.userTrtcEntryStatus = 2;
}
}
});
console.log('---this.removeMember', this.memberList, id);
},
//设置进行时长 1表示为问诊 2为接诊 3为问诊开始 4为问诊结束
setTime(flag) {
let text = "";
switch (flag) {
case 1:
text = "askTime";
break;
case 2:
text = "answerTime";
break;
case 3:
text = "useTime";
break;
case 4:
text = "loseTime";
break;
default:
break;
}
let t = 0;
let liveTime = Number(sessionStorage.getItem(`TIME_${text}`) || t);
this[`${text}Fn`] = setInterval(() => {
liveTime += 1000;
this[text] = getLiveTimeText(liveTime, text);
}, 1000);
},
// 问诊是否进行中
ispending() {
if (this.startTime < new Date() < this.endTime) {
this.setTime(3);
this.loseTimeFn = setInterval(() => {
this.loseTime = countDown(this.endTime);
let timeObj = laseTime(this.endTime);
if (
(timeObj.leftm == 5 || timeObj.leftm == 3 || timeObj.leftm == 1) &&
timeObj.lefts == 0 &&
timeObj.lefth == 0
) {
this.$nextTick(() => {
this.$refs.alert
.init({
confirmTxt: "我知道了",
title: `距离会诊结束还剩不足${timeObj.leftm}分钟`,
})
.then(() => {})
.catch((err) => {});
});
}
}, 1000);
} else if (new Date() < this.startTime) {
let t = setInterval(() => {
if (new Date() > this.startTime) {
clearInterval(t);
this.ispending();
}
}, 1000);
}
},
// client离开房间
leave() {
this.rtc.leave();
this.clearSession();
window.location.href = "about:blank";
window.close();
},
// 结束会话
overFn() {
this.$refs.alert
.init({
cancleTxt: "取消",
confirmTxt: "我知道了",
title: `确定要结束会话么?`,
})
.then(() => {
this.out();
})
.catch((err) => {});
},
out() {
let url = `/diagnose/admin/diagnose/endCall/${this.diagnoseLogId}`;
let params = {};
this.POST(url, params)
.then((res) => {
if (res.code == "000000") {
this.leave();
} else {
this.$refs.alert
.init({
confirmTxt: "我知道了",
title: `操作失败,请稍后重试`,
})
.then(() => {})
.catch((err) => {});
}
})
.catch(() => {
this.$refs.alert
.init({
confirmTxt: "我知道了",
title: `操作失败,请稍后重试`,
})
.then(() => {})
.catch((err) => {});
});
},
// 获取信息失败
getErr() {
closeLoading(this);
// this.$nextTick(() => {
// this.$refs.alert
// .init({
// confirmTxt: "我知道了",
// title: `获取信息失败,请稍后重试`,
// })
// .then(() => {
// // this.$router.go(-1);
// })
// .catch((err) => {
// // this.$router.go(-1);
// });
// });
},
reloadfn(msg) {
this.$nextTick(() => {
this.$refs.alert
.init({
confirmTxt: "我知道了",
title: `加入房间失败,重新加入`,
})
.then(() => {
// location.reload();
})
.catch((err) => {
// location.reload();
});
});
},
clearTime() {
clearInterval(this.askTimeFn);
clearInterval(this.answerTimeFn);
clearInterval(this.useTimeFn);
clearInterval(this.loseTimeFn);
},
// 清除直播时间相关的seession
clearSession() {
sessionStorage.removeItem("TIME_askTime");
sessionStorage.removeItem("TIME_answerTime");
sessionStorage.removeItem("TIME_useTime");
sessionStorage.removeItem("TIME_loseTime");
},
// 检查是否为chrome
checkChrome() {
return getBroswer().broswer == "Chrome";
},
},
beforeDestroy() {
this.clearTime();
},
};
</script>
<style lang="less" scoped>
.livebox {
display: flex;
flex-direction: column;
background: #ffffff;
padding: 15px 24px;
padding-top: 0px;
.top {
.top-left {
text-align: left;
display: flex;
.time-message {
display: flex;
height: 24px;
line-height: 24px;
background: #F0F2F5;
border-radius: 23px;
color: #6A7990;
font-size: 14px;
padding: 0px 15px;
.msg-img{
width: 12px;
height: 12px;
margin-right: 10px;
img{
width: 100%;
height: 100%;
}
}
}
.ml10{
margin-left: 10px;
}
}
.top-right {
margin: 15px 25px 0 0;
display: flex;
align-items: center;
justify-content: center;
.icon {
width: 32px;
height: 32px;
border-radius: 50%;
cursor: pointer;
}
.close {
width: 102px;
height: 32px;
background: #ff4d4f;
border-radius: 2px;
font-size: 14px;
color: #ffffff;
line-height: 32px;
text-align: center;
margin-left: 20px;
cursor: pointer;
}
}
}
.main {
margin-top: 25px;
display: flex;
flex: 1;
.viedo-wrapper {
width: 224px;
// height: 240px;
background: #F0F2F5;
border-radius: 18px;
padding: 15px;
margin-right: 2%;
position: relative;
.text {
display: flex;
.text-left{
width: 36px;
height: 36px;
background: #DDDDDD;
border-radius: 36px;
img {
width: 100%;
height: 100%;
}
}
.text-right {
margin-left: 5px;
text-align: left;
white-space: nowrap;
.text-name{
font-size: 18px;
color: #063948;
font-weight: bold;
}
.text-dep{
margin-left: 5px;
font-size: 14px;
color: #063948;
}
.text-num{
font-size: 14px;
color: #6A7990;
}
}
}
.time {
display: flex;
flex-direction: column-reverse;
padding-bottom: 20px;
width: 100px;
margin-right: 24px;
margin-left: 5px;
color: #fff;
.time-content {
font-size: 12px;
display: flex;
flex-direction: column;
justify-content: flex-start;
align-items: flex-end;
}
}
.viedo-btn-wrap {
.call-btn{
width: 173px;
height: 38px;
background: #449284;
border-radius: 23px;
color: #ffffff;
margin-top: 15px;
border: none;
}
.calling1, .calling2 {
background: #9FC8C0;
}
.viedo-container{
width: 100px;
height:100px;
margin: auto;
margin-top: 15px;
// position: absolute;
// top: 0;
// left: 0;
// right: 0;
// bottom: 0;
// margin: auto;
}
}
.viedowrap{
height: 180px;
}
}
.vedio-man{
width: 120px;
height: 120px;
background: #F0F2F5;
border-radius: 18px;
padding: 9px;
.man-img{
width: 61px;
height: 61px;
border-radius: 61px;
background: #449284;
text-align: center;
margin: 0 auto;
img {
width: 100%;
}
}
.man-txt{
margin-top: 18px;
color: #449284;
font-size: 14px;
}
}
}
.out {
width: 102px;
height: 32px;
border-radius: 2px;
border: 1px solid #ffffff;
font-size: 14px;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
color: #ffffff;
text-align: center;
line-height: 32px;
cursor: pointer;
margin: 15px auto 6%;
}
}
</style>
......@@ -4,15 +4,20 @@
<div class="diog-main" @click.stop="">
<div class="diog-message">
<div class="diog-left">
<img :src="warningImg" alt="" srcset="">
<img :src="warningImg" alt="" srcset="" />
</div>
<div class="diog-right">
<p class="title">{{title}}</p>
<p class="title">{{ title }}</p>
</div>
</div>
<div class="diog-content" v-if="content">
{{ content }}
</div>
<div class="btn">
<div @click.stop="confirm" class="confirm-btn">{{confirmTxt}}</div>
<div @click.stop="cancle" class="cancle-btn" v-if="cancleTxt">{{cancleTxt}}</div>
<div @click.stop="confirm" class="confirm-btn">{{ confirmTxt }}</div>
<div @click.stop="cancle" class="cancle-btn" v-if="cancleTxt">
{{ cancleTxt }}
</div>
</div>
</div>
</div>
......@@ -23,48 +28,51 @@
export default {
data() {
return {
warningImg: require('@/assets/image/live/warning.png'),
warningImg: require("@/assets/image/live/warning.png"),
show: false,
title: '',
confirmTxt: '确定',
cancleTxt: '',
_promise: null
}
title: "",
content: "",
confirmTxt: "确定",
cancleTxt: "",
_promise: null,
};
},
created() {},
methods: {
reset() {
this.title = ''
this.confirmTxt = '确定'
this.cancleTxt = ''
this._promise = null
this.title = "";
this.confirmTxt = "确定";
this.cancleTxt = "";
this.content = "";
this._promise = null;
},
init(obj={}) {
Object.assign(this,obj)
this.show = true
return new Promise((resolve,reject) => {
init(obj = {}) {
Object.assign(this, obj);
console.log("obj---", obj);
this.show = true;
return new Promise((resolve, reject) => {
this._promise = {
resolve,
reject
reject,
};
})
});
},
async cancle() {
this.show = false
await this._promise.reject && this._promise.reject()
this.reset()
this.show = false;
(await this._promise.reject) && this._promise.reject();
this.reset();
},
async confirm() {
this.show = false
await this._promise.resolve && this._promise.resolve()
this.reset()
this.show = false;
(await this._promise.resolve) && this._promise.resolve();
this.reset();
},
hide() {
this.show = false
this.reset()
}
}
}
this.show = false;
this.reset();
},
},
};
</script>
......@@ -85,14 +93,16 @@ export default {
display: flex;
align-items: center;
justify-content: center;
background: rgba(0,0,0,0.6);
//background: rgba(0,0,0,0.6);
.diog-main {
width:480px;
width: 480px;
padding: 34px 32px 24px 34px;
box-sizing: border-box;
background:rgba(31,31,31,1);
box-shadow:0px 12px 48px 16px rgba(0,0,0,0.12),0px 9px 28px 0px rgba(0,0,0,0.2),0px 6px 16px -8px rgba(0,0,0,0.32);
border-radius:2px;
background: rgba(31, 31, 31, 1);
box-shadow: 0px 12px 48px 16px rgba(0, 0, 0, 0.12),
0px 9px 28px 0px rgba(0, 0, 0, 0.2),
0px 6px 16px -8px rgba(0, 0, 0, 0.32);
border-radius: 2px;
.diog-message {
display: flex;
.diog-left {
......@@ -102,14 +112,21 @@ export default {
}
.diog-right {
.title {
font-size:16px;
font-family:PingFangSC-Medium,PingFang SC;
font-weight:500;
color:rgba(255,255,255,0.85);
line-height:24px;
font-size: 16px;
font-family: PingFangSC-Medium, PingFang SC;
font-weight: 500;
color: rgba(255, 255, 255, 0.85);
line-height: 24px;
}
}
}
.diog-content {
font-size: 16px;
font-family: PingFangSC-Medium, PingFang SC;
font-weight: 500;
color: rgba(255, 255, 255, 0.85);
margin-top: 24px;
}
.btn {
margin-top: 24px;
display: flex;
......@@ -117,27 +134,27 @@ export default {
.confirm-btn {
margin-left: 12px;
padding: 0 16px;
height:32px;
background:rgba(47,134,246,1);
border-radius:2px;
font-size:14px;
font-family:PingFangSC-Regular,PingFang SC;
font-weight:400;
color:rgba(255,255,255,1);
line-height:32px;
height: 32px;
background: rgba(47, 134, 246, 1);
border-radius: 2px;
font-size: 14px;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
color: rgba(255, 255, 255, 1);
line-height: 32px;
text-align: center;
cursor: pointer;
}
.cancle-btn {
width:60px;
height:32px;
border-radius:2px;
border:1px solid rgba(255,255,255,0.2);
font-size:14px;
font-family:PingFangSC-Regular,PingFang SC;
font-weight:400;
color:rgba(255,255,255,0.65);
line-height:32px;
width: 60px;
height: 32px;
border-radius: 2px;
border: 1px solid rgba(255, 255, 255, 0.2);
font-size: 14px;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
color: rgba(255, 255, 255, 0.65);
line-height: 32px;
text-align: center;
cursor: pointer;
}
......@@ -145,5 +162,4 @@ export default {
}
}
}
</style>
<template>
<div class="consultationlist" @click="goworkBench" style="user-select: none">
<div class="list">
<div class="name">{{ operatorsItem.name || "" }}</div>
<div class="details">
<!-- <div class="handle">待处理: <span> 暂无</span></div> -->
<div class="see">
<span>查看详情</span>
<i class="el-icon-arrow-right"></i>
</div>
</div>
</div>
</div>
</template>
<script>
export default {
data() {
return {};
},
props: {
operatorsItem: {
type: Object,
default: {},
},
workbenchAdminDate: {
type: String,
default: "",
},
},
created() {
console.log("operatorsItem", this.operatorsItem);
},
methods: {
goworkBench() {
const p = {
dateTime: this.workbenchAdminDate,
operateUserId: this.operatorsItem.id,
pageNo: 1,
pageSize: 6,
returnStatus: 1,
};
this.$store.commit("clearRawCurrentCalList");
this.POST("/diagnose/socket/condition/update", p).then((res) => {
if (res.code == "000000") {
this.$store.commit("updateSoketQuest", p);
this.$router.push({ path: "/workbench" });
} else {
this.$message({
message: res.message,
type: "warning",
duration: 1000,
});
}
});
},
},
};
</script>
<style lang="scss">
.consultationlist {
padding: 25px;
width: 100%;
background: #ffffff;
border-radius: 18px;
cursor: pointer;
.list {
display: flex;
justify-content: space-between;
.details {
width: 120px;
height: 40px;
background: rgba(68, 146, 132, 0.24);
border-radius: 20px;
opacity: 0.44;
border: 1px solid #449284;
display: flex;
justify-content: space-evenly;
align-items: center;
cursor: pointer;
.handle {
font-size: 14px;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
color: #6a7990;
line-height: 18px;
span {
font-size: 18px;
font-family: PingFangSC-Medium, PingFang SC;
font-weight: 500;
color: #449284;
}
}
.see {
span {
font-size: 14px;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
color: #6a7990;
}
}
}
.name {
font-size: 24px;
font-family: PingFangSC-Medium, PingFang SC;
font-weight: 500;
color: #063948;
}
}
.data {
margin-top: 20px;
display: flex;
justify-content: space-between;
.totallist {
font-size: 18px;
font-family: PingFangSC-Medium, PingFang SC;
font-weight: 500;
color: #063948;
line-height: 25px;
}
.statelist {
font-size: 14px;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
color: #6a7990;
}
}
}
</style>
<template>
<div class="diagnoseAdvice-wrap" v-drag v-if="showAdvice">
<div class="header">
<span class="headernum">
问诊单{{ currentAdvice.diagnoseId }} 诊断建议</span
>
<el-button @click="closeadvice">退出</el-button>
</div>
<div class="center" v-stopdrag>
<span>诊断建议</span>
<el-input
rows="10"
type="textarea"
v-model="diagnoseAdvice"
placeholder="请输入内容"
></el-input>
</div>
<div class="record">
<span>录音/录像:</span>
<div
v-if="
currentAdvice.adviceAudioUrls != undefined &&
currentAdvice.adviceAudioUrls.length > 0
"
>
<div
v-for="itemAudio in currentAdvice.adviceAudioUrls"
:key="itemAudio.diagnoseId"
>
<el-link :href="itemAudio" target="_blank">{{ itemAudio }}</el-link>
</div>
</div>
<span style="color: #0d9078" v-else>无音频</span>
</div>
<div class="record">
<span>系统录音/录像:</span>
<div
v-if="
currentAdvice.vodList != undefined && currentAdvice.vodList.length > 0
"
>
<div v-for="(itemvod, index) in currentAdvice.vodList" :key="index">
<el-link :href="itemvod.url" target="_blank">{{
itemvod.name
}}</el-link>
</div>
</div>
<span style="color: #0d9078" v-else>无视频</span>
</div>
<div class="record flex">
<span>诊断建议:</span>
<div class="record-music">
<upload-music
:musicList="illnessAudioUrls"
ref="musicComponent"
></upload-music>
</div>
</div>
<div class="footer">
<el-button type="primary" style="height: 35px" @click="SaveAdvice"
>提交保存</el-button
>
</div>
</div>
</template>
<script>
import { mapState } from "vuex";
import uploadMusic from "@/components/editor/upload-music";
export default {
components: {
uploadMusic,
},
data() {
return {
diagnoseAdvice: "",
illnessAudioUrls: [],
};
},
props: {
showAdvice: {
type: Boolean,
default: false,
},
},
watch: {
showAdvice(newVal, oldVal) {
if (newVal !== oldVal && newVal) {
const c = this.currentAdvice && this.currentAdvice.content;
console.log("ccc=cc=c=c=", c);
if (c == null) {
this.diagnoseAdvice = "";
} else {
this.diagnoseAdvice = c;
}
}
},
},
created() {},
mounted() {},
computed: {
...mapState({
currentAdvice: "currentAdvice",
}),
},
methods: {
SaveAdvice() {
if (String(this.diagnoseAdvice).trim() === "") {
this.$message({
message: "请填写诊断建议",
type: "success",
});
return false;
}
const url = this.$refs.musicComponent
? [...this.$refs.musicComponent.setNewArr()]
: [];
let params = {
adviceAudioUrls: this.currentAdvice.adviceAudioUrls,
content: this.diagnoseAdvice,
diagnoseId: this.currentAdvice.diagnoseId, //id需要获取
illnessAudioUrls: url,
};
this.POST("/diagnose/admin/diagnose/doctorAdvice/create", params)
.then((res) => {
if (res.code == "000000") {
this.$message({
message: "保存成功",
type: "success",
});
this.closeadvice();
}
})
.catch((err) => {
console.log(err);
});
},
closeadvice() {
this.diagnoseAdvice = "";
this.$store.commit("updateShowAdvice", false);
},
},
directives: {
drag: {
// 指令的定义
bind: function (el) {
let odiv = el; //获取当前元素
el.onmousedown = (e) => {
//算出鼠标相对元素的位置
let disX = e.clientX - odiv.offsetLeft;
let disY = e.clientY - odiv.offsetTop;
let left = "";
let top = "";
document.onmousemove = (e) => {
//用鼠标的位置减去鼠标相对元素的位置,得到元素的位置
left = e.clientX - disX;
top = e.clientY - disY;
//绑定元素位置到positionX和positionY上面
//移动当前元素
odiv.style.left = left + "px";
odiv.style.top = top + "px";
};
document.onmouseup = (e) => {
document.onmousemove = null;
document.onmouseup = null;
};
};
},
},
stopdrag: {
inserted: function (el, binding, vnode) {
let element = el;
element.onmousedown = function (e) {
e.stopPropagation();
};
},
},
},
};
</script>
<style lang="scss">
.diagnoseAdvice-wrap {
position: absolute;
top: 125px;
right: 20px;
z-index: 1000;
width: 500px;
//height: 600px;
padding: 5px 5px 5px 6px;
background: #ffffff;
box-shadow: 10px 10px 50px 0px #d9d9d9;
overflow: hidden;
border-radius: 18px;
.header {
height: 60px;
border-bottom: 1px rgb(231, 228, 228) solid;
display: flex;
justify-content: space-between;
padding-left: 15px;
margin-bottom: 30px;
.headernum {
font-weight: 700;
line-height: 60px;
}
.el-button {
width: 85px;
height: 25px;
margin-top: 17px;
margin-right: 17px;
line-height: 0;
border-color: #9fba81;
color: #9fba81;
> span {
font-weight: 700;
}
}
}
.center {
display: flex;
margin-right: 28px;
margin-bottom: 30px;
height: 210px;
> span {
display: inline-block;
margin-top: 5px;
width: 110px;
}
.el-textarea {
height: 110px;
.el-textarea__inner {
height: 110px;
}
}
}
.record {
padding-left: 28px;
margin-top: 45px;
}
.flex {
display: flex;
.record-music {
flex: 1;
}
}
.footer {
bottom: 0;
left: 0;
text-align: center;
margin-top: 5px;
}
}
</style>
<template>
<div class="inquiry-wrap">
<div class="line">
<div class="left">
<div>
{{ item.diagnoseLogId }}&nbsp;
<span class="dep">{{ item.department }}</span>
</div>
</div>
<div class="right">
<div
class="right-status"
:class="{ grey: item.returnStatus >= 5, org: item.returnStatus == 1 }"
>
{{ returnStatusText }}
</div>
</div>
</div>
<div class="tag-container">
<div class="talk">
<i class="talk-icon" :class="diagnoseTypeIcon"></i
><span>{{ diagnoseType }}</span>
</div>
<div class="time">
<i class="appointment"></i><span>{{ appointBeginTime }}</span
>-<span>{{ appointEndTime }}</span>
</div>
</div>
<div class="line mt30">
<div class="inquiry-user-container">
<div class="inquiry-user">
<div class="inquiry-user-l">
<div class="inquiry-user-img">
<div
class="offline"
v-if="
(diagnoseTypeIcon== 'voice') &&
(item.returnStatus == 1 || item.returnStatus == 3) &&
doctorTrtcEntryStatus != 1
"
>
<img :src="offline" alt="" />
</div>
<div class="avatar">
<el-avatar :src="item.doctorImageUrl"></el-avatar>
</div>
</div>
<div class="inquiry-user-info">
<div class="info-name-wrap">
<span class="info-name">
{{ item.doctorName }}
</span>
<span>接诊医生</span>
</div>
<div class="info-container">
<div class="info-phone">
{{ item.doctorMobile }}
</div>
<div class="info-call-time" v-if="item.doctorCallTime">
{{ pastDoctorCallTime }}前呼叫
</div>
<div class="info-calling" v-if="doctorCallKfStatus == 1">
<img :src="infocallImg" alt="" />
</div>
</div>
</div>
</div>
<div
class="call-status"
v-if="
diagnoseTypeIcon== 'voice' &&
doctorTrtcEntryStatus != 1
"
>
<img
v-if="isCall"
@click="drivingCall(item.doctorId, 2)"
:src="isDoctorChat ? callouting : callout"
alt=""
/>
</div>
</div>
<div class="line-btn" @click="openChat">
<span v-if="userCallKfStatus == 1||doctorCallKfStatus==1">正在呼叫医助,进入诊室</span>
<span v-else>进入诊室</span>
</div>
</div>
<div class="inquiry-user-container">
<div class="inquiry-user">
<div class="inquiry-user-l">
<div class="inquiry-user-img">
<div
class="offline"
v-if="
diagnoseTypeIcon== 'voice' &&
(item.returnStatus == 1 || item.returnStatus == 3) &&
userTrtcEntryStatus != 1"
>
<img :src="offline" alt="" />
</div>
<div class="avatar">
<el-avatar :src="item.userImageUrl"></el-avatar>
</div>
</div>
<div class="inquiry-user-info">
<div class="info-name-wrap">
<span class="info-name">
{{ item.userName }}
</span>
<span>助诊医生</span>
</div>
<div class="info-container">
<div class="info-phone">
{{ item.userMobile }}
</div>
<div class="info-call-time" v-if="item.userCallTime">
{{ pastUserCallTime }}前呼叫
</div>
<div class="info-calling" v-if="userCallKfStatus == 1">
<img :src="infocallImg" alt="" />
</div>
</div>
</div>
</div>
<div
class="call-status"
v-if="diagnoseTypeIcon== 'voice' &&userTrtcEntryStatus != 1"
>
<img
v-if="isCall"
@click="drivingCall(item.userId, 1)"
:src="isUserChat ? callouting : callout"
alt=""
/>
</div>
</div>
<div class="line-btn" @click="openAdvice">
诊断建议
<div
class="line-btn-tap"
v-if="item.adviceStatus && item.adviceStatus == 2"
>
未写
</div>
</div>
</div>
</div>
</div>
</template>
<script>
import { mapState } from "vuex";
export default {
data() {
return {
infocallImg: require("@/assets/image/workbench/calling.png"),
callout: require("@/assets/image/workbench/callout.png"),
callouting: require("@/assets/image/workbench/callouting.png"),
offline: require("@/assets/image/workbench/offline.png"),
timer: null,
isChat: false,
isUserChat: false,
isDoctorChat: false,
isCall: false,
accId: "",
};
},
props: {
item: {
type: Object,
default: {},
},
},
created() {},
mounted() {
console.log("this.item", this.item);
if (this.item.returnStatus == 1 || this.item.returnStatus == 3) {
let nowData = new Date().getTime();
let timeleft = this.item.appointBeginTime - nowData;
if (timeleft < 120000 && nowData < this.item.appointEndTime) {
clearInterval(this.timer);
this.down();
} else {
this.isCall = true;
}
}
},
computed: {
...mapState({
showChat: "showChat",
showAdvice: "showAdvice",
}),
diagnoseType() {
switch (this.item.diagnoseType) {
case 1:
return "语音问诊";
case 2:
return "视频问诊";
case 3:
return "图文问诊";
default:
return "";
}
},
diagnoseTypeIcon() {
switch (this.item.diagnoseType) {
case 1:
return "voice";
case 2:
return "voice";
case 3:
return "photo";
default:
return "photo";
}
},
returnStatusText() {
switch (this.item.returnStatus) {
case 1:
return "待处理";
case 2:
return "待问诊";
case 3:
return "问诊进行中";
case 4:
return "问诊已完成";
case 5:
return "已取消";
default:
return "暂无";
}
},
appointBeginTime() {
return new Date(this.item.appointBeginTime).format("yyyy-MM-dd hh:mm");
},
appointEndTime() {
return new Date(this.item.appointEndTime).format("hh:mm");
},
userCallTime() {
return new Date(this.item.userCallTime).format("hh:mm");
},
// 助诊呼叫状态
userCallKfStatus() {
return this.item.userCallKfStatus;
},
// 接诊呼叫状态
doctorCallKfStatus() {
return this.item.doctorCallKfStatus;
},
// 接诊 在线状态
doctorTrtcEntryStatus() {
return this.item.doctorTrtcEntryStatus;
},
// 助诊 在线状态
userTrtcEntryStatus() {
return this.item.userTrtcEntryStatus;
},
pastUserCallTime() {
if (this.item.userCallTime) {
return this.formatDateData(this.item.userCallTime);
} else {
return null;
}
},
doctorCallTime() {
return new Date(this.item.doctorCallTime).format("hh:mm");
},
pastDoctorCallTime() {
if (this.item.doctorCallTime) {
return this.formatDateData(this.item.doctorCallTime);
} else {
return null;
}
},
nowtime() {
return new Date().getTime() - this.item.appointBeginTime;
},
},
methods: {
formatDateData(time) {
let now_data = new Date().getTime();
let my_time = now_data - time;
let hours = my_time / 1000 / 60 / 60;
let hoursRound = Math.floor(hours);
let minutes = my_time / 1000 / 60 - 60 * hoursRound;
let minutesRound = Math.floor(minutes);
let seconds = (
my_time / 1000 -
60 * 60 * hoursRound -
60 * minutesRound
).toFixed(0);
if (hoursRound > 0 && minutesRound > 0) {
return hoursRound + "小时" + minutesRound + "分" + seconds + "秒";
}
if (hoursRound == 0 && minutesRound > 0) {
return minutesRound + "分";
}
if (hoursRound == 0 && minutesRound == 0) {
return seconds + "秒";
}
},
down() {
this.timer = setInterval(() => {
let nowData = new Date().getTime();
let timeleft = this.item.appointBeginTime - nowData;
if (timeleft < 120000 && nowData < this.item.appointEndTime) {
this.isCall = true;
clearInterval(this.timer);
}
}, 1000);
},
getInfo(id) {
let url = `/im/team/detail?tid=${this.item.imTeamId}`;
return this.GET(url)
.then((res) => {
if (res.code == "000000") {
let { memberList } = res.data;
console.log("---memberList", memberList);
if (memberList) {
let accId = memberList.filter((val) => {
return val.id == id;
});
return accId[0].accId;
}
}
})
.catch(() => {});
},
// 主动呼叫 roletype 1:助诊医生 2:接诊医生
drivingCall(id, roletype) {
if (roletype == 1 && this.isUserChat) {
return false;
}
if (roletype == 2 && this.isDoctorChat) {
return false;
}
this.getInfo(id).then((res) => {
console.log(res);
let url = `/im/team/call/direct/`;
let params = {
imAccId: res,
imTeamId: this.item.imTeamId,
liveRoomId: this.item.roomId,
};
this.POST(url, params).then((res) => {
if (res.code === "000000") {
if (roletype == 1) {
this.isUserChat = true;
} else {
this.isDoctorChat = true;
}
} else {
this.$message({
message: res.message,
type: "warning",
});
}
});
});
},
openChat() {
if (this.showChat) {
this.$message({
message: "不可同时进入多个诊室,请先退出已进入的诊室,再试。",
type: "warning",
duration: 1000,
});
return false;
}
const i = this.item;
// this.$store.commit("updateCurrentChat", i);
this.$store.dispatch("gotoInquiry", i);
},
openAdvice() {
if (this.showAdvice) {
this.$message({
message: "不可同时打开多个诊断建议,请先退出已打开的诊断建议,再试。",
type: "warning",
duration: 1000,
});
return false;
}
const i = this.item.diagnoseLogId;
// const i = 11;
this.GET(`/diagnose/admin/diagnose/doctorAdvice/list/${i}`)
.then((res) => {
if (res.code == "000000") {
console.log(res.data);
this.$store.commit("updateShowAdvice", true);
this.$store.commit("updateCurrentAdvice", res.data);
} else {
this.$message({
message: res.message,
type: "warning",
duration: 1000,
});
}
})
.catch((err) => {
console.log(err);
});
},
},
};
</script>
<style lang="scss" scoped>
.inquiry-wrap {
box-sizing: border-box;
margin-bottom: 10px;
padding: 20px 32px;
background: #ffffff;
border-radius: 18px;
user-select: none;
// min-width: 610px;
border: 1px solid #cccccc;
.line {
display: flex;
justify-content: space-between;
.left {
color: #02120f;
font-size: 28px;
.dep {
font-size: 20px;
}
}
.right {
.right-status {
color: #0d9078;
font-size: 14px;
}
.right-time {
margin-top: 5px;
color: #6a7990;
font-size: 12px;
}
.grey {
color: #6a7990;
}
.org {
color: #ff5e57;
}
}
.inquiry-user-container {
width: 49%;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
.inquiry-user {
width: calc(100% - 10px);
display: flex;
justify-content: space-between;
margin-bottom: 20px;
padding: 0 5px;
.inquiry-user-l {
display: flex;
flex-direction: row;
justify-content: center;
align-items: center;
.inquiry-user-img {
display: flex;
flex-direction: column;
justify-content: center;
position: relative;
width: 40px;
height: 40px;
.offline {
position: absolute;
left: -4px;
top: -4px;
z-index: 10;
}
.avatar {
position: absolute;
left: 0;
top: 0;
background: #dddddd;
border-radius: 36px;
display: flex;
flex-direction: column;
justify-content: center;
}
}
.inquiry-user-info {
font-size: 14px;
margin-left: 15px;
display: flex;
flex-direction: column;
justify-content: center;
.info-name-wrap {
display: flex;
align-items: center;
}
.info-name {
display: inline-block;
max-width: 85px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
font-size: 18px;
color: #02120f;
font-weight: bold;
}
.info-container {
display: flex;
justify-content: flex-start;
align-items: center;
flex-direction: row;
height: 25px;
line-height: 25px;
.info-phone {
color: #6a7990;
font-size: 16px;
}
.info-call-time {
color: #ff5e57;
}
.info-calling {
width: 15px;
height: 25px;
display: flex;
justify-content: center;
align-items: center;
img {
width: 15px;
height: 15px;
}
}
}
}
}
.call-status {
width: 45px;
height: 46px;
img {
cursor: pointer;
width: 45px;
height: 46px;
}
}
}
}
.line-btn {
cursor: pointer;
position: relative;
width: 100%;
height: 37px;
background: rgba(68, 146, 132, 0.09);
border-radius: 23px;
border: 1px solid rgba(68, 146, 132, 0.31);
text-align: center;
line-height: 37px;
color: #0d9078;
font-size: 14px;
font-weight: bold;
.line-btn-tap {
position: absolute;
top: -10px;
right: 20px;
width: 48px;
height: 20px;
background: #0d9078;
border-radius: 7px 7px 7px 0px;
font-size: 14px;
color: #ffffff;
line-height: 20px;
}
span {
font-weight: bold;
}
}
}
.tag-container {
display: flex;
justify-content: flex-start;
.talk {
margin-right: 5px;
width: 120px;
height: 24px;
line-height: 24px;
background: #f0f2f5;
border-radius: 23px;
font-size: 14px;
color: #6a7990;
display: flex;
justify-content: center;
align-items: center;
.talk-icon {
margin-right: 5px;
}
}
.time {
display: flex;
justify-content: center;
align-items: center;
width: 217px;
height: 24px;
line-height: 24px;
background: #f0f2f5;
border-radius: 23px;
font-size: 14px;
color: #6a7990;
}
}
.mt30 {
margin-top: 30px;
}
.mt20 {
margin-top: 20px;
}
.appointment {
width: 12px;
height: 12px;
display: inline-block;
background: url("../../assets/image/workbench/appointment.png") no-repeat;
background-size: cover;
margin-right: 5px;
}
.video {
width: 12px;
height: 12px;
display: inline-block;
background: url("../../assets/image/workbench/video.png") no-repeat;
background-size: cover;
}
.photo {
width: 12px;
height: 12px;
display: inline-block;
background: url("../../assets/image/workbench/photo.png") no-repeat;
background-size: cover;
}
.voice {
width: 12px;
height: 12px;
display: inline-block;
background: url("../../assets/image/workbench/voice.png") no-repeat;
background-size: cover;
}
}
</style>
......@@ -49,6 +49,8 @@ const router = new VueRouter({
}
})
Vue.use(TRTC)
window.TRTC = TRTC
Vue.use(TIM)
......
......@@ -10,6 +10,9 @@ const diagnosisEditor = r => require.ensure([], () => r(require('../views/IM/dia
const diagnosisListNew = r => require.ensure([], () => r(require('../views/IM/diagnosis-admin/diagnosis-list-new.vue')), 'diagnosisListNew')
const downList = r => require.ensure([], () => r(require('../views/IM/diagnosis-admin/down-list.vue')), 'downList')
const operation= r => require.ensure([], () => r(require('../views/IM/diagnosis-admin/operation.vue')), 'downList')
const workbench= r => require.ensure([], () => r(require('../views/IM/diagnosis-admin/workbench.vue')), 'workbench')
const administrators= r => require.ensure([], () => r(require('../views/IM/diagnosis-admin/administrators.vue')), 'administrators')
export default [{
path: '/',
component: App,
......@@ -48,6 +51,13 @@ export default [{
},{
path: '/operation',
component: operation
},
{
path: '/workbench',
component: workbench
},{
path:'/administrators',
component:administrators
}
]
}]
export default {
gotoInquiry ({ commit }, current) {
if(current.imTeamId){
const params = {
teamIdList: [current.imTeamId]
}
_VM.POST(`/im/team/call/op/ack/`,params).then(res=>{
if(res.code == '000000'){
commit('updateShowChat', true);
commit('updateCurrentChat', current);
}
}).catch(err=>{
_VM.$message({
message: err.message,
type: "warning",
duration:1000
});
})
}
},
}
import education from './im/getters'
import { containObject } from '../utils/utils'
const getters = containObject(education)
const getters = {
_token: state => state.common._token,
isFromAssignTask: state => state.common.isFromAssignTask,
time:state => state.common.time,
}
export default getters
const getters = {
_token: state => state.common._token,
isFromAssignTask: state => state.common.isFromAssignTask,
time:state => state.common.time,
}
export default getters
import Vue from 'vue'
import Vuex from 'vuex'
import common from './im/common'
import common from './module/common'
import socket from './module/socket'
import getters from './getters'
import state from './state';
import mutations from './mutations/index';
import actions from './actions/index';
Vue.use(Vuex)
export default new Vuex.Store({
state,
getters,
mutations,
actions,
modules: {
common
common,
socket
},
getters
})
// ES6 import
import store from '../';
import storejs from 'storejs';
import io from 'socket.io-client';
let socketTimer = null;
export default {
namespaced: true,
state: {
socketClient: null,
},
actions: {
initSocket ({ commit, rootState }, payload) {
console.log('-=-=-initSocket次数',)
const socket = io.connect(payload.url, {
query: {
loginUserNum: `diagnose_list_socket_${payload.userId}`,
reconnection: false
}
});
commit('SET_SOCKET', socket);
commit('SET_IOLISTION');
},
},
mutations: {
SET_SOCKET: (state, payload) => {
window.socketClient = payload;
state.socketClient = payload;
},
SET_IOLISTION: (state, payload) => {
if(!state.socketClient){
return false;
}
state.socketClient.on("connect", (socket) => {
console.log ('socket 链接成功',socket);
console.log ('socketTimer---',socketTimer);
if(socketTimer){
clearInterval(socketTimer);
}
});
state.socketClient.on("connect_error", (err) => {
console.log ('socket connect_error',err);
});
state.socketClient.on("disconnect", (socket) => {
console.log ('socket disconnect----',socket);
store.commit('socket/RECONNECT_SOCKET');
});
state.socketClient.on("diagnose_push_event", (socket) => {
console.log('diagnose_push_event---', socket);
const {list,allSize,countRespList} = socket;
console.log('--_VM', _VM.$route)
store.commit('updateCurrentDiagList', list);
store.commit('updateAllSize', allSize);
store.commit('updateCurrentCalList', countRespList);
});
state.socketClient.on("diagnose_call_push_event", (socket) => {
console.log('diagnose_call_push_event---', socket);
const l = store.state.noticeList;
if(l.length >=5){
l.shift();
}
l.push(socket);
const n = {notifyIndex: l.length, ...socket}
store.commit('updateNoticeList', l);
console.log('--_VM', _VM)
const {path} =_VM.$route;
console.log("n--------",n)
const operateUserId=store.state.soketQuest.operateUserId?store.state.soketQuest.operateUserId:''
if(path && String(path).indexOf('workbench') > -1&&n.operateUserId==operateUserId){
store.commit('socket/SET_NOTIFY', n);
}
});
state.socketClient.on('ping', function () {
console.log('[E] 心跳请求已发出 →', true, socketTimer);
if(socketTimer){
clearInterval(socketTimer);
}
});
//收到
state.socketClient.on('pong', function () {
console.log('[E] 心跳响应已收到 ←', true);
});
state.socketClient.io.on("reconnect_attempt", (socket) => {
console.log('--reconnect_attempt', socket);
// ...
});
state.socketClient.on("reconnect", (socket) => {
console.log('--reconnect', socket);
// ...
});
},
SET_NOTIFY: (state, payload) => {
console.log('--payload', payload)
let doms = document.getElementsByClassName('el-notification')
if (doms.length >= 5) return
const h = _VM.$createElement;
const t = payload.department ? `问诊单${payload.diagnoseLogId}(${payload.department})` : `问诊单${payload.diagnoseLogId}`
// userCallKfStatus 医助呼叫
// doctorCallKfStatus 医生呼叫
let name= payload.userCallKfStatus==1 ? payload.userName:payload.doctorName
const cn = _VM.$notify({
title: t,
message: h("p", [
h("i", {style: `color: teal;`}, `${name}正在呼叫你`),
h(
"el-button",
{
style: `float:right;margin-top:${30}px;`,
on: {
click: function () {
console.log('----state', state)
if(state.showChat){
_VM.$message({
message: '不可同时进入多个诊室,请先退出已进入的诊室,再试。',
type: "warning",
duration:1000
});
return false;
}
store.dispatch('gotoInquiry', payload);
cn.close();
},
},
},
"进入诊室"
),
]),
onClose: function () {
console.log('--onClose',payload )
},
duration: 5000,
position: 'top-right',
})
},
RECONNECT_SOCKET: (state, payload) => {
if(socketTimer){
console.log('RECONNECT_SOCKET--已经存在');
}else{
const i = storejs.get('initSocketInfo');
console.log('RECONNECT_SOCKET-- 重新链接', i);
socketTimer = setInterval(function (){
console.log('----initSocketInfo', i);
store.dispatch( 'socket/initSocket', i)
}, 2000);
}
}
},
};
import storejs from 'storejs';
export default {
updateCurrentDiagList(state, obj) {
state.currentDiagList = obj;
},
updateAllSize(state,allSize){
state.allSize = allSize;
},
// 改变原数据
changeRawCurrentCalList(state,obj){
// console.log("obj",obj)
let index = state.RawCurrentCalList.findIndex(val=>{
return val.status==obj.status
})
if(index>-1){
state.RawCurrentCalList[index]=obj
state.currentCalList[index].is_dot=false
}
},
clearRawCurrentCalList(state){
state.RawCurrentCalList=[]
},
updateCurrentCalList(state, obj) {
let NewData=obj
if(state.RawCurrentCalList.length==0){
state.RawCurrentCalList=obj
}
let RawData=state.RawCurrentCalList
for (let i = 0; i < NewData.length; i++) {
let is_dot = false;
if (RawData.length > 0) {
is_dot = NewData[i].count > RawData[i].count ? true: false;
}
NewData[i] = {
...NewData[i],
is_dot: is_dot,
};
}
state.currentCalList = NewData;
},
updateCurrentChat(state, obj) {
state.currentChat = obj;
},
updateCurrentAdvice(state, obj) {
state.currentAdvice = obj;
},
updateSoketQuest(state, obj) {
storejs.set('soketQuest',obj);
state.soketQuest = obj;
},
updateShowChat(state, obj) {
state.showChat = obj;
},
updateShowAdvice(state, obj) {
state.showAdvice = obj;
},
updateNoticeList(state, obj) {
state.noticeList = obj;
},
updateIsSuperAdmin(state, obj) {
state.isSuperAdmin = obj;
},
};
/* 内存数据状态 */
export default {
currentDiagList:[],
allSize:0,
currentCalList:{},
RawCurrentCalList:[],
currentChat: {},
currentAdvice: {},
soketQuest: {},
noticeList: [],
showChat:false,
showAdvice:false,
isSuperAdmin: {
isSuper:false,
userID: ''
}
};
......@@ -128,7 +128,7 @@ html,body{
// width: 163vh !important;
// height: 66vh !important;
// height: 430px !important;
margin: 20px 30px 0px;
margin: 10px 10px 0px;
overflow: auto;
}
}
......@@ -138,7 +138,7 @@ html,body{
// height: 78vh !important;
// height: 800px !important;
overflow: auto;
margin: 20px 30px 0px;
margin: 10px 10px 0px;
}
}
......@@ -174,7 +174,7 @@ html,body{
// 消息推送
.el-notification.right {
top: 130px !important;
//top: 130px !important;
}
// 弹框按钮样式
......
class RtcClient {
constructor(options) {
this.sdkAppId_ = options.sdkAppId;
this.userId_ = options.userId;
this.userSig_ = options.userSig;
this.roomId_ = options.roomId;
this.role = options.role; // 用户的角色主播还是观众(这里的指的是trtc定义的anchor和audience)
this.nick = options.nick;
this.vueInstance = options.vueInstance;
this.isJoined_ = false;
this.isPublished_ = false;
this.isAudioMuted = false;
this.isVideoMuted = false;
this.localStream_ = null;
this.remoteStreams_ = [];
this.members_ = new Map();
this.inmembers_ = new Map();
this.viewslist = [];
this.isPushing = 0;
try {
this.client_ = TRTC.createClient({
mode: 'live',
sdkAppId: this.sdkAppId_,
userId: this.userId_,
userSig: this.userSig_
});
this.handleEvents();
} catch (error) {
console.log('创建client失败', error)
this.vueInstance.reloadfn()
}
}
// 加入房间
async join() {
if (this.isJoined_) {
alert('抱歉,您已经在房间里面为了')
return;
}
try {
await this.client_.join({
roomId: this.roomId_,
role: this.role
});
console.log('加入房间trtc成功');
this.isJoined_ = true;
// 不要指定cameraId/microphoneId以避免过度约束
this.localStream_ = TRTC.createStream({
audio: true,
video: false,
userId: this.userId_,
mirror: true
});
this.startRTC()
} catch (e) {
console.error('加入房间失败 ' + e);
this.vueInstance.reloadfn()
}
}
// 打开摄像头
async startRTC() {
// 连麦观众角色切换为主播,开始推流
// 设置视频分辨率等参数
this.localStream_.setVideoProfile({
width: this.vueInstance.viedoParams.webVideoWidth,
height: this.vueInstance.viedoParams.webVideoHeight,
frameRate: this.vueInstance.viedoParams.webVideoFramerate,
bitrate: this.vueInstance.viedoParams.webVideoBitrate /* kpbs */
});
// 避免重复开摄像头
this.stopPush()
}
// 设置本地流
async setLocalVideo() {
if (!this.isJoined_) {
console.warn('请先加入房间');
return;
}
if (this.isPublished_) {
console.warn('您已经发布过了');
return;
}
try {
this.localStream_.initialize().catch(error => {
this.vueInstance.$message({
message: '打开设备失败,请检查您的设备!',
type: 'error'
});
console.error('failed initialize localStream ' + error);
}).then(() => {
// 本地流在主播放器上播放,并且插入到一个关联的box中
var localVideoWrapEl = document.getElementById('ask');
this.localStream_.play(localVideoWrapEl, {
muted: true
});
//主播直接推流
if (this.role == 'anchor') {
this.publish()
}
}).catch(error => {
this.vueInstance.$message({
message: '麦克风打开失败!',
type: 'error'
});
});
} catch (e) {
this.isPublished_ = false;
}
this.isPublished_ = true;
}
//发布本地流
async publish() {
this.client_ && this.client_.publish(this.localStream_).then(() => {
console.log('本地流发布成功')
this.isPublished_ = true;
// 手动将麦克风打开
this.unmuteLocalAudio()
}).catch(error => {
console.log('本地流发布失败')
this.isPublished_ = false;
this.vueInstance.reloadfn()
});
}
/**
* 为避免重复推流,先结束当前推流
*/
async stopPush() {
if (this.localStream_ && this.isPublished_ && this.isJoined_) {
this.client_.unpublish(this.localStream_).then(() => {
this.isPublished_ = false;
this.localStream_.stop();
this.setLocalVideo()
});
} else {
this.setLocalVideo()
}
}
// 退出
async leave() {
if (!this.isJoined_) {
console.warn('leave() - please join() firstly');
return;
}
// 如果是正在发布流,就先停止流
await this.unpublish();
// 离开房间
await this.client_.leave();
if (this.localStream_) {
this.muteLocalAudio()
this.localStream_.stop();
this.localStream_.close();
this.localStream_ = null;
}
this.isJoined_ = false;
}
// 退出本地流
async unpublish() {
if (!this.isJoined_) {
console.warn('unpublish() - please join() firstly');
return;
}
if (!this.isPublished_) {
console.warn('RtcClient.unpublish() called but not published yet');
return;
}
await this.client_.unpublish(this.localStream_);
this.isPublished_ = false;
}
//禁用音频轨道
//对于本地流,调用该方法会停止发送音频,远端会触发 Client.on('mute-audio') 事件。
//对于远端流,调用该方法会停止播放音频,但是仍然接收音频数据。
muteLocalAudio() {
console.log('--this.localStream_', this.localStream_);
this.localStream_.muteAudio();
}
//启用音频轨道
//对于本地流,调用该方法会触发远端 Client.on('unmute-audio') 事件。
//音频轨道默认是开启的,若你调用 muteAudio() 后可用该方法重新启用音频。
unmuteLocalAudio() {
this.localStream_.unmuteAudio();
}
// 禁用视频轨道
// 对于本地流,调用该方法会停止发送视频,远端会触发 Client.on('mute-video') 事件。
// 如果视频是从摄像头采集,此时摄像头灯仍然是亮着的。若想完全禁用视频轨道(即关闭摄像头) ,
// 可以使用 removeTrack() 删除视频轨道然后调用 MediaStreamTrack.stop() 关闭视频轨道(关闭摄像头)。
// 对于远端流,调用该方法会停止播放视频,但是仍然接收视频数据.
muteLocalVideo() {
this.localStream_.muteVideo();
}
//恢复播放音视频
//在某些版本浏览器上移动传入 play() 的 div 容器可能会导致音视频播放器进入 ‘PAUSED’ 状态,此时 需要调用该接口恢复播放。
//由于浏览器自动播放策略的限制,在 play() 返回 PLAY_NOT_ALLOWED 错误后需要引导用户通过手势 调用该接口恢复播放
resumeStreams() {
this.localStream_.resume();
for (let stream of this.remoteStreams_) {
stream.resume();
}
}
// client的一些事件监听
handleEvents() {
// 报错
this.client_.on('error', err => {
console.log('client 报错了--------------------------------------------------------------')
console.log(err)
// alert(err);
window.onbeforeunload = null
location.reload();
});
// 房间被解散了
this.client_.on('client-banned', err => {
console.log('房间被解散了');
});
// 当一个远程同伴(必须推流)进入房间时触发
this.client_.on('peer-join', evt => {
const userId = evt.userId;
console.log('有远程同伴进入房间:', userId)
});
// 当远处的同伴离开房间时触发(删减好友列表)
this.client_.on('peer-leave', evt => {
const userId = evt.userId;
console.log('有远程同伴离开房间:' + userId);
this.removeUserList(userId)
});
// 在添加远程流时触发
this.client_.on('stream-added', evt => {
const remoteStream = evt.stream;
// 获取流的StreamId
const id = remoteStream.getId();
// 获取UserId
const userId = remoteStream.getUserId();
this.members_.set(userId, remoteStream);
this.inmembers_.set(userId, remoteStream);
console.log(`remote stream added: [${userId}] ID: ${id} type: ${remoteStream.getType()}`);
// 我们订阅远端的流
console.log('subscribe to this remote stream');
this.client_.subscribe(remoteStream);
});
// 在订阅远程流时触发
this.client_.on('stream-subscribed', evt => {
const remoteStream = evt.stream;
const id = remoteStream.getId();
const uid = remoteStream.userId_;
this.remoteStreams_.push(remoteStream);
remoteStream.on('player-state-changed', event => {
console.log(`${event.type} player is ${event.state}`);
// 远端流是播放还是暂停状态(显示按钮等画面不同)
if (event.type == 'video' && event.state == 'STOPPED') {
console.log(`${uid}----------远端流为停止`);
this.changeView(uid, 'mask', true)
}
if (event.type == 'video' && event.state == 'PAUSED') {
console.log(`${uid}----------远端流为暂停`);
this.changeView(uid, 'mask', true)
}
if (event.type == 'video' && event.state == 'PLAYING') {
console.log(`${uid}----------远端流为播放`);
this.changeView(uid, 'mask', false)
}
});
// 避免重复加载
for (let i = 0; i < this.viewslist.length; i++) {
if (this.viewslist[i] && uid == this.viewslist[i].userId) {
return
}
}
let isMask = false
// this.viewslist.push({ id: id, userId: uid, nick: uid, mask: isMask, vioce: true })
this.add(id, uid, isMask)
this.vueInstance.addNewMember(uid)
setTimeout(() => {
// 避免其他乱入视频
let index = this.viewslist.findIndex((item => {
if (item && item.userId) {
return item.userId == uid
} else {
return -1
}
}))
if (index < 0) {
return
}
// 播放视频
remoteStream.play(id);
if (!remoteStream.hasVideo()) {
this.changeView(id, 'mask', true)
}
if (!remoteStream.hasAudio()) {
this.changeView(id, 'vioce', false)
}
}, 1000)
});
// 当远程流被移除时触发
this.client_.on('stream-removed', evt => {
const remoteStream = evt.stream;
const id = remoteStream.getId();
const uid = remoteStream.userId_;
console.log(`${uid}------------远程流被移除时触发`);
// 停止播放并删除相应<video>标签
remoteStream.stop();
this.inmembers_.delete(uid)
this.remoteStreams_ = this.remoteStreams_.filter(stream => {
return stream.getId() !== id;
});
this.removeUserList(uid)
});
// 流更新
this.client_.on('stream-updated', evt => {
console.log('=========流更新========stream-updated===================');
console.log(evt);
const remoteStream = evt.stream;
let uid = this.getUidByStreamId(remoteStream.getId());
// remoteStream.hasVideo() // 是否有视频轨道
// remoteStream.hasAudio() //是否有音轨道
// remoteStream.getType() // 主要用于判断一个远端流是主音视频流还是辅路视频流,辅路视频流通常是一个屏幕分享流。
console.log('remoteStream ID: ' + remoteStream.getId() + ' was updated hasAudio: ' +
remoteStream.hasAudio() + ' hasVideo: ' + remoteStream.hasVideo());
});
// 关闭音轨道
this.client_.on('mute-audio', evt => {
this.changeView(evt.userId, 'vioce', false)
console.log(evt.userId + '关闭麦克风============================================');
});
// 打开音轨道
this.client_.on('unmute-audio', evt => {
this.changeView(evt.userId, 'vioce', true)
if (evt.type == 'audio' && evt.state == 'PLAYING' && this.vueInstance.type == 1) {
this.changeView(evt.userId, 'mask', true)
}
});
//关闭视频轨道
this.client_.on('mute-video', evt => {
console.log(evt.userId + '关闭 video==============================================');
this.changeView(evt.userId, 'mask', true);
});
// 打开视频轨道
this.client_.on('unmute-video', evt => {
console.log(evt.userId + '打开 video=============================================');
if (this.members_.get(evt.userId)) {
this.changeView(evt.userId, 'mask', false);
}
});
}
getUidByStreamId(streamId) {
for (let [uid, stream] of this.members_) {
if (stream.getId() == streamId) {
return uid;
}
}
}
// 移除视频数组
removeUserList(userId) {
for(let i = 0; i < this.viewslist.length; i++) {
if (this.viewslist[i] && this.viewslist[i].userId == userId) {
this.viewslist[i] = null
}
}
this.vueInstance.removeMember(userId)
};
// 改变视频数组属性
changeView(id,attr,val) {
for (let i = 0; i < this.viewslist.length; i++) {
if (this.viewslist[i] && (this.viewslist[i].userId == id || this.viewslist[i].id == id)) {
this.viewslist[i][attr] = val
}
}
}
add(id, uid, isMask) {
this.vueInstance.memberList.forEach((ele,index) => {
if (ele.liveUserId == uid) {
this.viewslist[index] = { id: id, userId: uid, nick: uid, mask: isMask, vioce: true }
}
});
}
}
export default RtcClient
......@@ -86,7 +86,7 @@ const vueFilter = {
},
dateFilter: (value) => {
if (!value) return '';
return new Date(value).format("yyyy-MM-dd hh:mm");
return new Date(value).format("yyyy-MM-dd");
},
moduleTypeFilter: (value, data) => { // 模块类型
for (let key in data) {
......
......@@ -54,7 +54,7 @@ class RtcClient {
userId: this.userId_,
mirror: true
});
this.startRTC()
// this.startRTC()
} catch (e) {
console.error('加入房间失败 ' + e);
this.vueInstance.reloadfn()
......@@ -425,5 +425,4 @@ class RtcClient {
}
}
export default RtcClient
......@@ -816,3 +816,41 @@ const change = (num) => {
}
return num;
}
// 拖拽
export const bindDragHeader = (classname,content) =>{
const dragDom = document.querySelector(classname);
const con = document.querySelector(content);
let translate,contranslate;
dragDom.onmousedown = (e) => {
const disX = e.clientX;
const disY = e.clientY;
translate = dragDom.style.transform.replace(/[^0-9\-,]/g,'').split(',');
contranslate = con.style.transform.replace(/[^0-9\-,]/g,'').split(',');
con.style.transition = "transform 100ms liner";
document.onmousemove = function (e) {
const l = e.clientX - disX;
const t = e.clientY - disY;
let x, y, tran;
if(contranslate.length> 1){
x= (l+ Number(contranslate[0])) + 'px';
y = (t + Number(contranslate[1])) + 'px';
}else{
x= (l) + 'px';
y = (t ) + 'px';
}
tran = `translate(${x},${y})`;
con.style.transform = tran;
};
document.onmouseup = function (e) {
document.onmousemove = null;
document.onmouseup = null;
};
}
}
<template>
<div class="administrators">
<!-- 头部 -->
<div class="header">
<!-- 面包屑 -->
<el-breadcrumb separator="/">
<el-breadcrumb-item>首页</el-breadcrumb-item>
<el-breadcrumb-item>我的工作台</el-breadcrumb-item>
</el-breadcrumb>
<el-row style="margin-top: 30px">
<el-col :span="12">
<div class="left">
<el-row type="flex" justify="space-between" :gutter="70">
<el-col :span="12">
<el-date-picker
style="margin-top: 10px"
v-model="workbenchAdminDate"
type="date"
value-format="yyyy-MM-dd"
placeholder="选择日期"
>
</el-date-picker>
</el-col>
</el-row>
</div>
</el-col>
</el-row>
</div>
<!-- 问诊列表 -->
<div class="consultation-container">
<div v-if="operatorslist" class="consultation-content">
<div
class="consultation-li"
v-for="(item, index) in operatorslist"
:key="index"
>
<consultationlist
:workbenchAdminDate="workbenchAdminDate"
:operatorsItem="item"
></consultationlist>
</div>
</div>
<div v-else class="nodata-container">
<img src="../../../assets/image/workbench/no_data_wz.png" alt="" />
<div class="nodata-title">暂无数据</div>
</div>
</div>
</div>
</template>
<script>
import consultationlist from "../../../components/common/consultation";
export default {
components: {
consultationlist,
},
data() {
const d =
localStorage.getItem("workbenchAdminDate") ||
new Date().format("yyyy-MM-dd");
return {
workbenchAdminDate: d,
operatorslist: [],
};
},
created() {
this.init();
},
watch: {},
methods: {
init() {
this.GET("/diagnose/match/list").then(({ code, data }) => {
if (code == "000000") {
this.operatorslist = data;
}
});
},
},
};
</script>
<style lang="scss" scoped>
.administrators {
height: calc(100% - 76px);
.header {
padding: 30px;
width: 100%;
background: #ffffff;
.el-input__inner {
width: 173px;
height: 47px;
background: #ffffff;
border-radius: 7px;
border: 1px solid #d9d9d9;
}
}
.detailslist {
display: flex;
// flex-wrap: wrap;
flex-direction: column;
.details {
flex: 1;
width: 572px;
height: 164px;
background: #ffffff;
border-radius: 18px;
}
}
.total {
width: 62px;
height: 40px;
font-size: 28px;
font-family: PingFangSC-Medium, PingFang SC;
font-weight: 500;
color: #063948;
line-height: 40px;
margin: 0 auto;
}
.state {
width: 28px;
height: 20px;
font-size: 14px;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
color: #6a7990;
line-height: 20px;
margin: 0 auto;
}
.consultation-container {
overflow-y: scroll;
height: calc(100% - 154px);
width: 100%;
padding: 20px;
.consultation-content {
display: grid;
grid-template-columns: 33.3% 33.3% 33.3%;
grid-row-gap: 20px;
// grid-column-gap: 20px;
overflow: hidden;
.consultation-li {
width: 90%;
margin: 0 auto;
display: flex;
justify-content: center;
}
}
.nodata-container {
background-color: #fff;
padding: 0 20px;
border-radius: 18px;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
height: 470px;
.nodata {
width: 100%;
}
img {
width: 298px;
height: 140px;
}
.nodata-title {
font-size: 18px;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
color: #6a7990;
margin-top: 50px;
}
}
}
.footer {
margin-top: 20px;
width: 100%;
height: 71px;
background: #ffffff;
border-radius: 18px;
padding-top: 20px;
}
}
.el-row {
margin-bottom: 20px;
&:last-child {
margin-bottom: 0;
}
}
.el-col {
border-radius: 4px;
}
.bg-purple-dark {
background: #99a9bf;
}
.bg-purple {
background: #d3dce6;
}
.bg-purple-light {
background: #e5e9f2;
}
.grid-content {
border-radius: 4px;
min-height: 36px;
}
.row-bg {
padding: 10px 0;
background-color: #f9fafc;
}
</style>
......@@ -271,6 +271,7 @@ export default {
created() {
_this = this;
console.log(_this);
this.picakfAccId = getPicaKFAccid();
this.tid = this.$route.query.tid || '';
this.getFiveContentList();
......
......@@ -99,7 +99,6 @@
</div>
</template>
<script>
import RtcClient from "@/utils/live/rtc-client.js";
import {
getLiveTimeText,
countDown,
......@@ -107,6 +106,7 @@ import {
laseTime,
lastm,
} from "@/utils/live";
import RtcClient from "../../../utils/live/RtcClient.js";
import { openLoading, closeLoading } from "@/utils/utils";
import alert from "@/components/common/alert.vue";
import timeLeft from "@/components/timeLeft";
......@@ -390,7 +390,6 @@ export default {
},
// 显示文案
showText(status, role, item) {
console.log("status", status);
// 1 呼叫中 2 接入 3离线
if (item.status == 2) {
item.timeleft = 0;
......@@ -555,19 +554,19 @@ export default {
// 获取信息失败
getErr() {
closeLoading(this);
this.$nextTick(() => {
this.$refs.alert
.init({
confirmTxt: "我知道了",
title: `获取信息失败,请稍后重试`,
})
.then(() => {
this.$router.go(-1);
})
.catch((err) => {
this.$router.go(-1);
});
});
// this.$nextTick(() => {
// this.$refs.alert
// .init({
// confirmTxt: "我知道了",
// title: `获取信息失败,请稍后重试`,
// })
// .then(() => {
// // this.$router.go(-1);
// })
// .catch((err) => {
// // this.$router.go(-1);
// });
// });
},
reloadfn(msg) {
this.$nextTick(() => {
......
<template>
<div class="workbench-container">
<div class="select-content">
<div class="title">我的工作台</div>
<div @click="socketRE">socket 测试</div>
<!-- 时间 -->
<div class="search-box">
<div class="search-item">
<el-date-picker
@change="changeDatetime"
v-model="searchParam.dateTime"
type="date"
size="small"
clear-icon="el-input-icon"
:clearable="false"
>
</el-date-picker>
</div>
</div>
<!-- tab栏 -->
<el-radio-group
@change="tabChange"
v-model="tabPosition"
class="workbench-tab"
>
<el-radio-button
v-for="(item, index) in currentCalList"
:key="'for' + index"
:label="item.status"
>
{{ item.statusStr }}({{ item.count }})
<i class="circle-red" v-if="item.is_dot"></i>
</el-radio-button>
<!-- <el-radio-button label="1">待处理({{currentCalList}})</el-radio-button>-->
</el-radio-group>
</div>
<div class="workbench-content">
<div class="workbench-li-c" v-if="currentDiagList">
<div class="grid-c">
<div
class="workbench-li"
v-for="(item, index) in currentDiagList"
:key="index"
>
<inquiryList-component :item="item"></inquiryList-component>
</div>
</div>
</div>
<div v-else class="nodata-container">
<img src="../../../assets/image/workbench/no_data_wz.png" alt="" />
<div class="nodata-title">暂时没有问诊</div>
</div>
<div class="pagination-container" v-if="allSize>0">
<el-pagination
background
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
:current-page="searchParam.pageNo"
:page-sizes="[6, 12, 18, 24]"
:page-size="searchParam.pageSize"
layout="prev, pager, next, sizes, jumper"
:total="allSize"
>
</el-pagination>
</div>
</div>
</div>
</template>
<script>
import { mapState } from "vuex";
import storejs from "storejs";
import InquiryListComponent from "../../../components/common/inquirylist.vue";
export default {
components: {
InquiryListComponent,
},
computed: {
...mapState({
allSize: "allSize",
currentDiagList: "currentDiagList",
currentCalList: "currentCalList",
soketQuest: "soketQuest",
isSuperAdmin: "isSuperAdmin",
}),
},
watch: {
isSuperAdmin(newdata, olddata) {
// console.log("ererer")
if (newdata !== olddata && newdata.userID) {
console.log('-isSuperAdminisSuperAdmin', newdata)
const s = storejs.get("soketQuest");
const d = s ? s.dateTime : new Date().format("yyyy-MM-dd");
let id =
s && s.operateUserId ? s.operateUserId : this.isSuperAdmin.userID;
const p = {
dateTime: d,
operateUserId: id,
pageNo: s ? s.pageNo : 1,
pageSize: s ? s.pageSize : 6,
returnStatus: s ? s.returnStatus : 1,
};
this.searchParam = p;
this.tabPosition=s?s.returnStatus:1
this.inquirySearch("clear");
}
},
},
data() {
const s = storejs.get("soketQuest");
const t = s?s.returnStatus:1;
const d = s ? s.dateTime : new Date().format("yyyy-MM-dd");
let id = s && s.operateUserId ? s.operateUserId : this.isSuperAdmin.userID;
return {
tabPosition: t,
showChat: true,
totalRows: 0,
loading: false,
searchParam: {
dateTime: d,
checkvalue: "", // 模拟值后去
operateUserId: id,
returnStatus: 1,
pageSize: 1,
pageNo: 1,
},
testlistdata: [
{
appointBeginTime: "2021-07-29T05:28:57.396Z",
appointEndTime: "2021-07-29T05:28:57.396Z",
department: "内科",
departmentId: 3876,
diagnoseLogId: 38,
diagnoseType: 1,
doctorCallKfStatus: 1,
doctorCallTime: "",
doctorId: 0,
doctorMobile: "16789987665",
doctorName: "孙思邈",
doctorTrtcEntryStatus: 1,
imStatus: 0,
imTeamId: "",
returnStatus: 1,
roomId: "string",
sort: 0,
status: 0,
userCallKfStatus: 0,
userCallTime: "",
userId: 0,
userMobile: "12343123233",
userName: "孙思邈",
userTrtcEntryStatus: 0,
},
],
};
},
created() {},
mounted() {},
methods: {
tabChange(val) {
const s = this.searchParam;
s.returnStatus = val;
this.searchParam = s;
this.inquirySearch("tab");
},
changeDatetime(val) {
const s = this.searchParam;
s.dateTime = val.format("yyyy-MM-dd");
this.searchParam = s;
this.inquirySearch("clear");
},
handleSizeChange(val) {
const s = this.searchParam;
s.pageSize = val;
this.searchParam = s;
},
handleCurrentChange(val) {
const s = this.searchParam;
s.pageNo = val;
this.searchParam = s;
this.inquirySearch();
},
inquirySearch(type) {
const p = this.searchParam;
if (type == "clear") {
this.$store.commit("clearRawCurrentCalList");
}
this.POST("/diagnose/socket/condition/update", p).then((res) => {
if (res.code == "000000") {
this.$store.commit("updateSoketQuest", p);
if (type == "tab") {
const returnStatus = p.returnStatus;
const RespList = res.data.list[0].recordResp.countRespList.filter(
(val) => {
return val.status == returnStatus;
}
);
this.$store.commit("changeRawCurrentCalList", RespList[0]);
}
} else {
this.$message({
message: res.message,
type: "warning",
duration: 1000,
});
}
});
// 测试代码
// const l = this.currentDiagList;
// l.push(...this.testlistdata);
// this.$store.commit('updateCurrentDiagList', l);
// this.$store.commit('socket/SET_NOTIFY', ...this.testlistdata);
},
socketRE() {
this.$store.dispatch( 'socket/RECONNECT_SOCKET')
}
},
};
</script>
<style lang='scss'>
.workbench-tab {
.el-radio-button__inner {
border: none;
position: relative;
&::after {
content: "";
position: absolute;
bottom: 0;
left: 50%;
right: 0;
height: 2px;
background: #fff;
width: 20px;
transform: translateX(-50%);
}
.circle-red {
display: block;
position: absolute;
width: 10px;
height: 10px;
border-radius: 50%;
background: red;
right: 15px;
top: 7px;
}
}
.el-radio-button:first-child .el-radio-button__inner {
border: none;
}
.el-radio-button__orig-radio:checked + .el-radio-button__inner {
background-color: #fff;
color: #0d9078;
box-shadow: none;
font-weight: 500;
&::after {
background: #0d9078;
}
}
}
</style>
<style lang="scss">
::v-deep {
.el-date-editor {
.el-input__inner {
background: red;
}
}
}
.workbench-container {
min-width: 1200px;
.select-content {
padding: 0 20px;
background: #fff;
overflow: hidden !important;
.search-box {
display: flex;
justify-content: flex-start;
width: 250px;
margin: 20px 0;
.search-item {
margin-right: 20px;
.input-item {
width: 333px;
}
}
}
.title {
height: 50px;
display: flex;
justify-content: flex-start;
align-items: center;
}
.radio {
border-bottom: 1px solid #ccc;
.el-radio-group {
margin-bottom: -1px !important;
}
}
}
.workbench-content {
//min-width: 1250px;
padding: 20px 10px;
.workbench-li-c {
width: 100%;
.grid-c {
width: calc(100% - 20px);
display: grid;
grid-template-columns: 50% 50%;
grid-row-gap: 20px;
grid-column-gap: 20px;
.workbench-li {
margin: 0 auto;
width: 100%;
}
}
}
.nodata-container {
background-color: #fff;
padding: 0 20px;
border-radius: 18px;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
height: 470px;
.nodata {
width: 100%;
}
img {
width: 298px;
height: 140px;
}
.nodata-title {
font-size: 18px;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
color: #6a7990;
margin-top: 50px;
}
}
.pagination-container {
background-color: #fff;
height: 71px;
background: #ffffff;
border-radius: 18px;
display: flex;
justify-content: flex-end;
align-items: center;
margin-top: 10px;
padding: 0 20px;
}
}
}
.bg-purple-dark {
background: #99a9bf;
}
.bg-purple {
background: #d3dce6;
}
.bg-purple-light {
background: #e5e9f2;
}
.grid-content {
border-radius: 4px;
min-height: 45px;
display: flex;
justify-content: space-evenly;
align-items: center;
font-size: 16px;
}
.row-bg {
padding: 10px 0;
background-color: #f9fafc;
}
// 屏幕适配
@media screen and (min-width: 1240px) and (max-width: 1441px){
.workbench-container{
.workbench-li-c{
.grid-c{
.workbench-li{
//max-width: 572px;
}
}
}
}
}
</style>
......@@ -136,7 +136,7 @@ export default {
// background-color: #242f42;
.logo {
float: left;
width: 255px;
width: 215px;
text-align: center;
color: #fff;
background: #0b2f3f;
......
......@@ -31,10 +31,9 @@
</div>
</template>
<script>
import { mapGetters } from "vuex";
import { setTimeout } from "timers";
import { isNotEmptyUtils } from "../../utils/utils";
import { getInnerLoginUrl } from "../../utils";
import storejs from 'storejs';
const BUILD_ENV = process.env.BUILD_ENV;
let vm = null;
export default {
props: {
......@@ -67,7 +66,8 @@ export default {
getNav() {
this.POST("/basic-data/menu/list", { systemType: this.systemType }).then(res => {
if (res.code == "000000") {
let { vueMenuDtos } = res.data;
let { vueMenuDtos, userId } = res.data;
console.log('---userId', res.data, userId);
// let vueMenuDtos = [];
// // TODO 开发调试时写死, 发布时去掉
......@@ -77,6 +77,24 @@ export default {
// subs: [],
// title: "订单管理"
// }];
const i = {
isSuper:false,
userID: userId
};
const u = this.getSocketUrl(BUILD_ENV);
storejs.set('initSocketInfo', {url: u,userId: userId});
this.$store.dispatch( 'socket/initSocket',{url: u,userId: userId})
vueMenuDtos.map( item => {
if(item.index.indexOf('administrators') > -1){
// 超级管理员
i.isSuper = true;
}else{
// 普通用户
i.isSuper = false;
}
});
this.$store.commit('updateIsSuperAdmin', i);
this.items = vueMenuDtos;
sessionStorage.setItem(
"ADMIN_IM_CENTER_NAVS",
......@@ -109,6 +127,27 @@ export default {
if (navList.indexOf(path) == -1) {
this.$router.push(`/${navList[0]}`);
}
},
getSocketUrl (env){
let url = '';
switch(env) {
case 'development':
url ='https://dev-sockets.yunqueyi.com';
break;
case 'test':
url ='https://test1-sockets.yunqueyi.com';
break;
case 'uat':
url ='https://uat-sso-sockets.yunqueyi.com';
break;
case 'pro':
url ='https://sso-sockets.yunqueyi.com';
break;
default:
url ='https://dev-sockets.yunqueyi.com';
break;
}
return url
}
}
};
......@@ -120,7 +159,7 @@ export default {
left: 0;
top: 64px;
bottom: 0;
width: 255px;
width: 215px;
background: #06232c;
.el-menu {
background: #06232c;
......
Markdown 格式
0% or
您添加了 0 到此讨论。请谨慎行事。
先完成此消息的编辑!
想要评论请 注册