46 changed files with 33 additions and 5094 deletions
-
11src/api/system/user.js
-
124src/views/components/Echarts.vue
-
74src/views/components/Editor.vue
-
46src/views/components/MarkDown.vue
-
207src/views/components/YamlEdit.vue
-
74src/views/components/icons/element-icons.js
-
97src/views/components/icons/index.vue
-
10src/views/components/icons/svg-icons.js
-
135src/views/dashboard/LineChart.vue
-
181src/views/dashboard/PanelGroup.vue
-
325src/views/generator/config.vue
-
114src/views/generator/index.vue
-
30src/views/generator/preview.vue
-
144src/views/mnt/app/index.vue
-
86src/views/mnt/database/execute.vue
-
148src/views/mnt/database/index.vue
-
190src/views/mnt/deploy/deploy.vue
-
229src/views/mnt/deploy/index.vue
-
108src/views/mnt/deploy/sysRestore.vue
-
93src/views/mnt/deployHistory/index.vue
-
136src/views/mnt/server/index.vue
-
135src/views/monitor/log/errorLog.vue
-
114src/views/monitor/log/index.vue
-
24src/views/monitor/log/search.vue
-
121src/views/monitor/online/index.vue
-
291src/views/monitor/server/index.vue
-
16src/views/monitor/sql/index.vue
-
115src/views/system/dict/dictDetail.vue
-
130src/views/system/dict/index.vue
-
110src/views/system/job/index.vue
-
110src/views/system/job/module/form.vue
-
32src/views/system/job/module/header.vue
-
210src/views/system/timing/index.vue
-
104src/views/system/timing/log.vue
-
98src/views/tools/aliPay/config.vue
-
48src/views/tools/aliPay/index.vue
-
86src/views/tools/aliPay/toPay.vue
-
91src/views/tools/email/config.vue
-
41src/views/tools/email/index.vue
-
142src/views/tools/email/send.vue
-
36src/views/tools/storage/index.vue
-
184src/views/tools/storage/local/index.vue
-
98src/views/tools/storage/qiniu/form.vue
-
189src/views/tools/storage/qiniu/index.vue
-
16src/views/tools/swagger/index.vue
-
24src/views/user/menu1.vue
@ -1,124 +0,0 @@ |
|||||
<template> |
|
||||
<div class="dashboard-container"> |
|
||||
<div class="dashboard-editor-container"> |
|
||||
<el-row style="background:#fff;padding:16px 16px 0;margin-bottom:32px;"> |
|
||||
<heat-map /> |
|
||||
</el-row> |
|
||||
<el-row :gutter="32"> |
|
||||
<el-col :xs="24" :sm="24" :lg="8"> |
|
||||
<div class="chart-wrapper"> |
|
||||
<radar-chart /> |
|
||||
</div> |
|
||||
</el-col> |
|
||||
<el-col :xs="24" :sm="24" :lg="8"> |
|
||||
<div class="chart-wrapper"> |
|
||||
<sunburst /> |
|
||||
</div> |
|
||||
</el-col> |
|
||||
<el-col :xs="24" :sm="24" :lg="8"> |
|
||||
<div class="chart-wrapper"> |
|
||||
<gauge /> |
|
||||
</div> |
|
||||
</el-col> |
|
||||
</el-row> |
|
||||
<el-row :gutter="12"> |
|
||||
<el-col :span="12"> |
|
||||
<div class="chart-wrapper"> |
|
||||
<rich /> |
|
||||
</div> |
|
||||
</el-col> |
|
||||
<el-col :span="12"> |
|
||||
<div class="chart-wrapper"> |
|
||||
<theme-river /> |
|
||||
</div> |
|
||||
</el-col> |
|
||||
</el-row> |
|
||||
<el-row :gutter="32"> |
|
||||
<el-col :xs="24" :sm="24" :lg="8"> |
|
||||
<div class="chart-wrapper"> |
|
||||
<graph /> |
|
||||
</div> |
|
||||
</el-col> |
|
||||
<el-col :xs="24" :sm="24" :lg="8"> |
|
||||
<div class="chart-wrapper"> |
|
||||
<sankey /> |
|
||||
</div> |
|
||||
</el-col> |
|
||||
<el-col :xs="24" :sm="24" :lg="8"> |
|
||||
<div class="chart-wrapper"> |
|
||||
<line3-d /> |
|
||||
</div> |
|
||||
</el-col> |
|
||||
</el-row> |
|
||||
<el-row :gutter="12"> |
|
||||
<el-col :span="12"> |
|
||||
<div class="chart-wrapper"> |
|
||||
<scatter /> |
|
||||
</div> |
|
||||
</el-col> |
|
||||
<el-col :span="12"> |
|
||||
<div class="chart-wrapper"> |
|
||||
<point /> |
|
||||
</div> |
|
||||
</el-col> |
|
||||
</el-row> |
|
||||
<el-row style="background:#fff;padding:16px 16px 0;margin-bottom:32px;"> |
|
||||
<div class="chart-wrapper"> |
|
||||
<word-cloud /> |
|
||||
</div> |
|
||||
</el-row> |
|
||||
<el-row style="background:#fff;padding:16px 16px 0;margin-bottom:32px;"> |
|
||||
<div class="chart-wrapper"> |
|
||||
<category /> |
|
||||
</div> |
|
||||
</el-row> |
|
||||
</div> |
|
||||
</div> |
|
||||
</template> |
|
||||
|
|
||||
<script> |
|
||||
import RadarChart from '@/components/Echarts/RadarChart' |
|
||||
import HeatMap from '@/components/Echarts/HeatMap' |
|
||||
import Gauge from '@/components/Echarts/Gauge' |
|
||||
import Rich from '@/components/Echarts/Rich' |
|
||||
import ThemeRiver from '@/components/Echarts/ThemeRiver' |
|
||||
import Sunburst from '@/components/Echarts/Sunburst' |
|
||||
import Graph from '@/components/Echarts/Graph' |
|
||||
import Sankey from '@/components/Echarts/Sankey' |
|
||||
import Scatter from '@/components/Echarts/Scatter' |
|
||||
import Line3D from '@/components/Echarts/Line3D' |
|
||||
import Category from '@/components/Echarts/Category' |
|
||||
import Point from '@/components/Echarts/Point' |
|
||||
import WordCloud from '@/components/Echarts/WordCloud' |
|
||||
|
|
||||
export default { |
|
||||
name: 'Echarts', |
|
||||
components: { |
|
||||
Point, |
|
||||
Category, |
|
||||
Graph, |
|
||||
HeatMap, |
|
||||
RadarChart, |
|
||||
Sunburst, |
|
||||
Gauge, |
|
||||
Rich, |
|
||||
ThemeRiver, |
|
||||
Sankey, |
|
||||
Line3D, |
|
||||
Scatter, |
|
||||
WordCloud |
|
||||
} |
|
||||
} |
|
||||
</script> |
|
||||
|
|
||||
<style rel="stylesheet/scss" lang="scss" scoped> |
|
||||
.dashboard-editor-container { |
|
||||
padding: 18px 22px 22px 22px; |
|
||||
background-color: rgb(240, 242, 245); |
|
||||
.chart-wrapper { |
|
||||
background: #fff; |
|
||||
padding: 16px 16px 0; |
|
||||
margin-bottom: 32px; |
|
||||
} |
|
||||
} |
|
||||
</style> |
|
||||
@ -1,74 +0,0 @@ |
|||||
<template> |
|
||||
<div class="app-container"> |
|
||||
<p class="warn-content"> |
|
||||
富文本基于 |
|
||||
<el-link type="primary" href="https://www.kancloud.cn/wangfupeng/wangeditor3/332599" target="_blank">wangEditor</el-link> |
|
||||
</p> |
|
||||
<el-row :gutter="10"> |
|
||||
<el-col :xs="24" :sm="24" :md="15" :lg="15" :xl="15"> |
|
||||
<div ref="editor" class="text"></div> |
|
||||
</el-col> |
|
||||
<el-col :xs="24" :sm="24" :md="9" :lg="9" :xl="9"> |
|
||||
<div v-html="editorContent"></div> |
|
||||
</el-col> |
|
||||
</el-row> |
|
||||
</div> |
|
||||
</template> |
|
||||
|
|
||||
<script> |
|
||||
import { mapGetters } from 'vuex' |
|
||||
import { upload } from '@/utils/upload' |
|
||||
import E from 'wangeditor' |
|
||||
export default { |
|
||||
name: 'Editor', |
|
||||
data() { |
|
||||
return { |
|
||||
editorContent: |
|
||||
` |
|
||||
<ul> |
|
||||
<li>更多帮助请查看官方文档:<a style="color: #42b983" target="_blank" href="https://www.kancloud.cn/wangfupeng/wangeditor3/332599">wangEditor</a></li> |
|
||||
</ul> |
|
||||
` |
|
||||
} |
|
||||
}, |
|
||||
computed: { |
|
||||
...mapGetters([ |
|
||||
'imagesUploadApi', |
|
||||
'baseApi' |
|
||||
]) |
|
||||
}, |
|
||||
mounted() { |
|
||||
const _this = this |
|
||||
var editor = new E(this.$refs.editor) |
|
||||
// 自定义菜单配置 |
|
||||
editor.customConfig.zIndex = 10 |
|
||||
// 文件上传 |
|
||||
editor.customConfig.customUploadImg = function(files, insert) { |
|
||||
// files 是 input 中选中的文件列表 |
|
||||
// insert 是获取图片 url 后,插入到编辑器的方法 |
|
||||
files.forEach(image => { |
|
||||
upload(_this.imagesUploadApi, image).then(res => { |
|
||||
const data = res.data |
|
||||
const url = _this.baseApi + '/file/' + data.type + '/' + data.realName |
|
||||
insert(url) |
|
||||
}) |
|
||||
}) |
|
||||
} |
|
||||
editor.customConfig.onchange = (html) => { |
|
||||
this.editorContent = html |
|
||||
} |
|
||||
editor.create() |
|
||||
// 初始化数据 |
|
||||
editor.txt.html(this.editorContent) |
|
||||
} |
|
||||
} |
|
||||
</script> |
|
||||
|
|
||||
<style scoped> |
|
||||
.text { |
|
||||
text-align:left; |
|
||||
} |
|
||||
::v-deep .w-e-text-container { |
|
||||
height: 420px !important; |
|
||||
} |
|
||||
</style> |
|
||||
@ -1,46 +0,0 @@ |
|||||
<template> |
|
||||
<div class="app-container"> |
|
||||
<p class="warn-content"> |
|
||||
Markdown 基于 |
|
||||
<el-link type="primary" href="https://github.com/hinesboy/mavonEditor" target="_blank">MavonEditor</el-link> |
|
||||
</p> |
|
||||
<mavon-editor ref="md" :style="'height:' + height" @imgAdd="imgAdd" /> |
|
||||
</div> |
|
||||
</template> |
|
||||
|
|
||||
<script> |
|
||||
import { upload } from '@/utils/upload' |
|
||||
import { mapGetters } from 'vuex' |
|
||||
export default { |
|
||||
name: 'Markdown', |
|
||||
data() { |
|
||||
return { |
|
||||
height: document.documentElement.clientHeight - 200 + 'px' |
|
||||
} |
|
||||
}, |
|
||||
computed: { |
|
||||
...mapGetters([ |
|
||||
'imagesUploadApi', |
|
||||
'baseApi' |
|
||||
]) |
|
||||
}, |
|
||||
mounted() { |
|
||||
const that = this |
|
||||
window.onresize = function temp() { |
|
||||
that.height = document.documentElement.clientHeight - 200 + 'px' |
|
||||
} |
|
||||
}, |
|
||||
methods: { |
|
||||
imgAdd(pos, $file) { |
|
||||
upload(this.imagesUploadApi, $file).then(res => { |
|
||||
const data = res.data |
|
||||
const url = this.baseApi + '/file/' + data.type + '/' + data.realName |
|
||||
this.$refs.md.$img2Url(pos, url) |
|
||||
}) |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
</script> |
|
||||
|
|
||||
<style scoped> |
|
||||
</style> |
|
||||
@ -1,207 +0,0 @@ |
|||||
<template> |
|
||||
<div class="app-container"> |
|
||||
<p class="warn-content"> |
|
||||
Yaml编辑器 基于 |
|
||||
<a href="https://github.com/codemirror/CodeMirror" target="_blank">CodeMirror</a>, |
|
||||
主题预览地址 <a href="https://codemirror.net/demo/theme.html#idea" target="_blank">Theme</a> |
|
||||
</p> |
|
||||
<Yaml :value="value" :height="height" /> |
|
||||
</div> |
|
||||
</template> |
|
||||
|
|
||||
<script> |
|
||||
import Yaml from '@/components/YamlEdit/index' |
|
||||
export default { |
|
||||
name: 'YamlEdit', |
|
||||
components: { Yaml }, |
|
||||
data() { |
|
||||
return { |
|
||||
height: document.documentElement.clientHeight - 210 + 'px', |
|
||||
value: '# 展示数据,如需更换主题,请在src/components/YamlEdit 目录中搜索原主题名称进行替换\n' + |
|
||||
'\n' + |
|
||||
'# ===================================================================\n' + |
|
||||
'# Spring Boot configuration.\n' + |
|
||||
'#\n' + |
|
||||
'# This configuration will be overridden by the Spring profile you use,\n' + |
|
||||
'# for example application-dev.yml if you use the "dev" profile.\n' + |
|
||||
'#\n' + |
|
||||
'# More information on profiles: https://www.jhipster.tech/profiles/\n' + |
|
||||
'# More information on configuration properties: https://www.jhipster.tech/common-application-properties/\n' + |
|
||||
'# ===================================================================\n' + |
|
||||
'\n' + |
|
||||
'# ===================================================================\n' + |
|
||||
'# Standard Spring Boot properties.\n' + |
|
||||
'# Full reference is available at:\n' + |
|
||||
'# http://docs.spring.io/spring-boot/docs/current/reference/html/common-application-properties.html\n' + |
|
||||
'# ===================================================================\n' + |
|
||||
'\n' + |
|
||||
'eureka:\n' + |
|
||||
' client:\n' + |
|
||||
' enabled: true\n' + |
|
||||
' healthcheck:\n' + |
|
||||
' enabled: true\n' + |
|
||||
' fetch-registry: true\n' + |
|
||||
' register-with-eureka: true\n' + |
|
||||
' instance-info-replication-interval-seconds: 10\n' + |
|
||||
' registry-fetch-interval-seconds: 10\n' + |
|
||||
' instance:\n' + |
|
||||
' appname: product\n' + |
|
||||
' instanceId: product:${spring.application.instance-id:${random.value}}\n' + |
|
||||
' #instanceId: 127.0.0.1:9080\n' + |
|
||||
' lease-renewal-interval-in-seconds: 5\n' + |
|
||||
' lease-expiration-duration-in-seconds: 10\n' + |
|
||||
' status-page-url-path: ${management.endpoints.web.base-path}/info\n' + |
|
||||
' health-check-url-path: ${management.endpoints.web.base-path}/health\n' + |
|
||||
' metadata-map:\n' + |
|
||||
' zone: primary # This is needed for the load balancer\n' + |
|
||||
' profile: ${spring.profiles.active}\n' + |
|
||||
' version: ${info.project.version:}\n' + |
|
||||
' git-version: ${git.commit.id.describe:}\n' + |
|
||||
' git-commit: ${git.commit.id.abbrev:}\n' + |
|
||||
' git-branch: ${git.branch:}\n' + |
|
||||
'ribbon:\n' + |
|
||||
' ReadTimeout: 120000\n' + |
|
||||
' ConnectTimeout: 300000\n' + |
|
||||
' eureka:\n' + |
|
||||
' enabled: true\n' + |
|
||||
'zuul:\n' + |
|
||||
' host:\n' + |
|
||||
' connect-timeout-millis: 5000\n' + |
|
||||
' max-per-route-connections: 10000\n' + |
|
||||
' max-total-connections: 5000\n' + |
|
||||
' socket-timeout-millis: 60000\n' + |
|
||||
' semaphore:\n' + |
|
||||
' max-semaphores: 500\n' + |
|
||||
'\n' + |
|
||||
'feign:\n' + |
|
||||
' hystrix:\n' + |
|
||||
' enabled: true\n' + |
|
||||
' client:\n' + |
|
||||
' config:\n' + |
|
||||
' default:\n' + |
|
||||
' connectTimeout: 500000\n' + |
|
||||
' readTimeout: 500000\n' + |
|
||||
'\n' + |
|
||||
'# See https://github.com/Netflix/Hystrix/wiki/Configuration\n' + |
|
||||
'hystrix:\n' + |
|
||||
' command:\n' + |
|
||||
' default:\n' + |
|
||||
' circuitBreaker:\n' + |
|
||||
' sleepWindowInMilliseconds: 100000\n' + |
|
||||
' forceClosed: true\n' + |
|
||||
' execution:\n' + |
|
||||
' isolation:\n' + |
|
||||
'# strategy: SEMAPHORE\n' + |
|
||||
'# See https://github.com/spring-cloud/spring-cloud-netflix/issues/1330\n' + |
|
||||
' thread:\n' + |
|
||||
' timeoutInMilliseconds: 60000\n' + |
|
||||
' shareSecurityContext: true\n' + |
|
||||
'\n' + |
|
||||
'management:\n' + |
|
||||
' endpoints:\n' + |
|
||||
' web:\n' + |
|
||||
' base-path: /management\n' + |
|
||||
' exposure:\n' + |
|
||||
' include: ["configprops", "env", "health", "info", "threaddump"]\n' + |
|
||||
' endpoint:\n' + |
|
||||
' health:\n' + |
|
||||
' show-details: when_authorized\n' + |
|
||||
' info:\n' + |
|
||||
' git:\n' + |
|
||||
' mode: full\n' + |
|
||||
' health:\n' + |
|
||||
' mail:\n' + |
|
||||
' enabled: false # When using the MailService, configure an SMTP server and set this to true\n' + |
|
||||
' metrics:\n' + |
|
||||
' enabled: false # http://micrometer.io/ is disabled by default, as we use http://metrics.dropwizard.io/ instead\n' + |
|
||||
'\n' + |
|
||||
'spring:\n' + |
|
||||
' application:\n' + |
|
||||
' name: product\n' + |
|
||||
' jpa:\n' + |
|
||||
' open-in-view: false\n' + |
|
||||
' hibernate:\n' + |
|
||||
' ddl-auto: update\n' + |
|
||||
' naming:\n' + |
|
||||
' physical-strategy: org.springframework.boot.orm.jpa.hibernate.SpringPhysicalNamingStrategy\n' + |
|
||||
' implicit-strategy: org.springframework.boot.orm.jpa.hibernate.SpringImplicitNamingStrategy\n' + |
|
||||
' messages:\n' + |
|
||||
' basename: i18n/messages\n' + |
|
||||
' mvc:\n' + |
|
||||
' favicon:\n' + |
|
||||
' enabled: false\n' + |
|
||||
' thymeleaf:\n' + |
|
||||
' mode: HTML\n' + |
|
||||
'security:\n' + |
|
||||
' oauth2:\n' + |
|
||||
' resource:\n' + |
|
||||
' filter-order: 3\n' + |
|
||||
'\n' + |
|
||||
'server:\n' + |
|
||||
' servlet:\n' + |
|
||||
' session:\n' + |
|
||||
' cookie:\n' + |
|
||||
' http-only: true\n' + |
|
||||
'\n' + |
|
||||
'# Properties to be exposed on the /info management endpoint\n' + |
|
||||
'info:\n' + |
|
||||
' # Comma separated list of profiles that will trigger the ribbon to show\n' + |
|
||||
' display-ribbon-on-profiles: "dev"\n' + |
|
||||
'\n' + |
|
||||
'# ===================================================================\n' + |
|
||||
'# JHipster specific properties\n' + |
|
||||
'#\n' + |
|
||||
'# Full reference is available at: https://www.jhipster.tech/common-application-properties/\n' + |
|
||||
'# ===================================================================\n' + |
|
||||
'\n' + |
|
||||
'jhipster:\n' + |
|
||||
' async:\n' + |
|
||||
' core-pool-size: 2\n' + |
|
||||
' max-pool-size: 50\n' + |
|
||||
' queue-capacity: 10000\n' + |
|
||||
' # By default CORS is disabled. Uncomment to enable.\n' + |
|
||||
' #cors:\n' + |
|
||||
' #allowed-origins: "*"\n' + |
|
||||
' #allowed-methods: "*"\n' + |
|
||||
' #allowed-headers: "*"\n' + |
|
||||
' #exposed-headers: "Authorization,Link,X-Total-Count"\n' + |
|
||||
' #allow-credentials: true\n' + |
|
||||
' #max-age: 1800\n' + |
|
||||
' mail:\n' + |
|
||||
' from: product@localhost\n' + |
|
||||
' swagger:\n' + |
|
||||
' default-include-pattern: /api/.*\n' + |
|
||||
' title: product API\n' + |
|
||||
' description: product API documentation\n' + |
|
||||
' version: 0.0.1\n' + |
|
||||
' terms-of-service-url:\n' + |
|
||||
' contact-name:\n' + |
|
||||
' contact-url:\n' + |
|
||||
' contact-email:\n' + |
|
||||
' license:\n' + |
|
||||
' license-url:\n' + |
|
||||
'\n' + |
|
||||
'# ===================================================================\n' + |
|
||||
'# Application specific properties\n' + |
|
||||
'# Add your own application properties here, see the ApplicationProperties class\n' + |
|
||||
'# to have type-safe configuration, like in the JHipsterProperties above\n' + |
|
||||
'#\n' + |
|
||||
'# More documentation is available at:\n' + |
|
||||
'# https://www.jhipster.tech/common-application-properties/\n' + |
|
||||
'# ===================================================================\n' + |
|
||||
'\n' + |
|
||||
'# application:\n' |
|
||||
} |
|
||||
}, |
|
||||
mounted() { |
|
||||
const that = this |
|
||||
window.onresize = function temp() { |
|
||||
that.height = document.documentElement.clientHeight - 210 + 'px' |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
</script> |
|
||||
|
|
||||
<style scoped> |
|
||||
|
|
||||
</style> |
|
||||
@ -1,74 +0,0 @@ |
|||||
const elementIcons = [ |
|
||||
'info', |
|
||||
'error', |
|
||||
'success', |
|
||||
'warning', |
|
||||
'question', |
|
||||
'back', |
|
||||
'arrow-left', |
|
||||
'arrow-down', |
|
||||
'arrow-right', |
|
||||
'arrow-up', |
|
||||
'caret-left', |
|
||||
'caret-bottom', |
|
||||
'caret-top', |
|
||||
'caret-right', |
|
||||
'd-arrow-left', |
|
||||
'd-arrow-right', |
|
||||
'minus', |
|
||||
'plus', |
|
||||
'remove', |
|
||||
'circle-plus', |
|
||||
'remove-outline', |
|
||||
'circle-plus-outline', |
|
||||
'close', |
|
||||
'check', |
|
||||
'circle-close', |
|
||||
'circle-check', |
|
||||
'circle-close-outline', |
|
||||
'circle-check-outline', |
|
||||
'zoom-out', |
|
||||
'zoom-in', |
|
||||
'd-caret', |
|
||||
'sort', |
|
||||
'sort-down', |
|
||||
'sort-up', |
|
||||
'tickets', |
|
||||
'document', |
|
||||
'goods', |
|
||||
'sold-out', |
|
||||
'news', |
|
||||
'message', |
|
||||
'date', |
|
||||
'printer', |
|
||||
'time', |
|
||||
'bell', |
|
||||
'mobile-phone', |
|
||||
'service', |
|
||||
'view', |
|
||||
'menu', |
|
||||
'more', |
|
||||
'more-outline', |
|
||||
'star-on', |
|
||||
'star-off', |
|
||||
'location', |
|
||||
'location-outline', |
|
||||
'phone', |
|
||||
'phone-outline', |
|
||||
'picture', |
|
||||
'picture-outline', |
|
||||
'delete', |
|
||||
'search', |
|
||||
'edit', |
|
||||
'edit-outline', |
|
||||
'rank', |
|
||||
'refresh', |
|
||||
'share', |
|
||||
'setting', |
|
||||
'upload', |
|
||||
'upload2', |
|
||||
'download', |
|
||||
'loading' |
|
||||
] |
|
||||
|
|
||||
export default elementIcons |
|
||||
@ -1,97 +0,0 @@ |
|||||
<template> |
|
||||
<div class="icons-container"> |
|
||||
<aside> |
|
||||
<a href="https:/www.aiyxadmin.com" target="_blank">Add and use |
|
||||
</a> |
|
||||
</aside> |
|
||||
<el-tabs type="border-card"> |
|
||||
<el-tab-pane label="Icons"> |
|
||||
<div class="grid"> |
|
||||
<div v-for="item of svgIcons" :key="item" @click="handleClipboard(generateIconCode(item),$event)"> |
|
||||
<el-tooltip placement="top"> |
|
||||
<div slot="content"> |
|
||||
{{ generateIconCode(item) }} |
|
||||
</div> |
|
||||
<div class="icon-item"> |
|
||||
<svg-icon :icon-class="item" class-name="disabled" /> |
|
||||
<span>{{ item }}</span> |
|
||||
</div> |
|
||||
</el-tooltip> |
|
||||
</div> |
|
||||
</div> |
|
||||
</el-tab-pane> |
|
||||
<el-tab-pane label="Element-UI Icons"> |
|
||||
<div class="grid"> |
|
||||
<div v-for="item of elementIcons" :key="item" @click="handleClipboard(generateElementIconCode(item),$event)"> |
|
||||
<el-tooltip placement="top"> |
|
||||
<div slot="content"> |
|
||||
{{ generateElementIconCode(item) }} |
|
||||
</div> |
|
||||
<div class="icon-item"> |
|
||||
<i :class="'el-icon-' + item" /> |
|
||||
<span>{{ item }}</span> |
|
||||
</div> |
|
||||
</el-tooltip> |
|
||||
</div> |
|
||||
</div> |
|
||||
</el-tab-pane> |
|
||||
</el-tabs> |
|
||||
</div> |
|
||||
</template> |
|
||||
|
|
||||
<script> |
|
||||
import clipboard from '@/utils/clipboard' |
|
||||
import svgIcons from './svg-icons' |
|
||||
import elementIcons from './element-icons' |
|
||||
export default { |
|
||||
name: 'Icons', |
|
||||
data() { |
|
||||
return { |
|
||||
svgIcons, |
|
||||
elementIcons |
|
||||
} |
|
||||
}, |
|
||||
methods: { |
|
||||
generateIconCode(symbol) { |
|
||||
return `<svg-icon icon-class="${symbol}" />` |
|
||||
}, |
|
||||
generateElementIconCode(symbol) { |
|
||||
return `<i class="el-icon-${symbol}" />` |
|
||||
}, |
|
||||
handleClipboard(text, event) { |
|
||||
clipboard(text, event) |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
</script> |
|
||||
|
|
||||
<style lang="scss" scoped> |
|
||||
.icons-container { |
|
||||
margin: 10px 20px 0; |
|
||||
overflow: hidden; |
|
||||
|
|
||||
.grid { |
|
||||
position: relative; |
|
||||
display: grid; |
|
||||
grid-template-columns: repeat(auto-fill, minmax(120px, 1fr)); |
|
||||
} |
|
||||
.icon-item { |
|
||||
margin: 20px; |
|
||||
height: 85px; |
|
||||
text-align: center; |
|
||||
width: 100px; |
|
||||
float: left; |
|
||||
font-size: 30px; |
|
||||
color: #24292e; |
|
||||
cursor: pointer; |
|
||||
} |
|
||||
span { |
|
||||
display: block; |
|
||||
font-size: 16px; |
|
||||
margin-top: 10px; |
|
||||
} |
|
||||
.disabled { |
|
||||
pointer-events: none; |
|
||||
} |
|
||||
} |
|
||||
</style> |
|
||||
@ -1,10 +0,0 @@ |
|||||
const req = require.context('../../../assets/icons/svg', false, /\.svg$/) |
|
||||
const requireAll = requireContext => requireContext.keys() |
|
||||
|
|
||||
const re = /\.\/(.*)\.svg/ |
|
||||
|
|
||||
const svgIcons = requireAll(req).map(i => { |
|
||||
return i.match(re)[1] |
|
||||
}) |
|
||||
|
|
||||
export default svgIcons |
|
||||
@ -1,135 +0,0 @@ |
|||||
<template> |
|
||||
<div :class="className" :style="{height:height,width:width}"></div> |
|
||||
</template> |
|
||||
|
|
||||
<script> |
|
||||
import echarts from 'echarts' |
|
||||
require('echarts/theme/macarons') // echarts theme |
|
||||
import resize from './mixins/resize' |
|
||||
|
|
||||
export default { |
|
||||
mixins: [resize], |
|
||||
props: { |
|
||||
className: { |
|
||||
type: String, |
|
||||
default: 'chart' |
|
||||
}, |
|
||||
width: { |
|
||||
type: String, |
|
||||
default: '100%' |
|
||||
}, |
|
||||
height: { |
|
||||
type: String, |
|
||||
default: '350px' |
|
||||
}, |
|
||||
autoResize: { |
|
||||
type: Boolean, |
|
||||
default: true |
|
||||
}, |
|
||||
chartData: { |
|
||||
type: Object, |
|
||||
required: true |
|
||||
} |
|
||||
}, |
|
||||
data() { |
|
||||
return { |
|
||||
chart: null |
|
||||
} |
|
||||
}, |
|
||||
watch: { |
|
||||
chartData: { |
|
||||
deep: true, |
|
||||
handler(val) { |
|
||||
this.setOptions(val) |
|
||||
} |
|
||||
} |
|
||||
}, |
|
||||
mounted() { |
|
||||
this.$nextTick(() => { |
|
||||
this.initChart() |
|
||||
}) |
|
||||
}, |
|
||||
beforeDestroy() { |
|
||||
if (!this.chart) { |
|
||||
return |
|
||||
} |
|
||||
this.chart.dispose() |
|
||||
this.chart = null |
|
||||
}, |
|
||||
methods: { |
|
||||
initChart() { |
|
||||
this.chart = echarts.init(this.$el, 'macarons') |
|
||||
this.setOptions(this.chartData) |
|
||||
}, |
|
||||
setOptions({ expectedData, actualData } = {}) { |
|
||||
this.chart.setOption({ |
|
||||
xAxis: { |
|
||||
data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'], |
|
||||
boundaryGap: false, |
|
||||
axisTick: { |
|
||||
show: false |
|
||||
} |
|
||||
}, |
|
||||
grid: { |
|
||||
left: 10, |
|
||||
right: 10, |
|
||||
bottom: 20, |
|
||||
top: 30, |
|
||||
containLabel: true |
|
||||
}, |
|
||||
tooltip: { |
|
||||
trigger: 'axis', |
|
||||
axisPointer: { |
|
||||
type: 'cross' |
|
||||
}, |
|
||||
padding: [5, 10] |
|
||||
}, |
|
||||
yAxis: { |
|
||||
axisTick: { |
|
||||
show: false |
|
||||
} |
|
||||
}, |
|
||||
legend: { |
|
||||
data: ['expected', 'actual'] |
|
||||
}, |
|
||||
series: [{ |
|
||||
name: 'expected', itemStyle: { |
|
||||
normal: { |
|
||||
color: '#FF005A', |
|
||||
lineStyle: { |
|
||||
color: '#FF005A', |
|
||||
width: 2 |
|
||||
} |
|
||||
} |
|
||||
}, |
|
||||
smooth: true, |
|
||||
type: 'line', |
|
||||
data: expectedData, |
|
||||
animationDuration: 2800, |
|
||||
animationEasing: 'cubicInOut' |
|
||||
}, |
|
||||
{ |
|
||||
name: 'actual', |
|
||||
smooth: true, |
|
||||
type: 'line', |
|
||||
itemStyle: { |
|
||||
normal: { |
|
||||
color: '#3888fa', |
|
||||
lineStyle: { |
|
||||
color: '#3888fa', |
|
||||
width: 2 |
|
||||
}, |
|
||||
areaStyle: { |
|
||||
color: '#f3f8ff' |
|
||||
} |
|
||||
} |
|
||||
}, |
|
||||
data: actualData, |
|
||||
animationDuration: 2800, |
|
||||
animationEasing: 'quadraticOut' |
|
||||
}] |
|
||||
}) |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
</script> |
|
||||
@ -1,181 +0,0 @@ |
|||||
<template> |
|
||||
<el-row :gutter="40" class="panel-group"> |
|
||||
<el-col :xs="12" :sm="12" :lg="6" class="card-panel-col"> |
|
||||
<div class="card-panel" @click="handleSetLineChartData('newVisitis')"> |
|
||||
<div class="card-panel-icon-wrapper icon-people"> |
|
||||
<svg-icon icon-class="peoples" class-name="card-panel-icon" /> |
|
||||
</div> |
|
||||
<div class="card-panel-description"> |
|
||||
<div class="card-panel-text"> |
|
||||
New Visits |
|
||||
</div> |
|
||||
<count-to :start-val="0" :end-val="102400" :duration="2600" class="card-panel-num" /> |
|
||||
</div> |
|
||||
</div> |
|
||||
</el-col> |
|
||||
<el-col :xs="12" :sm="12" :lg="6" class="card-panel-col"> |
|
||||
<div class="card-panel" @click="handleSetLineChartData('messages')"> |
|
||||
<div class="card-panel-icon-wrapper icon-message"> |
|
||||
<svg-icon icon-class="message" class-name="card-panel-icon" /> |
|
||||
</div> |
|
||||
<div class="card-panel-description"> |
|
||||
<div class="card-panel-text"> |
|
||||
Messages |
|
||||
</div> |
|
||||
<count-to :start-val="0" :end-val="81212" :duration="3000" class="card-panel-num" /> |
|
||||
</div> |
|
||||
</div> |
|
||||
</el-col> |
|
||||
<el-col :xs="12" :sm="12" :lg="6" class="card-panel-col"> |
|
||||
<div class="card-panel" @click="handleSetLineChartData('purchases')"> |
|
||||
<div class="card-panel-icon-wrapper icon-money"> |
|
||||
<svg-icon icon-class="money" class-name="card-panel-icon" /> |
|
||||
</div> |
|
||||
<div class="card-panel-description"> |
|
||||
<div class="card-panel-text"> |
|
||||
Purchases |
|
||||
</div> |
|
||||
<count-to :start-val="0" :end-val="9280" :duration="3200" class="card-panel-num" /> |
|
||||
</div> |
|
||||
</div> |
|
||||
</el-col> |
|
||||
<el-col :xs="12" :sm="12" :lg="6" class="card-panel-col"> |
|
||||
<div class="card-panel" @click="handleSetLineChartData('shoppings')"> |
|
||||
<div class="card-panel-icon-wrapper icon-shopping"> |
|
||||
<svg-icon icon-class="shopping" class-name="card-panel-icon" /> |
|
||||
</div> |
|
||||
<div class="card-panel-description"> |
|
||||
<div class="card-panel-text"> |
|
||||
Shoppings |
|
||||
</div> |
|
||||
<count-to :start-val="0" :end-val="13600" :duration="3600" class="card-panel-num" /> |
|
||||
</div> |
|
||||
</div> |
|
||||
</el-col> |
|
||||
</el-row> |
|
||||
</template> |
|
||||
|
|
||||
<script> |
|
||||
import CountTo from 'vue-count-to' |
|
||||
|
|
||||
export default { |
|
||||
components: { |
|
||||
CountTo |
|
||||
}, |
|
||||
methods: { |
|
||||
handleSetLineChartData(type) { |
|
||||
this.$emit('handleSetLineChartData', type) |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
</script> |
|
||||
|
|
||||
<style lang="scss" scoped> |
|
||||
.panel-group { |
|
||||
margin-top: 18px; |
|
||||
|
|
||||
.card-panel-col { |
|
||||
margin-bottom: 32px; |
|
||||
} |
|
||||
|
|
||||
.card-panel { |
|
||||
height: 108px; |
|
||||
cursor: pointer; |
|
||||
font-size: 12px; |
|
||||
position: relative; |
|
||||
overflow: hidden; |
|
||||
color: #666; |
|
||||
background: #fff; |
|
||||
box-shadow: 4px 4px 40px rgba(0, 0, 0, .05); |
|
||||
border-color: rgba(0, 0, 0, .05); |
|
||||
|
|
||||
&:hover { |
|
||||
.card-panel-icon-wrapper { |
|
||||
color: #fff; |
|
||||
} |
|
||||
|
|
||||
.icon-people { |
|
||||
background: #40c9c6; |
|
||||
} |
|
||||
|
|
||||
.icon-message { |
|
||||
background: #36a3f7; |
|
||||
} |
|
||||
|
|
||||
.icon-money { |
|
||||
background: #f4516c; |
|
||||
} |
|
||||
|
|
||||
.icon-shopping { |
|
||||
background: #34bfa3 |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
.icon-people { |
|
||||
color: #40c9c6; |
|
||||
} |
|
||||
|
|
||||
.icon-message { |
|
||||
color: #36a3f7; |
|
||||
} |
|
||||
|
|
||||
.icon-money { |
|
||||
color: #f4516c; |
|
||||
} |
|
||||
|
|
||||
.icon-shopping { |
|
||||
color: #34bfa3 |
|
||||
} |
|
||||
|
|
||||
.card-panel-icon-wrapper { |
|
||||
float: left; |
|
||||
margin: 14px 0 0 14px; |
|
||||
padding: 16px; |
|
||||
transition: all 0.38s ease-out; |
|
||||
border-radius: 6px; |
|
||||
} |
|
||||
|
|
||||
.card-panel-icon { |
|
||||
float: left; |
|
||||
font-size: 48px; |
|
||||
} |
|
||||
|
|
||||
.card-panel-description { |
|
||||
float: right; |
|
||||
font-weight: bold; |
|
||||
margin: 26px; |
|
||||
margin-left: 0px; |
|
||||
|
|
||||
.card-panel-text { |
|
||||
line-height: 18px; |
|
||||
color: rgba(0, 0, 0, 0.45); |
|
||||
font-size: 16px; |
|
||||
margin-bottom: 12px; |
|
||||
} |
|
||||
|
|
||||
.card-panel-num { |
|
||||
font-size: 20px; |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
@media (max-width:550px) { |
|
||||
.card-panel-description { |
|
||||
display: none; |
|
||||
} |
|
||||
|
|
||||
.card-panel-icon-wrapper { |
|
||||
float: none !important; |
|
||||
width: 100%; |
|
||||
height: 100%; |
|
||||
margin: 0 !important; |
|
||||
|
|
||||
.svg-icon { |
|
||||
display: block; |
|
||||
margin: 14px auto !important; |
|
||||
float: none !important; |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
</style> |
|
||||
@ -1,325 +0,0 @@ |
|||||
<template> |
|
||||
<div class="app-container"> |
|
||||
<el-row :gutter="15"> |
|
||||
<el-col style="margin-bottom: 10px"> |
|
||||
<el-card class="box-card" shadow="never"> |
|
||||
<div slot="header" class="clearfix"> |
|
||||
<span class="role-span">字段配置:{{ tableName }}</span> |
|
||||
<el-button |
|
||||
:loading="genLoading" |
|
||||
icon="el-icon-s-promotion" |
|
||||
size="mini" |
|
||||
style="float: right; padding: 6px 9px;" |
|
||||
type="success" |
|
||||
@click="toGen" |
|
||||
>保存&生成</el-button> |
|
||||
<el-button |
|
||||
:loading="columnLoading" |
|
||||
icon="el-icon-check" |
|
||||
size="mini" |
|
||||
style="float: right; padding: 6px 9px;margin-right: 9px" |
|
||||
type="primary" |
|
||||
@click="saveColumnConfig" |
|
||||
>保存</el-button> |
|
||||
<el-tooltip class="item" effect="dark" content="数据库中表字段变动时使用该功能" placement="top-start"> |
|
||||
<el-button |
|
||||
:loading="syncLoading" |
|
||||
icon="el-icon-refresh" |
|
||||
size="mini" |
|
||||
style="float: right; padding: 6px 9px;" |
|
||||
type="info" |
|
||||
@click="sync" |
|
||||
>同步</el-button> |
|
||||
</el-tooltip> |
|
||||
</div> |
|
||||
<el-form size="small" label-width="90px"> |
|
||||
<el-table v-loading="loading" :data="data" :max-height="tableHeight" size="small" style="width: 100%;margin-bottom: 15px"> |
|
||||
<el-table-column prop="columnName" label="字段名称" /> |
|
||||
<el-table-column prop="columnType" label="字段类型" /> |
|
||||
<el-table-column prop="remark" label="字段描述"> |
|
||||
<template slot-scope="scope"> |
|
||||
<el-input v-model="data[scope.$index].remark" size="mini" class="edit-input" /> |
|
||||
</template> |
|
||||
</el-table-column> |
|
||||
<el-table-column align="center" label="必填" width="70px"> |
|
||||
<template slot-scope="scope"> |
|
||||
<el-checkbox v-model="data[scope.$index].notNull" /> |
|
||||
</template> |
|
||||
</el-table-column> |
|
||||
<el-table-column align="center" label="列表" width="70px"> |
|
||||
<template slot-scope="scope"> |
|
||||
<el-checkbox v-model="data[scope.$index].listShow" /> |
|
||||
</template> |
|
||||
</el-table-column> |
|
||||
<el-table-column align="center" label="表单" width="70px"> |
|
||||
<template slot-scope="scope"> |
|
||||
<el-checkbox v-model="data[scope.$index].formShow" /> |
|
||||
</template> |
|
||||
</el-table-column> |
|
||||
<el-table-column label="表单类型"> |
|
||||
<template slot-scope="scope"> |
|
||||
<el-select v-model="data[scope.$index].formType" filterable class="edit-input" clearable size="mini" placeholder="请选择"> |
|
||||
<el-option |
|
||||
label="文本框" |
|
||||
value="Input" |
|
||||
/> |
|
||||
<el-option |
|
||||
label="文本域" |
|
||||
value="Textarea" |
|
||||
/> |
|
||||
<el-option |
|
||||
label="单选框" |
|
||||
value="Radio" |
|
||||
/> |
|
||||
<el-option |
|
||||
label="下拉框" |
|
||||
value="Select" |
|
||||
/> |
|
||||
<el-option |
|
||||
label="日期框" |
|
||||
value="Date" |
|
||||
/> |
|
||||
</el-select> |
|
||||
</template> |
|
||||
</el-table-column> |
|
||||
<el-table-column label="查询方式"> |
|
||||
<template slot-scope="scope"> |
|
||||
<el-select v-model="data[scope.$index].queryType" filterable class="edit-input" clearable size="mini" placeholder="请选择"> |
|
||||
<el-option |
|
||||
label="=" |
|
||||
value="=" |
|
||||
/> |
|
||||
<el-option |
|
||||
label="!=" |
|
||||
value="!=" |
|
||||
/> |
|
||||
<el-option |
|
||||
label=">=" |
|
||||
value=">=" |
|
||||
/> |
|
||||
<el-option |
|
||||
label="<=" |
|
||||
value="<=" |
|
||||
/> |
|
||||
<el-option |
|
||||
label="Like" |
|
||||
value="Like" |
|
||||
/> |
|
||||
<el-option |
|
||||
label="NotNull" |
|
||||
value="NotNull" |
|
||||
/> |
|
||||
<el-option |
|
||||
label="BetWeen" |
|
||||
value="BetWeen" |
|
||||
/> |
|
||||
</el-select> |
|
||||
</template> |
|
||||
</el-table-column> |
|
||||
<el-table-column label="日期注解"> |
|
||||
<template slot-scope="scope"> |
|
||||
<el-select v-model="data[scope.$index].dateAnnotation" filterable class="edit-input" clearable size="mini" placeholder="请选择"> |
|
||||
<el-option |
|
||||
label="自动创建时间" |
|
||||
value="CreationTimestamp" |
|
||||
/> |
|
||||
<el-option |
|
||||
label="自动更新时间" |
|
||||
value="UpdateTimestamp" |
|
||||
/> |
|
||||
</el-select> |
|
||||
</template> |
|
||||
</el-table-column> |
|
||||
<el-table-column label="关联字典"> |
|
||||
<template slot-scope="scope"> |
|
||||
<el-select v-model="data[scope.$index].dictName" filterable class="edit-input" clearable size="mini" placeholder="请选择"> |
|
||||
<el-option v-for="item in dicts" :key="item.id" :label="item.remark === '' ? item.name : item.remark" :value="item.name" /> |
|
||||
</el-select> |
|
||||
</template> |
|
||||
</el-table-column> |
|
||||
</el-table> |
|
||||
</el-form> |
|
||||
</el-card> |
|
||||
</el-col> |
|
||||
<el-col> |
|
||||
<el-card class="box-card" shadow="never"> |
|
||||
<div slot="header" class="clearfix"> |
|
||||
<span class="role-span">生成配置</span> |
|
||||
<el-button |
|
||||
:loading="configLoading" |
|
||||
icon="el-icon-check" |
|
||||
size="mini" |
|
||||
style="float: right; padding: 6px 9px" |
|
||||
type="primary" |
|
||||
@click="doSubmit" |
|
||||
>保存</el-button> |
|
||||
</div> |
|
||||
<el-form ref="form" :model="form" :rules="rules" size="small" label-width="78px"> |
|
||||
<el-form-item label="作者名称" prop="author"> |
|
||||
<el-input v-model="form.author" style="width: 40%" /> |
|
||||
<span style="color: #C0C0C0;margin-left: 10px;">类上面的作者名称</span> |
|
||||
</el-form-item> |
|
||||
<el-form-item label="模块名称" prop="moduleName"> |
|
||||
<el-input v-model="form.moduleName" style="width: 40%" /> |
|
||||
<span style="color: #C0C0C0;margin-left: 10px;">模块的名称,请选择项目中已存在的模块</span> |
|
||||
</el-form-item> |
|
||||
<el-form-item label="至于包下" prop="pack"> |
|
||||
<el-input v-model="form.pack" style="width: 40%" /> |
|
||||
<span style="color: #C0C0C0;margin-left: 10px;">项目包的名称,生成的代码放到哪个包里面</span> |
|
||||
</el-form-item> |
|
||||
<el-form-item label="接口名称" prop="apiAlias"> |
|
||||
<el-input v-model="form.apiAlias" style="width: 40%" /> |
|
||||
<span style="color: #C0C0C0;margin-left: 10px;">接口的名称,用于控制器与接口文档中</span> |
|
||||
</el-form-item> |
|
||||
<el-form-item label="前端路径" prop="path"> |
|
||||
<el-input v-model="form.path" style="width: 40%" /> |
|
||||
<span style="color: #C0C0C0;margin-left: 10px;">输入views文件夹下的目录,不存在即创建</span> |
|
||||
</el-form-item> |
|
||||
<!-- <el-form-item label="接口目录">--> |
|
||||
<!-- <el-input v-model="form.apiPath" style="width: 40%" />--> |
|
||||
<!-- <span style="color: #C0C0C0;margin-left: 10px;">Api存放路径[src/api],为空则自动生成路径</span>--> |
|
||||
<!-- </el-form-item>--> |
|
||||
<el-form-item label="去表前缀" prop="prefix"> |
|
||||
<el-input v-model="form.prefix" placeholder="默认不去除表前缀" style="width: 40%" /> |
|
||||
<span style="color: #C0C0C0;margin-left: 10px;">默认不去除表前缀,可自定义</span> |
|
||||
</el-form-item> |
|
||||
<el-form-item label="是否覆盖" prop="cover"> |
|
||||
<el-radio-group v-model="form.cover" size="mini" style="width: 40%"> |
|
||||
<el-radio-button label="true">是</el-radio-button> |
|
||||
<el-radio-button label="false">否</el-radio-button> |
|
||||
</el-radio-group> |
|
||||
<span style="color: #C0C0C0;margin-left: 10px;">谨防误操作,请慎重选择</span> |
|
||||
</el-form-item> |
|
||||
</el-form> |
|
||||
</el-card> |
|
||||
</el-col> |
|
||||
</el-row> |
|
||||
</div> |
|
||||
</template> |
|
||||
|
|
||||
<script> |
|
||||
import crud from '@/mixins/crud' |
|
||||
import { update, get } from '@/api/generator/genConfig' |
|
||||
import { save, sync, generator } from '@/api/generator/generator' |
|
||||
import { getDicts } from '@/api/system/dict' |
|
||||
export default { |
|
||||
name: 'GeneratorConfig', |
|
||||
components: {}, |
|
||||
mixins: [crud], |
|
||||
data() { |
|
||||
return { |
|
||||
activeName: 'first', tableName: '', tableHeight: 550, columnLoading: false, configLoading: false, dicts: [], syncLoading: false, genLoading: false, |
|
||||
form: { id: null, tableName: '', author: '', pack: '', path: '', moduleName: '', cover: 'false', apiPath: '', prefix: '', apiAlias: null }, |
|
||||
rules: { |
|
||||
author: [ |
|
||||
{ required: true, message: '作者不能为空', trigger: 'blur' } |
|
||||
], |
|
||||
pack: [ |
|
||||
{ required: true, message: '包路径不能为空', trigger: 'blur' } |
|
||||
], |
|
||||
moduleName: [ |
|
||||
{ required: true, message: '包路径不能为空', trigger: 'blur' } |
|
||||
], |
|
||||
path: [ |
|
||||
{ required: true, message: '前端路径不能为空', trigger: 'blur' } |
|
||||
], |
|
||||
apiAlias: [ |
|
||||
{ required: true, message: '接口名称不能为空', trigger: 'blur' } |
|
||||
], |
|
||||
cover: [ |
|
||||
{ required: true, message: '不能为空', trigger: 'blur' } |
|
||||
] |
|
||||
} |
|
||||
} |
|
||||
}, |
|
||||
created() { |
|
||||
this.tableHeight = document.documentElement.clientHeight - 385 |
|
||||
this.tableName = this.$route.params.tableName |
|
||||
this.$nextTick(() => { |
|
||||
this.init() |
|
||||
get(this.tableName).then(data => { |
|
||||
this.form = data |
|
||||
this.form.cover = this.form.cover.toString() |
|
||||
}) |
|
||||
getDicts().then(data => { |
|
||||
this.dicts = data |
|
||||
}) |
|
||||
}) |
|
||||
}, |
|
||||
methods: { |
|
||||
beforeInit() { |
|
||||
this.url = 'api/generator/columns' |
|
||||
const tableName = this.tableName |
|
||||
this.params = { tableName } |
|
||||
return true |
|
||||
}, |
|
||||
saveColumnConfig() { |
|
||||
this.columnLoading = true |
|
||||
save(this.data).then(res => { |
|
||||
this.notify('保存成功', 'success') |
|
||||
this.columnLoading = false |
|
||||
}).catch(err => { |
|
||||
this.columnLoading = false |
|
||||
console.log(err.response.data.message) |
|
||||
}) |
|
||||
}, |
|
||||
doSubmit() { |
|
||||
this.$refs['form'].validate((valid) => { |
|
||||
if (valid) { |
|
||||
this.configLoading = true |
|
||||
update(this.form).then(res => { |
|
||||
this.notify('保存成功', 'success') |
|
||||
this.form = res |
|
||||
this.form.cover = this.form.cover.toString() |
|
||||
this.configLoading = false |
|
||||
}).catch(err => { |
|
||||
this.configLoading = false |
|
||||
console.log(err.response.data.message) |
|
||||
}) |
|
||||
} |
|
||||
}) |
|
||||
}, |
|
||||
sync() { |
|
||||
this.syncLoading = true |
|
||||
sync([this.tableName]).then(() => { |
|
||||
this.init() |
|
||||
this.notify('同步成功', 'success') |
|
||||
this.syncLoading = false |
|
||||
}).then(() => { |
|
||||
this.syncLoading = false |
|
||||
}) |
|
||||
}, |
|
||||
toGen() { |
|
||||
this.genLoading = true |
|
||||
save(this.data).then(res => { |
|
||||
this.notify('保存成功', 'success') |
|
||||
// 生成代码 |
|
||||
generator(this.tableName, 0).then(data => { |
|
||||
this.genLoading = false |
|
||||
this.notify('生成成功', 'success') |
|
||||
}).catch(err => { |
|
||||
this.genLoading = false |
|
||||
console.log(err.response.data.message) |
|
||||
}) |
|
||||
}).catch(err => { |
|
||||
this.genLoading = false |
|
||||
console.log(err.response.data.message) |
|
||||
}) |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
</script> |
|
||||
|
|
||||
<style rel="stylesheet/scss" lang="scss"> |
|
||||
.edit-input { |
|
||||
.el-input__inner { |
|
||||
border: 1px solid #e5e6e7; |
|
||||
} |
|
||||
} |
|
||||
</style> |
|
||||
|
|
||||
<style scoped> |
|
||||
::v-deep .input-with-select .el-input-group__prepend { |
|
||||
background-color: #fff; |
|
||||
} |
|
||||
</style> |
|
||||
@ -1,114 +0,0 @@ |
|||||
<template> |
|
||||
<div class="app-container"> |
|
||||
<!--工具栏--> |
|
||||
<div class="head-container"> |
|
||||
<div v-if="crud.props.searchToggle"> |
|
||||
<el-input v-model="query.name" clearable size="small" placeholder="请输入表名" style="width: 200px;" class="filter-item" @keyup.enter.native="crud.toQuery" /> |
|
||||
<rrOperation /> |
|
||||
</div> |
|
||||
<crudOperation> |
|
||||
<el-tooltip slot="right" class="item" effect="dark" content="数据库中表字段变动时使用该功能" placement="top-start"> |
|
||||
<el-button |
|
||||
class="filter-item" |
|
||||
size="mini" |
|
||||
type="success" |
|
||||
icon="el-icon-refresh" |
|
||||
:loading="syncLoading" |
|
||||
:disabled="crud.selections.length === 0" |
|
||||
@click="sync" |
|
||||
>同步</el-button> |
|
||||
</el-tooltip> |
|
||||
</crudOperation> |
|
||||
</div> |
|
||||
<!--表格渲染--> |
|
||||
<el-table ref="table" v-loading="crud.loading" :data="crud.data" style="width: 100%;" @selection-change="crud.selectionChangeHandler"> |
|
||||
<el-table-column type="selection" width="55" /> |
|
||||
<el-table-column :show-overflow-tooltip="true" prop="tableName" label="表名" /> |
|
||||
<el-table-column :show-overflow-tooltip="true" prop="engine" label="数据库引擎" /> |
|
||||
<el-table-column :show-overflow-tooltip="true" prop="coding" label="字符编码集" /> |
|
||||
<el-table-column :show-overflow-tooltip="true" prop="remark" label="备注" /> |
|
||||
<el-table-column prop="createTime" label="创建日期" /> |
|
||||
<el-table-column label="操作" width="160px" align="center" fixed="right"> |
|
||||
<template slot-scope="scope"> |
|
||||
<el-button size="mini" style="margin-right: 2px" type="text"> |
|
||||
<router-link :to="'/sys-tools/generator/preview/' + scope.row.tableName"> |
|
||||
预览 |
|
||||
</router-link> |
|
||||
</el-button> |
|
||||
<el-button size="mini" style="margin-left: -1px;margin-right: 2px" type="text" @click="toDownload(scope.row.tableName)">下载</el-button> |
|
||||
<el-button size="mini" style="margin-left: -1px;margin-right: 2px" type="text"> |
|
||||
<router-link :to="'/sys-tools/generator/config/' + scope.row.tableName"> |
|
||||
配置 |
|
||||
</router-link> |
|
||||
</el-button> |
|
||||
<el-button type="text" style="margin-left: -1px" size="mini" @click="toGen(scope.row.tableName)">生成</el-button> |
|
||||
</template> |
|
||||
</el-table-column> |
|
||||
</el-table> |
|
||||
<!--分页组件--> |
|
||||
<pagination /> |
|
||||
</div> |
|
||||
</template> |
|
||||
|
|
||||
<script> |
|
||||
|
|
||||
import { generator, sync } from '@/api/generator/generator' |
|
||||
import { downloadFile } from '@/utils/index' |
|
||||
import CRUD, { presenter, header } from '@crud/crud' |
|
||||
import rrOperation from '@crud/RR.operation' |
|
||||
import crudOperation from '@crud/CRUD.operation' |
|
||||
import pagination from '@crud/Pagination' |
|
||||
|
|
||||
export default { |
|
||||
name: 'GeneratorIndex', |
|
||||
components: { pagination, crudOperation, rrOperation }, |
|
||||
cruds() { |
|
||||
return CRUD({ url: 'api/generator/tables' }) |
|
||||
}, |
|
||||
mixins: [presenter(), header()], |
|
||||
data() { |
|
||||
return { |
|
||||
syncLoading: false |
|
||||
} |
|
||||
}, |
|
||||
created() { |
|
||||
this.crud.optShow = { add: false, edit: false, del: false, download: false } |
|
||||
}, |
|
||||
methods: { |
|
||||
toGen(tableName) { |
|
||||
// 生成代码 |
|
||||
generator(tableName, 0).then(data => { |
|
||||
this.$notify({ |
|
||||
title: '生成成功', |
|
||||
type: 'success', |
|
||||
duration: 2500 |
|
||||
}) |
|
||||
}) |
|
||||
}, |
|
||||
toDownload(tableName) { |
|
||||
// 打包下载 |
|
||||
generator(tableName, 2).then(data => { |
|
||||
downloadFile(data, tableName, 'zip') |
|
||||
}) |
|
||||
}, |
|
||||
sync() { |
|
||||
const tables = [] |
|
||||
this.crud.selections.forEach(val => { |
|
||||
tables.push(val.tableName) |
|
||||
}) |
|
||||
this.syncLoading = true |
|
||||
sync(tables).then(() => { |
|
||||
this.crud.refresh() |
|
||||
this.crud.notify('同步成功', CRUD.NOTIFICATION_TYPE.SUCCESS) |
|
||||
this.syncLoading = false |
|
||||
}).then(() => { |
|
||||
this.syncLoading = false |
|
||||
}) |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
</script> |
|
||||
|
|
||||
<style scoped> |
|
||||
|
|
||||
</style> |
|
||||
@ -1,30 +0,0 @@ |
|||||
<template> |
|
||||
<el-tabs v-model="activeName" type="card"> |
|
||||
<el-tab-pane v-for="item in data" :key="item.name" :lazy="true" :label="item.name" :name="item.name"> |
|
||||
<Java :value="item.content" :height="height" /> |
|
||||
</el-tab-pane> |
|
||||
</el-tabs> |
|
||||
</template> |
|
||||
|
|
||||
<script> |
|
||||
import Java from '@/components/JavaEdit/index' |
|
||||
import { generator } from '@/api/generator/generator' |
|
||||
export default { |
|
||||
name: 'Preview', |
|
||||
components: { Java }, |
|
||||
data() { |
|
||||
return { |
|
||||
data: null, height: '', activeName: 'Entity' |
|
||||
} |
|
||||
}, |
|
||||
created() { |
|
||||
this.height = document.documentElement.clientHeight - 180 + 'px' |
|
||||
const tableName = this.$route.params.tableName |
|
||||
generator(tableName, 1).then(data => { |
|
||||
this.data = data |
|
||||
}).catch(() => { |
|
||||
this.$router.go(-1) |
|
||||
}) |
|
||||
} |
|
||||
} |
|
||||
</script> |
|
||||
@ -1,144 +0,0 @@ |
|||||
<template> |
|
||||
<div class="app-container"> |
|
||||
<!--工具栏--> |
|
||||
<div class="head-container"> |
|
||||
<div v-if="crud.props.searchToggle"> |
|
||||
<!-- 搜索 --> |
|
||||
<el-input v-model="query.name" clearable placeholder="输入名称搜索" style="width: 200px" class="filter-item" @keyup.enter.native="crud.toQuery" /> |
|
||||
<date-range-picker v-model="query.createTime" class="date-item" /> |
|
||||
<rrOperation /> |
|
||||
</div> |
|
||||
<crudOperation :permission="permission"> |
|
||||
<el-button |
|
||||
slot="left" |
|
||||
v-permission="['admin','app:add']" |
|
||||
:disabled="!currentRow" |
|
||||
class="filter-item" |
|
||||
size="mini" |
|
||||
type="primary" |
|
||||
icon="el-icon-plus" |
|
||||
@click="copy" |
|
||||
>复制</el-button> |
|
||||
</crudOperation> |
|
||||
</div> |
|
||||
<!--表单组件--> |
|
||||
<el-dialog append-to-body :close-on-click-modal="false" :before-close="crud.cancelCU" :visible.sync="crud.status.cu > 0" :title="crud.status.title" width="800px"> |
|
||||
<el-form ref="form" :model="form" :rules="rules" size="small" label-width="100px"> |
|
||||
<el-form-item label="应用名称" prop="name"> |
|
||||
<el-input v-model="form.name" style="width: 670px" placeholder="部署后的文件或者目录名称,用于备份" /> |
|
||||
</el-form-item> |
|
||||
<el-form-item label="应用端口" prop="port"> |
|
||||
<el-input-number v-model.number="form.port" placeholder="例如:8080" /> |
|
||||
</el-form-item> |
|
||||
<el-form-item label="上传目录" prop="uploadPath"> |
|
||||
<el-input v-model="form.uploadPath" style="width: 670px" placeholder="例如: /opt/upload" /> |
|
||||
</el-form-item> |
|
||||
<el-form-item label="部署目录" prop="deployPath"> |
|
||||
<el-input v-model="form.deployPath" style="width: 670px" placeholder="例如: /opt/app" /> |
|
||||
</el-form-item> |
|
||||
<el-form-item label="备份目录" prop="backupPath"> |
|
||||
<el-input v-model="form.backupPath" style="width: 670px" placeholder="例如: /opt/backup" /> |
|
||||
</el-form-item> |
|
||||
<el-form-item label="部署脚本" prop="deployScript"> |
|
||||
<el-input v-model="form.deployScript" :rows="3" type="textarea" autosize style="width: 670px" placeholder="" /> |
|
||||
</el-form-item> |
|
||||
<el-form-item label="启动脚本" prop="startScript"> |
|
||||
<el-input v-model="form.startScript" :rows="3" type="textarea" autosize style="width: 670px" placeholder="" /> |
|
||||
</el-form-item> |
|
||||
</el-form> |
|
||||
<div slot="footer" class="dialog-footer"> |
|
||||
<el-button type="text" @click="crud.cancelCU">取消</el-button> |
|
||||
<el-button :loading="crud.status.cu === 2" type="primary" @click="crud.submitCU">确认</el-button> |
|
||||
</div> |
|
||||
</el-dialog> |
|
||||
<!--表格渲染--> |
|
||||
<el-table ref="table" v-loading="crud.loading" :data="crud.data" highlight-current-row style="width: 100%" @selection-change="crud.selectionChangeHandler" @current-change="handleCurrentChange"> |
|
||||
<el-table-column type="selection" width="55" /> |
|
||||
<el-table-column prop="name" label="应用名称" /> |
|
||||
<el-table-column prop="port" label="端口号" /> |
|
||||
<el-table-column prop="uploadPath" label="上传目录" /> |
|
||||
<el-table-column prop="deployPath" label="部署目录" /> |
|
||||
<el-table-column prop="backupPath" label="备份目录" /> |
|
||||
<el-table-column prop="createTime" label="创建日期" /> |
|
||||
<el-table-column v-if="checkPer(['admin','app:edit','app:del'])" label="操作" width="150px" align="center"> |
|
||||
<template slot-scope="scope"> |
|
||||
<udOperation |
|
||||
:data="scope.row" |
|
||||
:permission="permission" |
|
||||
/> |
|
||||
</template> |
|
||||
</el-table-column> |
|
||||
</el-table> |
|
||||
<!--分页组件--> |
|
||||
<pagination /> |
|
||||
</div> |
|
||||
</template> |
|
||||
|
|
||||
<script> |
|
||||
import crudApp from '@/api/mnt/app' |
|
||||
import CRUD, { presenter, header, form, crud } from '@crud/crud' |
|
||||
import rrOperation from '@crud/RR.operation' |
|
||||
import crudOperation from '@crud/CRUD.operation' |
|
||||
import udOperation from '@crud/UD.operation' |
|
||||
import pagination from '@crud/Pagination' |
|
||||
import DateRangePicker from '@/components/DateRangePicker' |
|
||||
|
|
||||
const defaultForm = { id: null, name: null, port: 8080, uploadPath: '/opt/upload', deployPath: '/opt/app', backupPath: '/opt/backup', startScript: null, deployScript: null } |
|
||||
export default { |
|
||||
name: 'App', |
|
||||
components: { pagination, crudOperation, rrOperation, udOperation, DateRangePicker }, |
|
||||
cruds() { |
|
||||
return CRUD({ title: '应用', url: 'api/app', crudMethod: { ...crudApp }}) |
|
||||
}, |
|
||||
mixins: [presenter(), header(), form(defaultForm), crud()], |
|
||||
data() { |
|
||||
return { |
|
||||
currentRow: null, |
|
||||
permission: { |
|
||||
add: ['admin', 'app:add'], |
|
||||
edit: ['admin', 'app:edit'], |
|
||||
del: ['admin', 'app:del'] |
|
||||
}, |
|
||||
rules: { |
|
||||
name: [ |
|
||||
{ required: true, message: '请输入应用名称', trigger: 'blur' } |
|
||||
], |
|
||||
port: [ |
|
||||
{ required: true, message: '请输入应用端口', trigger: 'blur', type: 'number' } |
|
||||
], |
|
||||
uploadPath: [ |
|
||||
{ required: true, message: '请输入上传目录', trigger: 'blur' } |
|
||||
], |
|
||||
deployPath: [ |
|
||||
{ required: true, message: '请输入部署目录', trigger: 'blur' } |
|
||||
], |
|
||||
backupPath: [ |
|
||||
{ required: true, message: '请输入备份目录', trigger: 'blur' } |
|
||||
], |
|
||||
startScript: [ |
|
||||
{ required: true, message: '请输入启动脚本', trigger: 'blur' } |
|
||||
], |
|
||||
deployScript: [ |
|
||||
{ required: true, message: '请输入部署脚本', trigger: 'blur' } |
|
||||
] |
|
||||
} |
|
||||
} |
|
||||
}, |
|
||||
methods: { |
|
||||
copy() { |
|
||||
for (const key in this.currentRow) { |
|
||||
this.form[key] = this.currentRow[key] |
|
||||
} |
|
||||
this.form.id = null |
|
||||
this.form.createTime = null |
|
||||
this.crud.toAdd() |
|
||||
}, |
|
||||
handleCurrentChange(row) { |
|
||||
this.currentRow = JSON.parse(JSON.stringify(row)) |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
</script> |
|
||||
|
|
||||
<style scoped> |
|
||||
</style> |
|
||||
@ -1,86 +0,0 @@ |
|||||
<template> |
|
||||
<el-dialog append-to-body :close-on-click-modal="false" :visible.sync="dialog" title="执行脚本" width="400px"> |
|
||||
<el-form ref="form" :rules="rules" size="small"> |
|
||||
<el-upload |
|
||||
:action="databaseUploadApi" |
|
||||
:data="databaseInfo" |
|
||||
:headers="headers" |
|
||||
:on-success="handleSuccess" |
|
||||
:on-error="handleError" |
|
||||
class="upload-demo" |
|
||||
drag |
|
||||
> |
|
||||
<i class="el-icon-upload"></i> |
|
||||
<div class="el-upload__text"> |
|
||||
将文件拖到此处,或 |
|
||||
<em>点击上传</em> |
|
||||
</div> |
|
||||
<div slot="tip" class="el-upload__tip">上传后,系统会自动执行SQL脚本</div> |
|
||||
</el-upload> |
|
||||
</el-form> |
|
||||
<div slot="footer" class="dialog-footer"> |
|
||||
<el-button type="primary" @click="cancel">关闭</el-button> |
|
||||
</div> |
|
||||
</el-dialog> |
|
||||
</template> |
|
||||
|
|
||||
<script> |
|
||||
import { mapGetters } from 'vuex' |
|
||||
import { getToken } from '@/utils/auth' |
|
||||
export default { |
|
||||
props: { |
|
||||
databaseInfo: { |
|
||||
type: Object, |
|
||||
default() { |
|
||||
return {} |
|
||||
} |
|
||||
} |
|
||||
}, |
|
||||
data() { |
|
||||
return { |
|
||||
loading: false, |
|
||||
dialog: false, |
|
||||
headers: { |
|
||||
Authorization: getToken() |
|
||||
}, |
|
||||
rules: {} |
|
||||
} |
|
||||
}, |
|
||||
computed: { |
|
||||
...mapGetters(['databaseUploadApi']) |
|
||||
}, |
|
||||
mounted() { |
|
||||
}, |
|
||||
methods: { |
|
||||
cancel() { |
|
||||
this.dialog = false |
|
||||
}, |
|
||||
handleSuccess(response, file, fileList) { |
|
||||
if (response === 'success') { |
|
||||
this.$notify({ |
|
||||
title: '执行成功', |
|
||||
type: 'success', |
|
||||
duration: 2500 |
|
||||
}) |
|
||||
} else { |
|
||||
this.$notify({ |
|
||||
title: response, |
|
||||
type: 'error', |
|
||||
duration: 0 |
|
||||
}) |
|
||||
} |
|
||||
}, |
|
||||
handleError(e, file, fileList) { |
|
||||
const msg = JSON.parse(e.message) |
|
||||
this.$notify({ |
|
||||
title: msg.message, |
|
||||
type: 'error', |
|
||||
duration: 0 |
|
||||
}) |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
</script> |
|
||||
|
|
||||
<style scoped> |
|
||||
</style> |
|
||||
@ -1,148 +0,0 @@ |
|||||
<template> |
|
||||
<div class="app-container"> |
|
||||
<!--工具栏--> |
|
||||
<div class="head-container"> |
|
||||
<div v-if="crud.props.searchToggle"> |
|
||||
<!-- 搜索 --> |
|
||||
<el-input v-model="query.blurry" clearable placeholder="模糊搜索" style="width: 200px" class="filter-item" @keyup.enter.native="crud.toQuery" /> |
|
||||
<date-range-picker v-model="query.createTime" class="date-item" /> |
|
||||
<rrOperation /> |
|
||||
</div> |
|
||||
<crudOperation :permission="permission"> |
|
||||
<el-button |
|
||||
slot="right" |
|
||||
v-permission="['admin','database:add']" |
|
||||
:disabled="!selectIndex" |
|
||||
class="filter-item" |
|
||||
size="mini" |
|
||||
type="warning" |
|
||||
icon="el-icon-upload" |
|
||||
@click="execute" |
|
||||
>执行脚本 |
|
||||
</el-button> |
|
||||
</crudOperation> |
|
||||
</div> |
|
||||
<!--表单组件--> |
|
||||
<eForm ref="execute" :database-info="currentRow" /> |
|
||||
<el-dialog append-to-body :close-on-click-modal="false" :before-close="crud.cancelCU" :visible.sync="crud.status.cu > 0" :title="crud.status.title" width="530px"> |
|
||||
<el-form ref="form" :model="form" :rules="rules" size="small" label-width="100px"> |
|
||||
<el-form-item label="连接名称" prop="name"> |
|
||||
<el-input v-model="form.name" style="width: 370px" /> |
|
||||
</el-form-item> |
|
||||
<el-form-item label="JDBC地址" prop="jdbcUrl"> |
|
||||
<el-input v-model="form.jdbcUrl" style="width: 300px" /> |
|
||||
<el-button :loading="loading" type="success" @click="testConnectDatabase">测试</el-button> |
|
||||
</el-form-item> |
|
||||
<el-form-item label="用户" prop="userName"> |
|
||||
<el-input v-model="form.userName" style="width: 370px" /> |
|
||||
</el-form-item> |
|
||||
<el-form-item label="密码" prop="pwd"> |
|
||||
<el-input v-model="form.pwd" type="password" style="width: 370px" /> |
|
||||
</el-form-item> |
|
||||
</el-form> |
|
||||
<div slot="footer" class="dialog-footer"> |
|
||||
<el-button type="text" @click="crud.cancelCU">取消</el-button> |
|
||||
<el-button :loading="crud.status.cu === 2" type="primary" @click="crud.submitCU">确认</el-button> |
|
||||
</div> |
|
||||
</el-dialog> |
|
||||
<!--表格渲染--> |
|
||||
<el-table ref="table" v-loading="crud.loading" :data="crud.data" highlight-current-row stripe style="width: 100%" @selection-change="handleCurrentChange"> |
|
||||
<el-table-column type="selection" width="55" /> |
|
||||
<el-table-column prop="name" width="130px" label="数据库名称" /> |
|
||||
<el-table-column prop="jdbcUrl" label="连接地址" /> |
|
||||
<el-table-column prop="userName" width="200px" label="用户名" /> |
|
||||
<el-table-column prop="createTime" width="200px" label="创建日期" /> |
|
||||
<el-table-column v-if="checkPer(['admin','database:edit','database:del'])" label="操作" width="150px" align="center"> |
|
||||
<template slot-scope="scope"> |
|
||||
<udOperation |
|
||||
:data="scope.row" |
|
||||
:permission="permission" |
|
||||
/> |
|
||||
</template> |
|
||||
</el-table-column> |
|
||||
</el-table> |
|
||||
<!--分页组件--> |
|
||||
<pagination /> |
|
||||
</div> |
|
||||
</template> |
|
||||
|
|
||||
<script> |
|
||||
import crudDatabase from '@/api/mnt/database' |
|
||||
import { testDbConnect } from '@/api/mnt/connect' |
|
||||
import eForm from './execute' |
|
||||
import CRUD, { presenter, header, form, crud } from '@crud/crud' |
|
||||
import rrOperation from '@crud/RR.operation' |
|
||||
import crudOperation from '@crud/CRUD.operation' |
|
||||
import udOperation from '@crud/UD.operation' |
|
||||
import pagination from '@crud/Pagination' |
|
||||
import DateRangePicker from '@/components/DateRangePicker' |
|
||||
|
|
||||
const defaultForm = { id: null, name: null, jdbcUrl: 'jdbc:mysql://', userName: null, pwd: null } |
|
||||
export default { |
|
||||
name: 'DataBase', |
|
||||
components: { eForm, pagination, crudOperation, rrOperation, udOperation, DateRangePicker }, |
|
||||
cruds() { |
|
||||
return CRUD({ title: '数据库', url: 'api/database', crudMethod: { ...crudDatabase }}) |
|
||||
}, |
|
||||
mixins: [presenter(), header(), form(defaultForm), crud()], |
|
||||
data() { |
|
||||
return { |
|
||||
currentRow: {}, |
|
||||
selectIndex: '', |
|
||||
databaseInfo: '', |
|
||||
loading: false, |
|
||||
permission: { |
|
||||
add: ['admin', 'database:add'], |
|
||||
edit: ['admin', 'database:edit'], |
|
||||
del: ['admin', 'database:del'] |
|
||||
}, |
|
||||
rules: { |
|
||||
name: [ |
|
||||
{ required: true, message: '请输入数据库名称', trigger: 'blur' } |
|
||||
], |
|
||||
jdbcUrl: [ |
|
||||
{ required: true, message: '请输入数据库连接地址', trigger: 'blur' } |
|
||||
], |
|
||||
userName: [ |
|
||||
{ required: true, message: '请输入用户名', trigger: 'blur' } |
|
||||
], |
|
||||
pwd: [ |
|
||||
{ required: true, message: '请输入数据库密码', trigger: 'blur' } |
|
||||
] |
|
||||
} |
|
||||
} |
|
||||
}, |
|
||||
methods: { |
|
||||
testConnectDatabase() { |
|
||||
this.$refs['form'].validate((valid) => { |
|
||||
if (valid) { |
|
||||
this.loading = true |
|
||||
testDbConnect(this.form).then((res) => { |
|
||||
this.loading = false |
|
||||
this.crud.notify(res ? '连接成功' : '连接失败', res ? 'success' : 'error') |
|
||||
}).catch(() => { |
|
||||
this.loading = false |
|
||||
}) |
|
||||
} |
|
||||
}) |
|
||||
}, |
|
||||
execute() { |
|
||||
this.$refs.execute.dialog = true |
|
||||
}, |
|
||||
handleCurrentChange(selection) { |
|
||||
this.crud.selections = selection |
|
||||
if (selection.length === 1) { |
|
||||
const row = selection[0] |
|
||||
this.selectIndex = row.id |
|
||||
this.currentRow = row |
|
||||
} else { |
|
||||
this.currentRow = {} |
|
||||
this.selectIndex = '' |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
</script> |
|
||||
|
|
||||
<style scoped> |
|
||||
</style> |
|
||||
@ -1,190 +0,0 @@ |
|||||
<template> |
|
||||
<el-dialog append-to-body :close-on-click-modal="false" :visible.sync="dialog" title="应用部署" width="400px"> |
|
||||
<el-form ref="form" :model="form" :rules="rules" size="small"> |
|
||||
<el-upload |
|
||||
:action="deployUploadApi" |
|
||||
:data="deployInfo" |
|
||||
:headers="headers" |
|
||||
:on-success="handleSuccess" |
|
||||
:on-error="handleError" |
|
||||
class="upload-demo" |
|
||||
drag |
|
||||
> |
|
||||
<i class="el-icon-upload"></i> |
|
||||
<div class="el-upload__text"> |
|
||||
将文件拖到此处,或 |
|
||||
<em>点击上传</em> |
|
||||
</div> |
|
||||
<div slot="tip" class="el-upload__tip">多个应用上传文件名称为all.zip,数据库更新脚本扩展名为.sql,上传成功后系统自动部署系统。</div> |
|
||||
</el-upload> |
|
||||
</el-form> |
|
||||
<div slot="footer" class="dialog-footer"> |
|
||||
<el-button type="primary" @click="cancel">关闭</el-button> |
|
||||
</div> |
|
||||
</el-dialog> |
|
||||
</template> |
|
||||
|
|
||||
<script> |
|
||||
import { add, edit, getApps, getServers } from '@/api/mnt/deploy' |
|
||||
import { mapGetters } from 'vuex' |
|
||||
import { getToken } from '@/utils/auth' |
|
||||
|
|
||||
export default { |
|
||||
props: {}, |
|
||||
data() { |
|
||||
return { |
|
||||
loading: false, |
|
||||
dialog: false, |
|
||||
apps: [], |
|
||||
servers: [], |
|
||||
headers: { |
|
||||
Authorization: getToken() |
|
||||
}, |
|
||||
deployInfo: {}, |
|
||||
form: { |
|
||||
id: '', |
|
||||
appId: '', |
|
||||
ip: '', |
|
||||
selectIp: [] |
|
||||
}, |
|
||||
rules: {} |
|
||||
} |
|
||||
}, |
|
||||
computed: { |
|
||||
...mapGetters(['deployUploadApi']) |
|
||||
}, |
|
||||
created() { |
|
||||
this.initWebSocket() |
|
||||
}, |
|
||||
mounted() { |
|
||||
this.initSelect() |
|
||||
}, |
|
||||
methods: { |
|
||||
cancel() { |
|
||||
this.resetForm() |
|
||||
}, |
|
||||
doSubmit() { |
|
||||
this.loading = true |
|
||||
if (this.isAdd) { |
|
||||
this.doAdd() |
|
||||
} else { |
|
||||
this.doEdit() |
|
||||
} |
|
||||
}, |
|
||||
joinIp() { |
|
||||
this.form.ip = '' |
|
||||
this.form.selectIp.forEach(ip => { |
|
||||
if (this.form.ip !== '') { |
|
||||
this.form.ip += ',' |
|
||||
} |
|
||||
this.form.ip += ip |
|
||||
}) |
|
||||
}, |
|
||||
doAdd() { |
|
||||
this.joinIp() |
|
||||
add(this.form) |
|
||||
.then(res => { |
|
||||
this.resetForm() |
|
||||
this.$notify({ |
|
||||
title: '添加成功', |
|
||||
type: 'success', |
|
||||
duration: 2500 |
|
||||
}) |
|
||||
this.loading = false |
|
||||
this.$parent.init() |
|
||||
}) |
|
||||
.catch(err => { |
|
||||
this.loading = false |
|
||||
console.log(err.response.data.message) |
|
||||
}) |
|
||||
}, |
|
||||
doEdit() { |
|
||||
this.joinIp() |
|
||||
edit(this.form) |
|
||||
.then(res => { |
|
||||
this.resetForm() |
|
||||
this.$notify({ |
|
||||
title: '修改成功', |
|
||||
type: 'success', |
|
||||
duration: 2500 |
|
||||
}) |
|
||||
this.loading = false |
|
||||
this.$parent.init() |
|
||||
}) |
|
||||
.catch(err => { |
|
||||
this.loading = false |
|
||||
console.log(err.response.data.message) |
|
||||
}) |
|
||||
}, |
|
||||
resetForm() { |
|
||||
this.dialog = false |
|
||||
this.$refs['form'].resetFields() |
|
||||
this.form = { |
|
||||
id: '', |
|
||||
appId: '', |
|
||||
ip: '', |
|
||||
selectIp: [] |
|
||||
} |
|
||||
}, |
|
||||
initSelect() { |
|
||||
getApps().then(res => { |
|
||||
this.apps = res.content |
|
||||
}) |
|
||||
getServers().then(res => { |
|
||||
this.servers = res.content |
|
||||
}) |
|
||||
}, |
|
||||
handleSuccess(response, file, fileList) { |
|
||||
this.cancel() |
|
||||
}, |
|
||||
// 监听上传失败 |
|
||||
handleError(e, file, fileList) { |
|
||||
const msg = JSON.parse(e.message) |
|
||||
this.$notify({ |
|
||||
title: msg.message, |
|
||||
type: 'error', |
|
||||
duration: 2500 |
|
||||
}) |
|
||||
}, |
|
||||
initWebSocket() { |
|
||||
const wsUri = process.env.VUE_APP_WS_API + '/webSocket/deploy' |
|
||||
this.websock = new WebSocket(wsUri) |
|
||||
this.websock.onerror = this.webSocketOnError |
|
||||
this.websock.onmessage = this.webSocketOnMessage |
|
||||
}, |
|
||||
webSocketOnError(e) { |
|
||||
this.$notify({ |
|
||||
title: 'WebSocket连接发生错误', |
|
||||
type: 'error', |
|
||||
duration: 0 |
|
||||
}) |
|
||||
}, |
|
||||
webSocketOnMessage(e) { |
|
||||
const data = JSON.parse(e.data) |
|
||||
if (data.msgType === 'INFO') { |
|
||||
this.$notify({ |
|
||||
title: '', |
|
||||
message: data.msg, |
|
||||
type: 'success', |
|
||||
dangerouslyUseHTMLString: true, |
|
||||
duration: 5500 |
|
||||
}) |
|
||||
} else if (data.msgType === 'ERROR') { |
|
||||
this.$notify({ |
|
||||
title: '', |
|
||||
message: data.msg, |
|
||||
dangerouslyUseHTMLString: true, |
|
||||
type: 'error', |
|
||||
duration: 0 |
|
||||
}) |
|
||||
} |
|
||||
}, |
|
||||
webSocketSend(agentData) { |
|
||||
this.websock.send(agentData) |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
</script> |
|
||||
|
|
||||
<style scoped> |
|
||||
</style> |
|
||||
@ -1,229 +0,0 @@ |
|||||
<template> |
|
||||
<div class="app-container"> |
|
||||
<!--工具栏--> |
|
||||
<div class="head-container"> |
|
||||
<div v-if="crud.props.searchToggle"> |
|
||||
<!-- 搜索 --> |
|
||||
<el-input v-model="query.appName" clearable placeholder="输入应用名称查询" style="width: 200px" class="filter-item" @keyup.enter.native="crud.toQuery" /> |
|
||||
<date-range-picker v-model="query.createTime" class="date-item" /> |
|
||||
<rrOperation /> |
|
||||
</div> |
|
||||
<crudOperation :permission="permission"> |
|
||||
<template slot="right"> |
|
||||
<el-button |
|
||||
v-permission="['admin','deploy:add']" |
|
||||
:disabled="!selectIndex" |
|
||||
class="filter-item" |
|
||||
size="mini" |
|
||||
type="primary" |
|
||||
icon="el-icon-upload" |
|
||||
@click="sysRestore" |
|
||||
>系统还原 |
|
||||
</el-button> |
|
||||
<el-button |
|
||||
v-permission="['admin','deploy:add']" |
|
||||
:disabled="!selectIndex" |
|
||||
class="filter-item" |
|
||||
size="mini" |
|
||||
type="primary" |
|
||||
icon="el-icon-upload" |
|
||||
@click="serverStatus" |
|
||||
>状态查询 |
|
||||
</el-button> |
|
||||
<el-button |
|
||||
v-permission="['admin','deploy:add']" |
|
||||
:disabled="!selectIndex" |
|
||||
class="filter-item" |
|
||||
size="mini" |
|
||||
type="success" |
|
||||
icon="el-icon-upload" |
|
||||
@click="startServer" |
|
||||
>启动 |
|
||||
</el-button> |
|
||||
<el-button |
|
||||
v-permission="['admin','deploy:add']" |
|
||||
:disabled="!selectIndex" |
|
||||
class="filter-item" |
|
||||
size="mini" |
|
||||
type="danger" |
|
||||
icon="el-icon-upload" |
|
||||
@click="stopServer" |
|
||||
>停止 |
|
||||
</el-button> |
|
||||
<el-button |
|
||||
v-permission="['admin','deploy:add']" |
|
||||
:disabled="!selectIndex" |
|
||||
class="filter-item" |
|
||||
size="mini" |
|
||||
type="warning" |
|
||||
icon="el-icon-upload" |
|
||||
@click="deploy" |
|
||||
>一键部署 |
|
||||
</el-button> |
|
||||
</template> |
|
||||
</crudOperation> |
|
||||
</div> |
|
||||
<!--表单组件--> |
|
||||
<el-dialog append-to-body :close-on-click-modal="false" :before-close="crud.cancelCU" :visible.sync="crud.status.cu > 0" :title="crud.status.title" width="500px"> |
|
||||
<el-form ref="form" :model="form" :rules="rules" size="small" label-width="80px"> |
|
||||
<el-form-item label="应用" prop="app.id"> |
|
||||
<el-select v-model.number="form.app.id" placeholder="请选择" style="width: 370px"> |
|
||||
<el-option v-for="item in apps" :key="item.id" :label="item.name" :value="item.id" /> |
|
||||
</el-select> |
|
||||
</el-form-item> |
|
||||
<el-form-item label="服务器" prop="deploys"> |
|
||||
<el-select v-model="form.deploys" multiple placeholder="请选择" style="width: 370px"> |
|
||||
<el-option v-for="item in servers" :key="item.id" :label="item.name" :value="item.id" /> |
|
||||
</el-select> |
|
||||
</el-form-item> |
|
||||
</el-form> |
|
||||
<div slot="footer" class="dialog-footer"> |
|
||||
<el-button type="text" @click="crud.cancelCU">取消</el-button> |
|
||||
<el-button :loading="crud.status.cu === 2" type="primary" @click="crud.submitCU">确认</el-button> |
|
||||
</div> |
|
||||
</el-dialog> |
|
||||
<!--统还原组件--> |
|
||||
<fForm ref="sysRestore" :key="times" :app-name="appName" /> |
|
||||
<dForm ref="deploy" /> |
|
||||
<!--表格渲染--> |
|
||||
<el-table ref="table" v-loading="crud.loading" :data="crud.data" highlight-current-row stripe style="width: 100%" @selection-change="handleCurrentChange"> |
|
||||
<el-table-column type="selection" width="55" /> |
|
||||
<el-table-column prop="app.name" label="应用名称" /> |
|
||||
<el-table-column prop="servers" label="服务器列表" /> |
|
||||
<el-table-column prop="createTime" label="部署日期" /> |
|
||||
<el-table-column v-if="checkPer(['admin','deploy:edit','deploy:del'])" label="操作" width="150px" align="center"> |
|
||||
<template slot-scope="scope"> |
|
||||
<udOperation |
|
||||
:data="scope.row" |
|
||||
:permission="permission" |
|
||||
/> |
|
||||
</template> |
|
||||
</el-table-column> |
|
||||
</el-table> |
|
||||
<!--分页组件--> |
|
||||
<pagination /> |
|
||||
</div> |
|
||||
</template> |
|
||||
|
|
||||
<script> |
|
||||
import crudDeploy from '@/api/mnt/deploy' |
|
||||
import dForm from './deploy' |
|
||||
import fForm from './sysRestore' |
|
||||
import CRUD, { presenter, header, form, crud } from '@crud/crud' |
|
||||
import rrOperation from '@crud/RR.operation' |
|
||||
import crudOperation from '@crud/CRUD.operation' |
|
||||
import udOperation from '@crud/UD.operation' |
|
||||
import pagination from '@crud/Pagination' |
|
||||
import DateRangePicker from '@/components/DateRangePicker' |
|
||||
|
|
||||
const defaultForm = { id: null, app: { id: null }, deploys: [] } |
|
||||
export default { |
|
||||
name: 'Deploy', |
|
||||
components: { dForm, fForm, pagination, crudOperation, rrOperation, udOperation, DateRangePicker }, |
|
||||
cruds() { |
|
||||
return CRUD({ title: '部署', url: 'api/deploy', crudMethod: { ...crudDeploy }}) |
|
||||
}, |
|
||||
mixins: [presenter(), header(), form(defaultForm), crud()], |
|
||||
data() { |
|
||||
return { |
|
||||
currentRow: {}, selectIndex: '', appName: '', urlHistory: '', |
|
||||
times: 0, appId: '', deployId: '', apps: [], servers: [], |
|
||||
permission: { |
|
||||
add: ['admin', 'deploy:add'], |
|
||||
edit: ['admin', 'deploy:edit'], |
|
||||
del: ['admin', 'deploy:del'] |
|
||||
}, |
|
||||
rules: { |
|
||||
'app.id': [ |
|
||||
{ required: true, message: '应用不能为空', trigger: 'blur', type: 'number' } |
|
||||
], |
|
||||
deploys: [ |
|
||||
{ required: true, message: '服务器不能为空', trigger: 'blur' } |
|
||||
] |
|
||||
} |
|
||||
} |
|
||||
}, |
|
||||
methods: { |
|
||||
[CRUD.HOOK.beforeRefresh]() { |
|
||||
this.selectIndex = '' |
|
||||
return true |
|
||||
}, |
|
||||
// 新增编辑前做的操作 |
|
||||
[CRUD.HOOK.beforeToCU](crud, form) { |
|
||||
this.initSelect() |
|
||||
const deploys = [] |
|
||||
form.deploys.forEach(function(deploy, index) { |
|
||||
deploys.push(deploy.id) |
|
||||
}) |
|
||||
this.form.deploys = deploys |
|
||||
}, |
|
||||
// 提交前 |
|
||||
[CRUD.HOOK.beforeSubmit]() { |
|
||||
const deploys = [] |
|
||||
this.form.deploys.forEach(function(data, index) { |
|
||||
const deploy = { id: data } |
|
||||
deploys.push(deploy) |
|
||||
}) |
|
||||
this.form.deploys = deploys |
|
||||
return true |
|
||||
}, |
|
||||
deploy() { |
|
||||
this.$refs.deploy.dialog = true |
|
||||
this.$refs.deploy.deployInfo = this.currentRow |
|
||||
}, |
|
||||
sysRestore() { |
|
||||
this.$refs.sysRestore.dialog = true |
|
||||
}, |
|
||||
handleCurrentChange(selection) { |
|
||||
this.crud.selections = selection |
|
||||
if (selection.length === 1) { |
|
||||
const row = selection[0] |
|
||||
this.selectIndex = row.id |
|
||||
this.currentRow = row |
|
||||
this.appName = row.app.name |
|
||||
this.times = this.times + 1 |
|
||||
this.appId = row.appId |
|
||||
this.deployId = row.id |
|
||||
} else { |
|
||||
this.currentRow = {} |
|
||||
this.selectIndex = '' |
|
||||
} |
|
||||
}, |
|
||||
startServer() { |
|
||||
crudDeploy.startServer(JSON.stringify(this.currentRow)) |
|
||||
.then(res => { |
|
||||
}) |
|
||||
.catch(err => { |
|
||||
console.log('error:' + err.response.data.message) |
|
||||
}) |
|
||||
}, |
|
||||
stopServer() { |
|
||||
crudDeploy.stopServer(JSON.stringify(this.currentRow)) |
|
||||
.then(res => { |
|
||||
}) |
|
||||
.catch(err => { |
|
||||
console.log('error:' + err.response.data.message) |
|
||||
}) |
|
||||
}, |
|
||||
serverStatus() { |
|
||||
crudDeploy.serverStatus(JSON.stringify(this.currentRow)) |
|
||||
.then(res => { |
|
||||
}) |
|
||||
.catch(err => { |
|
||||
console.log('error:' + err.response.data.message) |
|
||||
}) |
|
||||
}, |
|
||||
initSelect() { |
|
||||
crudDeploy.getApps().then(res => { |
|
||||
this.apps = res.content |
|
||||
}) |
|
||||
crudDeploy.getServers().then(res => { |
|
||||
this.servers = res.content |
|
||||
}) |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
</script> |
|
||||
|
|
||||
<style scoped> |
|
||||
</style> |
|
||||
@ -1,108 +0,0 @@ |
|||||
<template> |
|
||||
<el-dialog append-to-body :close-on-click-modal="false" :visible.sync="dialog" title="系统还原" width="800px"> |
|
||||
<!--工具栏--> |
|
||||
<div class="head-container"> |
|
||||
<date-range-picker v-model="query.createTime" class="date-item" /> |
|
||||
<el-button class="filter-item" size="mini" type="success" icon="el-icon-search" @click="toQuery">搜索</el-button> |
|
||||
</div> |
|
||||
<el-form size="small" label-width="80px"> |
|
||||
<!--表格渲染--> |
|
||||
<el-table v-loading="loading" :data="data" style="width: 100%" @row-click="showRow"> |
|
||||
<el-table-column width="30px"> |
|
||||
<template slot-scope="scope"> |
|
||||
<el-radio v-model="radio" :label="scope.$index" /> |
|
||||
</template> |
|
||||
</el-table-column> |
|
||||
<el-table-column prop="appName" label="应用名称" /> |
|
||||
<el-table-column prop="ip" label="部署IP" /> |
|
||||
<el-table-column prop="deployDate" label="部署时间" /> |
|
||||
<el-table-column prop="deployUser" label="部署人员" /> |
|
||||
</el-table> |
|
||||
</el-form> |
|
||||
<div slot="footer" class="dialog-footer"> |
|
||||
<el-button type="text" @click="cancel">取消</el-button> |
|
||||
<el-button v-permission="['admin','deploy:add']" :loading="submitLoading" type="primary" @click="doSubmit">确认</el-button> |
|
||||
</div> |
|
||||
<!--分页组件--> |
|
||||
<el-pagination |
|
||||
:total="total" |
|
||||
:current-page="page + 1" |
|
||||
style="margin-top: 8px" |
|
||||
layout="total, prev, pager, next, sizes" |
|
||||
@size-change="sizeChange" |
|
||||
@current-change="pageChange" |
|
||||
/> |
|
||||
</el-dialog> |
|
||||
</template> |
|
||||
|
|
||||
<script> |
|
||||
import crud from '@/mixins/crud' |
|
||||
import { reducte } from '@/api/mnt/deployHistory' |
|
||||
import DateRangePicker from '@/components/DateRangePicker' |
|
||||
export default { |
|
||||
components: { DateRangePicker }, |
|
||||
mixins: [crud], |
|
||||
props: { |
|
||||
appName: { |
|
||||
type: String, |
|
||||
default: '' |
|
||||
} |
|
||||
}, |
|
||||
data() { |
|
||||
return { |
|
||||
submitLoading: false, |
|
||||
dialog: false, |
|
||||
history: [], |
|
||||
radio: '', |
|
||||
appNames: '', |
|
||||
selectIndex: '' |
|
||||
} |
|
||||
}, |
|
||||
created() { |
|
||||
this.$nextTick(() => { |
|
||||
this.init() |
|
||||
}) |
|
||||
}, |
|
||||
methods: { |
|
||||
beforeInit() { |
|
||||
this.url = 'api/deployHistory' |
|
||||
this.deployId = this.$parent.deployId |
|
||||
if (this.deployId === '') { |
|
||||
return false |
|
||||
} |
|
||||
this.sort = 'deployDate,desc' |
|
||||
this.params['deployId'] = this.deployId |
|
||||
return true |
|
||||
}, |
|
||||
showRow(row) { |
|
||||
this.radio = this.data.indexOf(row) |
|
||||
this.selectIndex = row.id |
|
||||
}, |
|
||||
cancel() { |
|
||||
this.dialog = false |
|
||||
this.submitLoading = false |
|
||||
}, |
|
||||
doSubmit() { |
|
||||
if (this.selectIndex === '') { |
|
||||
this.$message.error('请选择要还原的备份') |
|
||||
} else { |
|
||||
this.submitLoading = true |
|
||||
reducte(JSON.stringify(this.data[this.radio])) |
|
||||
.then(res => { |
|
||||
this.dialog = false |
|
||||
this.submitLoading = false |
|
||||
this.appNames = '' |
|
||||
this.$parent.crud.toQuery() |
|
||||
}) |
|
||||
.catch(err => { |
|
||||
this.submitLoading = false |
|
||||
console.log('error:' + err.response.data.message) |
|
||||
}) |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
</script> |
|
||||
|
|
||||
<style scoped> |
|
||||
</style> |
|
||||
@ -1,93 +0,0 @@ |
|||||
<template> |
|
||||
<div class="app-container"> |
|
||||
<!--工具栏--> |
|
||||
<div class="head-container"> |
|
||||
<div v-if="crud.props.searchToggle"> |
|
||||
<!-- 搜索 --> |
|
||||
<el-input v-model="query.blurry" clearable placeholder="输入搜索内容" style="width: 200px" class="filter-item" @keyup.enter.native="crud.toQuery" /> |
|
||||
<date-range-picker v-model="query.deployDate" class="date-item" /> |
|
||||
<rrOperation /> |
|
||||
</div> |
|
||||
<crudOperation :permission="permission" /> |
|
||||
</div> |
|
||||
<!--表格渲染--> |
|
||||
<el-table ref="table" v-loading="crud.loading" :data="crud.data" style="width: 100%" @selection-change="crud.selectionChangeHandler"> |
|
||||
<el-table-column type="selection" width="55" /> |
|
||||
<el-table-column prop="appName" label="应用名称" /> |
|
||||
<el-table-column prop="ip" label="部署IP" /> |
|
||||
<el-table-column prop="deployUser" label="部署人员" /> |
|
||||
<el-table-column prop="deployDate" label="部署时间" /> |
|
||||
<el-table-column v-if="checkPer(['admin','deployHistory:del'])" label="操作" width="100px" align="center"> |
|
||||
<template slot-scope="scope"> |
|
||||
<el-popover |
|
||||
:ref="scope.row.id" |
|
||||
v-permission="['admin','deployHistory:del']" |
|
||||
placement="top" |
|
||||
width="180" |
|
||||
> |
|
||||
<p>确定删除本条数据吗?</p> |
|
||||
<div style="text-align: right; margin: 0"> |
|
||||
<el-button size="mini" type="text" @click="$refs[scope.row.id].doClose()">取消</el-button> |
|
||||
<el-button :loading="delLoading" type="primary" size="mini" @click="delMethod(scope.row.id)">确定</el-button> |
|
||||
</div> |
|
||||
<el-button slot="reference" type="danger" icon="el-icon-delete" size="mini" /> |
|
||||
</el-popover> |
|
||||
</template> |
|
||||
</el-table-column> |
|
||||
</el-table> |
|
||||
<!--分页组件--> |
|
||||
<pagination /> |
|
||||
</div> |
|
||||
</template> |
|
||||
|
|
||||
<script> |
|
||||
import { del } from '@/api/mnt/deployHistory' |
|
||||
import CRUD, { presenter, header } from '@crud/crud' |
|
||||
import rrOperation from '@crud/RR.operation' |
|
||||
import crudOperation from '@crud/CRUD.operation' |
|
||||
import pagination from '@crud/Pagination' |
|
||||
import DateRangePicker from '@/components/DateRangePicker' |
|
||||
|
|
||||
export default { |
|
||||
name: 'DeployHistory', |
|
||||
components: { pagination, crudOperation, rrOperation, DateRangePicker }, |
|
||||
cruds() { |
|
||||
return CRUD({ title: '部署历史', url: 'api/deployHistory', crudMethod: { del }}) |
|
||||
}, |
|
||||
mixins: [presenter(), header()], |
|
||||
data() { |
|
||||
return { |
|
||||
delLoading: false, |
|
||||
permission: { |
|
||||
del: ['admin', 'deployHistory:del'] |
|
||||
} |
|
||||
} |
|
||||
}, |
|
||||
created() { |
|
||||
this.crud.optShow = { |
|
||||
add: false, |
|
||||
edit: false, |
|
||||
del: true, |
|
||||
download: true |
|
||||
} |
|
||||
}, |
|
||||
methods: { |
|
||||
delMethod(id) { |
|
||||
this.delLoading = true |
|
||||
del([id]).then(() => { |
|
||||
this.delLoading = false |
|
||||
this.$refs[id].doClose() |
|
||||
this.crud.dleChangePage(1) |
|
||||
this.crud.delSuccessNotify() |
|
||||
this.crud.toQuery() |
|
||||
}).catch(() => { |
|
||||
this.delLoading = false |
|
||||
this.$refs[id].doClose() |
|
||||
}) |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
</script> |
|
||||
|
|
||||
<style scoped> |
|
||||
</style> |
|
||||
@ -1,136 +0,0 @@ |
|||||
<template> |
|
||||
<div class="app-container"> |
|
||||
<!--工具栏--> |
|
||||
<div class="head-container"> |
|
||||
<div v-if="crud.props.searchToggle"> |
|
||||
<!-- 搜索 --> |
|
||||
<el-input v-model="query.id" clearable placeholder="输入名称或IP搜索" style="width: 200px" class="filter-item" @keyup.enter.native="crud.toQuery" /> |
|
||||
<date-range-picker v-model="query.createTime" class="date-item" /> |
|
||||
<rrOperation /> |
|
||||
</div> |
|
||||
<crudOperation :permission="permission" /> |
|
||||
</div> |
|
||||
<!--表单组件--> |
|
||||
<el-dialog append-to-body :close-on-click-modal="false" :before-close="crud.cancelCU" :visible.sync="crud.status.cu > 0" :title="crud.status.title" width="470px"> |
|
||||
<el-form ref="form" :model="form" :rules="rules" size="small" label-width="55px"> |
|
||||
<el-form-item label="名称" prop="name"> |
|
||||
<el-input v-model="form.name" style="width: 370px" /> |
|
||||
</el-form-item> |
|
||||
<el-form-item label="IP" prop="ip"> |
|
||||
<el-input v-model="form.ip" style="width: 370px" /> |
|
||||
</el-form-item> |
|
||||
<el-form-item label="端口" prop="port"> |
|
||||
<el-input-number v-model.number="form.port" controls-position="right" style="width: 370px;" /> |
|
||||
</el-form-item> |
|
||||
<el-form-item label="账号" prop="account"> |
|
||||
<el-input v-model="form.account" style="width: 370px" /> |
|
||||
</el-form-item> |
|
||||
<el-form-item label="密码" prop="password"> |
|
||||
<el-input v-model="form.password" type="password" style="width: 200px" /> |
|
||||
<el-button :loading="loading" type="success" style="align: right;" @click="testConnectServer">测试连接</el-button> |
|
||||
</el-form-item> |
|
||||
</el-form> |
|
||||
<div slot="footer" class="dialog-footer"> |
|
||||
<el-button type="text" @click="crud.cancelCU">取消</el-button> |
|
||||
<el-button :loading="crud.status.cu === 2" type="primary" @click="crud.submitCU">确认</el-button> |
|
||||
</div> |
|
||||
</el-dialog> |
|
||||
<!--表格渲染--> |
|
||||
<el-table ref="table" v-loading="crud.loading" :data="crud.data" style="width: 100%" @selection-change="crud.selectionChangeHandler"> |
|
||||
<el-table-column type="selection" width="55" /> |
|
||||
<el-table-column prop="name" label="名称" /> |
|
||||
<el-table-column prop="ip" label="IP" /> |
|
||||
<el-table-column prop="port" label="端口" /> |
|
||||
<el-table-column prop="account" label="账号" /> |
|
||||
<el-table-column prop="createTime" label="创建日期" /> |
|
||||
<el-table-column v-if="checkPer(['admin','serverDeploy:edit','serverDeploy:del'])" label="操作" width="150px" align="center"> |
|
||||
<template slot-scope="scope"> |
|
||||
<udOperation |
|
||||
:data="scope.row" |
|
||||
:permission="permission" |
|
||||
/> |
|
||||
</template> |
|
||||
</el-table-column> |
|
||||
</el-table> |
|
||||
<!--分页组件--> |
|
||||
<pagination /> |
|
||||
</div> |
|
||||
</template> |
|
||||
|
|
||||
<script> |
|
||||
|
|
||||
import crudServer from '@/api/mnt/serverDeploy' |
|
||||
import { testServerConnect } from '@/api/mnt/connect' |
|
||||
import { validateIP } from '@/utils/validate' |
|
||||
import CRUD, { presenter, header, form, crud } from '@crud/crud' |
|
||||
import rrOperation from '@crud/RR.operation' |
|
||||
import crudOperation from '@crud/CRUD.operation' |
|
||||
import udOperation from '@crud/UD.operation' |
|
||||
import pagination from '@crud/Pagination' |
|
||||
import DateRangePicker from '@/components/DateRangePicker' |
|
||||
|
|
||||
const defaultForm = { id: null, name: null, ip: null, port: 22, account: 'root', password: null } |
|
||||
export default { |
|
||||
name: 'Server', |
|
||||
components: { pagination, crudOperation, rrOperation, udOperation, DateRangePicker }, |
|
||||
cruds() { |
|
||||
return CRUD({ title: '服务器', url: 'api/serverDeploy', crudMethod: { ...crudServer }}) |
|
||||
}, |
|
||||
mixins: [presenter(), header(), form(defaultForm), crud()], |
|
||||
data() { |
|
||||
return { |
|
||||
accountList: [], |
|
||||
accountMap: {}, |
|
||||
loading: false, |
|
||||
permission: { |
|
||||
add: ['admin', 'serverDeploy:add'], |
|
||||
edit: ['admin', 'serverDeploy:edit'], |
|
||||
del: ['admin', 'serverDeploy:del'] |
|
||||
}, |
|
||||
rules: { |
|
||||
name: [ |
|
||||
{ required: true, message: '请输入名称', trigger: 'blur' } |
|
||||
], |
|
||||
ip: [ |
|
||||
{ required: true, message: '请输入IP', trigger: 'blur' }, |
|
||||
{ validator: validateIP, trigger: 'change' } |
|
||||
], |
|
||||
port: [ |
|
||||
{ required: true, message: '请输入端口', trigger: 'blur', type: 'number' } |
|
||||
], |
|
||||
account: [ |
|
||||
{ required: true, message: '请输入账号', trigger: 'blur' } |
|
||||
], |
|
||||
password: [ |
|
||||
{ required: true, message: '请输入密码', trigger: 'blur' } |
|
||||
] |
|
||||
} |
|
||||
} |
|
||||
}, |
|
||||
methods: { |
|
||||
testConnectServer() { |
|
||||
this.$refs['form'].validate((valid) => { |
|
||||
if (valid) { |
|
||||
this.loading = true |
|
||||
testServerConnect(this.form).then((res) => { |
|
||||
this.loading = false |
|
||||
this.$notify({ |
|
||||
title: res ? '连接成功' : '连接失败', |
|
||||
type: res ? 'success' : 'error', |
|
||||
duration: 2500 |
|
||||
}) |
|
||||
}).catch(() => { |
|
||||
this.loading = false |
|
||||
}) |
|
||||
} |
|
||||
}) |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
</script> |
|
||||
|
|
||||
<style rel="stylesheet/scss" lang="scss" scoped> |
|
||||
::v-deep .el-input-number .el-input__inner { |
|
||||
text-align: left; |
|
||||
} |
|
||||
</style> |
|
||||
@ -1,135 +0,0 @@ |
|||||
<template> |
|
||||
<div class="app-container"> |
|
||||
<div class="head-container"> |
|
||||
<Search /> |
|
||||
<crudOperation> |
|
||||
<el-button |
|
||||
slot="left" |
|
||||
class="filter-item" |
|
||||
type="danger" |
|
||||
icon="el-icon-delete" |
|
||||
size="mini" |
|
||||
:loading="crud.delAllLoading" |
|
||||
@click="confirmDelAll()" |
|
||||
> |
|
||||
清空 |
|
||||
</el-button> |
|
||||
</crudOperation> |
|
||||
</div> |
|
||||
<!--表格渲染--> |
|
||||
<el-table ref="table" v-loading="crud.loading" :data="crud.data" style="width: 100%;" @selection-change="crud.selectionChangeHandler"> |
|
||||
<el-table-column type="expand"> |
|
||||
<template slot-scope="props"> |
|
||||
<el-form label-position="left" inline class="demo-table-expand"> |
|
||||
<el-form-item label="请求方法"> |
|
||||
<span>{{ props.row.method }}</span> |
|
||||
</el-form-item> |
|
||||
<el-form-item label="请求参数"> |
|
||||
<span>{{ props.row.params }}</span> |
|
||||
</el-form-item> |
|
||||
</el-form> |
|
||||
</template> |
|
||||
</el-table-column> |
|
||||
<el-table-column prop="username" label="用户名" /> |
|
||||
<el-table-column prop="requestIp" label="IP" /> |
|
||||
<el-table-column :show-overflow-tooltip="true" prop="address" label="IP来源" /> |
|
||||
<el-table-column prop="description" label="描述" /> |
|
||||
<el-table-column prop="browser" label="浏览器" /> |
|
||||
<el-table-column prop="createTime" label="创建日期" /> |
|
||||
<el-table-column label="异常详情" width="100px"> |
|
||||
<template slot-scope="scope"> |
|
||||
<el-button size="mini" type="text" @click="info(scope.row.id)">查看详情</el-button> |
|
||||
</template> |
|
||||
</el-table-column> |
|
||||
</el-table> |
|
||||
<el-dialog :visible.sync="dialog" title="异常详情" append-to-body top="30px" width="85%"> |
|
||||
<pre v-highlightjs="errorInfo"><code class="java" /></pre> |
|
||||
</el-dialog> |
|
||||
<!--分页组件--> |
|
||||
<pagination /> |
|
||||
</div> |
|
||||
</template> |
|
||||
|
|
||||
<script> |
|
||||
import { getErrDetail, delAllError } from '@/api/monitor/log' |
|
||||
import Search from './search' |
|
||||
import CRUD, { presenter } from '@crud/crud' |
|
||||
import crudOperation from '@crud/CRUD.operation' |
|
||||
import pagination from '@crud/Pagination' |
|
||||
|
|
||||
export default { |
|
||||
name: 'ErrorLog', |
|
||||
components: { Search, crudOperation, pagination }, |
|
||||
cruds() { |
|
||||
return CRUD({ title: '异常日志', url: 'api/logs/error' }) |
|
||||
}, |
|
||||
mixins: [presenter()], |
|
||||
data() { |
|
||||
return { |
|
||||
errorInfo: '', dialog: false |
|
||||
} |
|
||||
}, |
|
||||
created() { |
|
||||
this.crud.optShow = { |
|
||||
add: false, |
|
||||
edit: false, |
|
||||
del: false, |
|
||||
download: true |
|
||||
} |
|
||||
}, |
|
||||
methods: { |
|
||||
// 获取异常详情 |
|
||||
info(id) { |
|
||||
this.dialog = true |
|
||||
getErrDetail(id).then(res => { |
|
||||
this.errorInfo = res.exception |
|
||||
}) |
|
||||
}, |
|
||||
confirmDelAll() { |
|
||||
this.$confirm(`确认清空所有异常日志吗?`, '提示', { |
|
||||
confirmButtonText: '确定', |
|
||||
cancelButtonText: '取消', |
|
||||
type: 'warning' |
|
||||
}).then(() => { |
|
||||
this.crud.delAllLoading = true |
|
||||
delAllError().then(res => { |
|
||||
this.crud.delAllLoading = false |
|
||||
this.crud.dleChangePage(1) |
|
||||
this.crud.delSuccessNotify() |
|
||||
this.crud.toQuery() |
|
||||
}).catch(err => { |
|
||||
this.crud.delAllLoading = false |
|
||||
console.log(err.response.data.message) |
|
||||
}) |
|
||||
}).catch(() => { |
|
||||
}) |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
</script> |
|
||||
|
|
||||
<style scoped> |
|
||||
.demo-table-expand { |
|
||||
font-size: 0; |
|
||||
} |
|
||||
.demo-table-expand label { |
|
||||
width: 70px; |
|
||||
color: #99a9bf; |
|
||||
} |
|
||||
.demo-table-expand .el-form-item { |
|
||||
margin-right: 0; |
|
||||
margin-bottom: 0; |
|
||||
width: 100%; |
|
||||
} |
|
||||
.demo-table-expand .el-form-item__content { |
|
||||
font-size: 12px; |
|
||||
} |
|
||||
/deep/ .el-dialog__body { |
|
||||
padding: 0 20px 10px 20px !important; |
|
||||
} |
|
||||
.java.hljs { |
|
||||
color: #444; |
|
||||
background: #ffffff !important; |
|
||||
height: 630px !important; |
|
||||
} |
|
||||
</style> |
|
||||
@ -1,114 +0,0 @@ |
|||||
<template> |
|
||||
<div class="app-container"> |
|
||||
<div class="head-container"> |
|
||||
<Search /> |
|
||||
<crudOperation> |
|
||||
<el-button |
|
||||
slot="left" |
|
||||
class="filter-item" |
|
||||
type="danger" |
|
||||
icon="el-icon-delete" |
|
||||
size="mini" |
|
||||
:loading="crud.delAllLoading" |
|
||||
@click="confirmDelAll()" |
|
||||
> |
|
||||
清空 |
|
||||
</el-button> |
|
||||
</crudOperation> |
|
||||
</div> |
|
||||
<!--表格渲染--> |
|
||||
<el-table ref="table" v-loading="crud.loading" :data="crud.data" style="width: 100%;" @selection-change="crud.selectionChangeHandler"> |
|
||||
<el-table-column type="expand"> |
|
||||
<template slot-scope="props"> |
|
||||
<el-form label-position="left" inline class="demo-table-expand"> |
|
||||
<el-form-item label="请求方法"> |
|
||||
<span>{{ props.row.method }}</span> |
|
||||
</el-form-item> |
|
||||
<el-form-item label="请求参数"> |
|
||||
<span>{{ props.row.params }}</span> |
|
||||
</el-form-item> |
|
||||
</el-form> |
|
||||
</template> |
|
||||
</el-table-column> |
|
||||
<el-table-column prop="username" label="用户名" /> |
|
||||
<el-table-column prop="requestIp" label="IP" /> |
|
||||
<el-table-column :show-overflow-tooltip="true" prop="address" label="IP来源" /> |
|
||||
<el-table-column prop="description" label="描述" /> |
|
||||
<el-table-column prop="browser" label="浏览器" /> |
|
||||
<el-table-column prop="time" label="请求耗时" align="center"> |
|
||||
<template slot-scope="scope"> |
|
||||
<el-tag v-if="scope.row.time <= 300">{{ scope.row.time }}ms</el-tag> |
|
||||
<el-tag v-else-if="scope.row.time <= 1000" type="warning">{{ scope.row.time }}ms</el-tag> |
|
||||
<el-tag v-else type="danger">{{ scope.row.time }}ms</el-tag> |
|
||||
</template> |
|
||||
</el-table-column> |
|
||||
<el-table-column prop="createTime" label="创建日期" width="180px" /> |
|
||||
</el-table> |
|
||||
<!--分页组件--> |
|
||||
<pagination /> |
|
||||
</div> |
|
||||
</template> |
|
||||
|
|
||||
<script> |
|
||||
import Search from './search' |
|
||||
import { delAllInfo } from '@/api/monitor/log' |
|
||||
import CRUD, { presenter } from '@crud/crud' |
|
||||
import crudOperation from '@crud/CRUD.operation' |
|
||||
import pagination from '@crud/Pagination' |
|
||||
|
|
||||
export default { |
|
||||
name: 'Log', |
|
||||
components: { Search, crudOperation, pagination }, |
|
||||
cruds() { |
|
||||
return CRUD({ title: '日志', url: 'api/logs' }) |
|
||||
}, |
|
||||
mixins: [presenter()], |
|
||||
created() { |
|
||||
this.crud.optShow = { |
|
||||
add: false, |
|
||||
edit: false, |
|
||||
del: false, |
|
||||
download: true |
|
||||
} |
|
||||
}, |
|
||||
methods: { |
|
||||
confirmDelAll() { |
|
||||
this.$confirm(`确认清空所有操作日志吗?`, '提示', { |
|
||||
confirmButtonText: '确定', |
|
||||
cancelButtonText: '取消', |
|
||||
type: 'warning' |
|
||||
}).then(() => { |
|
||||
this.crud.delAllLoading = true |
|
||||
delAllInfo().then(res => { |
|
||||
this.crud.delAllLoading = false |
|
||||
this.crud.dleChangePage(1) |
|
||||
this.crud.delSuccessNotify() |
|
||||
this.crud.toQuery() |
|
||||
}).catch(err => { |
|
||||
this.crud.delAllLoading = false |
|
||||
console.log(err.response.data.message) |
|
||||
}) |
|
||||
}).catch(() => { |
|
||||
}) |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
</script> |
|
||||
|
|
||||
<style> |
|
||||
.demo-table-expand { |
|
||||
font-size: 0; |
|
||||
} |
|
||||
.demo-table-expand label { |
|
||||
width: 70px; |
|
||||
color: #99a9bf; |
|
||||
} |
|
||||
.demo-table-expand .el-form-item { |
|
||||
margin-right: 0; |
|
||||
margin-bottom: 0; |
|
||||
width: 100%; |
|
||||
} |
|
||||
.demo-table-expand .el-form-item__content { |
|
||||
font-size: 12px; |
|
||||
} |
|
||||
</style> |
|
||||
@ -1,24 +0,0 @@ |
|||||
<template> |
|
||||
<div v-if="crud.props.searchToggle"> |
|
||||
<el-input |
|
||||
v-model="query.blurry" |
|
||||
clearable |
|
||||
size="small" |
|
||||
placeholder="请输入你要搜索的内容" |
|
||||
style="width: 200px;" |
|
||||
class="filter-item" |
|
||||
/> |
|
||||
<date-range-picker v-model="query.createTime" class="date-item" /> |
|
||||
<rrOperation /> |
|
||||
</div> |
|
||||
</template> |
|
||||
|
|
||||
<script> |
|
||||
import { header } from '@crud/crud' |
|
||||
import rrOperation from '@crud/RR.operation' |
|
||||
import DateRangePicker from '@/components/DateRangePicker' |
|
||||
export default { |
|
||||
components: { rrOperation, DateRangePicker }, |
|
||||
mixins: [header()] |
|
||||
} |
|
||||
</script> |
|
||||
@ -1,121 +0,0 @@ |
|||||
<template> |
|
||||
<div class="app-container"> |
|
||||
<div class="head-container"> |
|
||||
<div v-if="crud.props.searchToggle"> |
|
||||
<el-input v-model="query.filter" clearable size="small" placeholder="全表模糊搜索" style="width: 200px;" class="filter-item" @keyup.enter.native="crud.toQuery" /> |
|
||||
<rrOperation /> |
|
||||
</div> |
|
||||
<crudOperation> |
|
||||
<el-button |
|
||||
slot="left" |
|
||||
class="filter-item" |
|
||||
type="danger" |
|
||||
icon="el-icon-delete" |
|
||||
size="mini" |
|
||||
:loading="delLoading" |
|
||||
:disabled="crud.selections.length === 0" |
|
||||
@click="doDelete(crud.selections)" |
|
||||
> |
|
||||
强退 |
|
||||
</el-button> |
|
||||
</crudOperation> |
|
||||
</div> |
|
||||
<!--表格渲染--> |
|
||||
<el-table ref="table" v-loading="crud.loading" :data="crud.data" style="width: 100%;" @selection-change="crud.selectionChangeHandler"> |
|
||||
<el-table-column type="selection" width="55" /> |
|
||||
<el-table-column prop="userName" label="用户名" /> |
|
||||
<el-table-column prop="nickName" label="用户昵称" /> |
|
||||
<el-table-column prop="dept" label="部门" /> |
|
||||
<el-table-column prop="ip" label="登录IP" /> |
|
||||
<el-table-column :show-overflow-tooltip="true" prop="address" label="登录地点" /> |
|
||||
<el-table-column prop="browser" label="浏览器" /> |
|
||||
<el-table-column prop="loginTime" label="登录时间" /> |
|
||||
<el-table-column label="操作" width="70px" fixed="right"> |
|
||||
<template slot-scope="scope"> |
|
||||
<el-popover |
|
||||
:ref="scope.$index" |
|
||||
v-permission="['admin']" |
|
||||
placement="top" |
|
||||
width="180" |
|
||||
> |
|
||||
<p>确定强制退出该用户吗?</p> |
|
||||
<div style="text-align: right; margin: 0"> |
|
||||
<el-button size="mini" type="text" @click="$refs[scope.$index].doClose()">取消</el-button> |
|
||||
<el-button :loading="delLoading" type="primary" size="mini" @click="delMethod(scope.row.key, scope.$index)">确定</el-button> |
|
||||
</div> |
|
||||
<el-button slot="reference" size="mini" type="text">强退</el-button> |
|
||||
</el-popover> |
|
||||
</template> |
|
||||
</el-table-column> |
|
||||
</el-table> |
|
||||
<!--分页组件--> |
|
||||
<pagination /> |
|
||||
</div> |
|
||||
</template> |
|
||||
|
|
||||
<script> |
|
||||
import { del } from '@/api/monitor/online' |
|
||||
import CRUD, { presenter, header, crud } from '@crud/crud' |
|
||||
import rrOperation from '@crud/RR.operation' |
|
||||
import crudOperation from '@crud/CRUD.operation' |
|
||||
import pagination from '@crud/Pagination' |
|
||||
|
|
||||
export default { |
|
||||
name: 'OnlineUser', |
|
||||
components: { pagination, crudOperation, rrOperation }, |
|
||||
cruds() { |
|
||||
return CRUD({ url: 'auth/online', title: '在线用户' }) |
|
||||
}, |
|
||||
mixins: [presenter(), header(), crud()], |
|
||||
data() { |
|
||||
return { |
|
||||
delLoading: false, |
|
||||
permission: {} |
|
||||
} |
|
||||
}, |
|
||||
created() { |
|
||||
this.crud.msg.del = '强退成功!' |
|
||||
this.crud.optShow = { |
|
||||
add: false, |
|
||||
edit: false, |
|
||||
del: false, |
|
||||
download: true |
|
||||
} |
|
||||
}, |
|
||||
methods: { |
|
||||
doDelete(datas) { |
|
||||
this.$confirm(`确认强退选中的${datas.length}个用户?`, '提示', { |
|
||||
confirmButtonText: '确定', |
|
||||
cancelButtonText: '取消', |
|
||||
type: 'warning' |
|
||||
}).then(() => { |
|
||||
this.delMethod(datas) |
|
||||
}).catch(() => {}) |
|
||||
}, |
|
||||
// 踢出用户 |
|
||||
delMethod(key, index) { |
|
||||
const ids = [] |
|
||||
if (key instanceof Array) { |
|
||||
key.forEach(val => { |
|
||||
ids.push(val.key) |
|
||||
}) |
|
||||
} else ids.push(key) |
|
||||
this.delLoading = true |
|
||||
del(ids).then(() => { |
|
||||
this.delLoading = false |
|
||||
if (this.$refs[index]) { |
|
||||
this.$refs[index].doClose() |
|
||||
} |
|
||||
this.crud.dleChangePage(1) |
|
||||
this.crud.delSuccessNotify() |
|
||||
this.crud.toQuery() |
|
||||
}).catch(() => { |
|
||||
this.delLoading = false |
|
||||
if (this.$refs[index]) { |
|
||||
this.$refs[index].doClose() |
|
||||
} |
|
||||
}) |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
</script> |
|
||||
@ -1,291 +0,0 @@ |
|||||
<template> |
|
||||
<div v-loading="!show" element-loading-text="数据加载中..." :style="!show ? 'height: 500px' : 'height: 100%'" class="app-container"> |
|
||||
<div v-if="show"> |
|
||||
<el-card class="box-card"> |
|
||||
<div style="color: #666;font-size: 13px;"> |
|
||||
<svg-icon icon-class="system" style="margin-right: 5px" /> |
|
||||
<span> |
|
||||
系统:{{ data.sys.os }} |
|
||||
</span> |
|
||||
<span> |
|
||||
IP:{{ data.sys.ip }} |
|
||||
</span> |
|
||||
<span> |
|
||||
项目已不间断运行:{{ data.sys.day }} |
|
||||
</span> |
|
||||
<i class="el-icon-refresh" style="margin-left: 40px" @click="init" /> |
|
||||
</div> |
|
||||
</el-card> |
|
||||
<el-card class="box-card"> |
|
||||
<div slot="header" class="clearfix"> |
|
||||
<span style="font-weight: bold;color: #666;font-size: 15px">状态</span> |
|
||||
</div> |
|
||||
<div> |
|
||||
<el-col :xs="24" :sm="24" :md="6" :lg="6" :xl="6" style="margin-bottom: 10px"> |
|
||||
<div class="title">CPU使用率</div> |
|
||||
<el-tooltip placement="top-end"> |
|
||||
<div slot="content" style="font-size: 12px;"> |
|
||||
<div style="padding: 3px;"> |
|
||||
{{ data.cpu.name }} |
|
||||
</div> |
|
||||
<div style="padding: 3px"> |
|
||||
{{ data.cpu.package }} |
|
||||
</div> |
|
||||
<div style="padding: 3px"> |
|
||||
{{ data.cpu.core }} |
|
||||
</div> |
|
||||
<div style="padding: 3px"> |
|
||||
{{ data.cpu.logic }} |
|
||||
</div> |
|
||||
</div> |
|
||||
<div class="content"> |
|
||||
<el-progress type="dashboard" :percentage="parseFloat(data.cpu.used)" /> |
|
||||
</div> |
|
||||
</el-tooltip> |
|
||||
<div class="footer">{{ data.cpu.coreNumber }} 核心</div> |
|
||||
</el-col> |
|
||||
<el-col :xs="24" :sm="24" :md="6" :lg="6" :xl="6" style="margin-bottom: 10px"> |
|
||||
<div class="title">内存使用率</div> |
|
||||
<el-tooltip placement="top-end"> |
|
||||
<div slot="content" style="font-size: 12px;"> |
|
||||
<div style="padding: 3px;"> |
|
||||
总量:{{ data.memory.total }} |
|
||||
</div> |
|
||||
<div style="padding: 3px"> |
|
||||
已使用:{{ data.memory.used }} |
|
||||
</div> |
|
||||
<div style="padding: 3px"> |
|
||||
空闲:{{ data.memory.available }} |
|
||||
</div> |
|
||||
</div> |
|
||||
<div class="content"> |
|
||||
<el-progress type="dashboard" :percentage="parseFloat(data.memory.usageRate)" /> |
|
||||
</div> |
|
||||
</el-tooltip> |
|
||||
<div class="footer">{{ data.memory.used }} / {{ data.memory.total }}</div> |
|
||||
</el-col> |
|
||||
<el-col :xs="24" :sm="24" :md="6" :lg="6" :xl="6" style="margin-bottom: 10px"> |
|
||||
<div class="title">交换区使用率</div> |
|
||||
<el-tooltip placement="top-end"> |
|
||||
<div slot="content" style="font-size: 12px;"> |
|
||||
<div style="padding: 3px;"> |
|
||||
总量:{{ data.swap.total }} |
|
||||
</div> |
|
||||
<div style="padding: 3px"> |
|
||||
已使用:{{ data.swap.used }} |
|
||||
</div> |
|
||||
<div style="padding: 3px"> |
|
||||
空闲:{{ data.swap.available }} |
|
||||
</div> |
|
||||
</div> |
|
||||
<div class="content"> |
|
||||
<el-progress type="dashboard" :percentage="parseFloat(data.swap.usageRate)" /> |
|
||||
</div> |
|
||||
</el-tooltip> |
|
||||
<div class="footer">{{ data.swap.used }} / {{ data.swap.total }}</div> |
|
||||
</el-col> |
|
||||
<el-col :xs="24" :sm="24" :md="6" :lg="6" :xl="6" style="margin-bottom: 10px"> |
|
||||
<div class="title">磁盘使用率</div> |
|
||||
<div class="content"> |
|
||||
<el-tooltip placement="top-end"> |
|
||||
<div slot="content" style="font-size: 12px;"> |
|
||||
<div style="padding: 3px"> |
|
||||
总量:{{ data.disk.total }} |
|
||||
</div> |
|
||||
<div style="padding: 3px"> |
|
||||
空闲:{{ data.disk.available }} |
|
||||
</div> |
|
||||
</div> |
|
||||
<div class="content"> |
|
||||
<el-progress type="dashboard" :percentage="parseFloat(data.disk.usageRate)" /> |
|
||||
</div> |
|
||||
</el-tooltip> |
|
||||
</div> |
|
||||
<div class="footer">{{ data.disk.used }} / {{ data.disk.total }}</div> |
|
||||
</el-col> |
|
||||
</div> |
|
||||
</el-card> |
|
||||
|
|
||||
<div> |
|
||||
<el-row :gutter="6"> |
|
||||
<el-col :xs="24" :sm="24" :md="12" :lg="12" :xl="12" style="margin-bottom: 10px"> |
|
||||
<el-card class="box-card"> |
|
||||
<div slot="header" class="clearfix"> |
|
||||
<span style="font-weight: bold;color: #666;font-size: 15px">CPU使用率监控</span> |
|
||||
</div> |
|
||||
<div> |
|
||||
<v-chart :options="cpuInfo" /> |
|
||||
</div> |
|
||||
</el-card> |
|
||||
</el-col> |
|
||||
<el-col :xs="24" :sm="24" :md="12" :lg="12" :xl="12" style="margin-bottom: 10px"> |
|
||||
<el-card class="box-card"> |
|
||||
<div slot="header" class="clearfix"> |
|
||||
<span style="font-weight: bold;color: #666;font-size: 15px">内存使用率监控</span> |
|
||||
</div> |
|
||||
<div> |
|
||||
<v-chart :options="memoryInfo" /> |
|
||||
</div> |
|
||||
</el-card> |
|
||||
</el-col> |
|
||||
</el-row> |
|
||||
</div> |
|
||||
</div> |
|
||||
</div> |
|
||||
</template> |
|
||||
|
|
||||
<script> |
|
||||
import ECharts from 'vue-echarts' |
|
||||
import 'echarts/lib/chart/line' |
|
||||
import 'echarts/lib/component/polar' |
|
||||
import { initData } from '@/api/data' |
|
||||
export default { |
|
||||
name: 'ServerMonitor', |
|
||||
components: { |
|
||||
'v-chart': ECharts |
|
||||
}, |
|
||||
data() { |
|
||||
return { |
|
||||
show: false, |
|
||||
monitor: null, |
|
||||
url: 'api/monitor', |
|
||||
data: {}, |
|
||||
cpuInfo: { |
|
||||
tooltip: { |
|
||||
trigger: 'axis' |
|
||||
}, |
|
||||
xAxis: { |
|
||||
type: 'category', |
|
||||
boundaryGap: false, |
|
||||
data: [] |
|
||||
}, |
|
||||
yAxis: { |
|
||||
type: 'value', |
|
||||
min: 0, |
|
||||
max: 100, |
|
||||
interval: 20 |
|
||||
}, |
|
||||
series: [{ |
|
||||
data: [], |
|
||||
type: 'line', |
|
||||
areaStyle: { |
|
||||
normal: { |
|
||||
color: 'rgb(32, 160, 255)' // 改变区域颜色 |
|
||||
} |
|
||||
}, |
|
||||
itemStyle: { |
|
||||
normal: { |
|
||||
color: '#6fbae1', |
|
||||
lineStyle: { |
|
||||
color: '#6fbae1' // 改变折线颜色 |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
}] |
|
||||
}, |
|
||||
memoryInfo: { |
|
||||
tooltip: { |
|
||||
trigger: 'axis' |
|
||||
}, |
|
||||
xAxis: { |
|
||||
type: 'category', |
|
||||
boundaryGap: false, |
|
||||
data: [] |
|
||||
}, |
|
||||
yAxis: { |
|
||||
type: 'value', |
|
||||
min: 0, |
|
||||
max: 100, |
|
||||
interval: 20 |
|
||||
}, |
|
||||
series: [{ |
|
||||
data: [], |
|
||||
type: 'line', |
|
||||
areaStyle: { |
|
||||
normal: { |
|
||||
color: 'rgb(32, 160, 255)' // 改变区域颜色 |
|
||||
} |
|
||||
}, |
|
||||
itemStyle: { |
|
||||
normal: { |
|
||||
color: '#6fbae1', |
|
||||
lineStyle: { |
|
||||
color: '#6fbae1' // 改变折线颜色 |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
}] |
|
||||
} |
|
||||
} |
|
||||
}, |
|
||||
created() { |
|
||||
this.init() |
|
||||
this.monitor = window.setInterval(() => { |
|
||||
setTimeout(() => { |
|
||||
this.init() |
|
||||
}, 2) |
|
||||
}, 3500) |
|
||||
}, |
|
||||
destroyed() { |
|
||||
clearInterval(this.monitor) |
|
||||
}, |
|
||||
methods: { |
|
||||
init() { |
|
||||
initData(this.url, {}).then(data => { |
|
||||
this.data = data |
|
||||
this.show = true |
|
||||
if (this.cpuInfo.xAxis.data.length >= 8) { |
|
||||
this.cpuInfo.xAxis.data.shift() |
|
||||
this.memoryInfo.xAxis.data.shift() |
|
||||
this.cpuInfo.series[0].data.shift() |
|
||||
this.memoryInfo.series[0].data.shift() |
|
||||
} |
|
||||
this.cpuInfo.xAxis.data.push(data.time) |
|
||||
this.memoryInfo.xAxis.data.push(data.time) |
|
||||
this.cpuInfo.series[0].data.push(parseFloat(data.cpu.used)) |
|
||||
this.memoryInfo.series[0].data.push(parseFloat(data.memory.usageRate)) |
|
||||
}) |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
</script> |
|
||||
|
|
||||
<style rel="stylesheet/scss" lang="scss" scoped> |
|
||||
::v-deep .box-card { |
|
||||
margin-bottom: 5px; |
|
||||
span { |
|
||||
margin-right: 28px; |
|
||||
} |
|
||||
.el-icon-refresh { |
|
||||
margin-right: 10px; |
|
||||
float: right; |
|
||||
cursor:pointer; |
|
||||
} |
|
||||
} |
|
||||
.cpu, .memory, .swap, .disk { |
|
||||
width: 20%; |
|
||||
float: left; |
|
||||
padding-bottom: 20px; |
|
||||
margin-right: 5%; |
|
||||
} |
|
||||
.title { |
|
||||
text-align: center; |
|
||||
font-size: 15px; |
|
||||
font-weight: 500; |
|
||||
color: #999; |
|
||||
margin-bottom: 16px; |
|
||||
} |
|
||||
.footer { |
|
||||
text-align: center; |
|
||||
font-size: 15px; |
|
||||
font-weight: 500; |
|
||||
color: #999; |
|
||||
margin-top: -5px; |
|
||||
margin-bottom: 10px; |
|
||||
} |
|
||||
.content { |
|
||||
text-align: center; |
|
||||
margin-top: 5px; |
|
||||
margin-bottom: 5px; |
|
||||
} |
|
||||
</style> |
|
||||
@ -1,16 +0,0 @@ |
|||||
<template> |
|
||||
<elFrame :src="sqlApi" /> |
|
||||
</template> |
|
||||
<script> |
|
||||
import { mapGetters } from 'vuex' |
|
||||
import elFrame from '@/components/Iframe/index' |
|
||||
export default { |
|
||||
name: 'Sql', |
|
||||
components: { elFrame }, |
|
||||
computed: { |
|
||||
...mapGetters([ |
|
||||
'sqlApi' |
|
||||
]) |
|
||||
} |
|
||||
} |
|
||||
</script> |
|
||||
@ -1,115 +0,0 @@ |
|||||
<template> |
|
||||
<div> |
|
||||
<div v-if="query.dictName === ''"> |
|
||||
<div class="my-code">点击字典查看详情</div> |
|
||||
</div> |
|
||||
<div v-else> |
|
||||
<!--工具栏--> |
|
||||
<div class="head-container"> |
|
||||
<div v-if="crud.props.searchToggle"> |
|
||||
<!-- 搜索 --> |
|
||||
<el-input v-model="query.label" clearable size="small" placeholder="输入字典标签查询" style="width: 200px;" class="filter-item" @keyup.enter.native="toQuery" /> |
|
||||
<rrOperation /> |
|
||||
</div> |
|
||||
</div> |
|
||||
<!--表单组件--> |
|
||||
<el-dialog append-to-body :close-on-click-modal="false" :before-close="crud.cancelCU" :visible="crud.status.cu > 0" :title="crud.status.title" width="500px"> |
|
||||
<el-form ref="form" :model="form" :rules="rules" size="small" label-width="80px"> |
|
||||
<el-form-item label="字典标签" prop="label"> |
|
||||
<el-input v-model="form.label" style="width: 370px;" /> |
|
||||
</el-form-item> |
|
||||
<el-form-item label="字典值" prop="value"> |
|
||||
<el-input v-model="form.value" style="width: 370px;" /> |
|
||||
</el-form-item> |
|
||||
<el-form-item label="排序" prop="dictSort"> |
|
||||
<el-input-number v-model.number="form.dictSort" :min="0" :max="999" controls-position="right" style="width: 370px;" /> |
|
||||
</el-form-item> |
|
||||
</el-form> |
|
||||
<div slot="footer" class="dialog-footer"> |
|
||||
<el-button type="text" @click="crud.cancelCU">取消</el-button> |
|
||||
<el-button :loading="crud.status.cu === 2" type="primary" @click="crud.submitCU">确认</el-button> |
|
||||
</div> |
|
||||
</el-dialog> |
|
||||
<!--表格渲染--> |
|
||||
<el-table ref="table" v-loading="crud.loading" :data="crud.data" highlight-current-row style="width: 100%;" @selection-change="crud.selectionChangeHandler"> |
|
||||
<el-table-column label="所属字典"> |
|
||||
{{ query.dictName }} |
|
||||
</el-table-column> |
|
||||
<el-table-column prop="label" label="字典标签" /> |
|
||||
<el-table-column prop="value" label="字典值" /> |
|
||||
<el-table-column prop="dictSort" label="排序" /> |
|
||||
<el-table-column v-if="checkPer(['admin','dict:edit','dict:del'])" label="操作" width="130px" align="center" fixed="right"> |
|
||||
<template slot-scope="scope"> |
|
||||
<udOperation |
|
||||
:data="scope.row" |
|
||||
:permission="permission" |
|
||||
/> |
|
||||
</template> |
|
||||
</el-table-column> |
|
||||
</el-table> |
|
||||
<!--分页组件--> |
|
||||
<pagination /> |
|
||||
</div> |
|
||||
</div> |
|
||||
</template> |
|
||||
|
|
||||
<script> |
|
||||
import crudDictDetail from '@/api/system/dictDetail' |
|
||||
import CRUD, { presenter, header, form } from '@crud/crud' |
|
||||
import pagination from '@crud/Pagination' |
|
||||
import rrOperation from '@crud/RR.operation' |
|
||||
import udOperation from '@crud/UD.operation' |
|
||||
|
|
||||
const defaultForm = { id: null, label: null, value: null, dictSort: 999 } |
|
||||
|
|
||||
export default { |
|
||||
components: { pagination, rrOperation, udOperation }, |
|
||||
cruds() { |
|
||||
return [ |
|
||||
CRUD({ title: '字典详情', url: 'api/dictDetail', query: { dictName: '' }, sort: ['dictSort,asc', 'id,desc'], |
|
||||
crudMethod: { ...crudDictDetail }, |
|
||||
optShow: { |
|
||||
add: true, |
|
||||
edit: true, |
|
||||
del: true, |
|
||||
reset: false |
|
||||
}, |
|
||||
queryOnPresenterCreated: false |
|
||||
}) |
|
||||
] |
|
||||
}, |
|
||||
mixins: [ |
|
||||
presenter(), |
|
||||
header(), |
|
||||
form(function() { |
|
||||
return Object.assign({ dict: { id: this.dictId }}, defaultForm) |
|
||||
})], |
|
||||
data() { |
|
||||
return { |
|
||||
dictId: null, |
|
||||
rules: { |
|
||||
label: [ |
|
||||
{ required: true, message: '请输入字典标签', trigger: 'blur' } |
|
||||
], |
|
||||
value: [ |
|
||||
{ required: true, message: '请输入字典值', trigger: 'blur' } |
|
||||
], |
|
||||
dictSort: [ |
|
||||
{ required: true, message: '请输入序号', trigger: 'blur', type: 'number' } |
|
||||
] |
|
||||
}, |
|
||||
permission: { |
|
||||
add: ['admin', 'dict:add'], |
|
||||
edit: ['admin', 'dict:edit'], |
|
||||
del: ['admin', 'dict:del'] |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
</script> |
|
||||
|
|
||||
<style rel="stylesheet/scss" lang="scss" scoped> |
|
||||
::v-deep .el-input-number .el-input__inner { |
|
||||
text-align: left; |
|
||||
} |
|
||||
</style> |
|
||||
@ -1,130 +0,0 @@ |
|||||
<template> |
|
||||
<div class="app-container"> |
|
||||
<!--表单组件--> |
|
||||
<el-dialog append-to-body :close-on-click-modal="false" :before-close="crud.cancelCU" :visible="crud.status.cu > 0" :title="crud.status.title" width="500px"> |
|
||||
<el-form ref="form" :model="form" :rules="rules" size="small" label-width="80px"> |
|
||||
<el-form-item label="字典名称" prop="name"> |
|
||||
<el-input v-model="form.name" style="width: 370px;" /> |
|
||||
</el-form-item> |
|
||||
<el-form-item label="描述"> |
|
||||
<el-input v-model="form.description" style="width: 370px;" /> |
|
||||
</el-form-item> |
|
||||
</el-form> |
|
||||
<div slot="footer" class="dialog-footer"> |
|
||||
<el-button type="text" @click="crud.cancelCU">取消</el-button> |
|
||||
<el-button :loading="crud.status.cu === 2" type="primary" @click="crud.submitCU">确认</el-button> |
|
||||
</div> |
|
||||
</el-dialog> |
|
||||
<!-- 字典列表 --> |
|
||||
<el-row :gutter="10"> |
|
||||
<el-col :xs="24" :sm="24" :md="10" :lg="11" :xl="11" style="margin-bottom: 10px"> |
|
||||
<el-card class="box-card"> |
|
||||
<!--工具栏--> |
|
||||
<div class="head-container"> |
|
||||
<div v-if="crud.props.searchToggle"> |
|
||||
<!-- 搜索 --> |
|
||||
<el-input v-model="query.blurry" clearable size="small" placeholder="输入名称或者描述搜索" style="width: 200px;" class="filter-item" @keyup.enter.native="crud.toQuery" /> |
|
||||
<rrOperation /> |
|
||||
</div> |
|
||||
<crudOperation :permission="permission" /> |
|
||||
</div> |
|
||||
<!--表格渲染--> |
|
||||
<el-table ref="table" v-loading="crud.loading" :data="crud.data" highlight-current-row style="width: 100%;" @selection-change="crud.selectionChangeHandler" @current-change="handleCurrentChange"> |
|
||||
<el-table-column type="selection" width="55" /> |
|
||||
<el-table-column :show-overflow-tooltip="true" prop="name" label="名称" /> |
|
||||
<el-table-column :show-overflow-tooltip="true" prop="description" label="描述" /> |
|
||||
<el-table-column v-if="checkPer(['admin','dict:edit','dict:del'])" label="操作" width="130px" align="center" fixed="right"> |
|
||||
<template slot-scope="scope"> |
|
||||
<udOperation |
|
||||
:data="scope.row" |
|
||||
:permission="permission" |
|
||||
/> |
|
||||
</template> |
|
||||
</el-table-column> |
|
||||
</el-table> |
|
||||
<!--分页组件--> |
|
||||
<pagination /> |
|
||||
</el-card> |
|
||||
</el-col> |
|
||||
<!-- 字典详情列表 --> |
|
||||
<el-col :xs="24" :sm="24" :md="14" :lg="13" :xl="13"> |
|
||||
<el-card class="box-card"> |
|
||||
<div slot="header" class="clearfix"> |
|
||||
<span>字典详情</span> |
|
||||
<el-button |
|
||||
v-if="checkPer(['admin','dict:add']) && this.$refs.dictDetail && this.$refs.dictDetail.query.dictName" |
|
||||
class="filter-item" |
|
||||
size="mini" |
|
||||
style="float: right;padding: 4px 10px" |
|
||||
type="primary" |
|
||||
icon="el-icon-plus" |
|
||||
@click="$refs.dictDetail && $refs.dictDetail.crud.toAdd()" |
|
||||
>新增</el-button> |
|
||||
</div> |
|
||||
<dictDetail ref="dictDetail" :permission="permission" /> |
|
||||
</el-card> |
|
||||
</el-col> |
|
||||
</el-row> |
|
||||
</div> |
|
||||
</template> |
|
||||
|
|
||||
<script> |
|
||||
import dictDetail from './dictDetail' |
|
||||
import crudDict from '@/api/system/dict' |
|
||||
import CRUD, { presenter, header, form } from '@crud/crud' |
|
||||
import crudOperation from '@crud/CRUD.operation' |
|
||||
import pagination from '@crud/Pagination' |
|
||||
import rrOperation from '@crud/RR.operation' |
|
||||
import udOperation from '@crud/UD.operation' |
|
||||
|
|
||||
const defaultForm = { id: null, name: null, description: null, dictDetails: [] } |
|
||||
|
|
||||
export default { |
|
||||
name: 'Dict', |
|
||||
components: { crudOperation, pagination, rrOperation, udOperation, dictDetail }, |
|
||||
cruds() { |
|
||||
return [ |
|
||||
CRUD({ title: '字典', url: 'api/dict', crudMethod: { ...crudDict }}) |
|
||||
] |
|
||||
}, |
|
||||
mixins: [presenter(), header(), form(defaultForm)], |
|
||||
data() { |
|
||||
return { |
|
||||
queryTypeOptions: [ |
|
||||
{ key: 'name', display_name: '字典名称' }, |
|
||||
{ key: 'description', display_name: '描述' } |
|
||||
], |
|
||||
rules: { |
|
||||
name: [ |
|
||||
{ required: true, message: '请输入名称', trigger: 'blur' } |
|
||||
] |
|
||||
}, |
|
||||
permission: { |
|
||||
add: ['admin', 'dict:add'], |
|
||||
edit: ['admin', 'dict:edit'], |
|
||||
del: ['admin', 'dict:del'] |
|
||||
} |
|
||||
} |
|
||||
}, |
|
||||
methods: { |
|
||||
// 获取数据前设置好接口地址 |
|
||||
[CRUD.HOOK.beforeRefresh]() { |
|
||||
if (this.$refs.dictDetail) { |
|
||||
this.$refs.dictDetail.query.dictName = '' |
|
||||
} |
|
||||
return true |
|
||||
}, |
|
||||
// 选中字典后,设置字典详情数据 |
|
||||
handleCurrentChange(val) { |
|
||||
if (val) { |
|
||||
this.$refs.dictDetail.query.dictName = val.name |
|
||||
this.$refs.dictDetail.dictId = val.id |
|
||||
this.$refs.dictDetail.crud.toQuery() |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
</script> |
|
||||
|
|
||||
<style scoped> |
|
||||
</style> |
|
||||
@ -1,110 +0,0 @@ |
|||||
<template> |
|
||||
<div class="app-container"> |
|
||||
<!--工具栏--> |
|
||||
<div class="head-container"> |
|
||||
<eHeader :dict="dict" :permission="permission" /> |
|
||||
<crudOperation :permission="permission" /> |
|
||||
</div> |
|
||||
<!--表格渲染--> |
|
||||
<el-table ref="table" v-loading="crud.loading" :data="crud.data" style="width: 100%;" @selection-change="crud.selectionChangeHandler"> |
|
||||
<el-table-column type="selection" width="55" /> |
|
||||
<el-table-column prop="name" label="名称" /> |
|
||||
<el-table-column prop="jobSort" label="排序"> |
|
||||
<template slot-scope="scope"> |
|
||||
{{ scope.row.jobSort }} |
|
||||
</template> |
|
||||
</el-table-column> |
|
||||
<el-table-column prop="status" label="状态" align="center"> |
|
||||
<template slot-scope="scope"> |
|
||||
<el-switch |
|
||||
v-model="scope.row.enabled" |
|
||||
active-color="#409EFF" |
|
||||
inactive-color="#F56C6C" |
|
||||
@change="changeEnabled(scope.row, scope.row.enabled)" |
|
||||
/> |
|
||||
</template> |
|
||||
</el-table-column> |
|
||||
<el-table-column prop="createTime" label="创建日期" /> |
|
||||
<!-- 编辑与删除 --> |
|
||||
<el-table-column |
|
||||
v-if="checkPer(['admin','job:edit','job:del'])" |
|
||||
label="操作" |
|
||||
width="130px" |
|
||||
align="center" |
|
||||
fixed="right" |
|
||||
> |
|
||||
<template slot-scope="scope"> |
|
||||
<udOperation |
|
||||
:data="scope.row" |
|
||||
:permission="permission" |
|
||||
/> |
|
||||
</template> |
|
||||
</el-table-column> |
|
||||
</el-table> |
|
||||
<!--分页组件--> |
|
||||
<pagination /> |
|
||||
<!--表单渲染--> |
|
||||
<eForm :job-status="dict.job_status" /> |
|
||||
</div> |
|
||||
</template> |
|
||||
|
|
||||
<script> |
|
||||
import crudJob from '@/api/system/job' |
|
||||
import eHeader from './module/header' |
|
||||
import eForm from './module/form' |
|
||||
import CRUD, { presenter } from '@crud/crud' |
|
||||
import crudOperation from '@crud/CRUD.operation' |
|
||||
import pagination from '@crud/Pagination' |
|
||||
import udOperation from '@crud/UD.operation' |
|
||||
export default { |
|
||||
name: 'Job', |
|
||||
components: { eHeader, eForm, crudOperation, pagination, udOperation }, |
|
||||
cruds() { |
|
||||
return CRUD({ |
|
||||
title: '岗位', |
|
||||
url: 'api/job', |
|
||||
sort: ['jobSort,asc', 'id,desc'], |
|
||||
crudMethod: { ...crudJob } |
|
||||
}) |
|
||||
}, |
|
||||
mixins: [presenter()], |
|
||||
// 数据字典 |
|
||||
dicts: ['job_status'], |
|
||||
data() { |
|
||||
return { |
|
||||
permission: { |
|
||||
add: ['admin', 'job:add'], |
|
||||
edit: ['admin', 'job:edit'], |
|
||||
del: ['admin', 'job:del'] |
|
||||
} |
|
||||
} |
|
||||
}, |
|
||||
methods: { |
|
||||
// 改变状态 |
|
||||
changeEnabled(data, val) { |
|
||||
this.$confirm('此操作将 "' + this.dict.label.job_status[val] + '" ' + data.name + '岗位, 是否继续?', '提示', { |
|
||||
confirmButtonText: '确定', |
|
||||
cancelButtonText: '取消', |
|
||||
type: 'warning' |
|
||||
}).then(() => { |
|
||||
// eslint-disable-next-line no-undef |
|
||||
crudJob.edit(data).then(() => { |
|
||||
// eslint-disable-next-line no-undef |
|
||||
this.crud.notify(this.dict.label.job_status[val] + '成功', 'success') |
|
||||
}).catch(err => { |
|
||||
data.enabled = !data.enabled |
|
||||
console.log(err.data.message) |
|
||||
}) |
|
||||
}).catch(() => { |
|
||||
data.enabled = !data.enabled |
|
||||
}) |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
</script> |
|
||||
|
|
||||
<style rel="stylesheet/scss" lang="scss" scoped> |
|
||||
::v-deep .el-input-number .el-input__inner { |
|
||||
text-align: left; |
|
||||
} |
|
||||
</style> |
|
||||
@ -1,110 +0,0 @@ |
|||||
<template> |
|
||||
<el-dialog |
|
||||
append-to-body |
|
||||
:close-on-click-modal="false" |
|
||||
:before-close="crud.cancelCU" |
|
||||
:visible="crud.status.cu > 0" |
|
||||
:title="crud.status.title" |
|
||||
width="500px" |
|
||||
> |
|
||||
<el-form |
|
||||
ref="form" |
|
||||
:model="form" |
|
||||
:rules="rules" |
|
||||
size="small" |
|
||||
label-width="80px" |
|
||||
> |
|
||||
<el-form-item |
|
||||
label="名称" |
|
||||
prop="name" |
|
||||
> |
|
||||
<el-input |
|
||||
v-model="form.name" |
|
||||
style="width: 370px;" |
|
||||
/> |
|
||||
</el-form-item> |
|
||||
<el-form-item |
|
||||
label="排序" |
|
||||
prop="jobSort" |
|
||||
> |
|
||||
<el-input-number |
|
||||
v-model.number="form.jobSort" |
|
||||
:min="0" |
|
||||
:max="999" |
|
||||
controls-position="right" |
|
||||
style="width: 370px;" |
|
||||
/> |
|
||||
</el-form-item> |
|
||||
<el-form-item |
|
||||
v-if="form.pid !== 0" |
|
||||
label="状态" |
|
||||
prop="enabled" |
|
||||
> |
|
||||
<el-radio |
|
||||
v-for="item in jobStatus" |
|
||||
:key="item.id" |
|
||||
v-model="form.enabled" |
|
||||
:label="item.value === 'true'" |
|
||||
> |
|
||||
{{ item.label }} |
|
||||
</el-radio> |
|
||||
</el-form-item> |
|
||||
</el-form> |
|
||||
<div |
|
||||
slot="footer" |
|
||||
class="dialog-footer" |
|
||||
> |
|
||||
<el-button |
|
||||
type="text" |
|
||||
@click="crud.cancelCU" |
|
||||
> |
|
||||
取消 |
|
||||
</el-button> |
|
||||
<el-button |
|
||||
:loading="crud.status.cu === 2" |
|
||||
type="primary" |
|
||||
@click="crud.submitCU" |
|
||||
> |
|
||||
确认 |
|
||||
</el-button> |
|
||||
</div> |
|
||||
</el-dialog> |
|
||||
</template> |
|
||||
|
|
||||
<script> |
|
||||
import { form } from '@crud/crud' |
|
||||
|
|
||||
const defaultForm = { |
|
||||
id: null, |
|
||||
name: '', |
|
||||
jobSort: 999, |
|
||||
enabled: true |
|
||||
} |
|
||||
export default { |
|
||||
mixins: [form(defaultForm)], |
|
||||
props: { |
|
||||
jobStatus: { |
|
||||
type: Array, |
|
||||
required: true |
|
||||
} |
|
||||
}, |
|
||||
data() { |
|
||||
return { |
|
||||
rules: { |
|
||||
name: [ |
|
||||
{ required: true, message: '请输入名称', trigger: 'blur' } |
|
||||
], |
|
||||
jobSort: [ |
|
||||
{ required: true, message: '请输入序号', trigger: 'blur', type: 'number' } |
|
||||
] |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
</script> |
|
||||
|
|
||||
<style rel="stylesheet/scss" lang="scss" scoped> |
|
||||
::v-deep .el-input-number .el-input__inner { |
|
||||
text-align: left; |
|
||||
} |
|
||||
</style> |
|
||||
@ -1,32 +0,0 @@ |
|||||
<template> |
|
||||
<div |
|
||||
v-if="crud.props.searchToggle" |
|
||||
> |
|
||||
<el-input v-model="query.name" clearable size="small" placeholder="输入岗位名称搜索" style="width: 200px;" class="filter-item" @keyup.enter.native="crud.toQuery" /> |
|
||||
<date-range-picker v-model="query.createTime" class="date-item" /> |
|
||||
<el-select v-model="query.enabled" clearable size="small" placeholder="状态" class="filter-item" style="width: 90px" @change="crud.toQuery"> |
|
||||
<el-option v-for="item in dict.dict.job_status" :key="item.value" :label="item.label" :value="item.value" /> |
|
||||
</el-select> |
|
||||
<rrOperation /> |
|
||||
</div> |
|
||||
</template> |
|
||||
|
|
||||
<script> |
|
||||
import { header } from '@crud/crud' |
|
||||
import rrOperation from '@crud/RR.operation' |
|
||||
import DateRangePicker from '@/components/DateRangePicker' |
|
||||
export default { |
|
||||
components: { rrOperation, DateRangePicker }, |
|
||||
mixins: [header()], |
|
||||
props: { |
|
||||
dict: { |
|
||||
type: Object, |
|
||||
required: true |
|
||||
}, |
|
||||
permission: { |
|
||||
type: Object, |
|
||||
required: true |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
</script> |
|
||||
@ -1,210 +0,0 @@ |
|||||
<template> |
|
||||
<div class="app-container"> |
|
||||
<!--工具栏--> |
|
||||
<div class="head-container"> |
|
||||
<div v-if="crud.props.searchToggle"> |
|
||||
<!-- 搜索 --> |
|
||||
<el-input v-model="query.jobName" clearable size="small" placeholder="输入任务名称搜索" style="width: 200px;" class="filter-item" @keyup.enter.native="toQuery" /> |
|
||||
<date-range-picker v-model="query.createTime" class="date-item" /> |
|
||||
<rrOperation /> |
|
||||
</div> |
|
||||
<crudOperation :permission="permission"> |
|
||||
<!-- 任务日志 --> |
|
||||
<el-button |
|
||||
slot="right" |
|
||||
class="filter-item" |
|
||||
size="mini" |
|
||||
type="info" |
|
||||
icon="el-icon-tickets" |
|
||||
@click="doLog" |
|
||||
>日志</el-button> |
|
||||
</crudOperation> |
|
||||
<Log ref="log" /> |
|
||||
</div> |
|
||||
<!--Form表单--> |
|
||||
<el-dialog :close-on-click-modal="false" :before-close="crud.cancelCU" :visible.sync="crud.status.cu > 0" :title="crud.status.title" append-to-body width="730px"> |
|
||||
<el-form ref="form" :inline="true" :model="form" :rules="rules" size="small" label-width="100px"> |
|
||||
<el-form-item label="任务名称" prop="jobName"> |
|
||||
<el-input v-model="form.jobName" style="width: 220px;" /> |
|
||||
</el-form-item> |
|
||||
<el-form-item label="任务描述" prop="description"> |
|
||||
<el-input v-model="form.description" style="width: 220px;" /> |
|
||||
</el-form-item> |
|
||||
<el-form-item label="Bean名称" prop="beanName"> |
|
||||
<el-input v-model="form.beanName" style="width: 220px;" /> |
|
||||
</el-form-item> |
|
||||
<el-form-item label="执行方法" prop="methodName"> |
|
||||
<el-input v-model="form.methodName" style="width: 220px;" /> |
|
||||
</el-form-item> |
|
||||
<el-form-item label="Cron表达式" prop="cronExpression"> |
|
||||
<el-input v-model="form.cronExpression" style="width: 220px;" /> |
|
||||
</el-form-item> |
|
||||
<el-form-item label="子任务ID"> |
|
||||
<el-input v-model="form.subTask" placeholder="多个用逗号隔开,按顺序执行" style="width: 220px;" /> |
|
||||
</el-form-item> |
|
||||
<el-form-item label="任务负责人" prop="personInCharge"> |
|
||||
<el-input v-model="form.personInCharge" style="width: 220px;" /> |
|
||||
</el-form-item> |
|
||||
<el-form-item label="告警邮箱" prop="email"> |
|
||||
<el-input v-model="form.email" placeholder="多个邮箱用逗号隔开" style="width: 220px;" /> |
|
||||
</el-form-item> |
|
||||
<el-form-item label="失败后暂停"> |
|
||||
<el-radio-group v-model="form.pauseAfterFailure" style="width: 220px"> |
|
||||
<el-radio :label="true">是</el-radio> |
|
||||
<el-radio :label="false">否</el-radio> |
|
||||
</el-radio-group> |
|
||||
</el-form-item> |
|
||||
<el-form-item label="任务状态"> |
|
||||
<el-radio-group v-model="form.isPause" style="width: 220px"> |
|
||||
<el-radio :label="false">启用</el-radio> |
|
||||
<el-radio :label="true">暂停</el-radio> |
|
||||
</el-radio-group> |
|
||||
</el-form-item> |
|
||||
<el-form-item label="参数内容"> |
|
||||
<el-input v-model="form.params" style="width: 556px;" rows="4" type="textarea" /> |
|
||||
</el-form-item> |
|
||||
</el-form> |
|
||||
<div slot="footer" class="dialog-footer"> |
|
||||
<el-button type="text" @click="crud.cancelCU">取消</el-button> |
|
||||
<el-button :loading="crud.status.cu === 2" type="primary" @click="crud.submitCU">确认</el-button> |
|
||||
</div> |
|
||||
</el-dialog> |
|
||||
<!--表格渲染--> |
|
||||
<el-table ref="table" v-loading="crud.loading" :data="crud.data" style="width: 100%;" @selection-change="crud.selectionChangeHandler"> |
|
||||
<el-table-column :selectable="checkboxT" type="selection" width="55" /> |
|
||||
<el-table-column :show-overflow-tooltip="true" prop="id" label="任务ID" /> |
|
||||
<el-table-column :show-overflow-tooltip="true" prop="jobName" label="任务名称" /> |
|
||||
<el-table-column :show-overflow-tooltip="true" prop="beanName" label="Bean名称" /> |
|
||||
<el-table-column :show-overflow-tooltip="true" prop="methodName" label="执行方法" /> |
|
||||
<el-table-column :show-overflow-tooltip="true" prop="params" label="参数" /> |
|
||||
<el-table-column :show-overflow-tooltip="true" prop="cronExpression" label="cron表达式" /> |
|
||||
<el-table-column :show-overflow-tooltip="true" prop="isPause" width="90px" label="状态"> |
|
||||
<template slot-scope="scope"> |
|
||||
<el-tag :type="scope.row.isPause ? 'warning' : 'success'">{{ scope.row.isPause ? '已暂停' : '运行中' }}</el-tag> |
|
||||
</template> |
|
||||
</el-table-column> |
|
||||
<el-table-column :show-overflow-tooltip="true" prop="description" width="150px" label="描述" /> |
|
||||
<el-table-column :show-overflow-tooltip="true" prop="createTime" width="136px" label="创建日期" /> |
|
||||
<el-table-column v-if="checkPer(['admin','timing:edit','timing:del'])" label="操作" width="170px" align="center" fixed="right"> |
|
||||
<template slot-scope="scope"> |
|
||||
<el-button v-permission="['admin','timing:edit']" size="mini" style="margin-right: 3px;" type="text" @click="crud.toEdit(scope.row)">编辑</el-button> |
|
||||
<el-button v-permission="['admin','timing:edit']" style="margin-left: -2px" type="text" size="mini" @click="execute(scope.row.id)">执行</el-button> |
|
||||
<el-button v-permission="['admin','timing:edit']" style="margin-left: 3px" type="text" size="mini" @click="updateStatus(scope.row.id,scope.row.isPause ? '恢复' : '暂停')"> |
|
||||
{{ scope.row.isPause ? '恢复' : '暂停' }} |
|
||||
</el-button> |
|
||||
<el-popover |
|
||||
:ref="scope.row.id" |
|
||||
v-permission="['admin','timing:del']" |
|
||||
placement="top" |
|
||||
width="200" |
|
||||
> |
|
||||
<p>确定停止并删除该任务吗?</p> |
|
||||
<div style="text-align: right; margin: 0"> |
|
||||
<el-button size="mini" type="text" @click="$refs[scope.row.id].doClose()">取消</el-button> |
|
||||
<el-button :loading="delLoading" type="primary" size="mini" @click="delMethod(scope.row.id)">确定</el-button> |
|
||||
</div> |
|
||||
<el-button slot="reference" type="text" size="mini">删除</el-button> |
|
||||
</el-popover> |
|
||||
</template> |
|
||||
</el-table-column> |
|
||||
</el-table> |
|
||||
<!--分页组件--> |
|
||||
<pagination /> |
|
||||
</div> |
|
||||
</template> |
|
||||
|
|
||||
<script> |
|
||||
import crudJob from '@/api/system/timing' |
|
||||
import Log from './log' |
|
||||
import CRUD, { presenter, header, form, crud } from '@crud/crud' |
|
||||
import rrOperation from '@crud/RR.operation' |
|
||||
import crudOperation from '@crud/CRUD.operation' |
|
||||
import pagination from '@crud/Pagination' |
|
||||
import DateRangePicker from '@/components/DateRangePicker' |
|
||||
|
|
||||
const defaultForm = { id: null, jobName: null, subTask: null, beanName: null, methodName: null, params: null, cronExpression: null, pauseAfterFailure: true, isPause: false, personInCharge: null, email: null, description: null } |
|
||||
export default { |
|
||||
name: 'Timing', |
|
||||
components: { Log, pagination, crudOperation, rrOperation, DateRangePicker }, |
|
||||
cruds() { |
|
||||
return CRUD({ title: '定时任务', url: 'api/jobs', crudMethod: { ...crudJob }}) |
|
||||
}, |
|
||||
mixins: [presenter(), header(), form(defaultForm), crud()], |
|
||||
data() { |
|
||||
return { |
|
||||
delLoading: false, |
|
||||
permission: { |
|
||||
add: ['admin', 'timing:add'], |
|
||||
edit: ['admin', 'timing:edit'], |
|
||||
del: ['admin', 'timing:del'] |
|
||||
}, |
|
||||
rules: { |
|
||||
jobName: [ |
|
||||
{ required: true, message: '请输入任务名称', trigger: 'blur' } |
|
||||
], |
|
||||
description: [ |
|
||||
{ required: true, message: '请输入任务描述', trigger: 'blur' } |
|
||||
], |
|
||||
beanName: [ |
|
||||
{ required: true, message: '请输入Bean名称', trigger: 'blur' } |
|
||||
], |
|
||||
methodName: [ |
|
||||
{ required: true, message: '请输入方法名称', trigger: 'blur' } |
|
||||
], |
|
||||
cronExpression: [ |
|
||||
{ required: true, message: '请输入Cron表达式', trigger: 'blur' } |
|
||||
], |
|
||||
personInCharge: [ |
|
||||
{ required: true, message: '请输入负责人名称', trigger: 'blur' } |
|
||||
] |
|
||||
} |
|
||||
} |
|
||||
}, |
|
||||
methods: { |
|
||||
// 执行 |
|
||||
execute(id) { |
|
||||
crudJob.execution(id).then(res => { |
|
||||
this.crud.notify('执行成功', CRUD.NOTIFICATION_TYPE.SUCCESS) |
|
||||
}).catch(err => { |
|
||||
console.log(err.response.data.message) |
|
||||
}) |
|
||||
}, |
|
||||
// 改变状态 |
|
||||
updateStatus(id, status) { |
|
||||
if (status === '恢复') { |
|
||||
this.updateParams(id) |
|
||||
} |
|
||||
crudJob.updateIsPause(id).then(res => { |
|
||||
this.crud.toQuery() |
|
||||
this.crud.notify(status + '成功', CRUD.NOTIFICATION_TYPE.SUCCESS) |
|
||||
}).catch(err => { |
|
||||
console.log(err.response.data.message) |
|
||||
}) |
|
||||
}, |
|
||||
updateParams(id) { |
|
||||
console.log(id) |
|
||||
}, |
|
||||
delMethod(id) { |
|
||||
this.delLoading = true |
|
||||
crudJob.del([id]).then(() => { |
|
||||
this.delLoading = false |
|
||||
this.$refs[id].doClose() |
|
||||
this.crud.dleChangePage(1) |
|
||||
this.crud.delSuccessNotify() |
|
||||
this.crud.toQuery() |
|
||||
}).catch(() => { |
|
||||
this.delLoading = false |
|
||||
this.$refs[id].doClose() |
|
||||
}) |
|
||||
}, |
|
||||
// 显示日志 |
|
||||
doLog() { |
|
||||
this.$refs.log.dialog = true |
|
||||
this.$refs.log.doInit() |
|
||||
}, |
|
||||
checkboxT(row, rowIndex) { |
|
||||
return row.id !== 1 |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
</script> |
|
||||
@ -1,104 +0,0 @@ |
|||||
<template> |
|
||||
<el-dialog :visible.sync="dialog" append-to-body title="执行日志" width="88%"> |
|
||||
<!-- 搜索 --> |
|
||||
<div class="head-container"> |
|
||||
<el-input v-model="query.jobName" clearable size="small" placeholder="输入任务名称搜索" style="width: 200px;" class="filter-item" @keyup.enter.native="toQuery" /> |
|
||||
<date-range-picker v-model="query.createTime" class="date-item" /> |
|
||||
<el-select v-model="query.isSuccess" placeholder="日志状态" clearable size="small" class="filter-item" style="width: 110px" @change="toQuery"> |
|
||||
<el-option v-for="item in enabledTypeOptions" :key="item.key" :label="item.display_name" :value="item.key" /> |
|
||||
</el-select> |
|
||||
<el-button class="filter-item" size="mini" type="success" icon="el-icon-search" @click="toQuery">搜索</el-button> |
|
||||
<!-- 导出 --> |
|
||||
<div style="display: inline-block;"> |
|
||||
<el-button |
|
||||
:loading="downloadLoading" |
|
||||
size="mini" |
|
||||
class="filter-item" |
|
||||
type="warning" |
|
||||
icon="el-icon-download" |
|
||||
@click="downloadMethod" |
|
||||
>导出</el-button> |
|
||||
</div> |
|
||||
</div> |
|
||||
<!--表格渲染--> |
|
||||
<el-table v-loading="loading" :data="data" style="width: 100%;margin-top: -10px;"> |
|
||||
<el-table-column :show-overflow-tooltip="true" prop="jobName" label="任务名称" /> |
|
||||
<el-table-column :show-overflow-tooltip="true" prop="beanName" label="Bean名称" /> |
|
||||
<el-table-column :show-overflow-tooltip="true" prop="methodName" label="执行方法" /> |
|
||||
<el-table-column :show-overflow-tooltip="true" prop="params" width="120px" label="参数" /> |
|
||||
<el-table-column :show-overflow-tooltip="true" prop="cronExpression" label="cron表达式" /> |
|
||||
<el-table-column prop="createTime" label="异常详情" width="110px"> |
|
||||
<template slot-scope="scope"> |
|
||||
<el-button v-show="scope.row.exceptionDetail" size="mini" type="text" @click="info(scope.row.exceptionDetail)">查看详情</el-button> |
|
||||
</template> |
|
||||
</el-table-column> |
|
||||
<el-table-column :show-overflow-tooltip="true" align="center" prop="time" width="100px" label="耗时(毫秒)" /> |
|
||||
<el-table-column align="center" prop="isSuccess" width="80px" label="状态"> |
|
||||
<template slot-scope="scope"> |
|
||||
<el-tag :type="scope.row.isSuccess ? 'success' : 'danger'">{{ scope.row.isSuccess ? '成功' : '失败' }}</el-tag> |
|
||||
</template> |
|
||||
</el-table-column> |
|
||||
<el-table-column :show-overflow-tooltip="true" prop="createTime" label="创建日期" /> |
|
||||
</el-table> |
|
||||
<el-dialog :visible.sync="errorDialog" append-to-body title="异常详情" width="85%"> |
|
||||
<pre v-highlightjs="errorInfo"><code class="java" /></pre> |
|
||||
</el-dialog> |
|
||||
<!--分页组件--> |
|
||||
<el-pagination |
|
||||
:total="total" |
|
||||
:current-page="page + 1" |
|
||||
:page-size="6" |
|
||||
style="margin-top:8px;" |
|
||||
layout="total, prev, pager, next" |
|
||||
@size-change="sizeChange" |
|
||||
@current-change="pageChange" |
|
||||
/> |
|
||||
</el-dialog> |
|
||||
</template> |
|
||||
|
|
||||
<script> |
|
||||
import crud from '@/mixins/crud' |
|
||||
import DateRangePicker from '@/components/DateRangePicker' |
|
||||
export default { |
|
||||
components: { DateRangePicker }, |
|
||||
mixins: [crud], |
|
||||
data() { |
|
||||
return { |
|
||||
title: '任务日志', |
|
||||
errorInfo: '', errorDialog: false, |
|
||||
enabledTypeOptions: [ |
|
||||
{ key: 'true', display_name: '成功' }, |
|
||||
{ key: 'false', display_name: '失败' } |
|
||||
] |
|
||||
} |
|
||||
}, |
|
||||
methods: { |
|
||||
doInit() { |
|
||||
this.$nextTick(() => { |
|
||||
this.init() |
|
||||
}) |
|
||||
}, |
|
||||
// 获取数据前设置好接口地址 |
|
||||
beforeInit() { |
|
||||
this.url = 'api/jobs/logs' |
|
||||
this.size = 6 |
|
||||
return true |
|
||||
}, |
|
||||
// 异常详情 |
|
||||
info(errorInfo) { |
|
||||
this.errorInfo = errorInfo |
|
||||
this.errorDialog = true |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
</script> |
|
||||
|
|
||||
<style scoped> |
|
||||
.java.hljs{ |
|
||||
color: #444; |
|
||||
background: #ffffff !important; |
|
||||
} |
|
||||
::v-deep .el-dialog__body{ |
|
||||
padding: 0 20px 10px 20px !important; |
|
||||
} |
|
||||
</style> |
|
||||
@ -1,98 +0,0 @@ |
|||||
<template> |
|
||||
<el-form ref="form" :model="form" :rules="rules" style="margin-top: 6px;" size="small" label-width="100px"> |
|
||||
<el-form-item label="appID" prop="appId"> |
|
||||
<el-input v-model="form.appId" style="width: 40%" /> |
|
||||
<span style="color: #C0C0C0;margin-left: 10px;">应用APPID,收款账号既是APPID对应支付宝账号</span> |
|
||||
</el-form-item> |
|
||||
<el-form-item label="商家账号" prop="sysServiceProviderId"> |
|
||||
<el-input v-model="form.sysServiceProviderId" style="width: 40%;" /> |
|
||||
<span style="color: #C0C0C0;margin-left: 10px;">商家账号</span> |
|
||||
</el-form-item> |
|
||||
<el-form-item label="商户私钥" prop="privateKey"> |
|
||||
<el-input v-model="form.privateKey" type="password" style="width: 40%;" /> |
|
||||
<span style="color: #C0C0C0;margin-left: 10px;">商户私钥,你的PKCS8格式RSA2私钥</span> |
|
||||
</el-form-item> |
|
||||
<el-form-item label="支付宝公钥" prop="publicKey"> |
|
||||
<el-input v-model="form.publicKey" type="password" style="width: 40%;" /> |
|
||||
<span style="color: #C0C0C0;margin-left: 10px;">支付宝公钥</span> |
|
||||
</el-form-item> |
|
||||
<el-form-item label="回调地址" prop="returnUrl"> |
|
||||
<el-input v-model="form.returnUrl" style="width: 40%;" /> |
|
||||
<span style="color: #C0C0C0;margin-left: 10px;">订单完成后返回的地址</span> |
|
||||
</el-form-item> |
|
||||
<el-form-item label="异步通知" prop="notifyUrl"> |
|
||||
<el-input v-model="form.notifyUrl" style="width: 40%;" /> |
|
||||
<span style="color: #C0C0C0;margin-left: 10px;">支付结果异步通知地址</span> |
|
||||
</el-form-item> |
|
||||
<el-form-item label=""> |
|
||||
<el-button :loading="loading" size="medium" type="primary" @click="doSubmit">保存配置</el-button> |
|
||||
</el-form-item> |
|
||||
</el-form> |
|
||||
</template> |
|
||||
|
|
||||
<script> |
|
||||
import { get, update } from '@/api/tools/alipay' |
|
||||
export default { |
|
||||
name: 'Config', |
|
||||
data() { |
|
||||
return { |
|
||||
loading: false, |
|
||||
form: { appId: '', sysServiceProviderId: '', privateKey: '', publicKey: '', returnUrl: '', notifyUrl: '' }, |
|
||||
rules: { |
|
||||
appId: [ |
|
||||
{ required: true, message: '请输入appID', trigger: 'blur' } |
|
||||
], |
|
||||
sysServiceProviderId: [ |
|
||||
{ required: true, message: '请输入商家账号', trigger: 'blur' } |
|
||||
], |
|
||||
privateKey: [ |
|
||||
{ required: true, message: '商户私钥不能为空', trigger: 'blur' } |
|
||||
], |
|
||||
publicKey: [ |
|
||||
{ required: true, message: '支付宝公钥不能为空', trigger: 'blur' } |
|
||||
], |
|
||||
returnUrl: [ |
|
||||
{ required: true, message: '回调地址不能为空', trigger: 'blur' } |
|
||||
], |
|
||||
notifyUrl: [ |
|
||||
{ required: true, message: '回调地址不能为空', trigger: 'blur' } |
|
||||
] |
|
||||
} |
|
||||
} |
|
||||
}, |
|
||||
created() { |
|
||||
this.init() |
|
||||
}, |
|
||||
methods: { |
|
||||
init() { |
|
||||
get().then(res => { |
|
||||
this.form = res |
|
||||
}) |
|
||||
}, |
|
||||
doSubmit() { |
|
||||
this.$refs['form'].validate((valid) => { |
|
||||
if (valid) { |
|
||||
this.loading = true |
|
||||
update(this.form).then(res => { |
|
||||
this.$notify({ |
|
||||
title: '修改成功', |
|
||||
type: 'success', |
|
||||
duration: 2500 |
|
||||
}) |
|
||||
this.loading = false |
|
||||
}).catch(err => { |
|
||||
this.loading = false |
|
||||
console.log(err.response.data.message) |
|
||||
}) |
|
||||
} else { |
|
||||
return false |
|
||||
} |
|
||||
}) |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
</script> |
|
||||
|
|
||||
<style scoped> |
|
||||
|
|
||||
</style> |
|
||||
@ -1,48 +0,0 @@ |
|||||
<template> |
|
||||
<el-tabs v-model="activeName" style="padding-left: 5px;"> |
|
||||
<el-tab-pane label="参数配置" name="first"> |
|
||||
<Config /> |
|
||||
</el-tab-pane> |
|
||||
<el-tab-pane label="支付测试" name="second"> |
|
||||
<ToPay /> |
|
||||
</el-tab-pane> |
|
||||
<el-tab-pane label="使用说明" name="third"> |
|
||||
<div> |
|
||||
<blockquote class="my-blockquote">注意</blockquote> |
|
||||
<pre class="my-code"> |
|
||||
测试所用参数都是沙箱环境,仅供测试使用,申请地址:<a style="color: #00a0e9" href="https://openhome.alipay.com/platform/appDaily.htm?tab=info" target="_blank">支付宝开发平台</a> |
|
||||
如需付款测试,请使用 |
|
||||
账号:uuxesw9745@sandbox.com |
|
||||
密码与支付密码:111111</pre> |
|
||||
<blockquote class="my-blockquote"> 支付设置</blockquote> |
|
||||
<pre class="my-code"> |
|
||||
// 支付提供两个接口, |
|
||||
// PC端与手机端,并且在前端使用代码识别 |
|
||||
if (/(Android)/i.test(navigator.userAgent)){ // 判断是否为Android手机 |
|
||||
url = "/aliPay/toPayAsWeb" |
|
||||
}else if(/(iPhone|iPad|iPod|iOS)/i.test(navigator.userAgent)){ // 判断是否为苹果手机 |
|
||||
url = "/aliPay/toPayAsWeb" |
|
||||
} else { |
|
||||
url = "/aliPay/toPayAsPC" |
|
||||
}</pre> |
|
||||
</div> |
|
||||
</el-tab-pane> |
|
||||
</el-tabs> |
|
||||
</template> |
|
||||
|
|
||||
<script> |
|
||||
import Config from './config' |
|
||||
import ToPay from './toPay' |
|
||||
export default { |
|
||||
name: 'AliPay', |
|
||||
components: { Config, ToPay }, |
|
||||
data() { |
|
||||
return { |
|
||||
activeName: 'second' |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
</script> |
|
||||
|
|
||||
<style scoped> |
|
||||
</style> |
|
||||
@ -1,86 +0,0 @@ |
|||||
<template> |
|
||||
<div> |
|
||||
<el-form ref="form" :model="form" :rules="rules" style="margin-top: 6px;" size="small" label-width="90px"> |
|
||||
<el-form-item label="商品名称" prop="subject"> |
|
||||
<el-input v-model="form.subject" style="width: 35%" /> |
|
||||
</el-form-item> |
|
||||
<el-form-item label="商品价格" prop="totalAmount"> |
|
||||
<el-input v-model="form.totalAmount" style="width: 35%" /> |
|
||||
<span style="color: #C0C0C0;margin-left: 10px;">测试允许区间(0,5000]</span> |
|
||||
</el-form-item> |
|
||||
<el-form-item label="商品描述" prop="body"> |
|
||||
<el-input v-model="form.body" style="width: 35%" rows="8" type="textarea" /> |
|
||||
</el-form-item> |
|
||||
<el-form-item label=""> |
|
||||
<el-button :loading="loading" size="medium" type="primary" @click="doSubmit">去支付</el-button> |
|
||||
</el-form-item> |
|
||||
</el-form> |
|
||||
</div> |
|
||||
</template> |
|
||||
|
|
||||
<script> |
|
||||
import { toAliPay } from '@/api/tools/alipay' |
|
||||
export default { |
|
||||
data() { |
|
||||
return { |
|
||||
url: '', |
|
||||
// 新窗口的引用 |
|
||||
newWin: null, |
|
||||
loading: false, form: { subject: '', totalAmount: '', body: '' }, |
|
||||
rules: { |
|
||||
subject: [ |
|
||||
{ required: true, message: '商品名称不能为空', trigger: 'blur' } |
|
||||
], |
|
||||
totalAmount: [ |
|
||||
{ required: true, message: '商品价格不能为空', trigger: 'blur' } |
|
||||
], |
|
||||
body: [ |
|
||||
{ required: true, message: '商品描述不能为空', trigger: 'blur' } |
|
||||
] |
|
||||
} |
|
||||
} |
|
||||
}, |
|
||||
watch: { |
|
||||
url(newVal, oldVal) { |
|
||||
if (newVal && this.newWin) { |
|
||||
this.newWin.sessionStorage.clear() |
|
||||
this.newWin.location.href = newVal |
|
||||
// 重定向后把url和newWin重置 |
|
||||
this.url = '' |
|
||||
this.newWin = null |
|
||||
} |
|
||||
} |
|
||||
}, |
|
||||
methods: { |
|
||||
doSubmit() { |
|
||||
this.$refs['form'].validate((valid) => { |
|
||||
if (valid) { |
|
||||
this.loading = true |
|
||||
// 先打开一个空的新窗口,再请求 |
|
||||
this.newWin = window.open() |
|
||||
let url = '' |
|
||||
if (/(Android)/i.test(navigator.userAgent)) { // 判断是否为Android手机 |
|
||||
url = 'aliPay/toPayAsWeb' |
|
||||
} else if (/(iPhone|iPad|iPod|iOS)/i.test(navigator.userAgent)) { // 判断是否为苹果手机 |
|
||||
url = 'aliPay/toPayAsWeb' |
|
||||
} else { |
|
||||
url = 'aliPay/toPayAsPC' |
|
||||
} |
|
||||
toAliPay(url, this.form).then(res => { |
|
||||
this.loading = false |
|
||||
this.url = res |
|
||||
}).catch(err => { |
|
||||
this.loading = false |
|
||||
console.log(err.response.data.message) |
|
||||
}) |
|
||||
} else { |
|
||||
return false |
|
||||
} |
|
||||
}) |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
</script> |
|
||||
|
|
||||
<style scoped> |
|
||||
</style> |
|
||||
@ -1,91 +0,0 @@ |
|||||
<template> |
|
||||
<el-form ref="form" :model="form" :rules="rules" style="margin-top: 6px;" size="small" label-width="100px"> |
|
||||
<el-form-item label="发件人邮箱" prop="fromUser"> |
|
||||
<el-input v-model="form.fromUser" style="width: 40%" /> |
|
||||
<span style="color: #C0C0C0;margin-left: 10px;">Sender mailbox</span> |
|
||||
</el-form-item> |
|
||||
<el-form-item label="发件用户名" prop="user"> |
|
||||
<el-input v-model="form.user" style="width: 40%;" /> |
|
||||
<span style="color: #C0C0C0;margin-left: 10px;">Sender usernamex</span> |
|
||||
</el-form-item> |
|
||||
<el-form-item label="邮箱密码" prop="pass"> |
|
||||
<el-input v-model="form.pass" type="password" style="width: 40%;" /> |
|
||||
<span style="color: #C0C0C0;margin-left: 10px;">email Password</span> |
|
||||
</el-form-item> |
|
||||
<el-form-item label="SMTP地址" prop="host"> |
|
||||
<el-input v-model="form.host" style="width: 40%;" /> |
|
||||
<span style="color: #C0C0C0;margin-left: 10px;">SMTP address</span> |
|
||||
</el-form-item> |
|
||||
<el-form-item label="SMTP端口" prop="port"> |
|
||||
<el-input v-model="form.port" style="width: 40%;" /> |
|
||||
<span style="color: #C0C0C0;margin-left: 10px;">SMTP port</span> |
|
||||
</el-form-item> |
|
||||
<el-form-item label=""> |
|
||||
<el-button :loading="loading" size="medium" type="primary" @click="doSubmit">保存配置</el-button> |
|
||||
</el-form-item> |
|
||||
</el-form> |
|
||||
</template> |
|
||||
|
|
||||
<script> |
|
||||
import { get, update } from '@/api/tools/email' |
|
||||
export default { |
|
||||
name: 'Config', |
|
||||
data() { |
|
||||
return { |
|
||||
loading: false, form: { id: 1, fromUser: '', user: '', pass: '', host: '', port: '', sslEnable: '' }, |
|
||||
rules: { |
|
||||
fromUser: [ |
|
||||
{ required: true, message: '请输入发件人邮箱', trigger: 'blur' }, |
|
||||
{ type: 'email', message: '请输入正确的邮箱地址', trigger: 'blur' } |
|
||||
], |
|
||||
user: [ |
|
||||
{ required: true, message: '请输入发件用户名', trigger: 'blur' } |
|
||||
], |
|
||||
pass: [ |
|
||||
{ required: true, message: '密码不能为空', trigger: 'blur' } |
|
||||
], |
|
||||
host: [ |
|
||||
{ required: true, message: 'SMTP地址不能为空', trigger: 'blur' } |
|
||||
], |
|
||||
port: [ |
|
||||
{ required: true, message: 'SMTP端口不能为空', trigger: 'blur' } |
|
||||
] |
|
||||
} |
|
||||
} |
|
||||
}, |
|
||||
created() { |
|
||||
this.init() |
|
||||
}, |
|
||||
methods: { |
|
||||
init() { |
|
||||
get().then(res => { |
|
||||
this.form = res |
|
||||
}) |
|
||||
}, |
|
||||
doSubmit() { |
|
||||
this.$refs['form'].validate((valid) => { |
|
||||
if (valid) { |
|
||||
this.loading = true |
|
||||
update(this.form).then(res => { |
|
||||
this.$notify({ |
|
||||
title: '修改成功', |
|
||||
type: 'success', |
|
||||
duration: 2500 |
|
||||
}) |
|
||||
this.loading = false |
|
||||
}).catch(err => { |
|
||||
this.loading = false |
|
||||
console.log(err.response.data.message) |
|
||||
}) |
|
||||
} else { |
|
||||
return false |
|
||||
} |
|
||||
}) |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
</script> |
|
||||
|
|
||||
<style scoped> |
|
||||
|
|
||||
</style> |
|
||||
@ -1,41 +0,0 @@ |
|||||
<template> |
|
||||
<el-tabs v-model="activeName" style="padding-left: 8px;"> |
|
||||
<el-tab-pane label="邮箱配置" name="first"> |
|
||||
<Config /> |
|
||||
</el-tab-pane> |
|
||||
<el-tab-pane label="发送邮件" name="second"> |
|
||||
<Send /> |
|
||||
</el-tab-pane> |
|
||||
<el-tab-pane label="使用说明" name="third"> |
|
||||
<div> |
|
||||
<blockquote class="my-blockquote"> 邮件服务器配置</blockquote> |
|
||||
<pre class="my-code"> |
|
||||
# 邮件服务器的SMTP地址,可选,默认为smtp |
|
||||
# 邮件服务器的SMTP端口,可选,默认465或者25 |
|
||||
# 发件人(必须正确,否则发送失败) |
|
||||
# 用户名,默认为发件人邮箱前缀 |
|
||||
# 密码(注意,某些邮箱需要为SMTP服务单独设置密码,如QQ和163等等) |
|
||||
# 是否开启ssl,默认开启</pre> |
|
||||
<blockquote class="my-blockquote">更多帮助</blockquote> |
|
||||
<pre class="my-code">更多帮助请查看文档:<a style="color:#009688" href="http://hutool.mydoc.io/#text_319499" target="_black">hutool工具包</a></pre> |
|
||||
</div> |
|
||||
</el-tab-pane> |
|
||||
</el-tabs> |
|
||||
</template> |
|
||||
|
|
||||
<script> |
|
||||
import Config from './config' |
|
||||
import Send from './send' |
|
||||
export default { |
|
||||
name: 'Email', |
|
||||
components: { Config, Send }, |
|
||||
data() { |
|
||||
return { |
|
||||
activeName: 'second' |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
</script> |
|
||||
|
|
||||
<style scoped> |
|
||||
</style> |
|
||||
@ -1,142 +0,0 @@ |
|||||
<template> |
|
||||
<div> |
|
||||
<el-form ref="form" :model="form" :rules="rules" style="margin-top: 6px;" size="small" label-width="100px"> |
|
||||
<el-form-item label="邮件标题" prop="subject"> |
|
||||
<el-input v-model="form.subject" style="width: 646px" /> |
|
||||
</el-form-item> |
|
||||
<el-form-item |
|
||||
v-for="(domain, index) in tos" |
|
||||
:key="domain.key" |
|
||||
:label="'收件邮箱' + (index === 0 ? '': index)" |
|
||||
> |
|
||||
<el-input v-model="domain.value" style="width: 550px" /> |
|
||||
<el-button icon="el-icon-plus" @click="addDomain" /> |
|
||||
<el-button style="margin-left:0;" icon="el-icon-minus" @click.prevent="removeDomain(domain)" /> |
|
||||
</el-form-item> |
|
||||
<div ref="editor" class="editor" /> |
|
||||
<el-button :loading="loading" style="margin-left:1.6%;" size="medium" type="primary" @click="doSubmit">发送邮件</el-button> |
|
||||
</el-form> |
|
||||
</div> |
|
||||
</template> |
|
||||
|
|
||||
<script> |
|
||||
import { send } from '@/api/tools/email' |
|
||||
import { upload } from '@/utils/upload' |
|
||||
import { validEmail } from '@/utils/validate' |
|
||||
import { mapGetters } from 'vuex' |
|
||||
import E from 'wangeditor' |
|
||||
export default { |
|
||||
name: 'Index', |
|
||||
data() { |
|
||||
return { |
|
||||
loading: false, form: { subject: '', tos: [], content: '' }, |
|
||||
tos: [{ |
|
||||
value: '' |
|
||||
}], |
|
||||
rules: { |
|
||||
subject: [ |
|
||||
{ required: true, message: '标题不能为空', trigger: 'blur' } |
|
||||
] |
|
||||
} |
|
||||
} |
|
||||
}, |
|
||||
computed: { |
|
||||
...mapGetters([ |
|
||||
'imagesUploadApi' |
|
||||
]) |
|
||||
}, |
|
||||
mounted() { |
|
||||
const _this = this |
|
||||
var editor = new E(this.$refs.editor) |
|
||||
// 自定义菜单配置 |
|
||||
editor.customConfig.zIndex = 10 |
|
||||
// 文件上传 |
|
||||
editor.customConfig.customUploadImg = function(files, insert) { |
|
||||
// files 是 input 中选中的文件列表 |
|
||||
// insert 是获取图片 url 后,插入到编辑器的方法 |
|
||||
files.forEach(image => { |
|
||||
files.forEach(image => { |
|
||||
upload(_this.imagesUploadApi, image).then(data => { |
|
||||
insert(data.data.url) |
|
||||
}) |
|
||||
}) |
|
||||
}) |
|
||||
} |
|
||||
editor.customConfig.onchange = (html) => { |
|
||||
this.form.content = html |
|
||||
} |
|
||||
editor.create() |
|
||||
}, |
|
||||
methods: { |
|
||||
removeDomain(item) { |
|
||||
var index = this.tos.indexOf(item) |
|
||||
if (index !== -1 && this.tos.length !== 1) { |
|
||||
this.tos.splice(index, 1) |
|
||||
} else { |
|
||||
this.$message({ |
|
||||
message: '请至少保留一位联系人', |
|
||||
type: 'warning' |
|
||||
}) |
|
||||
} |
|
||||
}, |
|
||||
addDomain() { |
|
||||
this.tos.push({ |
|
||||
value: '', |
|
||||
key: Date.now() |
|
||||
}) |
|
||||
}, |
|
||||
doSubmit() { |
|
||||
const _this = this |
|
||||
this.$refs['form'].validate((valid) => { |
|
||||
this.form.tos = [] |
|
||||
if (valid) { |
|
||||
let sub = false |
|
||||
this.tos.forEach(function(data, index) { |
|
||||
if (data.value === '') { |
|
||||
_this.$message({ |
|
||||
message: '收件邮箱不能为空', |
|
||||
type: 'warning' |
|
||||
}) |
|
||||
sub = true |
|
||||
} else if (validEmail(data.value)) { |
|
||||
_this.form.tos.push(data.value) |
|
||||
} else { |
|
||||
_this.$message({ |
|
||||
message: '收件邮箱格式错误', |
|
||||
type: 'warning' |
|
||||
}) |
|
||||
sub = true |
|
||||
} |
|
||||
}) |
|
||||
if (sub) { return false } |
|
||||
this.loading = true |
|
||||
send(this.form).then(res => { |
|
||||
this.$notify({ |
|
||||
title: '发送成功', |
|
||||
type: 'success', |
|
||||
duration: 2500 |
|
||||
}) |
|
||||
this.loading = false |
|
||||
}).catch(err => { |
|
||||
this.loading = false |
|
||||
console.log(err.response.data.message) |
|
||||
}) |
|
||||
} else { |
|
||||
return false |
|
||||
} |
|
||||
}) |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
</script> |
|
||||
|
|
||||
<style scoped> |
|
||||
.editor{ |
|
||||
text-align:left; |
|
||||
margin: 20px; |
|
||||
width: 730px; |
|
||||
} |
|
||||
::v-deep .w-e-text-container { |
|
||||
height: 360px !important; |
|
||||
} |
|
||||
</style> |
|
||||
@ -1,36 +0,0 @@ |
|||||
<template> |
|
||||
<el-tabs v-model="activeName" style="padding-left: 8px;" @tab-click="tabClick"> |
|
||||
<el-tab-pane label="本地存储" name="first"> |
|
||||
<Local ref="local" /> |
|
||||
</el-tab-pane> |
|
||||
<el-tab-pane label="七牛云存储" name="second"> |
|
||||
<QiNiu ref="qiNiu" /> |
|
||||
</el-tab-pane> |
|
||||
</el-tabs> |
|
||||
</template> |
|
||||
|
|
||||
<script> |
|
||||
import QiNiu from './qiniu/index' |
|
||||
import Local from './local/index' |
|
||||
export default { |
|
||||
name: 'Storage', |
|
||||
components: { QiNiu, Local }, |
|
||||
data() { |
|
||||
return { |
|
||||
activeName: 'first' |
|
||||
} |
|
||||
}, |
|
||||
methods: { |
|
||||
tabClick(name) { |
|
||||
if (this.activeName === 'first') { |
|
||||
this.$refs.local.crud.toQuery() |
|
||||
} else { |
|
||||
this.$refs.qiNiu.crud.toQuery() |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
</script> |
|
||||
|
|
||||
<style scoped> |
|
||||
</style> |
|
||||
@ -1,184 +0,0 @@ |
|||||
<template> |
|
||||
<div class="app-container" style="padding: 8px;"> |
|
||||
<!--工具栏--> |
|
||||
<div class="head-container"> |
|
||||
<div v-if="crud.props.searchToggle"> |
|
||||
<!-- 搜索 --> |
|
||||
<el-input v-model="query.blurry" clearable size="small" placeholder="输入内容模糊搜索" style="width: 200px;" class="filter-item" @keyup.enter.native="crud.toQuery" /> |
|
||||
<date-range-picker v-model="query.createTime" class="date-item" /> |
|
||||
<rrOperation /> |
|
||||
</div> |
|
||||
<crudOperation :permission="permission"> |
|
||||
<!-- 新增 --> |
|
||||
<el-button |
|
||||
slot="left" |
|
||||
v-permission="['admin','storage:add']" |
|
||||
class="filter-item" |
|
||||
size="mini" |
|
||||
type="primary" |
|
||||
icon="el-icon-upload" |
|
||||
@click="crud.toAdd" |
|
||||
>上传 |
|
||||
</el-button> |
|
||||
</crudOperation> |
|
||||
</div> |
|
||||
<!--表单组件--> |
|
||||
<el-dialog append-to-body :close-on-click-modal="false" :before-close="crud.cancelCU" :visible.sync="crud.status.cu > 0" :title="crud.status.add ? '文件上传' : '编辑文件'" width="500px"> |
|
||||
<el-form ref="form" :model="form" size="small" label-width="80px"> |
|
||||
<el-form-item label="文件名"> |
|
||||
<el-input v-model="form.name" style="width: 370px;" /> |
|
||||
</el-form-item> |
|
||||
<!-- 上传文件 --> |
|
||||
<el-form-item v-if="crud.status.add" label="上传"> |
|
||||
<el-upload |
|
||||
ref="upload" |
|
||||
:limit="1" |
|
||||
:before-upload="beforeUpload" |
|
||||
:auto-upload="false" |
|
||||
:headers="headers" |
|
||||
:on-success="handleSuccess" |
|
||||
:on-error="handleError" |
|
||||
:action="fileUploadApi + '?name=' + form.name" |
|
||||
> |
|
||||
<div class="eladmin-upload"><i class="el-icon-upload" /> 添加文件</div> |
|
||||
<div slot="tip" class="el-upload__tip">可上传任意格式文件,且不超过100M</div> |
|
||||
</el-upload> |
|
||||
</el-form-item> |
|
||||
</el-form> |
|
||||
<div slot="footer" class="dialog-footer"> |
|
||||
<el-button type="text" @click="crud.cancelCU">取消</el-button> |
|
||||
<el-button v-if="crud.status.add" :loading="loading" type="primary" @click="upload">确认</el-button> |
|
||||
<el-button v-else :loading="crud.status.cu === 2" type="primary" @click="crud.submitCU">确认</el-button> |
|
||||
</div> |
|
||||
</el-dialog> |
|
||||
<!--表格渲染--> |
|
||||
<el-table ref="table" v-loading="crud.loading" :data="crud.data" style="width: 100%;" @selection-change="crud.selectionChangeHandler"> |
|
||||
<el-table-column type="selection" width="55" /> |
|
||||
<el-table-column prop="name" label="文件名"> |
|
||||
<template slot-scope="scope"> |
|
||||
<el-popover |
|
||||
:content="'file/' + scope.row.type + '/' + scope.row.realName" |
|
||||
placement="top-start" |
|
||||
title="路径" |
|
||||
width="200" |
|
||||
trigger="hover" |
|
||||
> |
|
||||
<a |
|
||||
slot="reference" |
|
||||
:href="baseApi + '/file/' + scope.row.type + '/' + scope.row.realName" |
|
||||
class="el-link--primary" |
|
||||
style="word-break:keep-all;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;color: #1890ff;font-size: 13px;" |
|
||||
target="_blank" |
|
||||
> |
|
||||
{{ scope.row.name }} |
|
||||
</a> |
|
||||
</el-popover> |
|
||||
</template> |
|
||||
</el-table-column> |
|
||||
<el-table-column prop="path" label="预览图"> |
|
||||
<template slot-scope="{row}"> |
|
||||
<el-image |
|
||||
:src=" baseApi + '/file/' + row.type + '/' + row.realName" |
|
||||
:preview-src-list="[baseApi + '/file/' + row.type + '/' + row.realName]" |
|
||||
fit="contain" |
|
||||
lazy |
|
||||
class="el-avatar" |
|
||||
> |
|
||||
<div slot="error"> |
|
||||
<i class="el-icon-document" /> |
|
||||
</div> |
|
||||
</el-image> |
|
||||
</template> |
|
||||
</el-table-column> |
|
||||
<el-table-column prop="suffix" label="文件类型" /> |
|
||||
<el-table-column prop="type" label="类别" /> |
|
||||
<el-table-column prop="size" label="大小" /> |
|
||||
<el-table-column prop="operate" label="操作人" /> |
|
||||
<el-table-column prop="createTime" label="创建日期" /> |
|
||||
</el-table> |
|
||||
<!--分页组件--> |
|
||||
<pagination /> |
|
||||
</div> |
|
||||
</template> |
|
||||
|
|
||||
<script> |
|
||||
import { mapGetters } from 'vuex' |
|
||||
import { getToken } from '@/utils/auth' |
|
||||
import crudFile from '@/api/tools/localStorage' |
|
||||
import CRUD, { presenter, header, form, crud } from '@crud/crud' |
|
||||
import rrOperation from '@crud/RR.operation' |
|
||||
import crudOperation from '@crud/CRUD.operation' |
|
||||
import pagination from '@crud/Pagination' |
|
||||
import DateRangePicker from '@/components/DateRangePicker' |
|
||||
|
|
||||
const defaultForm = { id: null, name: '' } |
|
||||
export default { |
|
||||
components: { pagination, crudOperation, rrOperation, DateRangePicker }, |
|
||||
cruds() { |
|
||||
return CRUD({ title: '文件', url: 'api/localStorage', crudMethod: { ...crudFile }}) |
|
||||
}, |
|
||||
mixins: [presenter(), header(), form(defaultForm), crud()], |
|
||||
data() { |
|
||||
return { |
|
||||
delAllLoading: false, |
|
||||
loading: false, |
|
||||
headers: { 'Authorization': getToken() }, |
|
||||
permission: { |
|
||||
edit: ['admin', 'storage:edit'], |
|
||||
del: ['admin', 'storage:del'] |
|
||||
} |
|
||||
} |
|
||||
}, |
|
||||
computed: { |
|
||||
...mapGetters([ |
|
||||
'baseApi', |
|
||||
'fileUploadApi' |
|
||||
]) |
|
||||
}, |
|
||||
created() { |
|
||||
this.crud.optShow.add = false |
|
||||
}, |
|
||||
methods: { |
|
||||
// 上传文件 |
|
||||
upload() { |
|
||||
this.$refs.upload.submit() |
|
||||
}, |
|
||||
beforeUpload(file) { |
|
||||
let isLt2M = true |
|
||||
isLt2M = file.size / 1024 / 1024 < 100 |
|
||||
if (!isLt2M) { |
|
||||
this.loading = false |
|
||||
this.$message.error('上传文件大小不能超过 100MB!') |
|
||||
} |
|
||||
this.form.name = file.name |
|
||||
return isLt2M |
|
||||
}, |
|
||||
handleSuccess(response, file, fileList) { |
|
||||
this.crud.notify('上传成功', CRUD.NOTIFICATION_TYPE.SUCCESS) |
|
||||
this.$refs.upload.clearFiles() |
|
||||
this.crud.status.add = CRUD.STATUS.NORMAL |
|
||||
this.crud.resetForm() |
|
||||
this.crud.toQuery() |
|
||||
}, |
|
||||
// 监听上传失败 |
|
||||
handleError(e, file, fileList) { |
|
||||
const msg = JSON.parse(e.message) |
|
||||
this.$notify({ |
|
||||
title: msg.message, |
|
||||
type: 'error', |
|
||||
duration: 2500 |
|
||||
}) |
|
||||
this.loading = false |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
</script> |
|
||||
|
|
||||
<style scoped> |
|
||||
::v-deep .el-image__error, .el-image__placeholder{ |
|
||||
background: none; |
|
||||
} |
|
||||
::v-deep .el-image-viewer__wrapper{ |
|
||||
top: 55px; |
|
||||
} |
|
||||
</style> |
|
||||
@ -1,98 +0,0 @@ |
|||||
<template> |
|
||||
<el-dialog :visible.sync="dialog" :close-on-click-modal="false" title="七牛云配置" append-to-body width="580px"> |
|
||||
<el-form ref="form" :model="form" :rules="rules" style="margin-top: 6px;" size="small" label-width="110px"> |
|
||||
<el-form-item label="Access Key" prop="accessKey"> |
|
||||
<el-input v-model="form.accessKey" style="width: 95%" placeholder="accessKey,在安全中心,秘钥管理中查看" /> |
|
||||
</el-form-item> |
|
||||
<el-form-item label="Secret Key" prop="secretKey"> |
|
||||
<el-input v-model="form.secretKey" type="password" style="width: 95%;" placeholder="secretKey,在安全中心,秘钥管理中查看" /> |
|
||||
</el-form-item> |
|
||||
<el-form-item label="空间名称" prop="bucket"> |
|
||||
<el-input v-model="form.bucket" style="width: 95%;" placeholder="存储空间名称作为唯一的 Bucket 识别符" /> |
|
||||
</el-form-item> |
|
||||
<el-form-item label="外链域名" prop="host"> |
|
||||
<el-input v-model="form.host" style="width: 95%;" placeholder="外链域名,可自定义,需在七牛云绑定" /> |
|
||||
</el-form-item> |
|
||||
<el-form-item label="存储区域"> |
|
||||
<el-select v-model="form.zone" placeholder="请选择存储区域"> |
|
||||
<el-option |
|
||||
v-for="item in zones" |
|
||||
:key="item" |
|
||||
:label="item" |
|
||||
:value="item" |
|
||||
/> |
|
||||
</el-select> |
|
||||
</el-form-item> |
|
||||
<el-form-item label="空间类型" prop="type"> |
|
||||
<el-radio v-model="form.type" label="公开">公开</el-radio> |
|
||||
<el-radio v-model="form.type" label="私有">私有</el-radio> |
|
||||
</el-form-item> |
|
||||
</el-form> |
|
||||
<div slot="footer" class="dialog-footer"> |
|
||||
<el-button type="text" @click="dialog = false">取消</el-button> |
|
||||
<el-button :loading="loading" type="primary" @click="doSubmit">确认</el-button> |
|
||||
</div> |
|
||||
</el-dialog> |
|
||||
</template> |
|
||||
|
|
||||
<script> |
|
||||
import { get, update } from '@/api/tools/qiniu' |
|
||||
export default { |
|
||||
data() { |
|
||||
return { |
|
||||
zones: ['华东', '华北', '华南', '北美', '东南亚'], dialog: false, |
|
||||
loading: false, form: { accessKey: '', secretKey: '', bucket: '', host: '', zone: '', type: '' }, |
|
||||
rules: { |
|
||||
accessKey: [ |
|
||||
{ required: true, message: '请输入accessKey', trigger: 'blur' } |
|
||||
], |
|
||||
secretKey: [ |
|
||||
{ required: true, message: '请输入secretKey', trigger: 'blur' } |
|
||||
], |
|
||||
bucket: [ |
|
||||
{ required: true, message: '请输入空间名称', trigger: 'blur' } |
|
||||
], |
|
||||
host: [ |
|
||||
{ required: true, message: '请输入外链域名', trigger: 'blur' } |
|
||||
], |
|
||||
type: [ |
|
||||
{ required: true, message: '空间类型不能为空', trigger: 'blur' } |
|
||||
] |
|
||||
} |
|
||||
} |
|
||||
}, |
|
||||
methods: { |
|
||||
init() { |
|
||||
get().then(res => { |
|
||||
this.form = res |
|
||||
}) |
|
||||
}, |
|
||||
doSubmit() { |
|
||||
this.$refs['form'].validate((valid) => { |
|
||||
if (valid) { |
|
||||
this.loading = true |
|
||||
update(this.form).then(res => { |
|
||||
this.$notify({ |
|
||||
title: '修改成功', |
|
||||
type: 'success', |
|
||||
duration: 2500 |
|
||||
}) |
|
||||
this.$parent.crud.toQuery() |
|
||||
this.loading = false |
|
||||
this.dialog = false |
|
||||
}).catch(err => { |
|
||||
this.loading = false |
|
||||
console.log(err.response.data.message) |
|
||||
}) |
|
||||
} else { |
|
||||
return false |
|
||||
} |
|
||||
}) |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
</script> |
|
||||
|
|
||||
<style scoped> |
|
||||
|
|
||||
</style> |
|
||||
@ -1,189 +0,0 @@ |
|||||
<template> |
|
||||
<div class="app-container" style="padding: 8px;"> |
|
||||
<!--表单组件--> |
|
||||
<eForm ref="form" /> |
|
||||
<!-- 工具栏 --> |
|
||||
<div class="head-container"> |
|
||||
<div v-if="crud.props.searchToggle"> |
|
||||
<!-- 搜索 --> |
|
||||
<el-input v-model="query.key" clearable size="small" placeholder="输入文件名称搜索" style="width: 200px;" class="filter-item" @keyup.enter.native="toQuery" /> |
|
||||
<date-range-picker v-model="query.createTime" class="date-item" /> |
|
||||
<rrOperation /> |
|
||||
</div> |
|
||||
<crudOperation :permission="permission"> |
|
||||
<template slot="left"> |
|
||||
<!-- 上传 --> |
|
||||
<el-button class="filter-item" size="mini" type="primary" icon="el-icon-upload" @click="dialog = true">上传</el-button> |
|
||||
<!-- 同步 --> |
|
||||
<el-button :icon="icon" class="filter-item" size="mini" type="warning" @click="synchronize">同步</el-button> |
|
||||
<!-- 配置 --> |
|
||||
<el-button |
|
||||
class="filter-item" |
|
||||
size="mini" |
|
||||
type="success" |
|
||||
icon="el-icon-s-tools" |
|
||||
@click="doConfig" |
|
||||
>配置</el-button> |
|
||||
</template> |
|
||||
</crudOperation> |
|
||||
<!-- 文件上传 --> |
|
||||
<el-dialog :visible.sync="dialog" :close-on-click-modal="false" append-to-body width="500px" @close="doSubmit"> |
|
||||
<el-upload |
|
||||
:before-remove="handleBeforeRemove" |
|
||||
:on-success="handleSuccess" |
|
||||
:on-error="handleError" |
|
||||
:file-list="fileList" |
|
||||
:headers="headers" |
|
||||
:action="qiNiuUploadApi" |
|
||||
class="upload-demo" |
|
||||
multiple |
|
||||
> |
|
||||
<el-button size="small" type="primary">点击上传</el-button> |
|
||||
<div slot="tip" style="display: block;" class="el-upload__tip">请勿上传违法文件,且文件不超过15M</div> |
|
||||
</el-upload> |
|
||||
<div slot="footer" class="dialog-footer"> |
|
||||
<el-button type="primary" @click="doSubmit">确认</el-button> |
|
||||
</div> |
|
||||
</el-dialog> |
|
||||
<!--表格渲染--> |
|
||||
<el-table ref="table" v-loading="crud.loading" :data="crud.data" style="width: 100%;" @selection-change="crud.selectionChangeHandler"> |
|
||||
<el-table-column type="selection" width="55" /> |
|
||||
<el-table-column prop="name" :show-overflow-tooltip="true" label="文件名"> |
|
||||
<template slot-scope="scope"> |
|
||||
<a href="JavaScript:" class="el-link el-link--primary" target="_blank" type="primary" @click="download(scope.row.id)">{{ scope.row.key }}</a> |
|
||||
</template> |
|
||||
</el-table-column> |
|
||||
<el-table-column :show-overflow-tooltip="true" prop="suffix" label="文件类型" @selection-change="crud.selectionChangeHandler" /> |
|
||||
<el-table-column prop="bucket" label="空间名称" /> |
|
||||
<el-table-column prop="size" label="文件大小" /> |
|
||||
<el-table-column prop="type" label="空间类型" /> |
|
||||
<el-table-column prop="updateTime" label="创建日期" /> |
|
||||
</el-table> |
|
||||
<!--分页组件--> |
|
||||
<pagination /> |
|
||||
</div> |
|
||||
</div> |
|
||||
</template> |
|
||||
|
|
||||
<script> |
|
||||
import crudQiNiu from '@/api/tools/qiniu' |
|
||||
import { mapGetters } from 'vuex' |
|
||||
import { getToken } from '@/utils/auth' |
|
||||
import eForm from './form' |
|
||||
import CRUD, { presenter, header, crud } from '@crud/crud' |
|
||||
import rrOperation from '@crud/RR.operation' |
|
||||
import crudOperation from '@crud/CRUD.operation' |
|
||||
import pagination from '@crud/Pagination' |
|
||||
import DateRangePicker from '@/components/DateRangePicker' |
|
||||
|
|
||||
export default { |
|
||||
components: { eForm, pagination, crudOperation, rrOperation, DateRangePicker }, |
|
||||
cruds() { |
|
||||
return CRUD({ title: '七牛云文件', url: 'api/qiNiuContent', crudMethod: { ...crudQiNiu }}) |
|
||||
}, |
|
||||
mixins: [presenter(), header(), crud()], |
|
||||
data() { |
|
||||
return { |
|
||||
permission: { |
|
||||
del: ['admin', 'storage:del'] |
|
||||
}, |
|
||||
title: '文件', dialog: false, |
|
||||
icon: 'el-icon-refresh', |
|
||||
url: '', headers: { 'Authorization': getToken() }, |
|
||||
dialogImageUrl: '', dialogVisible: false, fileList: [], files: [], newWin: null |
|
||||
} |
|
||||
}, |
|
||||
computed: { |
|
||||
...mapGetters([ |
|
||||
'qiNiuUploadApi' |
|
||||
]) |
|
||||
}, |
|
||||
watch: { |
|
||||
url(newVal, oldVal) { |
|
||||
if (newVal && this.newWin) { |
|
||||
this.newWin.sessionStorage.clear() |
|
||||
this.newWin.location.href = newVal |
|
||||
// 重定向后把url和newWin重置 |
|
||||
this.url = '' |
|
||||
this.newWin = null |
|
||||
} |
|
||||
} |
|
||||
}, |
|
||||
created() { |
|
||||
this.crud.optShow.add = false |
|
||||
this.crud.optShow.edit = false |
|
||||
}, |
|
||||
methods: { |
|
||||
// 七牛云配置 |
|
||||
doConfig() { |
|
||||
const _this = this.$refs.form |
|
||||
_this.init() |
|
||||
_this.dialog = true |
|
||||
}, |
|
||||
handleSuccess(response, file, fileList) { |
|
||||
const uid = file.uid |
|
||||
const id = response.id |
|
||||
this.files.push({ uid, id }) |
|
||||
}, |
|
||||
handleBeforeRemove(file, fileList) { |
|
||||
for (let i = 0; i < this.files.length; i++) { |
|
||||
if (this.files[i].uid === file.uid) { |
|
||||
crudQiNiu.del([this.files[i].id]).then(res => {}) |
|
||||
return true |
|
||||
} |
|
||||
} |
|
||||
}, |
|
||||
handlePictureCardPreview(file) { |
|
||||
this.dialogImageUrl = file.url |
|
||||
this.dialogVisible = true |
|
||||
}, |
|
||||
// 刷新列表数据 |
|
||||
doSubmit() { |
|
||||
this.fileList = [] |
|
||||
this.dialogVisible = false |
|
||||
this.dialogImageUrl = '' |
|
||||
this.dialog = false |
|
||||
this.crud.toQuery() |
|
||||
}, |
|
||||
// 监听上传失败 |
|
||||
handleError(e, file, fileList) { |
|
||||
const msg = JSON.parse(e.message) |
|
||||
this.crud.notify(msg.message, CRUD.NOTIFICATION_TYPE.ERROR) |
|
||||
}, |
|
||||
// 下载文件 |
|
||||
download(id) { |
|
||||
this.downloadLoading = true |
|
||||
// 先打开一个空的新窗口,再请求 |
|
||||
this.newWin = window.open() |
|
||||
crudQiNiu.download(id).then(res => { |
|
||||
this.downloadLoading = false |
|
||||
this.url = res.url |
|
||||
}).catch(err => { |
|
||||
this.downloadLoading = false |
|
||||
console.log(err.response.data.message) |
|
||||
}) |
|
||||
}, |
|
||||
// 同步数据 |
|
||||
synchronize() { |
|
||||
this.icon = 'el-icon-loading' |
|
||||
crudQiNiu.sync().then(res => { |
|
||||
this.icon = 'el-icon-refresh' |
|
||||
this.$message({ |
|
||||
showClose: true, |
|
||||
message: '数据同步成功', |
|
||||
type: 'success', |
|
||||
duration: 1500 |
|
||||
}) |
|
||||
this.crud.toQuery() |
|
||||
}).catch(err => { |
|
||||
this.icon = 'el-icon-refresh' |
|
||||
console.log(err.response.data.message) |
|
||||
}) |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
</script> |
|
||||
|
|
||||
<style scoped> |
|
||||
|
|
||||
</style> |
|
||||
@ -1,16 +0,0 @@ |
|||||
<template> |
|
||||
<elFrame :src="swaggerApi" /> |
|
||||
</template> |
|
||||
<script> |
|
||||
import { mapGetters } from 'vuex' |
|
||||
import elFrame from '@/components/Iframe/index' |
|
||||
export default { |
|
||||
name: 'Swagger', |
|
||||
components: { elFrame }, |
|
||||
computed: { |
|
||||
...mapGetters([ |
|
||||
'swaggerApi' |
|
||||
]) |
|
||||
} |
|
||||
} |
|
||||
</script> |
|
||||
Write
Preview
Loading…
Cancel
Save
Reference in new issue