MobilePlatform.vue 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373
  1. <template>
  2. <div class="menu-content">
  3. <div class="container">
  4. <div class="gradient-text title">手机工作台</div>
  5. <!-- <div class="box2">-->
  6. <div class="box-left">
  7. <el-input v-model="queryParams.keywords" class="custom-input" placeholder="搜索" @input="initData">
  8. <template #prefix>
  9. <el-icon class="el-input__icon"><search /></el-icon>
  10. </template>
  11. </el-input>
  12. <div class="btn" @click="handleCancel">取消</div>
  13. </div>
  14. </div>
  15. <!-- </div>-->
  16. <div class="custom-table">
  17. <div class="th">
  18. <div class="td">设备</div>
  19. <!--
  20. <div class="td">姓名</div>
  21. <div class="td">工作单位</div>
  22. <div class="td">职务</div>
  23. -->
  24. <div class="td" style="width: 330px; flex: unset">操作</div>
  25. </div>
  26. <div class="table-content">
  27. <div v-for="item in dataList" :key="item.dev_id" class="tr">
  28. <div class="td">{{ item.dev_name }}</div>
  29. <!--
  30. <div class="td">{{ item.name }}</div>
  31. <div class="td">{{ item.work_unit }}</div>
  32. <div class="td">{{ item.position }}</div>
  33. -->
  34. <div class="td" style="width: 330px; flex: unset">
  35. <div class="text" @click="handleConnect(item)">连线</div>
  36. <!--
  37. <div class="text" @click="handleCollaborate">协同</div>
  38. <div class="text" @click="handleTrack(item)">轨迹</div>
  39. -->
  40. </div>
  41. </div>
  42. </div>
  43. <div class="footer">
  44. <el-pagination
  45. background
  46. :hide-on-single-page="true"
  47. layout="total, prev, pager, next"
  48. :total="total"
  49. :page-size="queryParams.size"
  50. :current-current="queryParams.current"
  51. @current-change="handleChangePage"
  52. />
  53. </div>
  54. </div>
  55. <Contact v-if="shareState.showShare" v-model="shareState.showShare" @close="handleCloseShare" @confirm="handleShareConfirm" />
  56. <Dialog
  57. v-if="showOpenMeeting"
  58. custom-show
  59. type="xs"
  60. height="660px"
  61. title="发起会议"
  62. @confirm="handleStartCall"
  63. @close="closeOpenDialog"
  64. >
  65. <el-form ref="form2Ref" :model="openMeetingForm" :rules="rules2">
  66. <el-form-item label="账号" label-width="200px" prop="username">
  67. <el-input v-model="openMeetingForm.username" class="custom-input2" clearable placeholder="请输入设备账号" />
  68. </el-form-item>
  69. <el-form-item label="密码" label-width="200px" prop="userpass">
  70. <el-input v-model="openMeetingForm.userpass" type="password" class="custom-input2" clearable placeholder="请输入设备密码" />
  71. </el-form-item>
  72. </el-form>
  73. </Dialog>
  74. </div>
  75. </template>
  76. <script setup lang="ts">
  77. import { Search } from '@element-plus/icons-vue';
  78. import { getMobileWorkstationList, getMobileWorkstationTrajectory } from '@/api/globalMap/MobilePlatform';
  79. import { getStartMiniParam } from '@/api/emergencyCommandMap/communication';
  80. import { showSuccessMsg } from '@/utils/notification';
  81. import { parseTime } from '@/utils/ruoyi';
  82. const initDataToPlay = inject('initDataToPlay');
  83. // 数据列表,直接定义为数组
  84. const dataList = ref([]);
  85. //入参
  86. const queryParams = reactive({
  87. current: 1,
  88. size: 10,
  89. keywords: ''
  90. });
  91. const currentItem = ref(null);
  92. const total = ref(0);
  93. //调接口
  94. const initData = () => {
  95. getMobileWorkstationList({
  96. current: queryParams.current,
  97. size: queryParams.size,
  98. query: {
  99. keywords: queryParams.keywords
  100. }
  101. }).then((res) => {
  102. dataList.value = res.data;
  103. total.value = res.total;
  104. });
  105. };
  106. const handleChangePage = (newNum) => {
  107. queryParams.current = newNum;
  108. initData();
  109. };
  110. // 取消按钮的逻辑,搜索框清空并重新加载数据
  111. const handleCancel = () => {
  112. queryParams.keywords = '';
  113. queryParams.current = 1;
  114. initData();
  115. };
  116. const handleConnect = (item) => {
  117. currentItem.value = item;
  118. showOpenMeeting.value = true;
  119. };
  120. // 分享
  121. let shareState = reactive({
  122. type: '',
  123. showShare: false,
  124. id: ''
  125. });
  126. const handleCollaborate = (type, id?: string) => {
  127. shareState.type = type;
  128. shareState.id = id;
  129. shareState.showShare = true;
  130. };
  131. const handleCloseShare = () => {
  132. shareState.type = '';
  133. shareState.id = '';
  134. };
  135. const handleShareConfirm = (data) => {
  136. showSuccessMsg('开启协同成功');
  137. };
  138. // 轨迹
  139. const handleTrack = (item) => {
  140. getMobileWorkstationTrajectory(item.id).then((res) => {
  141. const trajectory = [];
  142. res.rows.forEach((item) => {
  143. trajectory.push({
  144. time: !!item.create_time ? parseTime(item.create_time, '{h}:{i}') : '',
  145. lnglat: [item.longitude, item.latitude]
  146. });
  147. });
  148. initDataToPlay({ type: 'track', data: trajectory, name: '手机工作台' });
  149. });
  150. };
  151. //调用函数
  152. onMounted(() => {
  153. const meeting_username = localStorage.getItem('meeting_username') || '';
  154. const meeting_userpass = localStorage.getItem('meeting_userpass') || '';
  155. openMeetingForm.username = meeting_username;
  156. openMeetingForm.userpass = meeting_userpass;
  157. initData();
  158. });
  159. //启动会议相关
  160. let form2Ref = ref();
  161. let showOpenMeeting = ref(false);
  162. let openMeetingForm = reactive({
  163. username: '',
  164. userpass: ''
  165. });
  166. const rules2 = reactive({
  167. username: [{ required: true, message: '会议账号不能为空', trigger: 'blur' }],
  168. userpass: [{ required: true, message: '会议密码不能为空', trigger: 'blur' }]
  169. });
  170. const closeOpenDialog = () => {
  171. showOpenMeeting.value = false;
  172. };
  173. const handleStartCall = () => {
  174. form2Ref.value?.validate((valid) => {
  175. if (valid) {
  176. let dev_list = [];
  177. dev_list.push({ id: currentItem.value.dev_id, avtype: 'av'}); // a 音频 v 视频 默认 av
  178. const screenWidth = window.screen.width * window.devicePixelRatio;
  179. const screenHeight = window.screen.height * window.devicePixelRatio;
  180. const data = {
  181. userid: openMeetingForm.username, // 空表示后台获取当前用户对应融合通信dev_id
  182. password: openMeetingForm.userpass,
  183. windowpos: { 'x': 0, 'y': 0, 'width': screenWidth, 'height': screenHeight, 'top': true },
  184. members: {
  185. num: dev_list.length + 2, // 配置多少个座位,一般就是邀请人多少个就多少个
  186. 'dev-list': dev_list
  187. }
  188. };
  189. getStartMiniParam(data).then((res) => {
  190. // 创建一个a标签元素
  191. const a = document.createElement('a');
  192. // 设置a标签的href属性
  193. a.href = res.data;
  194. // 触发点击事件
  195. a.click();
  196. // 保存账号和密码
  197. localStorage.setItem('meeting_username', openMeetingForm.username);
  198. localStorage.setItem('meeting_userpass', openMeetingForm.userpass);
  199. });
  200. closeOpenDialog();
  201. }
  202. });
  203. };
  204. </script>
  205. <style lang="scss" scoped>
  206. .menu-content {
  207. width: 1579px;
  208. height: 1394px;
  209. background: url('@/assets/images/map/rightMenu/content.png') no-repeat;
  210. padding: 130px 20px 20px 20px;
  211. font-size: 36px;
  212. position: relative;
  213. color: #ffffff;
  214. }
  215. .title {
  216. font-size: 60px;
  217. position: absolute;
  218. top: 30px;
  219. left: 160px;
  220. }
  221. .box-left {
  222. display: flex;
  223. margin-top: 30px;
  224. margin-bottom: 20px;
  225. .btn {
  226. width: 140px;
  227. min-width: 140px;
  228. height: 60px;
  229. background: url('@/assets/images/map/rightMenu/potentialFloodHazard/btn.png') no-repeat;
  230. display: flex;
  231. justify-content: center;
  232. align-items: center;
  233. cursor: pointer;
  234. margin-left: 20px;
  235. color: #ffffff;
  236. font-size: 32px;
  237. }
  238. }
  239. .custom-input {
  240. height: 60px;
  241. line-height: 40px;
  242. }
  243. .custom-table {
  244. width: 100%;
  245. height: 1120px;
  246. display: flex;
  247. flex-direction: column;
  248. .table-content {
  249. flex: 1;
  250. overflow-y: auto;
  251. }
  252. .th {
  253. width: 100%;
  254. height: 151px;
  255. background: url('@/assets/images/map/rightMenu/th.png') no-repeat;
  256. background-size: 100% 100%;
  257. display: flex;
  258. }
  259. .tr {
  260. width: 100%;
  261. height: 139px;
  262. background: url('@/assets/images/map/rightMenu/td.png') no-repeat;
  263. background-size: 100% 100%;
  264. display: flex;
  265. padding-right: 20px;
  266. &:hover {
  267. background: url('@/assets/images/map/rightMenu/td_checked.png') no-repeat;
  268. background-size: 100% 100%;
  269. }
  270. }
  271. .td {
  272. flex: 1;
  273. color: #edfaff;
  274. font-size: 38px;
  275. display: flex;
  276. justify-content: center;
  277. align-items: center;
  278. cursor: pointer;
  279. }
  280. .td-text {
  281. /* 设置字体透明 */
  282. color: transparent;
  283. /* 使用 -webkit-background-clip 属性将背景剪裁至文本形状 */
  284. -webkit-background-clip: text;
  285. /* 非Webkit内核浏览器需要使用标准前缀 */
  286. background-clip: text;
  287. font-family: 'YouSheBiaoTiHei';
  288. /* 设置线性渐变,从红色渐变到蓝色 */
  289. background-image: linear-gradient(to bottom, #ffffff 50%, #3075d3 100%);
  290. font-size: 48px;
  291. }
  292. .text-green {
  293. background-image: linear-gradient(to bottom, #ffffff 50%, #40c75f 100%);
  294. }
  295. .text-danger {
  296. background-image: linear-gradient(to bottom, #ffffff 50%, #ff2f3c 100%);
  297. }
  298. }
  299. .text {
  300. font-size: 38px;
  301. color: #00e8ff;
  302. margin-right: 20px;
  303. &:last-child {
  304. margin-right: 0;
  305. }
  306. }
  307. .footer {
  308. height: 64px;
  309. display: flex;
  310. justify-content: flex-end;
  311. margin-top: 25px;
  312. .pagination-container {
  313. height: 64px;
  314. margin: 0;
  315. }
  316. :deep(.el-pagination__total) {
  317. color: #a7ccdf;
  318. font-size: 32px;
  319. }
  320. :deep(.el-pagination) {
  321. .btn-next,
  322. .btn-prev {
  323. background-color: transparent;
  324. border: none;
  325. .el-icon {
  326. font-size: 22px;
  327. color: #a7ccdf;
  328. }
  329. }
  330. .btn-prev:disabled,
  331. .btn-next:disabled {
  332. background-color: transparent;
  333. border: none;
  334. }
  335. .el-pager li {
  336. width: 64px;
  337. height: 64px;
  338. line-height: 64px;
  339. text-align: center;
  340. font-size: 38px;
  341. color: #a7ccdf;
  342. background-color: #0e3064;
  343. border: 1px solid #0c57a7;
  344. margin: 0 6px;
  345. &:hover {
  346. background-color: #038dff;
  347. border: 1px solid #038dff;
  348. }
  349. }
  350. .el-pager li.is-active {
  351. background-color: #038dff;
  352. border: 1px solid #038dff;
  353. }
  354. .el-pagination__goto {
  355. font-size: 38px;
  356. color: #a7ccdf;
  357. }
  358. }
  359. }
  360. </style>