diff --git a/src/api/newChat.js b/src/api/newChat.js new file mode 100644 index 000000000..3e7f3ca06 --- /dev/null +++ b/src/api/newChat.js @@ -0,0 +1,174 @@ + +import request from '@/utils/request'; + +/** + * 获取群列表 + * @param {String} groupId 房间号 + * @returns + */ +export function getGroupList(groupId) { + return request({ + url: `/api/simulation/${groupId}/conversation/group/list`, + method: 'get' + }); +} + +/** + * 创建群 + * @param {String} groupId 房间号 + * @param {String} data + * @param {String} data.name 群组名称 + * @param {String} data.imageUrl 群组头像 + * @param {Array} data.memberIds 角色id列表 + * @returns + */ +export function createGroup(groupId, data) { + return request({ + url: `/simulation/${groupId}/operate/Conversation_Group_Create`, + method: 'post', + data + }); +} + +/** + * 修改群组名称 + * @param {String} groupId 房间号 + * @param {Object} data + * @param {String} data.id 群组id + * @param {String} data.name 群组名称 + * @returns + */ +export function updateGroupName(groupId, data) { + return request({ + url: `/simulation/${groupId}/operate/Conversation_Group_Update_Name`, + method: 'post', + data + }); +} + +/** + * 修改群组群主 + * @param {String} groupId 房间号 + * @param {Object} data + * @param {Number} data.id 群组id + * @param {String} data.memberId 角色id + * @returns + */ +export function updateGroupLeader(groupId, data) { + return request({ + url: `/simulation/${groupId}/operate/Conversation_Group_Update_Leader`, + method: 'post', + data + }); +} + +/** + * 邀请人员入群 + * @param {String} groupId 房间号 + * @param {Object} data + * @param {Number} data.id 群组id + * @param {Array} data.memberIds 角色id列表 + * @returns + */ +export function inviteMemberToGroup(groupId, data) { + return request({ + url: `/simulation/${groupId}/operate/Conversation_Group_Invite_Member`, + method: 'post', + data + }); +} + +/** + * 移除群内人员 + * @param {String} groupId 房间号 + * @param {Object} data + * @param {Number} data.id 群组id + * @param {Array} data.memberIds 角色id列表 + * @returns + */ +export function removeMemberFromGroup(groupId, data) { + return request({ + url: `/simulation/${groupId}/operate/Conversation_Group_Remove_Member`, + method: 'post', + data + }); +} + +/** + * 退出群组 + * @param {String} groupId 房间号 + * @param {Object} data + * @param {Number} data.id 群组id + * @returns + */ +export function exitGroup(groupId, data) { + return request({ + url: `/simulation/${groupId}/operate/Conversation_Group_Exit`, + method: 'post', + data + }); +} + +/** + * 解散群组 + * @param {String} groupId 房间号 + * @param {Object} data + * @param {Number} data.id 群组id + * @returns + */ +export function dissolveGroup(groupId, data) { + return request({ + url: `/simulation/${groupId}/operate/Conversation_Group_Dissolve`, + method: 'post', + data + }); +} + +/** + * 发送语音信息 + * @param {String} groupId 房间号 + * @param {Object} data + * @param {Number} data.id 群组id + * @param {String} data.audioPath 文件地址 + * @param {String} data.content 语音内容 + * @returns + */ +export function sendAudio(groupId, data) { + return request({ + url: `/simulation/${groupId}/operate/Conversation_Group_Audio_Chat`, + method: 'post', + data + }); +} + +/** + * 发送文字信息 + * @param {String} groupId 房间号 + * @param {Object} data + * @param {Number} data.id 群组id + * @param {String} data.content 文字内容 + * @returns + */ +export function sendText(groupId, data) { + return request({ + url: `/simulation/${groupId}/operate/Conversation_Group_Text_Chat`, + method: 'post', + data + }); +} + +/** + * 发送BASE64信息 + * @param {String} groupId 房间号 + * @param {Object} data + * @param {Number} data.id 群组id + * @param {String} data.fileBase64Str 文件base64码 + * @returns + */ +export function sendBase64(groupId, data) { + return request({ + url: `/simulation/${groupId}/operate/Conversation_Group_Audio_Base64`, + method: 'post', + data + }); +} diff --git a/src/scripts/cmdPlugin/CommandEnum.js b/src/scripts/cmdPlugin/CommandEnum.js index 85d887894..b72a36398 100644 --- a/src/scripts/cmdPlugin/CommandEnum.js +++ b/src/scripts/cmdPlugin/CommandEnum.js @@ -511,7 +511,9 @@ export default { }, Conversation: { CMD_Conversation_Chat_Text: {value: 'Conversation_Chat_Text', label: '发送文本消息'}, - CMD_Conversation_Chat_Audio_Base64: {value: 'Conversation_Chat_Audio_Base64', label: '发送语音消息'} + CMD_Conversation_Chat_Audio_Base64: {value: 'Conversation_Chat_Audio_Base64', label: '发送语音消息'}, + CMD_Conversation_Group_Text_Chat: {value: 'Conversation_Group_Text_Chat', label: '发送会话群文字消息'}, + CMD_Conversation_Group_Audio_Base64: {value: 'Conversation_Group_Audio_Base64', label: '发送会话群语音消息'} }, PSL: { CMD_PSL_PRESS_BUTTON: {value: 'PSL_PRESS_BUTTON', label: 'PSL按钮操作'} diff --git a/src/store/modules/map.js b/src/store/modules/map.js index e7a27d9ff..6a509048d 100644 --- a/src/store/modules/map.js +++ b/src/store/modules/map.js @@ -826,6 +826,19 @@ const map = { map.memberMap.EMERGENCY = []; } } + if (!map.conversationGroupMap) { + map.conversationGroupMap = { METRO: [], RAILWAY: [], EMERGENCY: [] }; + } else { + if (!map.conversationGroupMap.METRO) { + map.conversationGroupMap.METRO = []; + } + if (!map.conversationGroupMap.RAILWAY) { + map.conversationGroupMap.RAILWAY = []; + } + if (!map.conversationGroupMap.EMERGENCY) { + map.conversationGroupMap.EMERGENCY = []; + } + } state.map = map; let showConfig = {}; if (Vue.prototype.$jlmap && typeof Vue.prototype.$jlmap.getShowConfig === 'function') { diff --git a/src/store/modules/socket.js b/src/store/modules/socket.js index cb0d1c3e7..6b47d4722 100644 --- a/src/store/modules/socket.js +++ b/src/store/modules/socket.js @@ -120,6 +120,14 @@ const socket = { conversationMessage: {}, controlTransfer: {}, operationModeApplyList: [], // 模式转换消息列表 + conversationGroup: { // 群组 + JOIN: {}, // 创建或加入群组 + UPDATE_NAME: {}, // 更新名称 + UPDATE_MEMBER: {}, // 更新群成员 + EXIT: {}, // 退群 + MESSAGE: {}, // 消息 + MESSAGE_STATUS: {} // 消息状态 + }, nccRunData: [] // ncc运行数据 }, getters: { @@ -408,6 +416,17 @@ const socket = { } }); }, + setConversationGroup: (state, message) => { + if (state.conversationGroup[message.messageType] !== undefined) { + state.conversationGroup[message.messageType] = message; + } + }, + resetConversationGroup: (state) => { + const arr = ['JOIN', 'UPDATE_NAME', 'UPDATE_MEMBER', 'EXIT', 'MESSAGE', 'MESSAGE_STATUS']; + arr.forEach(key => { + state.conversationGroup[key] = {}; + }); + }, handleNccRun: (state, list) => { state.nccRunData = list; } @@ -649,6 +668,12 @@ const socket = { operationModeApply: ({ commit }, message) => { commit('operationModeApply', message); }, + setConversationGroup: ({ commit }, message) => { + commit('setConversationGroup', message); + }, + resetConversationGroup: ({ commit }) => { + commit('resetConversationGroup'); + }, handleNccRun: ({ commit }, message) => { commit('handleNccRun', message); } diff --git a/src/utils/subscribeCallback.js b/src/utils/subscribeCallback.js index 087ac9c05..dddf8f9a5 100644 --- a/src/utils/subscribeCallback.js +++ b/src/utils/subscribeCallback.js @@ -99,6 +99,9 @@ function handle(data) { case 'Simulation_Member': store.dispatch('socket/memberChangeCountIncrease'); break; + case 'Simulation_Conversation_Group': + store.dispatch('socket/setConversationGroup', msg); + break; case 'Simulation_Time_Sync': store.dispatch('socket/setSimulationTimeSync', msg); break; diff --git a/src/views/newMap/display/index.vue b/src/views/newMap/display/index.vue index 03ce0b51f..1f807ceda 100644 --- a/src/views/newMap/display/index.vue +++ b/src/views/newMap/display/index.vue @@ -29,7 +29,7 @@ import TrainingTip from './trainingList/trainingTip'; import TrainingPositionTip from './trainingList/trainingPositionTip.vue'; import TrainingMenu from './trainingList/trainingMenu'; import TrainingDesign from './trainingDesign/designPane.vue'; -import ChatBox from './chatBox'; +import ChatBox from './newChat/index.vue'; import TrainingLeftSlider from './trainingList/trainingLeftSlider'; import LineBoard from './lineBoard'; import BottomTable from './bottomTable'; diff --git a/src/views/newMap/display/newChat/chatContent.vue b/src/views/newMap/display/newChat/chatContent.vue new file mode 100644 index 000000000..ef69211bb --- /dev/null +++ b/src/views/newMap/display/newChat/chatContent.vue @@ -0,0 +1,528 @@ + + + + + + diff --git a/src/views/newMap/display/newChat/chatDialog.vue b/src/views/newMap/display/newChat/chatDialog.vue new file mode 100644 index 000000000..0c385f64b --- /dev/null +++ b/src/views/newMap/display/newChat/chatDialog.vue @@ -0,0 +1,430 @@ + + + + + + + diff --git a/src/views/newMap/display/newChat/editGroup.vue b/src/views/newMap/display/newChat/editGroup.vue new file mode 100644 index 000000000..72c8fcf85 --- /dev/null +++ b/src/views/newMap/display/newChat/editGroup.vue @@ -0,0 +1,570 @@ + + + + + + + diff --git a/src/views/newMap/display/newChat/index.vue b/src/views/newMap/display/newChat/index.vue new file mode 100644 index 000000000..5f8c99c71 --- /dev/null +++ b/src/views/newMap/display/newChat/index.vue @@ -0,0 +1,64 @@ + + + + + + diff --git a/src/views/newMap/newMapdraft/mapoperate/simulationMember/index.vue b/src/views/newMap/newMapdraft/mapoperate/simulationMember/index.vue index 2d101f2c8..32bcf076b 100644 --- a/src/views/newMap/newMapdraft/mapoperate/simulationMember/index.vue +++ b/src/views/newMap/newMapdraft/mapoperate/simulationMember/index.vue @@ -303,6 +303,123 @@ 一键清空 + + + +
+ +
群名称
+
群头像
+
群主
+
成员
+
操作
+
+ + + + + +
+ + + +
+
+ + + + + + + + + + + + 删除 + +
+
+
+ +
+ +
群名称
+
群头像
+
群主
+
成员
+
操作
+
+ + + + + +
+ + + +
+
+ + + + + + + + + + + + 删除 + +
+
+
+ +
+ +
群名称
+
群头像
+
群主
+
成员
+
操作
+
+ + + + + +
+ + + +
+
+ + + + + + + + + + + + 删除 + +
+
+
+
+
+ + 新建会话群 + +
+
@@ -310,6 +427,7 @@ import {mapGetters} from 'vuex'; import { getDisStationList } from '@/api/disStation'; import ConstConfig from '@/scripts/ConstConfig'; +import { getUploadUrl } from '@/api/projectConfig'; export default { name: 'SimulationMember', data() { @@ -317,6 +435,7 @@ export default { lazy: true, activeName: 'first', memberActive: 'METRO', + conversationActive: 'METRO', roleList: ConstConfig.ConstSelect.roleTypeList, systemList: [ { label: '地铁CBTC', value: 'METRO' }, @@ -377,6 +496,15 @@ export default { }, memberEmergencyList() { return this.$store.state.map.map.memberMap.EMERGENCY; + }, + conversationMetroList() { + return this.$store.state.map.map.conversationGroupMap.METRO; + }, + conversationRailwayList() { + return this.$store.state.map.map.conversationGroupMap.RAILWAY; + }, + conversationEmergencyList() { + return this.$store.state.map.map.conversationGroupMap.EMERGENCY; } }, watch: { @@ -386,6 +514,98 @@ export default { this.initDisStationList(); }, methods: { + getMemberTitle(val, list) { + const mapList = {}; + list.forEach(item => { + mapList[item.id] = item; + }); + const titleArr = []; + let valArr = []; + if (Array.isArray(val)) { + valArr = val; + } else if (typeof val == 'string') { + valArr = [val]; + } + valArr.forEach(id => { + if (mapList[id]) { + titleArr.push(this.getLabel(mapList[id])); + } + }); + return titleArr.join('\n'); + }, + getImgUrl(url) { + return url ? this.$store.state.user.ossUrl + '/conversationGroup/' + url : ''; + }, + getLabel(obj) { + let name = ''; + const findType = this.roleList.find(item => { + return item.value == obj.type; + }); + if (findType) { + name += findType.label; + } + name += '-'; + if (obj.type == 'DISPATCHER') { + const findDeviceCode = this.disStationList.find(item => { + return item.code == obj.deviceCode; + }); + if (findDeviceCode) { + name += findDeviceCode.name; + } + } else if (obj.type == 'DRIVER') { + const findDeviceCode = this.trainList.find(item => { + return item.groupNumber == obj.deviceCode; + }); + if (findDeviceCode) { + name += findDeviceCode.groupNumber; + } + } else { + const findDeviceCode = this.stationList.find(item => { + return item.code == obj.deviceCode; + }); + if (findDeviceCode) { + name += findDeviceCode.name; + } + } + return name; + }, + deleteConversation(index, type) { + const conversationMap = { METRO: this.conversationMetroList, RAILWAY: this.conversationRailwayList, EMERGENCY: this.conversationEmergencyList }; + if (conversationMap[this.conversationActive]) { + conversationMap[this.conversationActive].splice(index, 1); + } + }, + createConversation() { + const list = []; + this.conversationMetroList.forEach(item => { + if (item.id) { + list.push(item.id); + } + }); + this.conversationRailwayList.forEach(item => { + if (item.id) { + list.push(item.id); + } + }); + this.conversationEmergencyList.forEach(item => { + if (item.id) { + list.push(item.id); + } + }); + const maxNum = list.length ? Math.max(...list) : 0; + const obj = { + id: maxNum + 1, + name: '', + imageUrl: '', + leaderId: '', + memberIds: [] + }; + console.log('🚀 ~ file: index.vue:584 ~ createConversation ~ obj:', obj); + const conversationMap = { METRO: this.conversationMetroList, RAILWAY: this.conversationRailwayList, EMERGENCY: this.conversationEmergencyList }; + if (conversationMap[this.conversationActive]) { + conversationMap[this.conversationActive].push(obj); + } + }, initDisStationList() { getDisStationList(this.$route.params.mapId).then(resp => { this.disStationList = resp.data || []; @@ -836,11 +1056,94 @@ export default { keyClear() { const memberMap = { METRO: this.memberMetroList, RAILWAY: this.memberRailwayList, EMERGENCY: this.memberEmergencyList }; memberMap[this.clearForm.systemType].splice(0, memberMap[this.clearForm.systemType].length); + }, + uploadLogo(type, index) { + const pic = document.getElementById('upload_file_' + type + index); + if (!pic.files || !pic.files[0]) { + return; + } + const file = pic.files[0]; + const mineType = file.type; + const fileSize = file.size; + if (mineType != 'image/png' && mineType != 'image/jpeg') { + this.$message.error('仅支持png和jpeg格式的图片'); + return; + } + if (fileSize / (1024 * 1024) > 1) { + this.$message.error('图片应该小于1M'); + return; + } + const fileArray = file.name.split('.'); + const fileType = fileArray[fileArray.length - 1] || ''; + if (!fileType) { + return; + } + const params = { + directory:'conversationGroup', + fileName:'group_' + Math.floor(Math.random() * 1000000) + '.' + fileType, + method:'PUT' + }; + const conversationMap = { METRO: this.conversationMetroList, RAILWAY: this.conversationRailwayList, EMERGENCY: this.conversationEmergencyList }; + const that = this; + getUploadUrl(params).then((response) => { + const url = response.data; + if (url) { + const xhr = new XMLHttpRequest(); + xhr.open('PUT', url); + xhr.setRequestHeader('Content-Type', 'multipart/form-data'); + xhr.send(file); + xhr.onreadystatechange = function() { + if (xhr.readyState === 4 && xhr.status == 200) { + if (conversationMap[type] && conversationMap[type][index]) { + conversationMap[type][index].imageUrl = params.fileName; + } + } else if (xhr.status != 200) { + that.$message.error('上传失败,请稍后再试'); + } + }; + } + }); + + // 参数:directory:MINIO文件夹 + // fileName:存储文件名 + // method:生成链接的请求方式 } } }; -