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