index.vue 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190
  1. <template>
  2. <div class="page bg page-full padding border Ipt-2">
  3. <el-tabs v-model="activeName" @tab-click="handleClick">
  4. <el-tab-pane label="服务日志" name="1">
  5. <el-table ref="table" :data="tableData" style="width: 100%" row-key="id" v-loading="loading">
  6. <el-table-column prop="name" label="文件名" show-overflow-tooltip></el-table-column>
  7. <el-table-column prop="size" label="大小" show-overflow-tooltip></el-table-column>
  8. <el-table-column prop="changeAt" label="修改时间" min-width="100" align="center"></el-table-column>
  9. <el-table-column label="操作" width="200" align="center">
  10. <template #default="scope">
  11. <el-button size="small" text type="primary" v-if="!scope.row.folderName" @click="view(scope.row)">详情
  12. </el-button>
  13. <el-button size="small" text type="warning" v-auth="'download'" @click="down(scope.row)">下载</el-button>
  14. <el-button size="small" text type="info" v-auth="'del'" @click="onRowDel(scope.row)">删除</el-button>
  15. </template>
  16. </el-table-column>
  17. </el-table>
  18. </el-tab-pane>
  19. <el-tab-pane label="数据库日志" name="2">
  20. <el-table :data="tableData" style="width: 100%" row-key="id" v-loading="loading">
  21. <el-table-column prop="name" label="文件名" show-overflow-tooltip></el-table-column>
  22. <el-table-column prop="size" label="大小" show-overflow-tooltip></el-table-column>
  23. <el-table-column prop="changeAt" label="修改时间" min-width="100" align="center"></el-table-column>
  24. <el-table-column label="操作" width="200" align="center">
  25. <template #default="scope">
  26. <el-button size="small" text type="primary" v-if="!scope.row.folderName" @click="view(scope.row)">详情
  27. </el-button>
  28. <el-button size="small" text type="warning" v-auth="'download'" @click="down(scope.row)">下载</el-button>
  29. <el-button size="small" text type="info" v-auth="'del'" @click="onRowDel(scope.row)">删除</el-button>
  30. </template>
  31. </el-table-column>
  32. </el-table>
  33. </el-tab-pane>
  34. <el-tab-pane label="运行日志" name="3">
  35. <div v-for="line in topMsg" :key="line" class="error-line">{{ line }}</div>
  36. <div v-if="runButtonShow" v-loading="runLoading" v-for="line in runMessage" :key="line" class="error-line">{{ line }}</div>
  37. <div v-else class="error-line">暂无数据</div>
  38. <div class="run-button" v-if="runButtonShow">
  39. <el-button size="small" text type="warning" v-auth="'download'" @click="down">下载</el-button>
  40. <el-button size="small" text type="danger" v-auth="'del'" @click="onRowDel">删除</el-button>
  41. </div>
  42. </el-tab-pane>
  43. </el-tabs>
  44. <el-dialog v-model="dialogVisible" title="查看详情">
  45. <div v-for="line in topMsg" :key="line" class="error-line">{{ line }}</div>
  46. <div v-for="line in errorMessage" :key="line" class="error-line">{{ line }}</div>
  47. </el-dialog>
  48. <el-dialog v-model="dialogVisible" title="查看详情">
  49. <div v-for="line in topMsg" :key="line" class="error-line">{{ line }}</div>
  50. <div v-for="line in errorMessage" :key="line" class="error-line">{{ line }}</div>
  51. </el-dialog>
  52. </div>
  53. </template>
  54. <script lang="ts" setup>
  55. import api from '/@/api/system';
  56. import { useSearch } from '/@/hooks/useCommon';
  57. import getOrigin from '/@/utils/origin'
  58. import downloadFile from '/@/utils/download';
  59. import { ref, getCurrentInstance, nextTick, onMounted } from 'vue';
  60. import { ElMessage, ElMessageBox } from "element-plus";
  61. const dialogVisible = ref(false);
  62. const errorMessage = ref([]);
  63. const runMessage = ref([]);
  64. const topMsg = ref([]);
  65. const activeName = ref('1');
  66. const types = ref('service');
  67. const runLoading = ref(false);
  68. const isScrolling = ref(false);
  69. const chatContent: any = ref(null);
  70. const runButtonShow = ref(false);
  71. const runLogName = ref('');
  72. const { params, tableData, getList, loading } = useSearch<any[]>(api.lastLinesLog.getList, 'list', { types: types.value });
  73. getList();
  74. onMounted(() => {
  75. chatContent.value = document.getElementsByClassName('chatdoom')[0]
  76. scrollBottom()
  77. })
  78. const scrollBottom = () => {
  79. nextTick(() => {
  80. //注意要使用nextick以免获取不到dom
  81. if (!isScrolling.value) {
  82. // chatContent.value.scrollTop = chatContent.value.scrollHeight - chatContent.value.offsetHeight
  83. chatContent.value.scrollTop = chatContent.value.offsetHeight
  84. console.log(chatContent.value.scrollTop);
  85. }
  86. })
  87. }
  88. const view = (row: any) => {
  89. if (types.value == 'run') {
  90. row.name = row.value;
  91. }
  92. const es = new EventSource(getOrigin(import.meta.env.VITE_SERVER_URL + "/subscribe/logInfo?name=" + row.name + '&types=' + types.value));
  93. es.addEventListener('log', ({ data }) => {
  94. topMsg.value.unshift(data);
  95. });
  96. api.lastLinesLog.detail({ name: row.name, types: types.value }).then((res: any) => {
  97. if (types.value == 'run') {
  98. runMessage.value = res.list;
  99. runLoading.value = false;
  100. if (res.list.length > 0) {
  101. runButtonShow.value = true;
  102. }
  103. } else {
  104. errorMessage.value = res.list;
  105. dialogVisible.value = true;
  106. }
  107. });
  108. };
  109. const down = (row: any) => {
  110. if (types.value == 'run') {
  111. row.name = runLogName.value
  112. }
  113. api.lastLinesLog.down({ name: row.name, types: types.value }).then((res: any) => downloadFile(res, types.value + "-" + row.name))
  114. };
  115. const onRowDel = (row: any) => {
  116. if (types.value == 'run') {
  117. row.name = runLogName.value
  118. }
  119. let msg = '你确定要删除所选数据?';
  120. ElMessageBox.confirm(msg, '提示', {
  121. confirmButtonText: '确认',
  122. cancelButtonText: '取消',
  123. type: 'warning',
  124. }).then(() => {
  125. api.lastLinesLog.delete({ name: row.name, types: types.value }).then(() => {
  126. params.types = types.value;
  127. if (types.value == 'run') {
  128. runButtonShow.value = false;
  129. } else {
  130. getList()
  131. }
  132. ElMessage.success('删除成功');
  133. });
  134. }).catch(() => { });
  135. };
  136. // 切换tab
  137. const handleClick = (tab: any, event: Event) => {
  138. if (tab.props.name == 1) {
  139. types.value = 'service';
  140. // 获取日志列表
  141. params.types = types.value;
  142. getList()
  143. } else if (tab.props.name == 2) {
  144. types.value = 'sql'
  145. params.types = types.value;
  146. getList();
  147. } else if (tab.props.name == 3) {
  148. runLoading.value = true;
  149. types.value = 'run'
  150. runLogName.value = ''
  151. params.type = types.value
  152. view(runLogName)
  153. }
  154. }
  155. </script>
  156. <style scoped>
  157. .run-button {
  158. position: fixed;
  159. bottom: 50px;
  160. right: 80px;
  161. }
  162. .runMessage {
  163. height: 500px;
  164. }
  165. .content-box {
  166. width: 100%;
  167. padding: 5px 20px 20px 20px;
  168. }
  169. .error-line {
  170. white-space: pre-line;
  171. /* 保留换行符 */
  172. }
  173. .el-tabs--card {
  174. height: calc(100vh - 110px);
  175. overflow-y: auto;
  176. }
  177. </style>