|
|
@@ -0,0 +1,1450 @@
|
|
|
+<template>
|
|
|
+ <div id="message-send-box-wrapper" :style="focus ? {'backgroundColor': 'white'} : {}" @drop="dropHandler">
|
|
|
+ <div class="send-header-bar">
|
|
|
+ <el-popover placement="top" width="400" trigger="click">
|
|
|
+ <div class="emojis">
|
|
|
+ <div v-for="item in emojiName" class="emoji" :key="item" @click="chooseEmoji(item)">
|
|
|
+ <!--<img :src="emojiUrl + emojiMap[item]" style="width:30px;height:30px" />-->
|
|
|
+ <span style="width:30px;height:30px">
|
|
|
+ {{emojiCharMap[item]}}
|
|
|
+ </span>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <i class="iconfont icon-smile" slot="reference" title="发表情"></i>
|
|
|
+ </el-popover>
|
|
|
+ <i class="iconfont icon-tupian" title="发图片" @click="handleSendImageClick"></i>
|
|
|
+ <i class="el-icon-camera" title="发视频" @click="handleSendVideoClick"></i>
|
|
|
+ <i class="iconfont icon-wenjian" title="发文件" @click="handleSendFileClick"></i>
|
|
|
+ <!-- <i class="iconfont icon-zidingyi" title="发自定义消息" @click="sendCustomDialogVisible = true"></i> -->
|
|
|
+
|
|
|
+ <!-- <i class="iconfont icon-diaocha" title="小调查" @click="surveyDialogVisible = true"></i> -->
|
|
|
+ <el-dropdown>
|
|
|
+ <span class="el-dropdown-link" v-if="currentConversationType !== 3">
|
|
|
+ <i class="el-icon-phone-outline" v-if="toAccount !== userID&&((imType==1&&orderType==2)||imType==2)" title="语音通话"></i>
|
|
|
+ <i class="el-icon-phone-outline" title="语音通话"></i>
|
|
|
+ </span>
|
|
|
+ <el-dropdown-menu slot="dropdown">
|
|
|
+ <el-dropdown-item @click.native="trtcCalling('video')">视频通话</el-dropdown-item>
|
|
|
+ <el-dropdown-item @click.native="trtcCalling('audio')">语音通话</el-dropdown-item>
|
|
|
+ </el-dropdown-menu>
|
|
|
+ </el-dropdown>
|
|
|
+ <div class="group-live-icon-box" v-if="currentConversationType === 4&& groupProfile.type !== 'AVChatRoom'" title="群直播" @click="groupLive">
|
|
|
+ <i class="group-live-icon"></i>
|
|
|
+ <i class="group-live-icon-hover"></i>
|
|
|
+ </div>
|
|
|
+ <i class="el-icon-s-order" title="疗法" @click="handlePackageList()"></i>
|
|
|
+ <i class="el-icon-tickets" title="药品订单" @click="handleStoreOrder()"></i>
|
|
|
+ <i class="el-icon-edit-outline" title="会诊" @click="handlePrescribe()"></i>
|
|
|
+ <i class="el-icon-edit-outline" title="私域疗法券" @click="handleCoupon()"></i>
|
|
|
+ <!--<i class="el-icon-document" v-if="imType==1" title="诊断报告" @click="handleInquiryReport()"></i>
|
|
|
+ <i class="el-icon-finished" v-if="imType==2" title="随访单" @click="handleFollow()"></i>
|
|
|
+ <i class="el-icon-edit-outline" v-if="imType==2" title="开报告" @click="handleDrugReport()"></i>
|
|
|
+ <i class="el-icon-chat-dot-square" title="常用语" @click="handleDoctorWords()"></i>-->
|
|
|
+ </div>
|
|
|
+ <el-dialog title="发自定义消息" :append-to-body="true" :visible.sync="sendCustomDialogVisible" width="30%">
|
|
|
+ <el-form label-width="100px">
|
|
|
+ <el-form-item label="data">
|
|
|
+ <el-input v-model="form.data"></el-input>
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item label="description">
|
|
|
+ <el-input v-model="form.description"></el-input>
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item label="extension">
|
|
|
+ <el-input v-model="form.extension"></el-input>
|
|
|
+ </el-form-item>
|
|
|
+ </el-form>
|
|
|
+ <span slot="footer" class="dialog-footer">
|
|
|
+ <el-button @click="sendCustomDialogVisible = false">取 消</el-button>
|
|
|
+ <el-button type="primary" @click="sendCustomMessage">确 定</el-button>
|
|
|
+ </span>
|
|
|
+ </el-dialog>
|
|
|
+ <el-dialog title="对IM Web demo的建议和使用感受" :visible.sync="surveyDialogVisible" width="30%">
|
|
|
+ <el-form label-width="100px">
|
|
|
+ <el-form-item label="评分">
|
|
|
+ <div class="block">
|
|
|
+ <el-rate v-model="rate" :colors="colors" show-text></el-rate>
|
|
|
+ </div>
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item label="建议">
|
|
|
+ <el-input
|
|
|
+ type="textarea"
|
|
|
+ :rows="2"
|
|
|
+ placeholder="请输入内容"
|
|
|
+ resize="none"
|
|
|
+ v-model="suggestion"
|
|
|
+ ></el-input>
|
|
|
+ </el-form-item>
|
|
|
+ </el-form>
|
|
|
+ <span slot="footer" class="dialog-footer">
|
|
|
+ <el-button @click="surveyDialogVisible = false">取 消</el-button>
|
|
|
+ <el-button type="primary" @click="sendSurvey">确 定</el-button>
|
|
|
+ </span>
|
|
|
+ </el-dialog>
|
|
|
+ <div class="bottom">
|
|
|
+ <textarea
|
|
|
+ ref="text-input"
|
|
|
+ rows="4"
|
|
|
+ resize="false"
|
|
|
+ v-model="messageContent"
|
|
|
+ class="text-input"
|
|
|
+ @focus="focus = true"
|
|
|
+ @blur="focus = false"
|
|
|
+ @input="inputChange"
|
|
|
+ @keydown.enter.exact.prevent="handleEnter"
|
|
|
+ @keyup.ctrl.enter.prevent.exact="handleLine"
|
|
|
+ @keydown.up.stop="handleUp"
|
|
|
+ @keydown.down.stop="handleDown"
|
|
|
+ >
|
|
|
+ </textarea>
|
|
|
+ <el-tooltip
|
|
|
+ class="item"
|
|
|
+ effect="dark"
|
|
|
+ content="按Enter发送消息,Ctrl+Enter换行"
|
|
|
+ placement="left-start"
|
|
|
+ >
|
|
|
+ <div class="btn-send" @click="sendTextMessage">
|
|
|
+ <div class="tim-icon-send"></div>
|
|
|
+ </div>
|
|
|
+ </el-tooltip>
|
|
|
+ </div>
|
|
|
+ <input
|
|
|
+ type="file"
|
|
|
+ id="imagePicker"
|
|
|
+ ref="imagePicker"
|
|
|
+ accept=".jpg, .jpeg, .png, .gif, .bmp"
|
|
|
+ @change="sendImage"
|
|
|
+ style="display:none"
|
|
|
+ />
|
|
|
+ <input type="file" id="filePicker" ref="filePicker" @change="sendFile" style="display:none" />
|
|
|
+ <input type="file" id="videoPicker" ref="videoPicker" @change="sendVideo" style="display:none" accept=".mp4"/>
|
|
|
+ <div class="calling-member-list" v-if="currentConversationType === 3 && showCallingMember">
|
|
|
+ <calling-member-list @getList="getList" :type="listTpye"></calling-member-list>
|
|
|
+ <div class="calling-list-btn">
|
|
|
+ <span class="calling-btn" @click="cancelCalling">取消</span>
|
|
|
+ <span class="calling-btn" @click="callingHandler">确定</span>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <el-drawer :append-to-body="true" :with-header="false" size="75%" :title="show.title" :visible.sync="show.open">
|
|
|
+ <packageList v-if="show.type==1" ref="packageList" />
|
|
|
+ <storeOrderList v-if="show.type==2" ref="storeOrderList" />
|
|
|
+ <couponList v-if="show.type==3" ref="couponList" />
|
|
|
+<!-- <drugStore v-if="show.type==4" ref="drugStore" />-->
|
|
|
+<!-- <addInquiryOrderReport v-if="show.type==5" ref="addInquiryOrderReport" />-->
|
|
|
+<!-- <doctorWords v-if="show.type==6" @sendWords="sendWords" ref="doctorWords" />-->
|
|
|
+<!-- <addDrugReport v-if="show.type==7" ref="addDrugReport" />-->
|
|
|
+<!-- <addDrugReport v-if="show.type==8" ref="addDrugReport" />-->
|
|
|
+ </el-drawer>
|
|
|
+ <el-drawer
|
|
|
+ :append-to-body="true"
|
|
|
+ :with-header="false"
|
|
|
+ size="45%"
|
|
|
+ :title="show.title"
|
|
|
+ :visible.sync="inquiryConfigOpen"
|
|
|
+ >
|
|
|
+ <div style="padding: 20px;">
|
|
|
+ <el-table :data="inquiryConfig" border style="width: 100%">
|
|
|
+ <!-- 名称列 -->
|
|
|
+ <el-table-column prop="lable" label="名称" />
|
|
|
+
|
|
|
+ <!-- 操作列 -->
|
|
|
+ <el-table-column label="操作" align="center" width="120">
|
|
|
+ <template #default="{ row }">
|
|
|
+ <el-button
|
|
|
+ type="primary"
|
|
|
+ size="mini"
|
|
|
+ @click="sendInquiry(row.lable, row.value)"
|
|
|
+ >
|
|
|
+ 发送
|
|
|
+ </el-button>
|
|
|
+ </template>
|
|
|
+ </el-table-column>
|
|
|
+ </el-table>
|
|
|
+ </div>
|
|
|
+ </el-drawer>
|
|
|
+
|
|
|
+ </div>
|
|
|
+</template>
|
|
|
+
|
|
|
+<script>
|
|
|
+//import { finishOrder } from "@/api/inquiryOrder";
|
|
|
+//import { finishDrugReport } from "@/api/drugReport";
|
|
|
+import storeOrderList from '@/views/components/order/storeOrderList.vue';
|
|
|
+import couponList from '@/views/components/coupon/index.vue';
|
|
|
+import { mapGetters, mapState } from 'vuex'
|
|
|
+import callingMemberList from './trtc-calling/group-member-list'
|
|
|
+import packageList from '@/views/store/package/index.vue';
|
|
|
+import {getInquiryConfig,sendInquiry} from "@/api/common";
|
|
|
+import {listCoupon} from "@/api/coupon/coupon";
|
|
|
+import {
|
|
|
+ Form,
|
|
|
+ FormItem,
|
|
|
+ Input,
|
|
|
+ Dialog,
|
|
|
+ Popover,
|
|
|
+ Tooltip,
|
|
|
+ Rate
|
|
|
+} from 'element-ui'
|
|
|
+import { getOpenIM } from '@/utils/openIM';
|
|
|
+import { emojiMap, emojiName, emojiUrl,emojiCharMap } from '../../utils/emojiMap'
|
|
|
+
|
|
|
+export default {
|
|
|
+ name: 'message-send-box',
|
|
|
+ props: ['scrollMessageListToButtom'],
|
|
|
+ components: {
|
|
|
+ storeOrderList,
|
|
|
+ packageList,
|
|
|
+ couponList,
|
|
|
+ callingMemberList: callingMemberList,
|
|
|
+ ElInput: Input,
|
|
|
+ ElForm: Form,
|
|
|
+ ElFormItem: FormItem,
|
|
|
+ ElDialog: Dialog,
|
|
|
+ ElPopover: Popover,
|
|
|
+ ElTooltip: Tooltip,
|
|
|
+ ElRate: Rate
|
|
|
+ },
|
|
|
+ data() {
|
|
|
+ return {
|
|
|
+ showAtList: false,
|
|
|
+ atMembers: [],
|
|
|
+ searchMember: '',
|
|
|
+ cursorIndex: 0,
|
|
|
+ aite:"",
|
|
|
+ show:{
|
|
|
+ open:false,
|
|
|
+ title:""
|
|
|
+ },
|
|
|
+ inquiryConfigOpen:false,
|
|
|
+ inquiryConfig:{},
|
|
|
+ callingList: [],
|
|
|
+ groupAtList: [],
|
|
|
+ listTpye:'',
|
|
|
+ callingType: '',
|
|
|
+ groupAt:false,
|
|
|
+ showCallingMember: false,
|
|
|
+ colors: ['#99A9BF', '#F7BA2A', '#FF9900'],
|
|
|
+ messageContent: '',
|
|
|
+ isSendCustomMessage: false,
|
|
|
+ sendCustomDialogVisible: false,
|
|
|
+ surveyDialogVisible: false,
|
|
|
+ form: {
|
|
|
+ data: '',
|
|
|
+ description: '',
|
|
|
+ extension: ''
|
|
|
+ },
|
|
|
+ rate: 5, // 评分
|
|
|
+ suggestion: '', // 建议
|
|
|
+ file: '',
|
|
|
+ emojiMap: emojiMap,
|
|
|
+ emojiName: emojiName,
|
|
|
+ emojiUrl: emojiUrl,
|
|
|
+ emojiCharMap:emojiCharMap,
|
|
|
+ showAtGroupMember: false,
|
|
|
+ atUserID: '',
|
|
|
+ focus: false,
|
|
|
+ popoverVisible: false,
|
|
|
+ faceUrl: 'https://web.sdk.qcloud.com/im/assets/face-elem/',
|
|
|
+ emojiShow: true,
|
|
|
+ bigEmojiShow: false,
|
|
|
+ bigEmojiList: [
|
|
|
+ {
|
|
|
+ icon: 'yz00',
|
|
|
+ list: ['yz00', 'yz01', 'yz02', 'yz03', 'yz04', 'yz05', 'yz06', 'yz07', 'yz08', 'yz09', 'yz10', 'yz11', 'yz12', 'yz13', 'yz14', 'yz15', 'yz16', 'yz17']
|
|
|
+ },
|
|
|
+ {
|
|
|
+ icon: 'ys00',
|
|
|
+ list: ['ys00', 'ys01', 'ys02', 'ys03', 'ys04', 'ys05', 'ys06', 'ys07', 'ys08', 'ys09', 'ys10', 'ys11', 'ys12', 'ys13', 'ys14', 'ys15']
|
|
|
+ },
|
|
|
+ {
|
|
|
+ icon: 'gcs00',
|
|
|
+ list: ['gcs00', 'gcs01', 'gcs02', 'gcs03', 'gcs04', 'gcs05', 'gcs06', 'gcs07', 'gcs08', 'gcs09', 'gcs10', 'gcs11', 'gcs12', 'gcs13', 'gcs14', 'gcs15', 'gcs16']
|
|
|
+ }
|
|
|
+ ],
|
|
|
+ curItemIndex: 0,
|
|
|
+ curBigEmojiItemList: []
|
|
|
+ }
|
|
|
+ },
|
|
|
+ computed: {
|
|
|
+ ...mapGetters(['toAccount', 'currentConversationType']),
|
|
|
+ ...mapState({
|
|
|
+ orderId:state => state.conversation.orderId,
|
|
|
+ followId:state => state.conversation.followId,
|
|
|
+ orderType:state => state.conversation.orderType,
|
|
|
+ imType: state => state.conversation.imType,
|
|
|
+ memberList: state => state.group.currentMemberList,
|
|
|
+ userID: state => state.imuser.userID,
|
|
|
+ currentConversation :state=>state.conversation.currentConversation,
|
|
|
+ groupProfile: state => state.conversation.currentConversation.groupProfile
|
|
|
+ }),
|
|
|
+ icon() {
|
|
|
+ return aite
|
|
|
+ },
|
|
|
+ filteredAtMembers() {
|
|
|
+ if (!this.searchMember) return this.atMembers
|
|
|
+ return this.atMembers.filter(m =>
|
|
|
+ m.nickname?.includes(this.searchMember)
|
|
|
+ )
|
|
|
+ }
|
|
|
+ },
|
|
|
+ mounted() {
|
|
|
+ this.$refs['text-input'].addEventListener('paste', this.handlePaste)
|
|
|
+ this.$bus.$on('reEditMessage', this.reEditMessage)
|
|
|
+ },
|
|
|
+ beforeDestroy() {
|
|
|
+ this.$refs['text-input'].removeEventListener('paste', this.handlePaste)
|
|
|
+ },
|
|
|
+ created() {
|
|
|
+ if (!this.OpenIM) {
|
|
|
+ this.OpenIM = getOpenIM()
|
|
|
+ console.log("OpenIM SDK 初始化完成");
|
|
|
+ }
|
|
|
+ },
|
|
|
+ methods: {
|
|
|
+ handleSelectAtMember(member) {
|
|
|
+ this.showAtList = false
|
|
|
+ const text = member.userID === 'all' ? '@所有人 ' : `@${member.nickname} `
|
|
|
+ this.insertTextAtCursor(text)
|
|
|
+ },
|
|
|
+
|
|
|
+ insertTextAtCursor(text) {
|
|
|
+ const selection = window.getSelection()
|
|
|
+ if (!selection.rangeCount) return
|
|
|
+ const range = selection.getRangeAt(0)
|
|
|
+ range.deleteContents()
|
|
|
+ const textNode = document.createTextNode(text)
|
|
|
+ range.insertNode(textNode)
|
|
|
+ range.setStartAfter(textNode)
|
|
|
+ range.collapse(true)
|
|
|
+ selection.removeAllRanges()
|
|
|
+ selection.addRange(range)
|
|
|
+ },
|
|
|
+
|
|
|
+ getCursorPosition() {
|
|
|
+ const selection = window.getSelection()
|
|
|
+ if (!selection.rangeCount) return 0
|
|
|
+ const range = selection.getRangeAt(0)
|
|
|
+ return range.startOffset
|
|
|
+ },
|
|
|
+ openAtSelector() {
|
|
|
+ if (!this.currentConversation.groupID) return
|
|
|
+
|
|
|
+ this.getGroupMembers()
|
|
|
+ this.showAtList = true
|
|
|
+ },
|
|
|
+
|
|
|
+ getGroupMembers() {
|
|
|
+ // 从 store 或 OpenIM 获取群成员列表
|
|
|
+ this.OpenIM.getGroupMemberList({
|
|
|
+ groupID: this.currentConversation.groupID,
|
|
|
+ filter: 0,
|
|
|
+ offset: 0,
|
|
|
+ count: 1000
|
|
|
+ }).then(({ data }) => {
|
|
|
+ this.atMembers = data
|
|
|
+
|
|
|
+ // 如果当前用户是群主,加入 @所有人 选项
|
|
|
+ if (this.currentConversation.ownerUserID === this.$store.state.userInfo.userID) {
|
|
|
+ this.atMembers.unshift({
|
|
|
+ userID: 'all',
|
|
|
+ nickname: '所有人'
|
|
|
+ })
|
|
|
+ }
|
|
|
+ })
|
|
|
+ },
|
|
|
+ handleInput(e) {
|
|
|
+ const value = e.target.innerText
|
|
|
+ this.cursorIndex = this.getCursorPosition()
|
|
|
+
|
|
|
+ // 检测最后一个字符是否是 @
|
|
|
+ if (value[this.cursorIndex - 1] === '@') {
|
|
|
+ this.openAtSelector()
|
|
|
+ }
|
|
|
+ },
|
|
|
+ sendInquiry(lable, value) {
|
|
|
+ const massage={
|
|
|
+ sendID:this.userID,
|
|
|
+ recvID:this.toAccount,
|
|
|
+ inquiryName:lable,
|
|
|
+ type:value
|
|
|
+ }
|
|
|
+ sendInquiry(massage).then(res => {
|
|
|
+ // 根据接口返回判断
|
|
|
+ if (res.data && res.data.errCode === 0) {
|
|
|
+ this.$message.success("发送成功");
|
|
|
+ } else {
|
|
|
+ this.$message.error("发送失败:" + (res.data?.errMsg || "未知错误"));
|
|
|
+ }
|
|
|
+ }).catch(err => {
|
|
|
+ console.error("发送失败:", err);
|
|
|
+ this.$message.error("发送异常,请稍后重试");
|
|
|
+ });
|
|
|
+ console.log("发送的团队名称:",massage);
|
|
|
+ },
|
|
|
+ sendWords(msg){
|
|
|
+ console.log(msg)
|
|
|
+ this.show.open=false;
|
|
|
+ this.messageContent=msg;
|
|
|
+ this.sendTextMessage();
|
|
|
+
|
|
|
+ },
|
|
|
+ handlePackageList(){
|
|
|
+ console.log("this.$store.state.conversation11111",this.$store.state.conversation.currentConversation)
|
|
|
+ this.show.type = 1;
|
|
|
+ this.show.open = true;
|
|
|
+ setTimeout(() => {
|
|
|
+ this.$refs.packageList.updateOpenFrom(this.$store.state.conversation.currentConversation.userID);
|
|
|
+ }, 500);
|
|
|
+ },
|
|
|
+ handleCoupon() {
|
|
|
+ console.log("this.$store.state.conversation11111",this.$store.state.conversation.currentConversation)
|
|
|
+ this.show.type = 3;
|
|
|
+ this.show.open = true;
|
|
|
+ setTimeout(() => {
|
|
|
+ this.$refs.couponList.updateOpenFrom(this.$store.state.conversation.currentConversation.userID);
|
|
|
+ }, 500);
|
|
|
+ },
|
|
|
+ handleStoreOrder(){
|
|
|
+ var that=this;
|
|
|
+ this.show.type=2;
|
|
|
+ this.show.open=true;
|
|
|
+ this.show.title="药品订单"
|
|
|
+ const conversationID = this.$store.state.conversation.currentConversation.conversationID;
|
|
|
+ const match = conversationID.match(/U(\d+)/);
|
|
|
+ const userId = match ? Number(match[1]) : null;
|
|
|
+ setTimeout(() => {
|
|
|
+ that.$refs.storeOrderList.getData(userId);
|
|
|
+ }, 500);
|
|
|
+
|
|
|
+ },
|
|
|
+ handlePrescribe() {
|
|
|
+ this.inquiryConfigOpen = true;
|
|
|
+ this.show.title = "会诊";
|
|
|
+
|
|
|
+ getInquiryConfig().then(response => {
|
|
|
+ let data = response.msg;
|
|
|
+ try {
|
|
|
+ // 如果是字符串,先尝试 JSON.parse
|
|
|
+ if (typeof data === "string") {
|
|
|
+ data = JSON.parse(data);
|
|
|
+ }
|
|
|
+ // 如果是对象里有 list,就取 list
|
|
|
+ if (data && data.list) {
|
|
|
+ data = data.list;
|
|
|
+ }
|
|
|
+ // 确保最终一定是数组
|
|
|
+ this.inquiryConfig = Array.isArray(data) ? data : [];
|
|
|
+ } catch (e) {
|
|
|
+ this.inquiryConfig = [];
|
|
|
+ console.error("解析 inquiryConfig 失败", e);
|
|
|
+ }
|
|
|
+
|
|
|
+ console.log("最终 inquiryConfig:", this.inquiryConfig);
|
|
|
+ });
|
|
|
+ },
|
|
|
+
|
|
|
+
|
|
|
+ /*handleDoctorWords(){
|
|
|
+ var that=this;
|
|
|
+ this.show.type=6;
|
|
|
+ this.show.open=true;
|
|
|
+ this.show.title="常用语"
|
|
|
+ setTimeout(() => {
|
|
|
+ that.$refs.doctorWords.getData();
|
|
|
+ }, 500);
|
|
|
+ },
|
|
|
+ handleInquiryReport(){
|
|
|
+ var that=this;
|
|
|
+ this.show.type=5;
|
|
|
+ this.show.open=true;
|
|
|
+ this.show.title="问诊报告"
|
|
|
+ setTimeout(() => {
|
|
|
+ that.$refs.addInquiryOrderReport.getDetails(this.$store.state.conversation.orderId);
|
|
|
+ }, 500);
|
|
|
+ },
|
|
|
+
|
|
|
+ handleDrugReport(){
|
|
|
+ var that=this;
|
|
|
+ this.show.type=7;
|
|
|
+ this.show.open=true;
|
|
|
+ this.show.title="用药报告"
|
|
|
+ setTimeout(() => {
|
|
|
+ that.$refs.addDrugReport.openDrugReport(this.$store.state.conversation.followId);
|
|
|
+ }, 500);
|
|
|
+ },
|
|
|
+ handleFollow(){
|
|
|
+ var that=this;
|
|
|
+ this.show.type=3;
|
|
|
+ this.show.open=true;
|
|
|
+ this.show.title="随访单"
|
|
|
+ setTimeout(() => {
|
|
|
+ that.$refs.followDetails.getDetails(this.$store.state.conversation.followId,"随访单");
|
|
|
+ }, 500);
|
|
|
+
|
|
|
+ },
|
|
|
+
|
|
|
+ handleInquiryOrder(){
|
|
|
+ console.log(this.$store.state.conversation.orderId)
|
|
|
+ var that=this;
|
|
|
+ this.show.type=1;
|
|
|
+ this.show.open=true;
|
|
|
+ var userId=this.$store.state.conversation.currentConversation.conversationID.split("-")[1];
|
|
|
+ console.log(userId)
|
|
|
+ this.show.title="问诊订单"
|
|
|
+ setTimeout(() => {
|
|
|
+
|
|
|
+ that.$refs.inquiryOrderDetails.getDetails(userId);
|
|
|
+ }, 500);
|
|
|
+
|
|
|
+ },*/
|
|
|
+ /* handleFinishDrugReport(){
|
|
|
+ var that=this;
|
|
|
+ this.$confirm('确定结束咨询吗?', '提示', {
|
|
|
+ confirmButtonText: '确定',
|
|
|
+ cancelButtonText: '取消',
|
|
|
+ type: 'warning'
|
|
|
+ }).then(() => {
|
|
|
+ var data={followId:that.$store.state.conversation.followId}
|
|
|
+ console.log(data);
|
|
|
+ finishDrugReport(data).then(res => {
|
|
|
+
|
|
|
+ if(res.code==200){
|
|
|
+ that.$store.commit('setImType',0 )
|
|
|
+ }else{
|
|
|
+ this.msgError(res.msg);
|
|
|
+ }
|
|
|
+ });
|
|
|
+ }).catch(() => {
|
|
|
+
|
|
|
+ });
|
|
|
+ },*/
|
|
|
+ /*handleFinishInquiry(){
|
|
|
+ var that=this;
|
|
|
+ this.$confirm('确定结束问诊吗?', '提示', {
|
|
|
+ confirmButtonText: '确定',
|
|
|
+ cancelButtonText: '取消',
|
|
|
+ type: 'warning'
|
|
|
+ }).then(() => {
|
|
|
+ var data={orderId:that.$store.state.conversation.orderId}
|
|
|
+ finishOrder(data).then(res => {
|
|
|
+ if(res.code==200){
|
|
|
+ that.$store.commit('setImType',0 )
|
|
|
+ }else{
|
|
|
+ that.msgError(res.msg);
|
|
|
+ }
|
|
|
+ });
|
|
|
+ }).catch(() => {
|
|
|
+
|
|
|
+ });
|
|
|
+ },*/
|
|
|
+ getList(value) {
|
|
|
+ this.callingList = value.map((item) => {
|
|
|
+ let obj = JSON.parse(item)
|
|
|
+ return obj.userID
|
|
|
+ })
|
|
|
+ this.groupAtList = value.map((item) => {
|
|
|
+ let data = JSON.parse(item)
|
|
|
+ return data.nick
|
|
|
+ })
|
|
|
+ },
|
|
|
+ cancelCalling() {
|
|
|
+ this.showCallingMember = false
|
|
|
+ },
|
|
|
+ callingHandler() {
|
|
|
+ if (this.callingList.length < 1) {
|
|
|
+ this.$store.commit('showMessage', {
|
|
|
+ type: 'warning',
|
|
|
+ message: '请选择成员'
|
|
|
+ })
|
|
|
+ return
|
|
|
+ }
|
|
|
+ if (this.listTpye === 'groupAt') {
|
|
|
+ this.groupAtList.forEach((item, index) => {
|
|
|
+ if(index===0) {
|
|
|
+ this.messageContent += `${item} `
|
|
|
+ }else{
|
|
|
+ this.messageContent += `@${item} `
|
|
|
+ }
|
|
|
+ })
|
|
|
+ this.showCallingMember = false
|
|
|
+ this.$refs['text-input'].focus()
|
|
|
+ return
|
|
|
+ }
|
|
|
+ if (this.listTpye === 'calling') {
|
|
|
+ let callingData = {
|
|
|
+ memberList:this.callingList,
|
|
|
+ type:3
|
|
|
+ }
|
|
|
+ this.$store.commit('setCallingList',callingData)
|
|
|
+ if (this.callingType === 'video') {
|
|
|
+ this.$bus.$emit('video-call')
|
|
|
+ }
|
|
|
+ if (this.callingType === 'audio') {
|
|
|
+ this.$bus.$emit('audio-call')
|
|
|
+ }
|
|
|
+ this.showCallingMember = false
|
|
|
+ }
|
|
|
+
|
|
|
+ },
|
|
|
+ trtcCalling(type) {
|
|
|
+ console.log(`尝试发起${type === 'video' ? '视频' : '语音'}通话`)
|
|
|
+
|
|
|
+ // 1. 检查OpenIM是否初始化
|
|
|
+ /*if (!this.OpenIM) {
|
|
|
+ console.error('OpenIM未初始化')
|
|
|
+ this.$message.error('IM服务未就绪')
|
|
|
+ return
|
|
|
+ }*/
|
|
|
+
|
|
|
+ // 2. 设置通话类型
|
|
|
+ this.listTpye = 'calling'
|
|
|
+ this.callingType = type
|
|
|
+
|
|
|
+ // 3. 处理不同类型的会话
|
|
|
+ if (this.currentConversationType === 1) {
|
|
|
+ // 单聊
|
|
|
+ this.startSingleCall(type)
|
|
|
+ } else if (this.currentConversationType === 3) {
|
|
|
+ // 群聊 - 显示成员选择
|
|
|
+ this.showCallingMember = true
|
|
|
+ } else {
|
|
|
+ console.error('不支持的会话类型')
|
|
|
+ this.$message.error('当前会话不支持通话')
|
|
|
+ }
|
|
|
+ },
|
|
|
+// 发起单聊通话
|
|
|
+ async startSingleCall(type) {
|
|
|
+ try {
|
|
|
+ const member = [this.toAccount]
|
|
|
+ const callingData = {
|
|
|
+ memberList: member,
|
|
|
+ type: 1 // 单聊
|
|
|
+ }
|
|
|
+
|
|
|
+ // 1. 存储通话信息
|
|
|
+ this.$store.commit('setCallingList', callingData)
|
|
|
+ console.log("通话信息",callingData)
|
|
|
+ // 2. 触发通话事件
|
|
|
+ this.$bus.$emit(`${type}-call`)
|
|
|
+
|
|
|
+ // 3. 日志记录
|
|
|
+ console.log(`已触发${type}-call事件`, {
|
|
|
+ targetUser: this.toAccount,
|
|
|
+ conversationType: this.currentConversationType
|
|
|
+ })
|
|
|
+ } catch (error) {
|
|
|
+ console.error('发起通话失败:', error)
|
|
|
+ this.$message.error('发起通话失败')
|
|
|
+ }
|
|
|
+ },
|
|
|
+ handleEmojiShow () {
|
|
|
+ this.emojiShow = true
|
|
|
+ this.bigEmojiShow = false
|
|
|
+ },
|
|
|
+ handleBigEmojiShow(index) {
|
|
|
+ let elm = document.getElementById('bigEmojiBox')
|
|
|
+ elm && (elm.scrollTop = 0)
|
|
|
+ this.curItemIndex = index
|
|
|
+ this.curBigEmojiItemList = this.bigEmojiList[index].list
|
|
|
+ this.emojiShow = false
|
|
|
+ this.bigEmojiShow = true
|
|
|
+ },
|
|
|
+ chooseBigEmoji(item) {
|
|
|
+ this.popoverVisible = false
|
|
|
+ let message = this.OpenIM.createFaceMessage({
|
|
|
+ to: this.toAccount,
|
|
|
+ conversationType: this.currentConversationType,
|
|
|
+ payload: {
|
|
|
+ index: this.curItemIndex + 1,
|
|
|
+ data: `${item}@2x`
|
|
|
+ }
|
|
|
+ })
|
|
|
+ let offlinePushInfo = {
|
|
|
+ title:"芳华未来",
|
|
|
+ desc:"表情消息",
|
|
|
+ iOSPushSound:"",
|
|
|
+ iOSBadgeCount:true,
|
|
|
+ operatorUserID:"",
|
|
|
+ ex:""
|
|
|
+ }
|
|
|
+ this.$store.commit('pushCurrentMessageList', message)
|
|
|
+ this.updateConversationList()
|
|
|
+ this.$bus.$emit('scroll-bottom')
|
|
|
+ this.OpenIM.sendMessage(message,offlinePushInfo).catch(error => {
|
|
|
+ this.$store.commit('showMessage', {
|
|
|
+ type: 'error',
|
|
|
+ message: error.message
|
|
|
+ })
|
|
|
+ })
|
|
|
+ },
|
|
|
+ reEditMessage(payload) {
|
|
|
+ this.messageContent = payload
|
|
|
+ },
|
|
|
+ handleUp() {
|
|
|
+ const index = this.memberList.findIndex(
|
|
|
+ member => member.userID === this.atUserID
|
|
|
+ )
|
|
|
+ if (index - 1 < 0) {
|
|
|
+ return
|
|
|
+ }
|
|
|
+ this.atUserID = this.memberList[index - 1].userID
|
|
|
+ },
|
|
|
+ handleDown() {
|
|
|
+ const index = this.memberList.findIndex(
|
|
|
+ member => member.userID === this.atUserID
|
|
|
+ )
|
|
|
+ if (index + 1 >= this.memberList.length) {
|
|
|
+ return
|
|
|
+ }
|
|
|
+ this.atUserID = this.memberList[index + 1].userID
|
|
|
+ },
|
|
|
+ handleEnter() {
|
|
|
+ this.sendTextMessage()
|
|
|
+ },
|
|
|
+ inputChange(value) {
|
|
|
+ if (this.currentConversationType === 3 && value.data === '@') {
|
|
|
+ this.groupAt = true
|
|
|
+ this.listTpye = 'groupAt'
|
|
|
+ this.showCallingMember = true
|
|
|
+ }
|
|
|
+ if (value.data === ' ' && this.messageContent.indexOf('@ ') !== -1) {
|
|
|
+ this.groupAt = false
|
|
|
+ this.listTpye = ''
|
|
|
+ this.showCallingMember = false
|
|
|
+ }
|
|
|
+ },
|
|
|
+ handleLine() {
|
|
|
+ this.messageContent += '\n'
|
|
|
+ },
|
|
|
+ handlePaste(e) {
|
|
|
+ let clipboardData = e.clipboardData
|
|
|
+ let file
|
|
|
+ if (
|
|
|
+ clipboardData &&
|
|
|
+ clipboardData.files &&
|
|
|
+ clipboardData.files.length > 0
|
|
|
+ ) {
|
|
|
+ file = clipboardData.files[0]
|
|
|
+ }
|
|
|
+
|
|
|
+ if (typeof file === 'undefined') {
|
|
|
+ return
|
|
|
+ }
|
|
|
+ // 1. 创建消息实例,接口返回的实例可以上屏
|
|
|
+ let message = this.OpenIM.createImageMessageFromFullPath({
|
|
|
+ to: this.toAccount,
|
|
|
+ conversationType: this.currentConversationType,
|
|
|
+ payload: {
|
|
|
+ file: file
|
|
|
+ },
|
|
|
+ onProgress: percent => {
|
|
|
+ this.$set(message, 'progress', percent) // 手动给message 实例加个响应式属性: progress
|
|
|
+ }
|
|
|
+ })
|
|
|
+ this.$store.commit('pushCurrentMessageList', message)
|
|
|
+ this.updateConversationList()
|
|
|
+ // 2. 发送消息
|
|
|
+ let promise = this.OpenIM.sendMessage(message)
|
|
|
+ promise.catch(error => {
|
|
|
+ this.$store.commit('showMessage', {
|
|
|
+ type: 'error',
|
|
|
+ message: error.message
|
|
|
+ })
|
|
|
+ })
|
|
|
+ },
|
|
|
+ dropHandler(e) {
|
|
|
+ e.preventDefault()
|
|
|
+ let file = e.dataTransfer.files[0]
|
|
|
+ let message = {}
|
|
|
+ if (file.type === 'video/mp4') {
|
|
|
+ message = this.OpenIM.createVideoMessage({
|
|
|
+ to: this.toAccount,
|
|
|
+ conversationType: this.currentConversationType,
|
|
|
+ payload: {
|
|
|
+ file: file
|
|
|
+ },
|
|
|
+ onProgress: percent => {
|
|
|
+ this.$set(message, 'progress', percent) // 手动给message 实例加个响应式属性: progress
|
|
|
+ }
|
|
|
+ })
|
|
|
+ } else {
|
|
|
+ message = this.OpenIM.createFileMessage({
|
|
|
+ to: this.toAccount,
|
|
|
+ conversationType: this.currentConversationType,
|
|
|
+ payload: {
|
|
|
+ file: file
|
|
|
+ },
|
|
|
+ onProgress: percent => {
|
|
|
+ this.$set(message, 'progress', percent) // 手动给message 实例加个响应式属性: progress
|
|
|
+ }
|
|
|
+ })
|
|
|
+ }
|
|
|
+ this.$store.commit('pushCurrentMessageList', message)
|
|
|
+ this.updateConversationList()
|
|
|
+ this.OpenIM
|
|
|
+ .sendMessage(message)
|
|
|
+ .then(() => {
|
|
|
+ this.$refs.videoPicker.value = null
|
|
|
+ })
|
|
|
+ .catch(imError => {
|
|
|
+ this.$store.commit('showMessage', {
|
|
|
+ message: imError.message,
|
|
|
+ type: 'error'
|
|
|
+ })
|
|
|
+ })
|
|
|
+ },
|
|
|
+ sendTextMessage() {
|
|
|
+ if (
|
|
|
+ this.messageContent === '' ||
|
|
|
+ this.messageContent.trim().length === 0
|
|
|
+ ) {
|
|
|
+ this.messageContent = ''
|
|
|
+ this.$store.commit('showMessage', {
|
|
|
+ message: '不能发送空消息哦!',
|
|
|
+ type: 'info'
|
|
|
+ })
|
|
|
+ return
|
|
|
+ }
|
|
|
+ var customData={
|
|
|
+ type:this.$store.state.conversation.type,
|
|
|
+ imType:this.$store.state.conversation.imType,
|
|
|
+ orderId:this.$store.state.conversation.orderId,
|
|
|
+ followId:this.$store.state.conversation.followId,
|
|
|
+ orderType:this.$store.state.conversation.orderType
|
|
|
+ }
|
|
|
+ console.log("创建艾特消息",this.groupAt)
|
|
|
+ if (this.currentConversationType === 3 && this.groupAt) {
|
|
|
+ console.log("创建艾特消息",this.callingList)
|
|
|
+ console.log("创建艾特消息",this.messageContent)
|
|
|
+ console.log("创建艾特消息",customData)
|
|
|
+ const creageAtMessage = {
|
|
|
+ text: this.messageContent.trim(),
|
|
|
+ atUserIDList: this.callingList,
|
|
|
+ atUsersInfo: this.callingList.map((userID, index) => ({
|
|
|
+ atUserID: userID,
|
|
|
+ groupNickname: this.groupAtList[index] || "",
|
|
|
+ })),
|
|
|
+ message: {},
|
|
|
+ }
|
|
|
+ this.OpenIM.createTextAtMessage(creageAtMessage).then(({ data }) => {
|
|
|
+ //创建成功发送消息
|
|
|
+ const sendText={
|
|
|
+ message:data,
|
|
|
+ recvID:"",
|
|
|
+ groupID:this.currentConversation.groupID,
|
|
|
+ offlinePushInfo : {
|
|
|
+ title:data.senderNickname,
|
|
|
+ desc:this.messageContent,
|
|
|
+ iOSPushSound:"",
|
|
|
+ iOSBadgeCount:true,
|
|
|
+ operatorUserID:"",
|
|
|
+ ex:""
|
|
|
+ }
|
|
|
+ }
|
|
|
+ this.OpenIM.sendMessage(sendText).then(({ data }) => {
|
|
|
+ console.log("发送消息返回参数",data)
|
|
|
+ const msgList = Array.isArray(data) ? data : [data];
|
|
|
+ this.$store.commit('pushCurrentMessageList', msgList)
|
|
|
+ this.updateConversationList()
|
|
|
+ this.$bus.$emit('scroll-bottom')
|
|
|
+ }).catch(({ errCode, errMsg }) => {
|
|
|
+ // 调用失败
|
|
|
+ });
|
|
|
+ this.messageContent = ''
|
|
|
+ }).catch(({ errCode, errMsg }) => {
|
|
|
+ // 调用失败
|
|
|
+ console.log("创建@消息失败",errMsg)
|
|
|
+ //this.messageContent = ''
|
|
|
+ });
|
|
|
+ return
|
|
|
+ }
|
|
|
+ console.log("this.messageContent",this.messageContent)
|
|
|
+ console.log("this.currentConversation",this.currentConversation)
|
|
|
+ this.OpenIM.createTextMessage(this.messageContent).then(({ data }) => {
|
|
|
+ console.log("创建文本消息返回参数")
|
|
|
+ console.log(data)
|
|
|
+ console.log("接受哦人id"+ this.$store.getters.toAccount)
|
|
|
+ // 调用成功
|
|
|
+ //console.log("customData",customData)
|
|
|
+ data.ex = JSON.stringify(customData)
|
|
|
+ const sendText={
|
|
|
+ message:data,
|
|
|
+ recvID:this.$store.getters.toAccount||this.currentConversation.userID,
|
|
|
+ groupID:this.currentConversation.groupID,
|
|
|
+ offlinePushInfo : {
|
|
|
+ title:data.senderNickname,
|
|
|
+ desc:this.messageContent,
|
|
|
+ iOSPushSound:"",
|
|
|
+ iOSBadgeCount:true,
|
|
|
+ operatorUserID:"",
|
|
|
+ ex:""
|
|
|
+ }
|
|
|
+ }
|
|
|
+ console.log("发送消息参数",sendText)
|
|
|
+ console.log("发送消息参数",this.OpenIM)
|
|
|
+ console.log("发送消息参数",this.OpenIM.isLogin)
|
|
|
+ /*if (!this.OpenIM || !this.OpenIM.isLogin) {
|
|
|
+ console.warn('⚠️ OpenIM SDK 尚未登录完成,无法发起邀请');
|
|
|
+ return;
|
|
|
+ }*/
|
|
|
+ this.OpenIM.sendMessage(sendText).then(({ data }) => {
|
|
|
+ console.log("发送消息返回参数",data)
|
|
|
+ // 调用成功
|
|
|
+ console.log("customData",customData)
|
|
|
+ const msgList = Array.isArray(data) ? data : [data];
|
|
|
+ this.$store.commit('pushCurrentMessageList', msgList)
|
|
|
+ this.updateConversationList()
|
|
|
+ this.$bus.$emit('scroll-bottom')
|
|
|
+ }).catch(({ errCode, errMsg }) => {
|
|
|
+ // 调用失败
|
|
|
+ });
|
|
|
+ this.messageContent = ''
|
|
|
+ }).catch(({ errCode, errMsg }) => {
|
|
|
+ // 调用失败
|
|
|
+ });
|
|
|
+ /*{
|
|
|
+ cloudCustomData:JSON.stringify(customData),
|
|
|
+ to: this.toAccount,
|
|
|
+ conversationType: this.currentConversationType,
|
|
|
+ payload: { text: this.messageContent }
|
|
|
+ }*/
|
|
|
+
|
|
|
+
|
|
|
+ },
|
|
|
+ updateConversationList(){
|
|
|
+ this.OpenIM.getAllConversationList()
|
|
|
+ .then(({ data }) => {
|
|
|
+ // 调用成功
|
|
|
+ console.log(data,"147852")
|
|
|
+ this.$store.commit('updateConversationList', data)
|
|
|
+ })
|
|
|
+ .catch(({ errCode, errMsg }) => {
|
|
|
+ // 调用失败
|
|
|
+ })
|
|
|
+ },
|
|
|
+ sendCustomMessage() {
|
|
|
+ if (
|
|
|
+ this.form.data.length === 0 &&
|
|
|
+ this.form.description.length === 0 &&
|
|
|
+ this.form.extension.length === 0
|
|
|
+ ) {
|
|
|
+ this.$store.commit('showMessage', {
|
|
|
+ message: '不能发送空消息',
|
|
|
+ type: 'info'
|
|
|
+ })
|
|
|
+ return
|
|
|
+ }
|
|
|
+ var customData={
|
|
|
+ type:this.$store.state.conversation.type,
|
|
|
+ imType:this.$store.state.conversation.imType,
|
|
|
+ orderId:this.$store.state.conversation.orderId,
|
|
|
+ followId:this.$store.state.conversation.followId,
|
|
|
+ orderType:this.$store.state.conversation.orderType
|
|
|
+ }
|
|
|
+ const customMessageData = {
|
|
|
+ data:this.form.data,
|
|
|
+ description: this.form.description,
|
|
|
+ extension: this.form.extension
|
|
|
+ }
|
|
|
+ console.log("customMessageData",customMessageData)
|
|
|
+ this.OpenIM.createCustomMessage(customMessageData)
|
|
|
+ .then(({ data }) => {
|
|
|
+ // 调用成功
|
|
|
+ })
|
|
|
+ .catch(({ errCode, errMsg }) => {
|
|
|
+ // 调用失败
|
|
|
+ });
|
|
|
+ /*const message = this.OpenIM.createCustomMessage({
|
|
|
+ cloudCustomData:JSON.stringify(customData),
|
|
|
+ to: this.toAccount,
|
|
|
+ conversationType: this.currentConversationType,
|
|
|
+ payload: {
|
|
|
+ data: this.form.data,
|
|
|
+ description: this.form.description,
|
|
|
+ extension: this.form.extension
|
|
|
+ }
|
|
|
+ })*/
|
|
|
+ this.$store.commit('pushCurrentMessageList', message)
|
|
|
+ this.updateConversationList()
|
|
|
+ this.OpenIM.sendMessage(message).catch(error => {
|
|
|
+ this.$store.commit('showMessage', {
|
|
|
+ type: 'error',
|
|
|
+ message: error.message
|
|
|
+ })
|
|
|
+ })
|
|
|
+ Object.assign(this.form, {
|
|
|
+ data: '',
|
|
|
+ description: '',
|
|
|
+ extension: ''
|
|
|
+ })
|
|
|
+ this.sendCustomDialogVisible = false
|
|
|
+ },
|
|
|
+ random(min, max) {
|
|
|
+ return Math.floor(Math.random() * (max - min + 1) + min)
|
|
|
+ },
|
|
|
+ sendSurvey() {
|
|
|
+ var customData={
|
|
|
+ type:this.$store.state.conversation.type,
|
|
|
+ imType:this.$store.state.conversation.imType,
|
|
|
+ orderId:this.$store.state.conversation.orderId,
|
|
|
+ followId:this.$store.state.conversation.followId,
|
|
|
+ orderType:this.$store.state.conversation.orderType
|
|
|
+ }
|
|
|
+ console.log("创建自定义消息")
|
|
|
+ const message = this.OpenIM.createCustomMessage({
|
|
|
+ cloudCustomData:JSON.stringify(customData),
|
|
|
+ to: this.toAccount,
|
|
|
+ conversationType: this.currentConversationType,
|
|
|
+ payload: {
|
|
|
+ data: 'survey',
|
|
|
+ description: String(this.rate),
|
|
|
+ extension: this.suggestion
|
|
|
+ }
|
|
|
+ })
|
|
|
+ this.$store.commit('pushCurrentMessageList', message)
|
|
|
+ Object.assign(this.form, {
|
|
|
+ data: '',
|
|
|
+ description: '',
|
|
|
+ extension: ''
|
|
|
+ })
|
|
|
+ this.OpenIM
|
|
|
+ .sendMessage(message)
|
|
|
+ .then(() => {
|
|
|
+ console.log("发送自定义消息")
|
|
|
+ Object.assign(this, {
|
|
|
+ rate: 5,
|
|
|
+ suggestion: ''
|
|
|
+ })
|
|
|
+ })
|
|
|
+ .catch(error => {
|
|
|
+ this.$store.commit('showMessage', {
|
|
|
+ type: 'error',
|
|
|
+ message: error.message
|
|
|
+ })
|
|
|
+ })
|
|
|
+ this.surveyDialogVisible = false
|
|
|
+ },
|
|
|
+ chooseEmoji(item) {
|
|
|
+ const emojiChar = this.emojiCharMap[item] || item;
|
|
|
+ console.log("emojiChar",emojiChar)
|
|
|
+ this.messageContent += emojiChar;
|
|
|
+ },
|
|
|
+ handleSendImageClick() {
|
|
|
+ this.$refs.imagePicker.click()
|
|
|
+ },
|
|
|
+ handleSendFileClick() {
|
|
|
+ this.$refs.filePicker.click()
|
|
|
+ },
|
|
|
+ handleSendVideoClick() {
|
|
|
+ this.$refs.videoPicker.click()
|
|
|
+ },
|
|
|
+ groupLive() {
|
|
|
+ this.$store.commit('updateGroupLiveInfo', {
|
|
|
+ groupID: this.toAccount,
|
|
|
+ anchorID: this.userID,
|
|
|
+ })
|
|
|
+ this.$bus.$emit('open-group-live', { channel: 1 })
|
|
|
+ },
|
|
|
+ generateUUID() {
|
|
|
+ return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
|
|
|
+ var r = (Math.random() * 16) | 0,
|
|
|
+ v = c == 'x' ? r : (r & 0x3) | 0x8
|
|
|
+ return v.toString(16)
|
|
|
+ })
|
|
|
+ },
|
|
|
+ sendImage() {
|
|
|
+ const input = document.getElementById('imagePicker');
|
|
|
+ const imageFile = input?.files?.[0];
|
|
|
+ if (!imageFile) return;
|
|
|
+
|
|
|
+ const picBaseInfo = {
|
|
|
+ uuid: this.generateUUID(),
|
|
|
+ type: imageFile.type,
|
|
|
+ size: imageFile.size,
|
|
|
+ width: 0,
|
|
|
+ height: 0,
|
|
|
+ url: '',
|
|
|
+ };
|
|
|
+
|
|
|
+ const setImageDimensions = (file, callback) => {
|
|
|
+ const reader = new FileReader();
|
|
|
+ reader.onload = (e) => {
|
|
|
+ const img = new Image();
|
|
|
+ img.onload = () => {
|
|
|
+ callback({ width: img.width, height: img.height });
|
|
|
+ };
|
|
|
+ img.src = e.target.result;
|
|
|
+ };
|
|
|
+ reader.readAsDataURL(file);
|
|
|
+ };
|
|
|
+
|
|
|
+ setImageDimensions(imageFile, ({ width, height }) => {
|
|
|
+ // 创建图片对象
|
|
|
+ const updatedPicInfo = {
|
|
|
+ ...picBaseInfo,
|
|
|
+ width,
|
|
|
+ height,
|
|
|
+ };
|
|
|
+
|
|
|
+ const messageData = {
|
|
|
+ sourcePicture: { ...updatedPicInfo },
|
|
|
+ bigPicture: { ...updatedPicInfo },
|
|
|
+ snapshotPicture: { ...updatedPicInfo },
|
|
|
+ file: imageFile,
|
|
|
+ sourcePath: imageFile.name,
|
|
|
+ onProgress: percent => {
|
|
|
+ this.$set(updatedPicInfo, 'progress', percent);
|
|
|
+ },
|
|
|
+ };
|
|
|
+
|
|
|
+ this.OpenIM.createImageMessageByFile(messageData)
|
|
|
+ .then(({ data: message }) => {
|
|
|
+ const isGroup = this.currentConversationType === 3;
|
|
|
+ return this.OpenIM.sendMessage({
|
|
|
+ message,
|
|
|
+ recvID: isGroup ? '' : this.$store.getters.toAccount||this.currentConversation.userID,
|
|
|
+ groupID: isGroup ? this.currentConversation.groupID : '',
|
|
|
+ offlinePushInfo : {
|
|
|
+ title:message.senderNickname,
|
|
|
+ desc:"[图片]",
|
|
|
+ iOSPushSound:"",
|
|
|
+ iOSBadgeCount:true,
|
|
|
+ operatorUserID:"",
|
|
|
+ ex:""
|
|
|
+ }
|
|
|
+ });
|
|
|
+ })
|
|
|
+ .then(({ data }) => {
|
|
|
+ console.log('发送图片成功', data);
|
|
|
+ const msgList = Array.isArray(data) ? data : [data];
|
|
|
+ this.$store.commit('pushCurrentMessageList', msgList);
|
|
|
+ this.updateConversationList()
|
|
|
+ this.$bus.$emit('scroll-bottom');
|
|
|
+ this.$refs.imagePicker.value = null;
|
|
|
+ })
|
|
|
+ .catch(({ errCode, errMsg }) => {
|
|
|
+ console.error('发送图片失败', errCode, errMsg);
|
|
|
+ this.$store.commit('showMessage', {
|
|
|
+ message: errMsg,
|
|
|
+ type: 'error',
|
|
|
+ });
|
|
|
+ });
|
|
|
+ });
|
|
|
+ },
|
|
|
+
|
|
|
+ sendFile() {
|
|
|
+ const input = document.getElementById('filePicker');
|
|
|
+ const file = input.files[0];
|
|
|
+ if (!file) return;
|
|
|
+
|
|
|
+ const customData = {
|
|
|
+ type: this.$store.state.conversation.type,
|
|
|
+ imType: this.$store.state.conversation.imType,
|
|
|
+ orderId: this.$store.state.conversation.orderId,
|
|
|
+ followId: this.$store.state.conversation.followId,
|
|
|
+ orderType: this.$store.state.conversation.orderType
|
|
|
+ };
|
|
|
+
|
|
|
+ // 1. 创建文件消息
|
|
|
+ this.OpenIM.createFileMessageByFile({
|
|
|
+ filePath: file.name,
|
|
|
+ fileName: file.name,
|
|
|
+ uuid: this.generateUUID(),
|
|
|
+ sourceUrl: '',
|
|
|
+ fileSize: file.size,
|
|
|
+ fileType: file.type,
|
|
|
+ file,
|
|
|
+ cloudCustomData: JSON.stringify(customData),
|
|
|
+ onProgress: percent => {
|
|
|
+ this.$set(file, 'progress', percent);
|
|
|
+ }
|
|
|
+ }).then(({ data }) => {
|
|
|
+ // 2. 发送文件消息
|
|
|
+ const sendFile = {
|
|
|
+ message: data,
|
|
|
+ recvID: this.$store.getters.toAccount||this.currentConversation.userID,
|
|
|
+ groupID: this.currentConversationType === 3 ? this.currentConversation.groupID : "",
|
|
|
+ offlinePushInfo : {
|
|
|
+ title:data.senderNickname,
|
|
|
+ desc:"[文件]",
|
|
|
+ iOSPushSound:"",
|
|
|
+ iOSBadgeCount:true,
|
|
|
+ operatorUserID:"",
|
|
|
+ ex:""
|
|
|
+ }
|
|
|
+ };
|
|
|
+
|
|
|
+ return this.OpenIM.sendMessage(sendFile);
|
|
|
+ }).then(({ data }) => {
|
|
|
+ const msgList = Array.isArray(data) ? data : [data];
|
|
|
+ this.$store.commit('pushCurrentMessageList', msgList);
|
|
|
+ this.updateConversationList()
|
|
|
+ this.$bus.$emit('scroll-bottom');
|
|
|
+ this.$refs.filePicker.value = null;
|
|
|
+ }).catch(({ errCode, errMsg }) => {
|
|
|
+ console.error("发送文件失败", errCode, errMsg);
|
|
|
+ this.$store.commit('showMessage', {
|
|
|
+ message: errMsg,
|
|
|
+ type: 'error'
|
|
|
+ });
|
|
|
+ });
|
|
|
+ },
|
|
|
+ sendVideo() {
|
|
|
+ const videoInput = document.getElementById('videoPicker');
|
|
|
+ const file = videoInput.files[0];
|
|
|
+ if (!file) return;
|
|
|
+
|
|
|
+ const customData = {
|
|
|
+ type: this.$store.state.conversation.type,
|
|
|
+ imType: this.$store.state.conversation.imType,
|
|
|
+ orderId: this.$store.state.conversation.orderId,
|
|
|
+ followId: this.$store.state.conversation.followId,
|
|
|
+ orderType: this.$store.state.conversation.orderType,
|
|
|
+ };
|
|
|
+
|
|
|
+ const videoURL = URL.createObjectURL(file);
|
|
|
+ const video = document.createElement('video');
|
|
|
+ video.preload = 'metadata';
|
|
|
+ video.src = videoURL;
|
|
|
+
|
|
|
+ video.onloadedmetadata = () => {
|
|
|
+ URL.revokeObjectURL(videoURL); // 清理临时URL
|
|
|
+ const duration = Math.ceil(video.duration); // 视频时长
|
|
|
+
|
|
|
+ // 等待第一帧加载
|
|
|
+ video.currentTime = 0;
|
|
|
+ };
|
|
|
+
|
|
|
+ video.onloadeddata = () => {
|
|
|
+ // 创建 canvas 截取视频第一帧
|
|
|
+ const canvas = document.createElement('canvas');
|
|
|
+ canvas.width = video.videoWidth;
|
|
|
+ canvas.height = video.videoHeight;
|
|
|
+ const ctx = canvas.getContext('2d');
|
|
|
+ ctx.drawImage(video, 0, 0, canvas.width, canvas.height);
|
|
|
+
|
|
|
+ canvas.toBlob(snapshotBlob => {
|
|
|
+ const snapshotFile = new File([snapshotBlob], 'snapshot.png', { type: 'image/png' });
|
|
|
+
|
|
|
+ // 创建视频消息
|
|
|
+ this.OpenIM.createVideoMessageByFile({
|
|
|
+ cloudCustomData: JSON.stringify(customData),
|
|
|
+ videoPath: file.name,
|
|
|
+ duration: Math.ceil(video.duration),
|
|
|
+ videoType: file.type,
|
|
|
+ snapshotPath: snapshotFile.name,
|
|
|
+ videoUUID: '',
|
|
|
+ videoUrl: '',
|
|
|
+ videoSize: file.size,
|
|
|
+ snapshotUUID: '',
|
|
|
+ snapshotSize: snapshotFile.size,
|
|
|
+ snapshotUrl: '',
|
|
|
+ snapshotWidth: video.videoWidth,
|
|
|
+ snapshotHeight: video.videoHeight,
|
|
|
+ snapShotType: snapshotFile.type,
|
|
|
+ videoFile: file,
|
|
|
+ snapshotFile,
|
|
|
+ onProgress: percent => {
|
|
|
+ this.$set(this, 'videoProgress', percent);
|
|
|
+ }
|
|
|
+ }).then(({ data }) => {
|
|
|
+ const sendVideo = {
|
|
|
+ message: data,
|
|
|
+ recvID: this.$store.getters.toAccount||this.currentConversation.userID,
|
|
|
+ groupID: this.currentConversationType === 3 ? this.currentConversation.groupID : "",
|
|
|
+ offlinePushInfo : {
|
|
|
+ title:data.senderNickname,
|
|
|
+ desc:"[视频]",
|
|
|
+ iOSPushSound:"",
|
|
|
+ iOSBadgeCount:true,
|
|
|
+ operatorUserID:"",
|
|
|
+ ex:""
|
|
|
+ }
|
|
|
+ };
|
|
|
+
|
|
|
+ this.OpenIM.sendMessage(sendVideo).then(({ data }) => {
|
|
|
+ const msgList = Array.isArray(data) ? data : [data];
|
|
|
+ this.$store.commit('pushCurrentMessageList', msgList);
|
|
|
+ this.updateConversationList();
|
|
|
+ this.$bus.$emit('scroll-bottom');
|
|
|
+ this.$refs.videoPicker.value = null;
|
|
|
+ }).catch(({ errCode, errMsg }) => {
|
|
|
+ console.error("发送视频失败", errCode, errMsg);
|
|
|
+ });
|
|
|
+ });
|
|
|
+ }, 'image/png');
|
|
|
+ };
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ }
|
|
|
+}
|
|
|
+</script>
|
|
|
+<style lang="stylus" scoped>
|
|
|
+.at-member-box {
|
|
|
+ max-height: 260px;
|
|
|
+ overflow-y: auto;
|
|
|
+}
|
|
|
+
|
|
|
+.at-member-item {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ padding: 6px 8px;
|
|
|
+ cursor: pointer;
|
|
|
+}
|
|
|
+
|
|
|
+.at-member-item:hover {
|
|
|
+ background: #f5f7fa;
|
|
|
+}
|
|
|
+
|
|
|
+.avatar-border {
|
|
|
+ width: 24px;
|
|
|
+ height: 24px;
|
|
|
+ margin: 0 12px 0 0;
|
|
|
+ vertical-align: middle;
|
|
|
+ cursor: pointer;
|
|
|
+ transition: all 0.2s ease;
|
|
|
+ filter: grayscale(20%);
|
|
|
+}
|
|
|
+
|
|
|
+.avatar-border:hover {
|
|
|
+ transform: scale(1.2);
|
|
|
+ filter: grayscale(0%);
|
|
|
+}
|
|
|
+
|
|
|
+#message-send-box-wrapper {
|
|
|
+ box-sizing: border-box;
|
|
|
+ overflow: hidden;
|
|
|
+ padding: 3px 20px 20px 20px;
|
|
|
+ width : 100%;
|
|
|
+}
|
|
|
+
|
|
|
+.emojis {
|
|
|
+ height: 160px;
|
|
|
+ box-sizing: border-box;
|
|
|
+ display: flex;
|
|
|
+ flex-direction: row;
|
|
|
+ flex-wrap: wrap;
|
|
|
+ overflow-y: scroll;
|
|
|
+}
|
|
|
+
|
|
|
+.emoji {
|
|
|
+ height: 40px;
|
|
|
+ width: 40px;
|
|
|
+ box-sizing: border-box;
|
|
|
+}
|
|
|
+
|
|
|
+.send-header-bar {
|
|
|
+ box-sizing: border-box;
|
|
|
+ padding: 3px 0 0 0;
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+}
|
|
|
+
|
|
|
+.send-header-bar i {
|
|
|
+ cursor: pointer;
|
|
|
+ font-size: 24px;
|
|
|
+ color: gray;
|
|
|
+ margin: 0 12px 0 0;
|
|
|
+}
|
|
|
+
|
|
|
+.send-header-bar i:hover {
|
|
|
+ color: $black;
|
|
|
+}
|
|
|
+
|
|
|
+textarea {
|
|
|
+ resize: none;
|
|
|
+}
|
|
|
+
|
|
|
+.text-input {
|
|
|
+ font-size: 16px;
|
|
|
+ width: 100%;
|
|
|
+ box-sizing: box-sizing;
|
|
|
+ border: none;
|
|
|
+ outline: none;
|
|
|
+ background-color: transparent;
|
|
|
+}
|
|
|
+
|
|
|
+.block {
|
|
|
+ padding: 10px 0;
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+}
|
|
|
+
|
|
|
+.bottom {
|
|
|
+ padding-top: 10px;
|
|
|
+ position: relative;
|
|
|
+
|
|
|
+ .btn-send {
|
|
|
+ cursor: pointer;
|
|
|
+ position: absolute;
|
|
|
+ color: $primary;
|
|
|
+ font-size: 30px;
|
|
|
+ right: 0;
|
|
|
+ bottom: -5px;
|
|
|
+ padding: 6px 6px 4px 4px;
|
|
|
+ border-radius: 50%;
|
|
|
+ }
|
|
|
+}
|
|
|
+.group-live-icon-box {
|
|
|
+ display inline-block
|
|
|
+ position relative
|
|
|
+ top 3px
|
|
|
+ width 25px
|
|
|
+ height 25px
|
|
|
+ margin-right 12px
|
|
|
+ .group-live-icon {
|
|
|
+ display inline-block
|
|
|
+ position absolute
|
|
|
+ top 0
|
|
|
+ left 0
|
|
|
+ width 25px
|
|
|
+ height 25px
|
|
|
+ background url('../../assets/image/live-icon.png') center no-repeat
|
|
|
+ background-size cover
|
|
|
+ z-index 2
|
|
|
+ }
|
|
|
+ .group-live-icon-hover {
|
|
|
+ display inline-block
|
|
|
+ position absolute
|
|
|
+ top 0
|
|
|
+ left 0
|
|
|
+ width 25px
|
|
|
+ height 25px
|
|
|
+ background url('../../assets/image/live-icon-hover.png') center no-repeat
|
|
|
+ background-size cover
|
|
|
+ z-index 1
|
|
|
+ }
|
|
|
+}
|
|
|
+.group-live-icon-box:hover {
|
|
|
+ .group-live-icon {
|
|
|
+ z-index 1
|
|
|
+ }
|
|
|
+ .group-live-icon-hover{
|
|
|
+ z-index 2
|
|
|
+ }
|
|
|
+}
|
|
|
+.calling-member-list {
|
|
|
+ position absolute
|
|
|
+ top 50px
|
|
|
+ background #fff
|
|
|
+ margin-right 20px
|
|
|
+ .calling-list-btn {
|
|
|
+ width 140px
|
|
|
+ display flex
|
|
|
+ float right
|
|
|
+ margin 10px 0
|
|
|
+ .calling-btn {
|
|
|
+ cursor pointer
|
|
|
+ padding 6px 12px
|
|
|
+ background #00A4FF
|
|
|
+ color #ffffff
|
|
|
+ font-size 14px
|
|
|
+ border-radius 20px
|
|
|
+ margin-left 13px
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+.el-popover {
|
|
|
+ padding: 12px 0 0 0 !important;
|
|
|
+}
|
|
|
+</style>
|