Browse Source

文件整理

dev
xuhuajiao 4 years ago
parent
commit
a409ad1349
  1. 11
      src/api/system/user.js
  2. 124
      src/views/components/Echarts.vue
  3. 74
      src/views/components/Editor.vue
  4. 46
      src/views/components/MarkDown.vue
  5. 207
      src/views/components/YamlEdit.vue
  6. 74
      src/views/components/icons/element-icons.js
  7. 97
      src/views/components/icons/index.vue
  8. 10
      src/views/components/icons/svg-icons.js
  9. 135
      src/views/dashboard/LineChart.vue
  10. 181
      src/views/dashboard/PanelGroup.vue
  11. 325
      src/views/generator/config.vue
  12. 114
      src/views/generator/index.vue
  13. 30
      src/views/generator/preview.vue
  14. 144
      src/views/mnt/app/index.vue
  15. 86
      src/views/mnt/database/execute.vue
  16. 148
      src/views/mnt/database/index.vue
  17. 190
      src/views/mnt/deploy/deploy.vue
  18. 229
      src/views/mnt/deploy/index.vue
  19. 108
      src/views/mnt/deploy/sysRestore.vue
  20. 93
      src/views/mnt/deployHistory/index.vue
  21. 136
      src/views/mnt/server/index.vue
  22. 135
      src/views/monitor/log/errorLog.vue
  23. 114
      src/views/monitor/log/index.vue
  24. 24
      src/views/monitor/log/search.vue
  25. 121
      src/views/monitor/online/index.vue
  26. 291
      src/views/monitor/server/index.vue
  27. 16
      src/views/monitor/sql/index.vue
  28. 115
      src/views/system/dict/dictDetail.vue
  29. 130
      src/views/system/dict/index.vue
  30. 110
      src/views/system/job/index.vue
  31. 110
      src/views/system/job/module/form.vue
  32. 32
      src/views/system/job/module/header.vue
  33. 210
      src/views/system/timing/index.vue
  34. 104
      src/views/system/timing/log.vue
  35. 98
      src/views/tools/aliPay/config.vue
  36. 48
      src/views/tools/aliPay/index.vue
  37. 86
      src/views/tools/aliPay/toPay.vue
  38. 91
      src/views/tools/email/config.vue
  39. 41
      src/views/tools/email/index.vue
  40. 142
      src/views/tools/email/send.vue
  41. 36
      src/views/tools/storage/index.vue
  42. 184
      src/views/tools/storage/local/index.vue
  43. 98
      src/views/tools/storage/qiniu/form.vue
  44. 189
      src/views/tools/storage/qiniu/index.vue
  45. 16
      src/views/tools/swagger/index.vue
  46. 24
      src/views/user/menu1.vue

11
src/api/system/user.js

@ -19,6 +19,15 @@ export function FetchAddUser(parameter) {
}) })
} }
// 删除用户
export function FetchDeleteUser(parameter) {
return request({
url: 'api/users/delete',
method: 'delete',
data: parameter
})
}
export function add(data) { export function add(data) {
return request({ return request({
url: 'api/users', url: 'api/users',
@ -29,7 +38,7 @@ export function add(data) {
export function del(ids) { export function del(ids) {
return request({ return request({
url: 'api/users',
url: 'api/users/delete',
method: 'delete', method: 'delete',
data: ids data: ids
}) })

124
src/views/components/Echarts.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>

74
src/views/components/Editor.vue

@ -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>

46
src/views/components/MarkDown.vue

@ -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>

207
src/views/components/YamlEdit.vue

@ -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>

74
src/views/components/icons/element-icons.js

@ -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

97
src/views/components/icons/index.vue

@ -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>

10
src/views/components/icons/svg-icons.js

@ -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

135
src/views/dashboard/LineChart.vue

@ -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>

181
src/views/dashboard/PanelGroup.vue

@ -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>

325
src/views/generator/config.vue

@ -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>

114
src/views/generator/index.vue

@ -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>

30
src/views/generator/preview.vue

@ -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>

144
src/views/mnt/app/index.vue

@ -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>

86
src/views/mnt/database/execute.vue

@ -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>

148
src/views/mnt/database/index.vue

@ -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>

190
src/views/mnt/deploy/deploy.vue

@ -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>

229
src/views/mnt/deploy/index.vue

@ -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>

108
src/views/mnt/deploy/sysRestore.vue

@ -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>

93
src/views/mnt/deployHistory/index.vue

@ -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>

136
src/views/mnt/server/index.vue

@ -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>

135
src/views/monitor/log/errorLog.vue

@ -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>

114
src/views/monitor/log/index.vue

@ -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>

24
src/views/monitor/log/search.vue

@ -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>

121
src/views/monitor/online/index.vue

@ -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>

291
src/views/monitor/server/index.vue

@ -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>

16
src/views/monitor/sql/index.vue

@ -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>

115
src/views/system/dict/dictDetail.vue

@ -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>

130
src/views/system/dict/index.vue

@ -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>

110
src/views/system/job/index.vue

@ -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>

110
src/views/system/job/module/form.vue

@ -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>

32
src/views/system/job/module/header.vue

@ -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>

210
src/views/system/timing/index.vue

@ -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>

104
src/views/system/timing/log.vue

@ -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>

98
src/views/tools/aliPay/config.vue

@ -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>

48
src/views/tools/aliPay/index.vue

@ -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>

86
src/views/tools/aliPay/toPay.vue

@ -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
// urlnewWin
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>

91
src/views/tools/email/config.vue

@ -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>

41
src/views/tools/email/index.vue

@ -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>

142
src/views/tools/email/send.vue

@ -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>

36
src/views/tools/storage/index.vue

@ -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>

184
src/views/tools/storage/local/index.vue

@ -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>

98
src/views/tools/storage/qiniu/form.vue

@ -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>

189
src/views/tools/storage/qiniu/index.vue

@ -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
// urlnewWin
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>

16
src/views/tools/swagger/index.vue

@ -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>

24
src/views/user/menu1.vue

@ -187,6 +187,7 @@
type="danger" type="danger"
class="delt_btn" class="delt_btn"
:disabled="scope.row.id === user.id" :disabled="scope.row.id === user.id"
@click="deleteUser(scope.row)"
>删除</el-button> >删除</el-button>
</template> </template>
</el-table-column> </el-table-column>
@ -199,7 +200,7 @@
</template> </template>
<script> <script>
import { FetchUserList, FetchAddUser } from '@/api/system/user'
import { FetchUserList, FetchAddUser, FetchDeleteUser } from '@/api/system/user'
import { FetchDropDownList } from '@/api/system/role' import { FetchDropDownList } from '@/api/system/role'
import { isvalidPhone } from '@/utils/validate' import { isvalidPhone } from '@/utils/validate'
import { parseTime } from '@/utils/index.js' import { parseTime } from '@/utils/index.js'
@ -365,6 +366,27 @@ export default {
} }
}) })
}, },
//
deleteUser(row) {
const param = []
param.push(row.id)
this.$confirm('你确定要删除该用户, 是否继续?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
FetchDeleteUser(param).then(res => {
if (res.code == 200) {
this.$message.success('用户删除成功 !')
this.getUserList(this.page)
} else {
this.$message.error(res.msg)
}
})
}).catch(() => {
this.$message({ type: 'success', message: '已取消删除' })
})
},
// select - // select -
selectRoles(vId) { selectRoles(vId) {
let obj = {} let obj = {}

Loading…
Cancel
Save