ReportView.vue 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450
  1. <template>
  2. <div class="common-layout">
  3. <el-container>
  4. <el-header
  5. style="height: 250px; background-color: rgba(255,0,0,50%); display: flex; flex-direction: column; justify-content: center; align-items: center;">
  6. <div class="demo-image" style="text-align: center;"> <!-- 注意这里添加了 text-align: center; 但对于块级元素这不是必需的 -->
  7. <img src="../assets/pji-logo.jpg" alt="" style="max-width: 100%; height: auto;">
  8. <!-- 推荐使用 max-width 保持图片比例 -->
  9. </div>
  10. </el-header>
  11. <el-main style="background-color:white;">
  12. <div class="topbar">
  13. <el-form style=" background-color: rgba(0,0,0,0%);" :inline="true" :model="queryLine"
  14. class="demo-form-inline">
  15. <el-form-item label="数据名称">
  16. <el-input v-model="queryLine.dataName" placeholder="请输入数据名称" clearable/>
  17. </el-form-item>
  18. <!-- <el-form-item label="数据标签">-->
  19. <!-- <el-input v-model="queryLine.teamName" placeholder="请输入数据标签" clearable/>-->
  20. <!-- </el-form-item>-->
  21. <el-form-item label="设备名称">
  22. <el-input v-model="queryLine.equipmentName" placeholder="请输入设备名称" clearable/>
  23. </el-form-item>
  24. <el-form-item label="设备类型">
  25. <el-input v-model="queryLine.equipmentTypeName" placeholder="请输入设备类型" clearable/>
  26. </el-form-item>
  27. <el-form-item label="触发器名称">
  28. <el-input v-model="queryLine.triggerName" placeholder="请输入触发器名称" clearable/>
  29. </el-form-item>
  30. <el-form-item label="触发器类型">
  31. <el-input v-model="queryLine.triggerTypeName" placeholder="请输入触发器类型" clearable/>
  32. </el-form-item>
  33. <el-form-item>
  34. <el-button type="danger" @click="onSubmit">查询</el-button>
  35. </el-form-item>
  36. <el-form-item>
  37. <el-button type="danger" @click="onSubmit">重置</el-button>
  38. </el-form-item>
  39. </el-form>
  40. <el-button type="primary" @click="goToMapUpdate">地图更新</el-button>
  41. <el-button type="primary" @click="goToUpdateStat">地图更新统计</el-button>
  42. <el-button type="primary" @click="mapDialogVisible = true">地图续扫提醒阈值</el-button>
  43. <el-button type="primary" @click="goToMapRescan">地图续扫提醒</el-button>
  44. <el-dialog
  45. v-model="mapDialogVisible"
  46. title="地图续扫提醒"
  47. width="400"
  48. :before-close="handleClose"
  49. >
  50. <el-form :model="mapRescanForm">
  51. <el-form-item label="请输入地图续扫提醒阈值" label-width="170">
  52. <el-input v-model="mapRescanForm.name">
  53. <template #suffix>
  54. <i slot="suffix" style="color: #181818">%</i>
  55. </template>
  56. </el-input>
  57. </el-form-item>
  58. </el-form>
  59. <template #footer>
  60. <div class="dialog-footer">
  61. <el-button type="primary" @click="mapDialogVisible = false">
  62. 确认
  63. </el-button>
  64. </div>
  65. </template>
  66. </el-dialog>
  67. <div style="float: right">
  68. <el-switch
  69. style="margin-left: 10px;"
  70. v-model="value"
  71. size="large"
  72. inactive-text="算法容器"
  73. />
  74. <el-button type="primary" @click="algorithmDialogVisible = true" style="margin-left: 10px;">算法镜像导入</el-button>
  75. <el-dialog
  76. v-model="algorithmDialogVisible"
  77. title="请输入算法版本"
  78. width="300"
  79. :before-close="handleClose"
  80. >
  81. <template #footer>
  82. <div class="dialog-footer">
  83. <el-form :model="algorithmForm" label-width="auto">
  84. <el-form-item style="margin-bottom: 10px" label="sudo密码:">
  85. <el-input v-model="algorithmForm.sudoPassword"/>
  86. </el-form-item>
  87. <el-form-item style="margin-bottom: 10px" label="算法版本:">
  88. <el-input v-model="algorithmForm.tag"/>
  89. </el-form-item>
  90. </el-form>
  91. <!-- -->
  92. <!-- <el-button @click="algorithmDialogVisible = false">取消</el-button>-->
  93. <el-button type="primary" @click="algorithmImport">选择镜像文件</el-button>
  94. </div>
  95. </template>
  96. </el-dialog>
  97. <el-button style="margin-left: 10px;" type="primary" @click="algorithmImport">算法镜像选择</el-button>
  98. <!-- <el-switch-->
  99. <!-- v-model="algorithmContainerState"-->
  100. <!-- class="ml-2"-->
  101. <!-- inline-prompt-->
  102. <!-- style="margin-left: 100px;&#45;&#45;el-switch-on-color: #13ce66; &#45;&#45;el-switch-off-color: #ff4949"-->
  103. <!-- active-text="算法容器已开启"-->
  104. <!-- inactive-text="算法容器已关闭"-->
  105. <!-- />-->
  106. <!-- <el-switch-->
  107. <!-- v-model="gazeboState"-->
  108. <!-- class="ml-2"-->
  109. <!-- inline-prompt-->
  110. <!-- style="margin-left: 100px; &#45;&#45;el-switch-on-color: #13ce66; &#45;&#45;el-switch-off-color: #ff4949"-->
  111. <!-- active-text="Gazebo 已开启"-->
  112. <!-- inactive-text="Gazebo 已关闭"-->
  113. <!-- @click="gazebo"-->
  114. <!-- />-->
  115. <!-- <el-switch-->
  116. <!-- v-model="rvizState"-->
  117. <!-- class="ml-2"-->
  118. <!-- inline-prompt-->
  119. <!-- style="margin-left: 100px;&#45;&#45;el-switch-on-color: #13ce66; &#45;&#45;el-switch-off-color: #ff4949"-->
  120. <!-- active-text="Rviz 已开启"-->
  121. <!-- inactive-text="Rviz 已关闭"-->
  122. <!-- @click="rviz"-->
  123. <!-- />-->
  124. <el-button style="margin-left: 10px;" type="primary" @click="goToTestRecord">仿真测试记录</el-button>
  125. </div>
  126. </div>
  127. <el-table stripe style="background-color: rgba(255,0,0,99%);width: 100%" border :data="tableData"
  128. fixed ref="multipleTableRef" :cell-style="{ textAlign: 'center'}" :header-cell-style="{ textAlign: 'center'}">
  129. <el-table-column type="selection" width="55"/>
  130. <el-table-column prop="dataName" label="数据名称"/>
  131. <el-table-column prop="dataSize" label="数据容量" :formatter="dataSizeFormatter"/>
  132. <el-table-column prop="equipmentName" label="设备名称"/>
  133. <el-table-column prop="equipmentTypeName" label="设备类型"/>
  134. <el-table-column prop="triggerName" label="触发器名称"/>
  135. <el-table-column prop="triggerTypeName" label="触发器类型"/>
  136. <el-table-column prop="callbackTime" label="上报时间"/>
  137. <el-table-column prop="dataStateName" label="数据状态"/>
  138. <el-table-column width="300" fixed="right" label="操作">
  139. <el-button size="small" type="danger" @click="goToDetail">生成world</el-button>
  140. <el-button size="small" type="danger" @click="goToDetail">仿真测试</el-button>
  141. <!-- <el-button size="small" type="danger" @click="goToDetail">算法评价</el-button>-->
  142. </el-table-column>
  143. </el-table>
  144. <p></p> <!--空行-->
  145. <el-pagination
  146. v-model:current-page="currentPage"
  147. v-model:page-size="pageSize"
  148. :page-sizes="[10]"
  149. :small="small"
  150. :disabled="disabled"
  151. :background="true"
  152. layout="total, sizes, prev, pager, next, jumper"
  153. :total="total"
  154. @size-change="handleSizeChange"
  155. @current-change="handleCurrentChange"
  156. />
  157. <!-- <el-pagination background layout="prev, pager, next" :total="1000"/>-->
  158. </el-main>
  159. <!-- <el-footer style="background-color: rgba(255,0,0,99%)">国家智能网联汽车创新中心</el-footer>-->
  160. </el-container>
  161. </div>
  162. </template>
  163. <script lang="ts" setup>
  164. import {onBeforeMount, ref} from "vue";
  165. import axios from "axios";
  166. import {reactive} from 'vue'
  167. import {ElTable} from "element-plus";
  168. import {useRouter} from 'vue-router'; // 导入 Vue Router 的 useRouter 钩子
  169. const value
  170. = ref(true)
  171. const router = useRouter();
  172. const algorithmContainerState = ref(false)
  173. const gazeboState = ref(false)
  174. const rvizState = ref(false)
  175. const multipleTableRef = ref<InstanceType<typeof ElTable>>
  176. const algorithmDialogVisible = ref(false)
  177. const mapDialogVisible = ref(false)
  178. const handleClose = (done: () => void) => {
  179. done()
  180. }
  181. // do not use same name with ref
  182. const algorithmForm = reactive({
  183. sudoPassword: '',
  184. tag: '',
  185. // date1: '',
  186. // date2: '',
  187. // delivery: false,
  188. // type: [],
  189. // resource: '',
  190. // desc: '',
  191. })
  192. const mapRescanForm = reactive({
  193. name: ''
  194. })
  195. const currentTag = ref('')
  196. const algorithmImport = async () => {
  197. algorithmDialogVisible.value = false
  198. try {
  199. const result = await window.electronAPI.openFileManager();
  200. console.log('用户选择的文件路径为:', result, ',版本为:', algorithmForm.tag);
  201. window.electronAPI.dockerImport(algorithmForm.sudoPassword, result, algorithmForm.tag)
  202. } catch (error) {
  203. console.error('打开文件管理器时出错:', error);
  204. }
  205. };
  206. const goToDetail = () => {
  207. router.push('/about')
  208. }
  209. const goToMapUpdate = () => {
  210. router.push('/map_update')
  211. }
  212. const goToUpdateStat = () => {
  213. router.push('/update_stat')
  214. }
  215. const goToMapRescan = () => {
  216. router.push('/map_rescan')
  217. }
  218. const goToTestRecord = () => {
  219. router.push('/test_record')
  220. }
  221. // 数据容量单位从B转成MB
  222. const dataSizeFormatter = (row, column, cellValue, index) => {
  223. // 假设 1MB = 1024 * 1024 字节
  224. if (cellValue) {
  225. const mb = (cellValue / (1024 * 1024)).toFixed(2); // 保留两位小数
  226. return `${mb}MB`;
  227. }
  228. return cellValue; // 如果cellValue为null或undefined,则返回原值或你想要的默认值
  229. }
  230. const gazebo = () => {
  231. if (gazeboState.value) {
  232. if (window.electronAPI) {
  233. window.electronAPI.openGazebo(); // 关闭 gazebo
  234. } else {
  235. console.error('electronAPI is not defined');
  236. }
  237. // gazeboState.value = false
  238. } else {
  239. if (window.electronAPI) {
  240. window.electronAPI.closeGazebo();
  241. } else {
  242. console.error('electronAPI is not defined');
  243. }
  244. // gazeboState.value = true
  245. }
  246. }
  247. const rviz = () => {
  248. if (rvizState.value) {
  249. if (window.electronAPI) {
  250. window.electronAPI.openRviz();
  251. } else {
  252. console.error('electronAPI is not defined');
  253. }
  254. } else {
  255. if (window.electronAPI) {
  256. window.electronAPI.closeRviz();
  257. } else {
  258. console.error('electronAPI is not defined');
  259. }
  260. }
  261. }
  262. const downloadPdf = (index: number, row: any) => {
  263. console.log(index, row)
  264. axios.post('http://36.110.106.142:12341/web_server/exam/report',
  265. {
  266. "id": row.id,
  267. "teamName": row.teamName,
  268. "scoreOnline": row.scoreOnline,
  269. "beginTime": row.beginTime,
  270. "endTime": row.endTime
  271. },
  272. {
  273. headers: {
  274. "Authorization": "U9yKpD6kZZDDe4LFKK6myAxBUT1XRrDM"
  275. },
  276. responseType: 'blob' // 设置响应类型为二进制流
  277. }
  278. ).then(function (response) {
  279. const url = window.URL.createObjectURL(new Blob([response.data]));
  280. const link = document.createElement('a');
  281. link.href = url;
  282. link.setAttribute('download', row.topic + "-" + row.teamName + "-评分报告.pdf"); // 设置下载的文件名
  283. document.body.appendChild(link);
  284. link.click();
  285. }).catch(function (error) {
  286. console.log(error);
  287. });
  288. }
  289. const openPdf = (index: number, row: any) => {
  290. console.log(index, row)
  291. axios.post('http://36.110.106.142:12341/web_server/exam/report',
  292. {
  293. "id": row.id,
  294. "teamName": row.teamName,
  295. "scoreOnline": row.scoreOnline,
  296. "beginTime": row.beginTime,
  297. "endTime": row.endTime
  298. },
  299. {
  300. headers: {
  301. "Authorization": "U9yKpD6kZZDDe4LFKK6myAxBUT1XRrDM"
  302. },
  303. responseType: 'blob' // 设置响应类型为二进制流
  304. }
  305. ).then(function (response) {
  306. const url = window.URL.createObjectURL(new Blob([response.data], {type: 'application/pdf'}));
  307. window.open(url, '_blank');
  308. }).catch(function (error) {
  309. console.log(error);
  310. });
  311. }
  312. const queryLine = reactive({
  313. dataName: '',
  314. equipmentName: '',
  315. equipmentTypeName: '',
  316. triggerName: '',
  317. triggerTypeName: '',
  318. })
  319. const onSubmit = () => {
  320. page()
  321. }
  322. let total = ref(0)
  323. let tableData = ref([]);
  324. onBeforeMount(() => {
  325. page()
  326. })
  327. function page() {
  328. axios.get('http://1.202.169.139:8081/open/scene/list?equipmentType=YI_DAO_JI_QI_REN&page=' + currentPage.value + '&size=' + pageSize.value,
  329. {
  330. headers: {
  331. "Authorization": "4773hd92ysj54paflw2jem3onyhywxt2"
  332. }
  333. }
  334. ).then(function (response) {
  335. tableData.value = response.data.data.content
  336. total.value = response.data.data.totalElements
  337. // total.value = tableData.value.length
  338. // console.log(tableData);
  339. // console.log(response.data.data);
  340. }).catch(function (error) {
  341. console.log(error);
  342. });
  343. }
  344. const currentPage = ref(1)
  345. const pageSize = ref(10)
  346. const small = ref(false)
  347. const disabled = ref(false)
  348. const handleSizeChange = (val: number) => {
  349. pageSize.value = val
  350. page()
  351. if (tableData.value.length == 0) {
  352. page()
  353. }
  354. }
  355. const handleCurrentChange = (val: number) => {
  356. currentPage.value = val
  357. page()
  358. }
  359. const handleClick = () => {
  360. console.log('click')
  361. }
  362. </script>
  363. <style scoped>
  364. .demo-pagination-block + .demo-pagination-block {
  365. margin-top: 10px;
  366. }
  367. .demo-pagination-block .demonstration {
  368. margin-bottom: 16px;
  369. }
  370. .demo-form-inline .el-input {
  371. --el-input-width: 200px;
  372. }
  373. .demo-form-inline .el-select {
  374. --el-select-width: 400px;
  375. }
  376. .demo-image .block {
  377. padding: 30px 0;
  378. text-align: center;
  379. border-right: solid 1px var(--el-border-color);
  380. display: inline-block;
  381. width: 20%;
  382. box-sizing: border-box;
  383. vertical-align: top;
  384. }
  385. .demo-image .block:last-child {
  386. border-right: none;
  387. }
  388. .demo-image .demonstration {
  389. display: block;
  390. color: var(--el-text-color-secondary);
  391. font-size: 14px;
  392. margin-bottom: 20px;
  393. }
  394. .topbar {
  395. margin-bottom: 15px;
  396. }
  397. /* 假设 .el-pager__item 是分页按钮的类名,这可能需要你根据实际的 Element UI 版本和源码进行调整 */
  398. .el-pager__item {
  399. background-color: rgba(255, 0, 0, 50%) !important; /* 修改背景色 */
  400. color: #fff; /* 可能需要修改文本颜色以在红色背景上可见 */
  401. border-color: transparent; /* 如果需要,修改边框颜色 */
  402. }
  403. /* 修改当前选中页码的按钮样式 */
  404. .el-pager__item.is-active {
  405. background-color: rgba(255, 0, 0, 70%) !important; /* 选中时的背景色 */
  406. color: #fff; /* 选中时的文本颜色 */
  407. }
  408. </style>