home.vue 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631
  1. <!-- -->
  2. <template>
  3. <div class=''>
  4. <el-breadcrumb class="divi2" separator-class="el-icon-arrow-right">
  5. <el-breadcrumb-item :to="{ path: '/' }">首页</el-breadcrumb-item>
  6. <el-breadcrumb-item>数据质量探测</el-breadcrumb-item>
  7. </el-breadcrumb>
  8. <el-divider class="divi"></el-divider>
  9. <el-form :inline="true" :model="dataForm" @keyup.enter.native="getMeasureOrJobList">
  10. <el-form-item>
  11. <el-button v-if="isAuth('snoop:save')" type="primary" @click="addHandle()">新建探测</el-button>
  12. <el-button v-if="isAuth('snoop:delete')" type="danger" @click="measureAndJobDelete()"
  13. :disabled="dataListSelections.length <= 0">批量删除
  14. </el-button>
  15. </el-form-item>
  16. <el-form-item>
  17. <el-input v-model="dataForm.algorithmName" :placeholder="classificationtag=='度量'?'请输入度量名称':'请输入任务名称' " clearable
  18. @keyup.enter.native="pageIndex = 1;getMeasureList()"></el-input>
  19. </el-form-item>
  20. <el-form-item>
  21. <el-button @click="pageIndex = 1;getMeasureList()">查询</el-button>
  22. </el-form-item>
  23. <el-form-item>
  24. <el-tag>筛选:</el-tag>
  25. <el-select v-model="classificationtag" placeholder="类别" size="mini" style="width: 130px;"
  26. @change="pageIndex = 1;getMeasureOrJobList()">
  27. <el-option v-for="data in classification" :key="data" :label="data" :value="data">
  28. </el-option>
  29. </el-select>
  30. </el-form-item>
  31. </el-form>
  32. <div v-if="classificationtag === '度量'" >
  33. <el-table key="度量" :data="measureList" border
  34. v-loading="measDataListLoading"
  35. @selection-change="SelectionChange"
  36. style="width: 100%;">
  37. <el-table-column type="selection" header-align="center" align="center" width="50">
  38. </el-table-column>
  39. <el-table-column prop="Id" header-align="center" align="center" width="80" label="序号"
  40. type="index" :index='(index)=>{return (index+1) + (this.pageIndex-1)*this.pageSize}'>
  41. </el-table-column>
  42. <el-table-column prop="measureName" header-align="center" align="center" label="度量名称">
  43. </el-table-column>
  44. <el-table-column prop="measureType" header-align="center" align="center" label="度量类型"></el-table-column>
  45. <!-- <el-table-column prop="username" header-align="center" align="center" label="创建人">-->
  46. <!-- </el-table-column>-->
  47. <!-- <el-table-column prop="createTime" header-align="center" align="center" label="创建时间">-->
  48. <!-- </el-table-column>-->
  49. <el-table-column prop="remark" header-align="center" align="center" label="备注">
  50. </el-table-column>
  51. <el-table-column fixed="right" header-align="center" align="center" width="250" label="操作">
  52. <template slot-scope="scope">
  53. <el-button type="text" size="small" v-if="isAuth('snoop:measure:look')" @click="userwatch(scope.row)">查看</el-button>
  54. <el-button type="text" size="small" v-if="isAuth('snoop:delete')" @click="measureDeleteHandle(scope.row)">删除</el-button>
  55. </template>
  56. </el-table-column>
  57. </el-table>
  58. </div>
  59. <div v-if="classificationtag === '任务'">
  60. <el-table key="任务" :data="jobList" border
  61. v-loading="jobDataListLoading"
  62. @selection-change="SelectionChange"
  63. style="width: 100%;">
  64. <el-table-column type="selection" header-align="center" align="center" width="50">
  65. </el-table-column>
  66. <el-table-column prop="Id" header-align="center" align="center" width="80" label="序号"
  67. type="index" :index='(index)=>{return (index+1) + (this.pageIndex-1)*this.pageSize}'>
  68. </el-table-column>
  69. <el-table-column prop="jobName" header-align="center" align="center" label="任务名称">
  70. </el-table-column>
  71. <el-table-column prop="jobState.previousFireTime" header-align="center" align="center" label="上次执行时间">
  72. <template slot-scope="scope">
  73. {{ scope.row.jobState.previousFireTime | timeFormater }}
  74. </template>
  75. </el-table-column>
  76. <el-table-column prop="jobState.nextFireTime" header-align="center" align="center" label="下次执行时间">
  77. <template slot-scope="scope">
  78. {{ scope.row.jobState.nextFireTime | timeFormater }}
  79. </template>
  80. </el-table-column>
  81. <el-table-column prop="state" header-align="center" align="center" label="状态">
  82. <template slot-scope="scope">
  83. <el-tag v-if="scope.row.jobState.state === 'NORMAL'" size="small">正常</el-tag>
  84. <el-tag v-else size="small" type="danger">暂停</el-tag>
  85. </template>
  86. </el-table-column>
  87. <!-- <el-table-column prop="username" header-align="center" align="center" label="创建人">-->
  88. <!-- </el-table-column>-->
  89. <!-- <el-table-column prop="createTime" header-align="center" align="center" label="创建时间">-->
  90. <!-- </el-table-column>-->
  91. <el-table-column fixed="right" header-align="center" align="center" width="250" label="操作">
  92. <template slot-scope="scope">
  93. <el-button v-if="isAuth('snoop:job:look')" type="text" size="small" @click="jobWatch(scope.row)">查看
  94. </el-button>
  95. <el-button v-if="isAuth('snoop:job:delete')" type="text" size="small"
  96. @click="jobDeleteHandle(scope.row)">删除
  97. </el-button>
  98. <el-button v-if="isAuth('snoop:job:pause')" type="text" size="small"
  99. @click="jobPauseHandle(scope.row)" >
  100. 暂停
  101. </el-button>
  102. <el-button v-if="isAuth('snoop:job:resume')" type="text" size="small"
  103. @click="jobResumeHandle(scope.row)">恢复
  104. </el-button>
  105. <el-button v-if="isAuth('snoop:job:result')" type="text" size="small" @click="jobResHandle(scope.row)">结果
  106. </el-button>
  107. <el-button v-if="isAuth('sys:schedule:log')" type="text" size="small" @click="jobLogHandle(scope.row)">日志
  108. </el-button>
  109. </template>
  110. </el-table-column>
  111. </el-table>
  112. </div>
  113. <el-pagination @size-change="sizeChangeHandle" @current-change="currentChangeHandle" :current-page="pageIndex"
  114. :page-sizes="[10, 20, 50, 100]" :page-size="pageSize" :total="totalPage"
  115. layout="total, sizes, prev, pager, next, jumper">
  116. </el-pagination>
  117. <snoop v-if="addVisible" ref="addS" @refreshDataList="getMeasureList"></snoop>
  118. <measureUserWatch v-if="newWatchVisible" ref="measureWatch"></measureUserWatch>
  119. <job-watch v-if="jobWatchVisible" ref="jobWatch"></job-watch>
  120. <job-log v-if="jobLoghVisible" ref="jobLog"></job-log>
  121. <jobResultVisiEchars v-if="jobResVisible" ref="jobRes" ></jobResultVisiEchars>
  122. </div>
  123. </template>
  124. <script>
  125. // import AlgAdd from './alg-add.vue';
  126. // 这里可以导入其他文件(比如:组件,工具js,第三方插件js,json文件,图片文件等等)
  127. // 例如:import 《组件名称》 from '《组件路径》';
  128. // import AddOrUpdate from "./dataset-add-or-update";
  129. // import Watch from "./dataset-watch";
  130. import snoop from './snoop-add'
  131. import measureUserWatch from './measureUserWatch'
  132. import jobWatch from './jobWatch'
  133. import jobLog from './jobLog'
  134. // import jobResultVisi from './jobResult_visi'
  135. import jobResultVisiEchars from './jobResult_visi_echars'
  136. import { MessageBox } from 'element-ui'
  137. import { Message } from 'element-ui'
  138. export default {
  139. // import引入的组件需要注入到对象中才能使用
  140. data () {
  141. return {
  142. dataForm: {
  143. algorithmName: ''
  144. },
  145. userID: this.$store.state.user.id, // 用户编号
  146. // userName: this.$store.state.user.name, // 用户编号
  147. userName: 'test',
  148. measureList: [], // 分页使用 当前显示的度量数据
  149. measureListAll: [], // 分页使用 所用的度量数据
  150. jobList: [], // 分页使用 当前显示的任务数据
  151. jobListAll: [], // 分页使用 所用的任务数据
  152. pageIndex: 1,
  153. pageSize: 10,
  154. totalPage: 0,
  155. jobDataListLoading: false,
  156. measDataListLoading: false,
  157. dataListSelections: [],
  158. addOrUpdateVisible: false,
  159. newWatchVisible: false,
  160. jobWatchVisible: false,
  161. addVisible: false,
  162. jobLoghVisible: false,
  163. jobResVisible: false,
  164. classificationtag: '',
  165. classification: ['度量', '任务']
  166. }
  167. },
  168. components: {
  169. // AlgAdd
  170. // AddOrUpdate,
  171. // Watch,
  172. // Add
  173. snoop,
  174. measureUserWatch,
  175. jobWatch,
  176. jobLog,
  177. jobResultVisiEchars
  178. },
  179. activated () {
  180. // this.getMeasureList()
  181. // this.getJobList()
  182. this.classificationtag = this.classification[0]
  183. var sign = this.$route.query.status
  184. if (sign) {
  185. this.classificationtag = this.classification[sign]
  186. this.getMeasureOrJobList()
  187. }
  188. },
  189. mounted () {
  190. this.getMeasureList()
  191. },
  192. filters: {
  193. timeFormater (value) {
  194. var date = new Date(value)
  195. let years = date.getFullYear()
  196. let month = (date.getMonth() + 1) > 10 ? date.getMonth() + 1 : '0' + (date.getMonth() + 1)
  197. let day = (date.getDate() >= 10) ? date.getDate() : '0' + date.getDate()
  198. let hours = (date.getHours() >= 10) ? date.getHours() : '0' + date.getHours()
  199. let minutes = (date.getMinutes() >= 10) ? date.getMinutes() : '0' + date.getMinutes()
  200. let seconds = (date.getSeconds() >= 10) ? date.getSeconds() : '0' + date.getSeconds()
  201. if (value) {
  202. return years + '-' + month + '-' + day +
  203. ' ' + hours + ':' + minutes + ':' + seconds
  204. } else {
  205. return 'N/A'
  206. }
  207. }
  208. },
  209. methods: {
  210. getMeasureOrJobList () {
  211. if (this.classificationtag === '度量') {
  212. this.getMeasureList()
  213. } else {
  214. this.getJobList()
  215. }
  216. },
  217. // 获取数据列表
  218. getMeasureList () {
  219. this.measureListAll = []
  220. this.measureList = []
  221. this.measDataListLoading = true
  222. // this.measureList = [
  223. // {'measureID': 1, 'measureName': 'demo1', 'measureType': 'profiling', 'remark': '测试'},
  224. // {'measureID': 1, 'measureName': 'demo1', 'measureType': 'profiling', 'remark': '测试'}
  225. //
  226. // ]
  227. this.$http({
  228. url: this.$http.snoopUrl('/v1/measures/owner/') + this.userName,
  229. methods: 'get'
  230. }).then((datas) => {
  231. if (datas && datas.status === 200) {
  232. var res = datas.data.reverse()
  233. // console.log(res)
  234. res.map((info) => {
  235. var measure = {
  236. 'measureID': info['id'],
  237. 'measureName': info['name'],
  238. 'measureType': info['dq.type'],
  239. 'remark': info['description']
  240. }
  241. this.measureListAll.push(measure)
  242. })
  243. }
  244. this.unique(this.measureListAll)
  245. this.measureList = this.measureListAll.slice(0, this.pageSize)
  246. this.totalPage = this.measureListAll.length
  247. this.measDataListLoading = false
  248. })
  249. },
  250. toCamel (myString) {
  251. return myString.replace(/[.]([a-z])/g, function (g) {
  252. return g[1].toUpperCase()
  253. })
  254. },
  255. swapJson (json) {
  256. const ret = {}
  257. for (const key in json) {
  258. ret[this.toCamel(key)] = json[key]
  259. }
  260. return ret
  261. },
  262. getJobList () {
  263. this.jobListAll = []
  264. this.jobDataListLoading = true
  265. const self = this
  266. this.$http({
  267. url: this.$http.snoopUrl('/v1/jobs'),
  268. methods: 'get'
  269. }).then((datas) => {
  270. if (datas && datas.status === 200) {
  271. var data = datas.data
  272. const trans = Object.keys(data).map(function (index) {
  273. const job = self.swapJson(data[index])
  274. job.jobState.previousFireTime = job.jobState.previousFireTime < 0 ? '' : job.jobState.previousFireTime
  275. return job
  276. })
  277. this.jobListAll = Object.assign([], trans).reverse()
  278. this.jobList = this.jobListAll.slice(0, this.pageSize)
  279. this.totalPage = this.jobListAll.length
  280. }
  281. this.jobDataListLoading = false
  282. })
  283. },
  284. // 去重
  285. unique (arr) {
  286. var ss = []
  287. for (var i = 0; i < arr.length; i++) {
  288. ss[i] = arr[i].measureName
  289. }
  290. return Array.from(new Set(ss))
  291. },
  292. // 每页数
  293. sizeChangeHandle (val) {
  294. this.pageSize = val
  295. this.pageIndex = 1
  296. if (this.classificationtag === '任务') {
  297. let start = (this.pageIndex - 1) * this.pageSize
  298. this.jobList = this.jobListAll.slice(start, this.pageSize)
  299. } else {
  300. let start = (this.pageIndex - 1) * this.pageSize
  301. this.measureList = this.measureListAll.slice(start, this.pageSize)
  302. }
  303. },
  304. // 当前页
  305. currentChangeHandle (val) {
  306. this.pageIndex = val
  307. if (this.classificationtag === '任务') {
  308. let start = (this.pageIndex - 1) * this.pageSize
  309. let end = (this.pageIndex) * this.pageSize
  310. this.jobList = this.jobListAll.slice(start, end)
  311. } else {
  312. let start = (this.pageIndex - 1) * this.pageSize
  313. let end = (this.pageIndex) * this.pageSize
  314. this.measureList = this.measureListAll.slice(start, end)
  315. }
  316. },
  317. // **********************8多选
  318. SelectionChange (val) {
  319. this.dataListSelections = val
  320. },
  321. // 查看
  322. userwatch (info) {
  323. this.newWatchVisible = true
  324. this.$nextTick(() => {
  325. this.$refs.measureWatch.init(info)
  326. })
  327. },
  328. jobWatch (info) {
  329. this.jobWatchVisible = true
  330. this.$nextTick(() => {
  331. this.$refs.jobWatch.init(info)
  332. })
  333. },
  334. jobLogHandle (info) {
  335. this.jobLoghVisible = true
  336. this.$nextTick(() => {
  337. this.$refs.jobLog.init(info)
  338. })
  339. },
  340. jobResHandle (info) {
  341. this.jobResVisible = true
  342. this.$nextTick(() => {
  343. this.$refs.jobRes.init(info)
  344. })
  345. },
  346. // 这里处理新建
  347. addHandle () {
  348. this.addVisible = true
  349. this.$nextTick(() => {
  350. this.$refs.addS.init()
  351. })
  352. },
  353. jobResumeHandle (info) {
  354. MessageBox.confirm(
  355. `确定对[任务名=${info.jobName}]进行[恢复]操作?`,
  356. '提示',
  357. {
  358. confirmButtonText: '确定',
  359. cancelButtonText: '取消',
  360. type: 'warning'
  361. }
  362. ).then((data) => {
  363. this.jobDataListLoading = true
  364. // 进行后台请求
  365. this.$http({
  366. url: this.$http.snoopUrl('/v1/jobs/') + info.id + '?action=start',
  367. method: 'put'
  368. }).then((data) => {
  369. if (data && data.status === 200) {
  370. Message({
  371. message: '操作成功',
  372. type: 'success',
  373. duration: 1500,
  374. onClose: () => {
  375. this.getJobList()
  376. }
  377. })
  378. } else {
  379. this.$message.error(info.jobName + '恢复失败')
  380. this.getJobList()
  381. }
  382. })
  383. })
  384. .catch(() => {
  385. })
  386. },
  387. jobPauseHandle (info) {
  388. MessageBox.confirm(
  389. `确定对[任务名=${info.jobName}]进行[暂停]操作?`,
  390. '提示',
  391. {
  392. confirmButtonText: '确定',
  393. cancelButtonText: '取消',
  394. type: 'warning'
  395. }
  396. ).then((data) => {
  397. this.jobDataListLoading = true
  398. // 进行后台请求
  399. this.$http({
  400. url: this.$http.snoopUrl('/v1/jobs/') + info.id + '?action=stop',
  401. method: 'put'
  402. }).then((data) => {
  403. if (data && data.status === 200) {
  404. Message({
  405. message: '操作成功',
  406. type: 'success',
  407. duration: 1500,
  408. onClose: () => {
  409. this.getJobList()
  410. }
  411. })
  412. } else {
  413. this.$message.error(info.jobName + '恢复失败')
  414. this.getJobList()
  415. }
  416. })
  417. })
  418. .catch(() => {
  419. })
  420. },
  421. jobDeleteHandle (info) {
  422. MessageBox.confirm(
  423. `确定对[任务名=${info.jobName}]进行 [删除] 操作?`,
  424. '提示',
  425. {
  426. confirmButtonText: '确定',
  427. cancelButtonText: '取消',
  428. type: 'warning'
  429. }
  430. ).then(() => {
  431. this.jobDataListLoading = true
  432. // 进行后台请求
  433. this.$http({
  434. url: this.$http.snoopUrl('/v1/jobs/') + info.id,
  435. method: 'delete'
  436. }).then((data) => {
  437. // console.log(data)
  438. if (!data.data) {
  439. Message({
  440. message: '操作成功',
  441. type: 'success',
  442. duration: 1500,
  443. onClose: () => {
  444. this.getJobList()
  445. }
  446. })
  447. } else {
  448. MessageBox.error(info.jobName + '删除失败')
  449. this.getJobList()
  450. }
  451. })
  452. })
  453. .catch(() => {
  454. })
  455. },
  456. // ********** 删除
  457. measureDeleteHandle (info) {
  458. MessageBox.confirm(
  459. `确定对[${info.measureName}]进行[删除]操作? 删除后,对应job也会被删除`,
  460. '提示',
  461. {
  462. confirmButtonText: '确定',
  463. cancelButtonText: '取消',
  464. type: 'warning'
  465. }
  466. )
  467. .then(() => {
  468. this.$http({
  469. url: this.$http.snoopUrl('/v1/measures/') + info.measureID,
  470. method: 'delete'
  471. }).then(({data}) => {
  472. this.measDataListLoading = true
  473. if (!data.data) {
  474. Message({
  475. message: '操作成功',
  476. type: 'success',
  477. duration: 1500
  478. })
  479. this.measDataListLoading = false
  480. this.getMeasureList()
  481. this.pageIndex = 1
  482. } else {
  483. Message.error(data.msg)
  484. }
  485. })
  486. })
  487. .catch(() => {
  488. })
  489. },
  490. async measureAndJobDelete () {
  491. var waitSecond = 1
  492. if (this.classificationtag === '度量') {
  493. var allMeasureName = []
  494. for (var index in this.dataListSelections) {
  495. allMeasureName.push(this.dataListSelections[index].measureName)
  496. }
  497. await MessageBox.confirm(
  498. `确定对[${allMeasureName}]进行[删除]操作? 删除后,对应job也会被删除`,
  499. '提示',
  500. {
  501. confirmButtonText: '确定',
  502. cancelButtonText: '取消',
  503. type: 'warning'
  504. }
  505. ).then(() => {
  506. this.measDataListLoading = true
  507. let failure = []
  508. for (var index = 0; index < this.dataListSelections.length; index++) {
  509. waitSecond = waitSecond + 0.5
  510. this.$http({
  511. url: this.$http.snoopUrl('/v1/measures/') + this.dataListSelections[index].measureID,
  512. method: 'delete'
  513. }).then((data) => {
  514. if (data.data) {
  515. failure.push(this.dataListSelections[index])
  516. }
  517. })
  518. }
  519. if (failure.length === 0) {
  520. MessageBox({
  521. message: '操作成功',
  522. type: 'success',
  523. duration: 1500
  524. })
  525. } else {
  526. var msg = ''
  527. failure.forEach(x => {
  528. msg = msg + ' ' + x.measureName
  529. })
  530. MessageBox.error(msg)
  531. }
  532. setTimeout(() => {
  533. this.measDataListLoading = false
  534. this.getMeasureList()
  535. }, waitSecond * 1000)
  536. }).catch(() => {
  537. })
  538. } else {
  539. var allJobName = []
  540. for (var jobindex in this.dataListSelections) {
  541. allJobName.push(this.dataListSelections[jobindex].jobName)
  542. }
  543. await MessageBox.confirm(
  544. `确定对[${allJobName}]进行[删除]操作? `,
  545. '提示',
  546. {
  547. confirmButtonText: '确定',
  548. cancelButtonText: '取消',
  549. type: 'warning'
  550. }
  551. ).then(() => {
  552. this.jobDataListLoading = true
  553. let failure = []
  554. for (var index = 0; index < this.dataListSelections.length; index++) {
  555. waitSecond = waitSecond + 0.5
  556. this.$http({
  557. url: this.$http.snoopUrl('/v1/jobs/') + this.dataListSelections[index].id,
  558. method: 'delete'
  559. }).then((data) => {
  560. if (data.data) {
  561. failure.push(this.dataListSelections[index])
  562. }
  563. })
  564. }
  565. if (failure.length === 0) {
  566. MessageBox({
  567. message: '操作成功',
  568. type: 'success',
  569. duration: 1500
  570. })
  571. } else {
  572. var msg = ''
  573. failure.forEach(x => {
  574. msg = msg + ' ' + x.jobName
  575. })
  576. MessageBox.error(msg)
  577. }
  578. setTimeout(() => {
  579. this.jobDataListLoading = false
  580. this.getJobList()
  581. }, waitSecond * 1000)
  582. }).catch(() => {
  583. })
  584. }
  585. }
  586. }
  587. }
  588. </script>
  589. <style scoped>
  590. .divi {
  591. display: block;
  592. height: 1px;
  593. width: 100%;
  594. margin: 24px 0;
  595. background-color: #dcdfe6;
  596. position: relative;
  597. }
  598. .divi2 {
  599. display: block;
  600. height: 1px;
  601. width: 100%;
  602. position: relative;
  603. }
  604. .sele {
  605. border: 1px solid #409eff;
  606. border-radius: 5px;
  607. box-sizing: border-box;
  608. padding: 5px 0px;
  609. margin: 10px;
  610. }
  611. </style>