operation-log.vue 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535
  1. <template>
  2. <div class="content-box">
  3. <div class="left">
  4. <!-- <el-icon :size="23" class="camera"><VideoCameraFilled /></el-icon> -->
  5. <span class="cameratxt">操作日志</span>
  6. </div>
  7. <div class="scroll">
  8. <div class="middle">
  9. <div class="filter">
  10. <div class="condition">
  11. <span>操作人 :</span>
  12. <el-input
  13. clearable
  14. v-model.trim="searchInput.userName"
  15. class="w-50 m-2"
  16. placeholder="请输入操作人"
  17. style="width: 180px"
  18. />
  19. </div>
  20. <div class="condition">
  21. <span>操作模块 :</span>
  22. <el-input
  23. clearable
  24. v-model.trim="searchInput.operMode"
  25. class="w-50 m-2"
  26. placeholder="请输入操作模块"
  27. style="width: 180px"
  28. />
  29. </div>
  30. <div class="condition">
  31. <span>日志级别 :</span>
  32. <el-select
  33. clearable
  34. v-model="searchInput.olevelId"
  35. placeholder="请选择日志级别"
  36. >
  37. <el-option
  38. v-for="i in logList"
  39. :key="i.id"
  40. :label="i.name"
  41. :value="i.id"
  42. />
  43. </el-select>
  44. </div>
  45. <div class="condition">
  46. <span>操作时间 :</span>
  47. <el-date-picker
  48. v-model="searchInput.createTime"
  49. unlink-panels
  50. type="datetimerange"
  51. range-separator="-"
  52. start-placeholder="起始时间"
  53. end-placeholder="结束时间"
  54. format="YYYY-MM-DD HH:mm:ss"
  55. value-format="YYYY-MM-DD HH:mm:ss"
  56. placeholder="请选择日期"
  57. />
  58. </div>
  59. <el-button
  60. style="margin-left: 20px"
  61. color="rgba(38, 151, 255, 1)"
  62. type="primary"
  63. class="search"
  64. @click="searchBtn"
  65. ><span>查询</span></el-button
  66. >
  67. <el-button @click="resetBtn" plain color="rgba(43, 153, 255, 1)"
  68. >重置</el-button
  69. >
  70. </div>
  71. </div>
  72. <div class="footer" v-loading="loading">
  73. <el-table
  74. :row-class-name="tableRowClassName"
  75. :data="tableData.list"
  76. @selection-change="handleSelectionChange"
  77. style="width: 100%"
  78. :header-cell-style="{
  79. background: 'rgba(240, 243, 247, 1)',
  80. height: '50px',
  81. border: 0,
  82. }"
  83. >
  84. <!-- <el-table-column type="selection" align="center" width="55" /> -->
  85. <el-table-column align="center" prop="createTime" label="操作时间" />
  86. <el-table-column
  87. width="100"
  88. align="center"
  89. prop="userName"
  90. label="操作人"
  91. >
  92. </el-table-column>
  93. <el-table-column align="center" prop="operMode" label="操作模块" />
  94. <el-table-column align="center" prop="otype" label="操作类型" />
  95. <el-table-column align="center" prop="operation" label="操作内容" />
  96. <el-table-column align="center" prop="ip" label="IP地址" />
  97. <el-table-column align="center" prop="olevel" label="日志级别">
  98. <template #default="{ row }">
  99. <span v-if="row.olevel == '信息'" style="color: #409eff">{{row.olevel}}</span>
  100. <span v-if="row.olevel == '警告'" style="color: #e6a23c">{{row.olevel}}</span>
  101. <span v-if="row.olevel == '错误'" style="color: #f56c6c">{{row.olevel}}</span>
  102. </template>
  103. </el-table-column>
  104. </el-table>
  105. <!-- 分页组件 -->
  106. <div class="pageSize">
  107. <span></span>
  108. <el-pagination
  109. background
  110. :current-page="currentPage"
  111. :page-size="pageSize"
  112. :page-sizes="[10, 20, 30, 40]"
  113. layout="total,sizes, prev, pager, next, jumper, slot"
  114. :total="total"
  115. @size-change="handleSizeChange"
  116. @update:current-page="handleCurrentChange"
  117. />
  118. </div>
  119. </div>
  120. </div>
  121. </div>
  122. </template>
  123. <script setup>
  124. import {
  125. ref,
  126. watch,
  127. reactive,
  128. nextTick,
  129. onBeforeMount,
  130. onUnmounted,
  131. } from "vue";
  132. import { useRouter } from "vue-router";
  133. import { genFileId, ElMessage, ElMessageBox } from "element-plus";
  134. import { dayjs } from "element-plus";
  135. import lodash from "lodash";
  136. import { storeToRefs } from "pinia";
  137. import { useCounterStore } from "@/stores/index";
  138. import { getQueryLogPages, getQueryLogLevel } from "@/api/operation-log";
  139. const router = useRouter();
  140. const store = useCounterStore();
  141. // 为避免解构时失去响应性
  142. const { name, age, isCollapse, realAge, collegeRole } = storeToRefs(store);
  143. const menuList = ref({
  144. canAll: null,
  145. canApply: null,
  146. canDeleted: null,
  147. canDetail: null,
  148. canExport: null,
  149. canImport: null,
  150. canInsert: null,
  151. canTop: null,
  152. canUpdate: null,
  153. canView: null,
  154. });
  155. // 表格数据
  156. const loading = ref(false);
  157. const tableData = reactive({
  158. list: [{}],
  159. });
  160. const logList = ref([]); // 日志级别下拉列表数据
  161. const searchInput = reactive({
  162. userName: "",
  163. operMode: null,
  164. olevelId: null,
  165. createTime: null,
  166. }); // 搜索按钮数据
  167. const currentPage = ref(1); // 当前页
  168. const pageSize = ref(10);
  169. const total = ref(0); // 当前总数
  170. const selectIds = ref([]); // 勾选的全部数据
  171. // 获取账户列表
  172. const getList = async () => {
  173. loading.value = true;
  174. let params = {
  175. currentPage: currentPage.value, // 当前页
  176. pageCount: pageSize.value, // 一页数据条数
  177. userName: searchInput.userName,
  178. operMode: searchInput.operMode,
  179. olevelId: searchInput.olevelId,
  180. };
  181. if (searchInput.createTime) {
  182. params.startTime = searchInput.createTime[0];
  183. params.endTime = searchInput.createTime[1];
  184. }
  185. let res = await getQueryLogPages(params);
  186. console.log(res);
  187. if (res.code == 200) {
  188. tableData.list = res.data.list;
  189. total.value = res.data.totalCount;
  190. loading.value = false;
  191. } else {
  192. loading.value = false;
  193. ElMessage({
  194. type: "error",
  195. showClose: true,
  196. message: res.message,
  197. center: true,
  198. });
  199. }
  200. };
  201. // 搜索功能
  202. const searchBtn = lodash.debounce(async () => {
  203. currentPage.value = 1;
  204. getList();
  205. }, 300);
  206. const resetBtn = lodash.debounce(async () => {
  207. searchInput.userName = "";
  208. searchInput.operMode = "";
  209. searchInput.olevelId = "";
  210. searchInput.createTime = null;
  211. currentPage.value = 1;
  212. getList();
  213. }, 300);
  214. // 多选框功能
  215. const handleSelectionChange = (val) => {
  216. // console.log(val);
  217. selectIds.value = val.map((i) => i.id);
  218. console.log(selectIds.value);
  219. };
  220. // 表格斑马纹颜色修改
  221. const tableRowClassName = ({ row, rowIndex }) => {
  222. if (rowIndex % 2 === 0) {
  223. return "even";
  224. } else if (rowIndex % 2 !== 0) {
  225. return "odd";
  226. }
  227. return "";
  228. };
  229. // 每页显示条数
  230. const handleSizeChange = (value) => {
  231. console.log(value, "每页显示条数");
  232. pageSize.value = value;
  233. getList();
  234. };
  235. // 分页
  236. const handleCurrentChange = (value) => {
  237. // console.log(value);
  238. currentPage.value = value;
  239. getList();
  240. };
  241. const allLogLevel = async () => {
  242. let res = await getQueryLogLevel();
  243. console.log(res, "日志级别下拉列表数据");
  244. if (res.code == 200) {
  245. logList.value = res.data;
  246. } else {
  247. ElMessage({
  248. type: "error",
  249. showClose: true,
  250. message: res.message,
  251. center: true,
  252. });
  253. }
  254. };
  255. onBeforeMount(() => {
  256. getList();
  257. allLogLevel();
  258. let list = JSON.parse(sessionStorage.getItem("roleList"));
  259. console.log(list);
  260. list.forEach((i) => {
  261. if (i.menuName == "操作日志") {
  262. i.childs.forEach((item) => {
  263. if (item.menuName == "操作日志") {
  264. menuList.value = item;
  265. }
  266. });
  267. }
  268. });
  269. console.log(menuList.value);
  270. });
  271. onUnmounted(() => {
  272. // document.removeEventListener("keyup", Enters);
  273. });
  274. </script>
  275. <style scoped lang="scss">
  276. .content-box {
  277. width: calc(100% - 40px);
  278. height: calc(100% - 105px);
  279. margin: 20px auto;
  280. background-color: #fff;
  281. color: #000;
  282. display: flex;
  283. flex-direction: column;
  284. .svg {
  285. width: 22px;
  286. height: 22px;
  287. }
  288. .left {
  289. width: calc(100% - 60px);
  290. height: 60px;
  291. margin: 0 auto;
  292. display: flex;
  293. align-items: center;
  294. border-bottom: 1px solid #ccc;
  295. color: #000;
  296. font-size: 18px;
  297. font-weight: 600;
  298. .camera {
  299. margin-right: 15px;
  300. color: #4392f7;
  301. }
  302. }
  303. .scroll {
  304. width: calc(100% - 60px);
  305. height: calc(100% - 61px);
  306. margin: 0 auto;
  307. display: flex;
  308. flex-direction: column;
  309. .middle {
  310. width: calc(100%);
  311. color: #000;
  312. .filter {
  313. display: flex;
  314. flex-wrap: wrap;
  315. align-items: center;
  316. .search {
  317. margin-left: 0 !important;
  318. color: #fff;
  319. }
  320. .condition {
  321. display: flex;
  322. align-items: center;
  323. margin: 10px 30px 10px 0;
  324. :deep(.el-input .el-input__inner) {
  325. font-size: 14px;
  326. }
  327. .el-select {
  328. width: 220px;
  329. }
  330. span {
  331. margin: 0 10px 0 0;
  332. }
  333. }
  334. }
  335. .gongneng {
  336. margin: 10px 0;
  337. .el-button {
  338. color: #fff;
  339. margin-right: 15px;
  340. }
  341. }
  342. }
  343. .footer {
  344. width: calc(100%);
  345. flex: 1;
  346. margin: 0 auto;
  347. overflow: auto;
  348. .el-table--fit {
  349. height: calc(100% - 60px);
  350. :deep(.el-table__header-wrapper) {
  351. background-color: #000;
  352. font-size: 15px;
  353. color: #000;
  354. .cell {
  355. color: #000;
  356. }
  357. }
  358. :deep(.el-table__row) {
  359. height: 50px;
  360. font-size: 15px;
  361. color: #000;
  362. }
  363. :deep(.el-table__row td) {
  364. padding: 0;
  365. border: 0;
  366. }
  367. .el-button--primary {
  368. margin-left: 5px;
  369. }
  370. :deep(.el-table__body .even) {
  371. background-color: #fff;
  372. }
  373. :deep(.el-table__body .odd) {
  374. background-color: rgba(240, 243, 247, 1);
  375. }
  376. :deep(.options) {
  377. display: flex;
  378. justify-content: center;
  379. align-items: center;
  380. .open {
  381. color: #2697ff;
  382. cursor: pointer;
  383. margin: 0 15px 0 0;
  384. }
  385. .edit {
  386. margin: 0 15px 0 0;
  387. color: #2697ff;
  388. cursor: pointer;
  389. }
  390. .delete {
  391. color: #f56c6c;
  392. cursor: pointer;
  393. }
  394. }
  395. }
  396. .pageSize {
  397. display: flex;
  398. align-items: center;
  399. justify-content: space-between;
  400. margin: 0 30px;
  401. height: 60px;
  402. span {
  403. color: #000;
  404. }
  405. .el-pagination {
  406. // width: 1600px;
  407. :deep(.el-pagination__total) {
  408. color: #000;
  409. }
  410. :deep(.el-pagination__goto) {
  411. color: #000;
  412. }
  413. :deep(.el-pagination__classifier) {
  414. color: #000;
  415. }
  416. :deep(.el-input__wrapper) {
  417. border: 1px solid rgba(0, 0, 0, 1);
  418. border-radius: 5px;
  419. box-shadow: none;
  420. }
  421. :deep(.el-pager li) {
  422. margin: 0 5px;
  423. border: 1px solid rgba(0, 0, 0, 1);
  424. border-radius: 5px;
  425. background-color: transparent;
  426. }
  427. :deep(.el-pager li.is-active) {
  428. // background-color: rgba(0, 97, 255, 0.8);
  429. border: 1px solid rgba(0, 97, 255, 1);
  430. color: rgba(0, 97, 255, 1);
  431. }
  432. :deep(.btn-prev) {
  433. margin-right: 5px;
  434. border: 1px solid rgba(0, 0, 0, 1);
  435. border-radius: 5px;
  436. background-color: transparent;
  437. }
  438. :deep(.btn-next) {
  439. margin-left: 5px;
  440. border: 1px solid rgba(0, 0, 0, 1);
  441. border-radius: 5px;
  442. background-color: transparent;
  443. }
  444. }
  445. }
  446. }
  447. }
  448. // 添加员工弹窗样式
  449. :deep(.addStaff) {
  450. .el-dialog__body {
  451. padding: 20px 20px 10px 20px;
  452. .el-input {
  453. width: 400px;
  454. .el-input__suffix-inner {
  455. color: rgba(61, 81, 232, 1);
  456. }
  457. }
  458. .el-select {
  459. width: 400px;
  460. }
  461. .el-tree {
  462. width: 400px;
  463. }
  464. }
  465. }
  466. // 导入
  467. :deep(.projectImport) {
  468. .el-dialog__body {
  469. padding: 20px 30px 0 30px;
  470. .title {
  471. color: red;
  472. }
  473. .down {
  474. span:nth-child(1) {
  475. color: rgba(127, 127, 127, 1);
  476. }
  477. span:nth-child(2) {
  478. margin-left: 25px;
  479. color: rgba(2, 167, 240, 1);
  480. cursor: pointer;
  481. }
  482. }
  483. .options {
  484. margin: 50px 0 30px 0;
  485. display: flex;
  486. flex-direction: row-reverse;
  487. .queding {
  488. margin-left: 20px;
  489. background: linear-gradient(
  490. 90deg,
  491. rgba(38, 151, 255, 1) 0%,
  492. rgba(102, 181, 255, 1) 100%
  493. );
  494. border: none;
  495. }
  496. .quxiao {
  497. border: 1px solid rgba(43, 151, 252, 1);
  498. color: rgba(43, 151, 252, 1);
  499. }
  500. }
  501. }
  502. }
  503. }
  504. </style>