Compare commits

..

No commits in common. "5bc72e6f3b1d0acb69952659173c01010974770f" and "3cbab55eb8e9abfa2e78a831cc910e3d31c7f8bb" have entirely different histories.

298 changed files with 8540 additions and 3039 deletions

View File

@ -1,17 +1,26 @@
<h1 style="text-align: center">区块链技术的隐私保护和执法数据管理系统</h1> <h1 style="text-align: center">ELADMIN 后台管理系统</h1>
#### 项目简介 #### 项目简介
一个基于 Spring Boot 2.7.18 、 Mybatis-Plus、 JWT、Spring Security、Redis、Vue的前后端分离的后台管理系统 一个基于 Spring Boot 2.7.18 、 Mybatis-Plus、 JWT、Spring Security、Redis、Vue的前后端分离的后台管理系统
**开发文档:** [https://eladmin.vip](https://eladmin.vip)
**体验地址:** [https://eladmin.vip/demo](https://eladmin.vip/demo)
**账号密码:** `admin / 123456` **账号密码:** `admin / 123456`
#### 项目结构 #### 项目源码
项目采用按功能分模块的开发方式,结构如下
- `eladmin-common` 为系统的公共模块,各种工具类,公共配置存在该模块 | github | gitee |
|--------------------------------------| --- |
| https://github.com/elunez/eladmin-mp | https://gitee.com/elunez/eladmin-mp |
- `eladmin-system` 为系统核心模块也是项目入口模块,也是最终需要打包部署的模块 #### VPS推荐
<a href="https://bwh81.net/aff.php?aff=70876" target="_blank">
<img src="https://eladmin.vip/images/banner/side.jpeg" style="width: 435px;border-radius: 2px;" alt="帮瓦工">
</a>
使用优惠码: `BWHNCXNVXV`,可获得 6.81% 的折扣, [查看介绍](https://eladmin.vip/pages/040101/)
#### 主要特性 #### 主要特性
- 使用最新技术栈,社区资源丰富。 - 使用最新技术栈,社区资源丰富。
- 高效率开发,代码生成器可一键生成前后端代码 - 高效率开发,代码生成器可一键生成前后端代码
@ -32,7 +41,14 @@
- 岗位管理:配置各个部门的职位 - 岗位管理:配置各个部门的职位
- 字典管理:可维护常用一些固定的数据,如:状态,性别等 - 字典管理:可维护常用一些固定的数据,如:状态,性别等
- 系统日志:记录用户操作日志与异常日志,方便开发人员定位排错 - 系统日志:记录用户操作日志与异常日志,方便开发人员定位排错
- 执法数据:对执法信息的上链保护已经链路溯源 - SQL监控采用druid 监控数据库访问性能默认用户名admin密码123456
- 定时任务整合Quartz做定时任务加入任务日志任务运行情况一目了然
- 代码生成:高灵活度生成前后端代码,减少大量重复的工作任务
- 邮件工具配合富文本发送html格式的邮件
- 七牛云存储:可同步七牛云存储的数据到系统,无需登录七牛云直接操作云数据
- 支付宝支付:整合了支付宝支付并且提供了测试账号,可自行测试
- 服务监控:监控服务器的负载情况
- 运维管理:一键部署你的应用
#### 项目结构 #### 项目结构
项目采用按功能分模块的开发方式,结构如下 项目采用按功能分模块的开发方式,结构如下
@ -41,6 +57,12 @@
- `eladmin-system` 为系统核心模块也是项目入口模块,也是最终需要打包部署的模块 - `eladmin-system` 为系统核心模块也是项目入口模块,也是最终需要打包部署的模块
- `eladmin-logging` 为系统的日志模块,其他模块如果需要记录日志需要引入该模块
- `eladmin-tools` 为第三方工具模块,包含:邮件、七牛云存储、本地存储、支付宝
- `eladmin-generator` 为系统的代码生成模块支持生成前后端CRUD代码
#### 详细结构 #### 详细结构
``` ```
@ -65,5 +87,28 @@
- FileUtil 文件工具类 - FileUtil 文件工具类
- eladmin-system 系统核心模块(系统启动入口) - eladmin-system 系统核心模块(系统启动入口)
- sysrunner 程序启动后处理数据 - sysrunner 程序启动后处理数据
- modules 系统相关模块(登录授权、系统模块、运维模块) - modules 系统相关模块(登录授权、系统监控、定时任务、系统模块、运维模块)
- eladmin-logging 系统日志模块
- eladmin-tools 系统第三方工具模块
- email 邮件工具
- qiniu 七牛云存储工具
- alipay 支付宝支付工具
- local-storage 本地存储工具
- eladmin-generator 系统代码生成模块
``` ```
#### 特别鸣谢
- 感谢 [PanJiaChen](https://github.com/PanJiaChen/vue-element-admin) 大佬提供的前端模板
- 感谢 [Moxun](https://github.com/moxun1639) 大佬提供的前端 Curd 通用组件
- 感谢 [zhy6599](https://gitee.com/zhy6599) 大佬提供的后端运维管理相关功能
- 感谢 [j.yao.SUSE](https://github.com/everhopingandwaiting) 大佬提供的匿名接口与Redis限流等功能
#### 项目捐赠
项目的发展离不开你的支持,请作者喝杯咖啡吧☕ [Donate](https://eladmin.vip/pages/030101/)
#### 反馈交流
- QQ交流群891137268 、947578238、659622532

View File

@ -5,7 +5,7 @@
"author": "Zheng Jie", "author": "Zheng Jie",
"license": "Apache-2.0", "license": "Apache-2.0",
"scripts": { "scripts": {
"dev": "SET NODE_OPTIONS=--openssl-legacy-provider && vue-cli-service serve", "dev": "vue-cli-service serve",
"build:prod": "vue-cli-service build", "build:prod": "vue-cli-service build",
"build:stage": "vue-cli-service build --mode staging", "build:stage": "vue-cli-service build --mode staging",
"preview": "node build/index.js --preview", "preview": "node build/index.js --preview",

View File

@ -1,34 +0,0 @@
import request from '@/utils/request'
export function add(data) {
return request({
url: 'api/busLawEnforcement',
method: 'post',
data
})
}
export function del(ids) {
return request({
url: 'api/busLawEnforcement/',
method: 'delete',
data: ids
})
}
export function edit(data) {
return request({
url: 'api/busLawEnforcement',
method: 'put',
data
})
}
export function chainList(data) {
return request({
url: 'api/busLawEnforcement/chain' + data,
method: 'get',
})
}
export default { add, edit, del }

View File

@ -1,5 +1,5 @@
<template> <template>
<div style="display: inline-block"> <div>
<el-button v-permission="permission.edit" :loading="crud.status.cu === 2" :disabled="disabledEdit" size="mini" type="primary" icon="el-icon-edit" @click.stop="crud.toEdit(data)" /> <el-button v-permission="permission.edit" :loading="crud.status.cu === 2" :disabled="disabledEdit" size="mini" type="primary" icon="el-icon-edit" @click.stop="crud.toEdit(data)" />
<el-popover v-model="pop" v-permission="permission.del" placement="top" width="180" trigger="manual" @show="onPopoverShow" @hide="onPopoverHide"> <el-popover v-model="pop" v-permission="permission.del" placement="top" width="180" trigger="manual" @show="onPopoverShow" @hide="onPopoverHide">
<p>{{ msg }}</p> <p>{{ msg }}</p>

View File

@ -346,7 +346,7 @@ function CRUD(options) {
if (crud.params[item] === null || crud.params[item] === '') crud.params[item] = undefined if (crud.params[item] === null || crud.params[item] === '') crud.params[item] = undefined
}) })
return { return {
page: crud.page.page, current: crud.page.page,
size: crud.page.size, size: crud.page.size,
...crud.query, ...crud.query,
...crud.params ...crud.params

View File

@ -6,7 +6,6 @@
import echarts from 'echarts' import echarts from 'echarts'
require('echarts/theme/macarons') // echarts theme require('echarts/theme/macarons') // echarts theme
import { debounce } from '@/utils' import { debounce } from '@/utils'
import { getPieChatData } from '@/api/dashboard/dashboard'
export default { export default {
props: { props: {
@ -25,9 +24,7 @@ export default {
}, },
data() { data() {
return { return {
chart: null, chart: null
dataList: [],
dataTitle: [],
} }
}, },
mounted() { mounted() {
@ -48,22 +45,9 @@ export default {
this.chart = null this.chart = null
}, },
methods: { methods: {
async initChart() { initChart() {
let iDataList = [];
let iDataTitle = [];
await getPieChatData().then(res => {
res.forEach(function (rItem) {
let name = rItem.text;
let value = rItem.value;
let item = { name: name, value: value }
iDataTitle.push(name)
iDataList.push(item)
});
})
this.dataList = iDataList;
this.dataTitle = iDataTitle;
this.chart = echarts.init(this.$el, 'macarons') this.chart = echarts.init(this.$el, 'macarons')
this.chart.setOption({ this.chart.setOption({
tooltip: { tooltip: {
trigger: 'item', trigger: 'item',
@ -72,23 +56,29 @@ export default {
legend: { legend: {
left: 'center', left: 'center',
bottom: '10', bottom: '10',
data: this.dataTitle data: ['Industries', 'Technology', 'Forex', 'Gold', 'Forecasts']
}, },
calculable: true, calculable: true,
series: [ series: [
{ {
name: '案件类型统计', name: 'WEEKLY WRITE ARTICLES',
type: 'pie', type: 'pie',
roseType: 'radius', roseType: 'radius',
radius: [15, 95], radius: [15, 95],
center: ['50%', '38%'], center: ['50%', '38%'],
data: this.dataList, data: [
{ value: 320, name: 'Industries' },
{ value: 240, name: 'Technology' },
{ value: 149, name: 'Forex' },
{ value: 100, name: 'Gold' },
{ value: 59, name: 'Forecasts' }
],
animationEasing: 'cubicInOut', animationEasing: 'cubicInOut',
animationDuration: 2600 animationDuration: 2600
} }
] ]
}) })
}, }
} }
} }
</script> </script>

View File

@ -8,17 +8,17 @@
<template v-if="device!=='mobile'"> <template v-if="device!=='mobile'">
<search id="header-search" class="right-menu-item" /> <search id="header-search" class="right-menu-item" />
<!-- <el-tooltip content="项目文档" effect="dark" placement="bottom">--> <el-tooltip content="项目文档" effect="dark" placement="bottom">
<!-- <Doc class="right-menu-item hover-effect" />--> <Doc class="right-menu-item hover-effect" />
<!-- </el-tooltip>--> </el-tooltip>
<el-tooltip content="全屏缩放" effect="dark" placement="bottom"> <el-tooltip content="全屏缩放" effect="dark" placement="bottom">
<screenfull id="screenfull" class="right-menu-item hover-effect" /> <screenfull id="screenfull" class="right-menu-item hover-effect" />
</el-tooltip> </el-tooltip>
<!-- <el-tooltip content="布局设置" effect="dark" placement="bottom">--> <el-tooltip content="布局设置" effect="dark" placement="bottom">
<!-- <size-select id="size-select" class="right-menu-item hover-effect" />--> <size-select id="size-select" class="right-menu-item hover-effect" />
<!-- </el-tooltip>--> </el-tooltip>
</template> </template>

View File

@ -14,7 +14,7 @@
</template> </template>
<script> <script>
import Logo from '@/assets/images/logo2.png' import Logo from '@/assets/images/logo.png'
export default { export default {
name: 'SidebarLogo', name: 'SidebarLogo',
props: { props: {
@ -25,7 +25,7 @@ export default {
}, },
data() { data() {
return { return {
title: '数据安全中心', title: 'ELADMIN-后台管理',
logo: Logo logo: Logo
} }
} }

View File

@ -81,7 +81,7 @@ export default {
if (this.params[item] === null || this.params[item] === '') this.params[item] = undefined if (this.params[item] === null || this.params[item] === '') this.params[item] = undefined
}) })
return { return {
page: this.page, current: this.page,
size: this.size, size: this.size,
...this.query, ...this.query,
...this.params ...this.params

View File

@ -2,7 +2,7 @@ module.exports = {
/** /**
* @description 网站标题 * @description 网站标题
*/ */
title: '数据安全中心', title: 'ELADMIN',
/** /**
* @description 是否显示 tagsView * @description 是否显示 tagsView
*/ */
@ -34,7 +34,7 @@ module.exports = {
/** /**
* 是否显示设置的底部信息 * 是否显示设置的底部信息
*/ */
showFooter: false, showFooter: true,
/** /**
* 底部文字支持html语法 * 底部文字支持html语法
*/ */

View File

@ -61,10 +61,10 @@ export default {
this.chart = echarts.init(this.$el, 'macarons') this.chart = echarts.init(this.$el, 'macarons')
this.setOptions(this.chartData) this.setOptions(this.chartData)
}, },
setOptions({ data } = {}) { // , actualData setOptions({ expectedData, actualData } = {}) {
this.chart.setOption({ this.chart.setOption({
xAxis: { xAxis: {
data: ['前一天', '前两天', '前三天', '前四天', '前五天', '前六天', '前七天'], data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'],
boundaryGap: false, boundaryGap: false,
axisTick: { axisTick: {
show: false show: false
@ -90,10 +90,10 @@ export default {
} }
}, },
legend: { legend: {
data: ['数量'] // ,'actual' data: ['expected', 'actual']
}, },
series: [{ series: [{
name: '数量', itemStyle: { name: 'expected', itemStyle: {
normal: { normal: {
color: '#FF005A', color: '#FF005A',
lineStyle: { lineStyle: {
@ -104,31 +104,30 @@ export default {
}, },
smooth: true, smooth: true,
type: 'line', type: 'line',
data: data, data: expectedData,
animationDuration: 2800, animationDuration: 2800,
animationEasing: 'cubicInOut' animationEasing: 'cubicInOut'
}, },
// { {
// name: 'actual', name: 'actual',
// smooth: true, smooth: true,
// type: 'line', type: 'line',
// itemStyle: { itemStyle: {
// normal: { normal: {
// color: '#3888fa', color: '#3888fa',
// lineStyle: { lineStyle: {
// color: '#3888fa', color: '#3888fa',
// width: 2 width: 2
// }, },
// areaStyle: { areaStyle: {
// color: '#f3f8ff' color: '#f3f8ff'
// } }
// } }
// }, },
// data: actualData, data: actualData,
// animationDuration: 2800, animationDuration: 2800,
// animationEasing: 'quadraticOut' animationEasing: 'quadraticOut'
// } }]
]
}) })
} }
} }

View File

@ -1,54 +1,54 @@
<template> <template>
<el-row :gutter="40" class="panel-group"> <el-row :gutter="40" class="panel-group">
<el-col :xs="12" :sm="12" :lg="6" class="card-panel-col"> <el-col :xs="12" :sm="12" :lg="6" class="card-panel-col">
<div class="card-panel" @click="handleSetLineChartData('user')"> <div class="card-panel" @click="handleSetLineChartData('newVisitis')">
<div class="card-panel-icon-wrapper icon-people"> <div class="card-panel-icon-wrapper icon-people">
<svg-icon icon-class="peoples" class-name="card-panel-icon" /> <svg-icon icon-class="peoples" class-name="card-panel-icon" />
</div> </div>
<div class="card-panel-description"> <div class="card-panel-description">
<div class="card-panel-text"> <div class="card-panel-text">
用户统计 New Visits
</div> </div>
<count-to :start-val="0" :end-val="groupData.user" :duration="2600" class="card-panel-num" /> <count-to :start-val="0" :end-val="102400" :duration="2600" class="card-panel-num" />
</div> </div>
</div> </div>
</el-col> </el-col>
<el-col :xs="12" :sm="12" :lg="6" class="card-panel-col"> <el-col :xs="12" :sm="12" :lg="6" class="card-panel-col">
<div class="card-panel" @click="handleSetLineChartData('dept')"> <div class="card-panel" @click="handleSetLineChartData('messages')">
<div class="card-panel-icon-wrapper icon-message"> <div class="card-panel-icon-wrapper icon-message">
<svg-icon icon-class="dept" class-name="card-panel-icon" /> <svg-icon icon-class="message" class-name="card-panel-icon" />
</div> </div>
<div class="card-panel-description"> <div class="card-panel-description">
<div class="card-panel-text"> <div class="card-panel-text">
部门统计 Messages
</div> </div>
<count-to :start-val="0" :end-val="groupData.dept" :duration="3000" class="card-panel-num" /> <count-to :start-val="0" :end-val="81212" :duration="3000" class="card-panel-num" />
</div> </div>
</div> </div>
</el-col> </el-col>
<el-col :xs="12" :sm="12" :lg="6" class="card-panel-col"> <el-col :xs="12" :sm="12" :lg="6" class="card-panel-col">
<div class="card-panel" @click="handleSetLineChartData('role')"> <div class="card-panel" @click="handleSetLineChartData('purchases')">
<div class="card-panel-icon-wrapper icon-money"> <div class="card-panel-icon-wrapper icon-money">
<svg-icon icon-class="role" class-name="card-panel-icon" /> <svg-icon icon-class="money" class-name="card-panel-icon" />
</div> </div>
<div class="card-panel-description"> <div class="card-panel-description">
<div class="card-panel-text"> <div class="card-panel-text">
角色统计 Purchases
</div> </div>
<count-to :start-val="0" :end-val="groupData.role" :duration="3200" class="card-panel-num" /> <count-to :start-val="0" :end-val="9280" :duration="3200" class="card-panel-num" />
</div> </div>
</div> </div>
</el-col> </el-col>
<el-col :xs="12" :sm="12" :lg="6" class="card-panel-col"> <el-col :xs="12" :sm="12" :lg="6" class="card-panel-col">
<div class="card-panel" @click="handleSetLineChartData('law')"> <div class="card-panel" @click="handleSetLineChartData('shoppings')">
<div class="card-panel-icon-wrapper icon-shopping"> <div class="card-panel-icon-wrapper icon-shopping">
<svg-icon icon-class="server" class-name="card-panel-icon" /> <svg-icon icon-class="shopping" class-name="card-panel-icon" />
</div> </div>
<div class="card-panel-description"> <div class="card-panel-description">
<div class="card-panel-text"> <div class="card-panel-text">
执法数据 Shoppings
</div> </div>
<count-to :start-val="0" :end-val="groupData.law" :duration="3600" class="card-panel-num" /> <count-to :start-val="0" :end-val="13600" :duration="3600" class="card-panel-num" />
</div> </div>
</div> </div>
</el-col> </el-col>
@ -57,34 +57,15 @@
<script> <script>
import CountTo from 'vue-count-to' import CountTo from 'vue-count-to'
import {getCardData} from '@/api/dashboard/dashboard'
export default { export default {
components: { components: {
CountTo CountTo
}, },
data() {
return {
groupData: {
"user": 0,
"dept": 0,
"role": 0,
"law": 0,
}
}
},
created() {
this.getGroup();
},
methods: { methods: {
getGroup() {
getCardData().then(res => {
this.groupData = res
})
},
handleSetLineChartData(type) { handleSetLineChartData(type) {
this.$emit('handleSetLineChartData', type) this.$emit('handleSetLineChartData', type)
}, }
} }
} }
</script> </script>

View File

@ -1,82 +1,79 @@
<template> <template>
<div class="dashboard-container"> <div class="dashboard-container">
<div class="dashboard-editor-container"> <div class="dashboard-editor-container">
<github-corner class="github-corner" />
<panel-group @handleSetLineChartData="handleSetLineChartData" /> <panel-group @handleSetLineChartData="handleSetLineChartData" />
<el-row style="background:#fff;padding:16px 16px 0;margin-bottom:32px;"> <el-row style="background:#fff;padding:16px 16px 0;margin-bottom:32px;">
<line-chart :chart-data="lineChartData" :chartData="lineChartData" /> <line-chart :chart-data="lineChartData" />
</el-row> </el-row>
<el-row :gutter="32"> <el-row :gutter="32">
<!-- <el-col :xs="24" :sm="24" :lg="8">--> <el-col :xs="24" :sm="24" :lg="8">
<!-- <div class="chart-wrapper">--> <div class="chart-wrapper">
<!-- <radar-chart />--> <radar-chart />
<!-- </div>--> </div>
<!-- </el-col>--> </el-col>
<el-col :xs="24" :sm="24" :lg="24"> <el-col :xs="24" :sm="24" :lg="8">
<div class="chart-wrapper"> <div class="chart-wrapper">
<pie-chart /> <pie-chart />
</div> </div>
</el-col> </el-col>
<!-- <el-col :xs="24" :sm="24" :lg="12">--> <el-col :xs="24" :sm="24" :lg="8">
<!-- <div class="chart-wrapper">--> <div class="chart-wrapper">
<!-- <bar-chart />--> <bar-chart />
<!-- </div>--> </div>
<!-- </el-col>--> </el-col>
</el-row> </el-row>
</div> </div>
</div> </div>
</template> </template>
<script> <script>
import GithubCorner from '@/components/GithubCorner'
import PanelGroup from './dashboard/PanelGroup' import PanelGroup from './dashboard/PanelGroup'
import LineChart from './dashboard/LineChart' import LineChart from './dashboard/LineChart'
// import RadarChart from '@/components/Echarts/RadarChart' import RadarChart from '@/components/Echarts/RadarChart'
import PieChart from '@/components/Echarts/PieChart' import PieChart from '@/components/Echarts/PieChart'
// import BarChart from '@/components/Echarts/BarChart' import BarChart from '@/components/Echarts/BarChart'
import { getLineChart} from '@/api/dashboard/dashboard'
const lineChartData = { const lineChartData = {
user: { newVisitis: {
data: [100, 120, 161, 134, 105, 160, 165], expectedData: [100, 120, 161, 134, 105, 160, 165],
// actualData: [120, 82, 91, 154, 162, 140, 145] actualData: [120, 82, 91, 154, 162, 140, 145]
}, },
dept: { messages: {
data: [200, 192, 120, 144, 160, 130, 140], expectedData: [200, 192, 120, 144, 160, 130, 140],
// actualData: [180, 160, 151, 106, 145, 150, 130] actualData: [180, 160, 151, 106, 145, 150, 130]
}, },
role: { purchases: {
data: [80, 100, 121, 104, 105, 90, 100], expectedData: [80, 100, 121, 104, 105, 90, 100],
// actualData: [120, 90, 100, 138, 142, 130, 130] actualData: [120, 90, 100, 138, 142, 130, 130]
}, },
law: { shoppings: {
data: [130, 140, 141, 142, 145, 150, 160], expectedData: [130, 140, 141, 142, 145, 150, 160],
// actualData: [120, 82, 91, 154, 162, 140, 130] actualData: [120, 82, 91, 154, 162, 140, 130]
} }
} }
export default { export default {
name: 'Dashboard', name: 'Dashboard',
components: { components: {
GithubCorner,
PanelGroup, PanelGroup,
LineChart, LineChart,
// RadarChart, RadarChart,
PieChart, PieChart,
// BarChart BarChart
}, },
data() { data() {
return { return {
lineChartData: lineChartData.user lineChartData: lineChartData.newVisitis
} }
}, },
created() {
this.handleSetLineChartData("user");
},
methods: { methods: {
handleSetLineChartData(type) { handleSetLineChartData(type) {
getLineChart(type).then(res => { this.lineChartData = lineChartData[type]
this.lineChartData.data = res
})
} }
} }
} }

View File

@ -2,7 +2,7 @@
<div class="login" :style="'background-image:url('+ Background +');'"> <div class="login" :style="'background-image:url('+ Background +');'">
<el-form ref="loginForm" :model="loginForm" :rules="loginRules" label-position="left" label-width="0px" class="login-form"> <el-form ref="loginForm" :model="loginForm" :rules="loginRules" label-position="left" label-width="0px" class="login-form">
<h3 class="title"> <h3 class="title">
数据安全管理中心 ELADMIN 后台管理系统
</h3> </h3>
<el-form-item prop="username"> <el-form-item prop="username">
<el-input v-model="loginForm.username" type="text" auto-complete="off" placeholder="账号"> <el-input v-model="loginForm.username" type="text" auto-complete="off" placeholder="账号">
@ -47,7 +47,7 @@ import Config from '@/settings'
import { getCodeImg } from '@/api/login' import { getCodeImg } from '@/api/login'
import Cookies from 'js-cookie' import Cookies from 'js-cookie'
import qs from 'qs' import qs from 'qs'
import Background from '@/assets/images/background2.jpeg' import Background from '@/assets/images/background.jpeg'
export default { export default {
name: 'Login', name: 'Login',
data() { data() {

View File

@ -0,0 +1,144 @@
<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/maint/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>

View File

@ -0,0 +1,86 @@
<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" />
<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>

View File

@ -0,0 +1,148 @@
<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/maint/database'
import { testDbConnect } from '@/api/maint/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>

View File

@ -0,0 +1,190 @@
<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" />
<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/maint/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 === '/' ? '/' : (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>

View File

@ -0,0 +1,229 @@
<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/maint/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>

View File

@ -0,0 +1,107 @@
<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"
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/maint/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.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>

View File

@ -0,0 +1,93 @@
<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/maint/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>

View File

@ -0,0 +1,136 @@
<template>
<div class="app-container">
<!--工具栏-->
<div class="head-container">
<div v-if="crud.props.searchToggle">
<!-- 搜索 -->
<el-input v-model="query.blurry" 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/maint/serverDeploy'
import { testServerConnect } from '@/api/maint/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>

View File

@ -0,0 +1,36 @@
<template>
<div class="app-container">
<el-alert :closable="false" title="三级菜单1" type="success" />
<el-form label-width="170px" style="margin-top: 20px">
<el-form-item label="三级菜单缓存功能测试区">
<el-input v-model="input" placeholder="请输入内容" style="width: 360px;" />
</el-form-item>
</el-form>
<div>
<blockquote class="my-blockquote"> 三级菜单缓存配置教程</blockquote>
<pre class="my-code">
1将前后端代码更新为最新版版本或对照提交记录修改,点击查看-> <a href="https://gitee.com/elunez/eladmin/commit/43d1a63577f9d5347924355708429a2d210e29f7" target="_blank">提交(1)</a><a href="https://gitee.com/elunez/eladmin/commit/46393875148fcca5eaa327d4073f72edb3752f5c" target="_blank">提交(2)</a><a href="https://gitee.com/elunez/eladmin-web/commit/c93c99d8921abbb2c52afc806635f5ca08d6bda8" target="_blank">提交(3)</a>
2 二级菜单 菜单类型 设置为 目录 级别并且原有的 组件路径 需要清空
3 三级菜单 菜单缓存 设置为 最后将 组件名称 填写正确
4具体设置可参考 菜单管理 多级菜单 配置进行进行相应的修改
</pre>
<blockquote class="my-blockquote">更多帮助</blockquote>
<pre class="my-code">QQ交流群一群891137268二群947578238三群659622532</pre>
</div>
</div>
</template>
<script>
export default {
name: 'Test',
data() {
return {
input: ''
}
}
}
</script>
<style scoped>
.my-code a{
color:#009688;
}
</style>

View File

@ -0,0 +1,5 @@
<template>
<div style="padding:30px;">
<el-alert :closable="false" title="三级菜单2" type="success" />
</div>
</template>

View File

@ -0,0 +1,5 @@
<template>
<div style="padding:30px;">
<el-alert :closable="false" title="二级菜单" />
</div>
</template>

View File

@ -1,361 +0,0 @@
<template>
<div class="app-container">
<!--工具栏-->
<div class="head-container">
<div v-if="crud.props.searchToggle">
<!-- 搜索 -->
<el-input v-model="query.caseNumber" size="small" placeholder="输入案件编号搜索" style="width: 180px;"
class="filter-item" @keyup.enter.native="crud.toQuery"/>
<el-input v-model="query.involvedPerson" size="small" placeholder="输入涉案人员搜索"
style="width: 180px;" class="filter-item" @keyup.enter.native="crud.toQuery"/>
<el-input v-model="query.involvedCompany" size="small" placeholder="输入涉案企业搜索"
style="width: 180px;" class="filter-item" @keyup.enter.native="crud.toQuery"/>
<el-input v-model="query.lawEnforcementOfficer" size="small" placeholder="输入执法人员搜索"
style="width: 180px;" class="filter-item" @keyup.enter.native="crud.toQuery"/>
<date-range-picker v-model="query.filingTimes" startPlaceholder="立案开始时间" class="date-item"
endPlaceholder="立案结束时间"/>
<date-range-picker v-model="query.caseTimes" startPlaceholder="案发开始时间" class="date-item"
endPlaceholder="案发结束时间"/>
<el-select v-model="query.caseType" size="small" placeholder="案件类型" class="filter-item"
style="width: 120px" @change="crud.toQuery">
<el-option key="" label="全部" value=""/>
<el-option v-for="item in dict.case_type" :key="item.label" :label="item.value" :value="item.value"/>
</el-select>
<el-select v-model="query.caseStatus" size="small" placeholder="案件状态" class="filter-item"
style="width: 120px" @change="crud.toQuery">
<el-option key="" label="全部" value=""/>
<el-option v-for="item in caseStatusOptions" :key="item.key" :label="item.name" :value="item.key"/>
</el-select>
<rrOperation/>
</div>
<!--如果想在工具栏加入更多按钮可以使用插槽方式 slot = 'left' or 'right'-->
<crudOperation :permission="permission"/>
<!--表单组件-->
<el-dialog :close-on-click-modal="false" :before-close="crud.cancelCU" :visible.sync="crud.status.cu > 0" :title="crud.status.title" width="1080px">
<el-form ref="form" :model="form" :rules="rules" size="small" label-width="80px">
<div style="display: flex; gap: 10px;">
<el-form-item label="案件编号" prop="caseNumber">
<el-input v-model="form.caseNumber" style="width: 260px;"/>
</el-form-item>
<el-form-item label="案件类型" prop="caseType">
<el-select v-model="form.caseType" style="width: 260px">
<el-option v-for="item in dict.case_type" :key="item.label" :label="item.value" :value="item.value"/>
</el-select>
</el-form-item>
<el-form-item label="案件标题" prop="caseTitle">
<el-input v-model="form.caseTitle" style="width: 260px;"/>
</el-form-item>
</div>
<div style="display: flex; gap: 10px;">
<el-form-item label="案发地点" prop="caseLocation">
<el-input v-model="form.caseLocation" style="width: 260px;"/>
</el-form-item>
<el-form-item label="案件状态" prop="caseStatus">
<el-select v-model="form.caseStatus" size="small" placeholder="案件状态" class="filter-item"
style="width: 260px">
<el-option v-for="item in caseStatusOptions" :key="item.key" :label="item.name" :value="item.key"/>
</el-select>
</el-form-item>
<el-form-item label="案发时间" prop="caseTime">
<el-date-picker type="datetime" value-format="yyyy-MM-dd HH:mm:ss" v-model="form.caseTime"
style="width: 260px;"></el-date-picker>
</el-form-item>
</div>
<div style="display: flex; gap: 10px;">
<el-form-item label="案件描述" prop="caseDescription">
<el-input v-model="form.caseDescription" style="width: 960px;" rows="2" type="textarea"/>
</el-form-item>
</div>
<div style="display: flex; gap: 10px;">
<el-form-item label="涉案企业" prop="involvedCompany">
<el-input v-model="form.involvedCompany" style="width: 260px;"/>
</el-form-item>
<el-form-item label="涉案人员" prop="involvedPerson">
<el-input v-model="form.involvedPerson" style="width: 260px;"/>
</el-form-item>
<el-form-item label="涉案金额" prop="caseAmount">
<el-input v-model="form.caseAmount" style="width: 260px;" type="number" min="0"/>
</el-form-item>
</div>
<div style="display: flex; gap: 10px;">
<el-form-item label="执法人员" prop="lawEnforcementOfficer">
<el-input v-model="form.lawEnforcementOfficer" style="width: 260px;"/>
</el-form-item>
<el-form-item label="执法部门" prop="enforcementDepartment">
<el-input v-model="form.enforcementDepartment" style="width: 260px;"/>
</el-form-item>
<el-form-item label="执法行为" prop="enforcementAction">
<el-input v-model="form.enforcementAction" style="width: 260px;"/>
</el-form-item>
</div>
<div style="display: flex; gap: 10px;">
<el-form-item label="处罚类型" prop="punishmentType">
<el-input v-model="form.punishmentType" style="width: 260px;"/>
</el-form-item>
<el-form-item label="处罚金额" prop="punishmentAmount">
<el-input v-model="form.punishmentAmount" style="width: 260px;" type="number" min="0"/>
</el-form-item>
<el-form-item label="立案时间" prop="filingTime">
<el-date-picker type="datetime" value-format="yyyy-MM-dd HH:mm:ss" v-model="form.filingTime"
style="width: 260px;"></el-date-picker>
</el-form-item>
</div>
<div style="display: flex; gap: 10px;">
<el-form-item label="证据清单" prop="evidenceList">
<el-input v-model="form.evidenceList" style="width: 260px;"/>
</el-form-item>
<el-form-item label="法律依据" prop="legalBasis">
<el-input v-model="form.legalBasis" style="width: 260px;"/>
</el-form-item>
<el-form-item label="结案时间" prop="closingTime">
<el-date-picker type="datetime" value-format="yyyy-MM-dd HH:mm:ss" v-model="form.closingTime"
style="width: 260px;"></el-date-picker>
</el-form-item>
</div>
<el-form-item label="备注" prop="remark">
<el-input v-model="form.remark" style="width: 960px;" rows="2" type="textarea"/>
</el-form-item>
<el-form-item label="哈希">
<el-input v-model="form.hexId" style="width: 960px;" disabled/>
</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-dialog :close-on-click-modal="false" :visible.sync="showChainListData" title="溯源" width="1500px">
<el-table :data="chainListData" >
<el-table-column prop="caseNumber" label="案件编号" />
<el-table-column prop="caseType" label="案件类型" />
<el-table-column prop="caseTitle" label="案件标题" />
<el-table-column prop="caseDescription" label="案件描述" />
<el-table-column prop="involvedPerson" label="涉案人员" />
<el-table-column prop="involvedCompany" label="涉案企业" />
<el-table-column prop="caseAmount" label="涉案金额" />
<el-table-column prop="caseLocation" label="案发地点" />
<el-table-column prop="caseTime" label="案发时间" />
<el-table-column prop="lawEnforcementOfficer" label="执法人员" />
<el-table-column prop="enforcementDepartment" label="执法部门" />
<el-table-column prop="enforcementAction" label="执法行为" />
<el-table-column prop="punishmentType" label="处罚类型" />
<el-table-column prop="punishmentAmount" label="处罚金额" />
<el-table-column prop="caseStatus" label="案件状态" />
<el-table-column prop="filingTime" label="立案时间" />
<el-table-column prop="closingTime" label="结案时间" />
<el-table-column prop="evidenceList" label="证据清单" />
<el-table-column prop="legalBasis" label="法律依据" />
<el-table-column prop="remark" label="备注" />
<el-table-column prop="hexId" label="上链哈希"/>
<el-table-column prop="createTime" label="创建时间" />
</el-table>
<!--分页组件-->
<template>
<el-pagination
:page-size.sync="chainPage.size"
:total="chainPage.total"
:current-page.sync="chainPage.page"
style="margin-top: 8px;"
layout="total, prev, pager, next, sizes"
@size-change="chainSizeChangeHandler($event)"
@current-change="chainPageChangeHandler"
/>
</template>
</el-dialog>
<!--表格渲染-->
<el-table ref="table" v-loading="crud.loading" :data="crud.data" size="small" style="width: 100%;"
@selection-change="crud.selectionChangeHandler">
<el-table-column type="selection" width="55"/>
<el-table-column prop="caseNumber" label="案件编号"/>
<el-table-column prop="caseType" label="案件类型"/>
<el-table-column prop="caseTitle" label="案件标题"/>
<el-table-column prop="caseDescription" label="案件描述"/>
<el-table-column prop="involvedPerson" label="涉案人员"/>
<el-table-column prop="involvedCompany" label="涉案企业"/>
<el-table-column prop="caseAmount" label="涉案金额"/>
<el-table-column prop="caseLocation" label="案发地点"/>
<el-table-column prop="caseTime" label="案发时间"/>
<el-table-column prop="lawEnforcementOfficer" label="执法人员"/>
<el-table-column prop="enforcementDepartment" label="执法部门"/>
<el-table-column prop="enforcementAction" label="执法行为"/>
<el-table-column prop="punishmentType" label="处罚类型"/>
<el-table-column prop="punishmentAmount" label="处罚金额"/>
<el-table-column prop="caseStatus" label="案件状态"/>
<el-table-column prop="filingTime" label="立案时间"/>
<el-table-column prop="closingTime" label="结案时间"/>
<el-table-column prop="evidenceList" label="证据清单"/>
<el-table-column prop="legalBasis" label="法律依据"/>
<el-table-column prop="remark" label="备注"/>
<el-table-column prop="hexId" label="哈希"/>
<el-table-column prop="createTime" label="创建时间"/>
<el-table-column v-if="checkPer(['admin','busLawEnforcement:edit','busLawEnforcement:del'])" label="操作" width="260px" align="center">
<template slot-scope="scope">
<udOperation
:data="scope.row"
:permission="permission"
/>
<el-button type="success" size="mini" title="溯源" @click="openChainListData(scope.row.id)"><svg-icon icon-class="list"/></el-button>
</template>
</el-table-column>
</el-table>
<!--分页组件-->
<pagination/>
</div>
</div>
</template>
<script>
import crudBusLawEnforcement, {chainList} from '@/api/system/busLawEnforcement'
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/index.vue";
const defaultForm = {
id: null,
caseNumber: null,
caseType: null,
caseTitle: null,
caseDescription: null,
involvedPerson: null,
involvedCompany: null,
caseAmount: null,
caseLocation: null,
caseTimes: null,
caseTime: null,
lawEnforcementOfficer: null,
enforcementDepartment: null,
enforcementAction: null,
punishmentType: null,
punishmentAmount: null,
caseStatus: null,
filingTimes: null,
filingTime: null,
closingTime: null,
evidenceList: null,
legalBasis: null,
remark: null,
hexId: null,
createTime: null,
updateTime: null
}
export default {
name: 'BusLawEnforcement',
components: {DateRangePicker, pagination, crudOperation, rrOperation, udOperation},
mixins: [presenter(), header(), form(defaultForm), crud()],
//
dicts: ['case_type'],
cruds() {
return CRUD({
title: '',
url: 'api/busLawEnforcement',
idField: 'id',
sort: 'id,desc',
crudMethod: {...crudBusLawEnforcement}
})
},
data() {
return {
chainPage: { page: 1, size: 8, total: 0 },
chainLawId: null,
chainListData: [],
showChainListData: false,
permission: {
add: ['admin', 'busLawEnforcement:add'],
edit: ['admin', 'busLawEnforcement:edit'],
del: ['admin', 'busLawEnforcement:del']
},
caseStatusOptions: [
{'key': '处理中', 'name': '处理中'},
{'key': '已结案', 'name': '已结案'}
],
rules: {
caseNumber: [
{required: true, message: '案件编号不能为空', trigger: 'blur'}
],
caseType: [
{required: true, message: '案件类型不能为空', trigger: 'blur'}
],
caseTitle: [
{required: true, message: '案件标题不能为空', trigger: 'blur'}
],
caseLocation: [
{required: true, message: '案发地点不能为空', trigger: 'blur'}
],
caseTime: [
{required: true, message: '案发时间不能为空', trigger: 'blur'}
],
lawEnforcementOfficer: [
{required: true, message: '执法人员不能为空', trigger: 'blur'}
],
enforcementDepartment: [
{required: true, message: '执法部门不能为空', trigger: 'blur'}
],
enforcementAction: [
{required: true, message: '执法行为不能为空', trigger: 'blur'}
],
caseStatus: [
{required: true, message: '案件状态不能为空', trigger: 'blur'}
],
filingTime: [
{required: true, message: '立案时间不能为空', trigger: 'blur'}
],
legalBasis: [
{required: true, message: '法律依据不能为空', trigger: 'blur'}
],
},
}
},
created() {
this.crud.optShow = {add: true, edit: true, del: true, download: false}
},
methods: {
openChainListData(id) {
this.showChainListData = true;
this.chainLawId = id;
this.pageChainListData();
},
pageChainListData() {
let params = "?lawId=" + this.chainLawId + "&page=" + this.chainPage.page + "&size=" + this.chainPage.size;
chainList(params).then(res => {
this.chainListData = res.content;
this.chainPage.total = res.totalElements;
})
},
//
chainPageChangeHandler(e) {
this.chainPage.page = e
this.pageChainListData();
},
//
chainSizeChangeHandler(e) {
this.chainPage.size = e
this.chainPage.page = 1
this.pageChainListData();
},
// false
[CRUD.HOOK.beforeRefresh]() {
return true
},
}
}
</script>
<style scoped>
</style>

View File

@ -21,7 +21,7 @@
<ul class="user-info"> <ul class="user-info">
<li><div style="height: 100%"><svg-icon icon-class="login" /> 登录账号<div class="user-right">{{ user.username }}</div></div></li> <li><div style="height: 100%"><svg-icon icon-class="login" /> 登录账号<div class="user-right">{{ user.username }}</div></div></li>
<li><svg-icon icon-class="user1" /> 用户昵称 <div class="user-right">{{ user.nickName }}</div></li> <li><svg-icon icon-class="user1" /> 用户昵称 <div class="user-right">{{ user.nickName }}</div></li>
<li><svg-icon icon-class="dept" /> 所属医院 <div class="user-right"> {{ user.dept.name }}</div></li> <li><svg-icon icon-class="dept" /> 所属部门 <div class="user-right"> {{ user.dept.name }}</div></li>
<li><svg-icon icon-class="phone" /> 手机号码 <div class="user-right">{{ user.phone }}</div></li> <li><svg-icon icon-class="phone" /> 手机号码 <div class="user-right">{{ user.phone }}</div></li>
<li><svg-icon icon-class="email" /> 用户邮箱 <div class="user-right">{{ user.email }}</div></li> <li><svg-icon icon-class="email" /> 用户邮箱 <div class="user-right">{{ user.email }}</div></li>
<li> <li>

View File

@ -0,0 +1,98 @@
<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>

View File

@ -0,0 +1,48 @@
<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>

View File

@ -0,0 +1,86 @@
<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>

View File

@ -0,0 +1,91 @@
<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>

View File

@ -0,0 +1,41 @@
<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>

View File

@ -0,0 +1,98 @@
<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" placeholder="请输入邮件标题,标题不能为空" />
</el-form-item>
<el-form-item label="收件地址" prop="tos">
<el-input v-model="form.tos" style="width: 646px" placeholder="请输入收件地址,多个地址英文逗号,隔开" />
</el-form-item>
<div ref="editor" class="editor" />
<el-button :loading="loading" style="margin-left:1.6%;margin-bottom: 30px" 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 { mapGetters } from 'vuex'
import E from 'wangeditor'
export default {
name: 'Index',
data() {
return {
loading: false, form: { subject: '', tos: '', content: '' },
rules: {
subject: [
{ required: true, message: '标题不能为空', trigger: 'blur' }
],
tos: [
{ required: true, message: '收件人不能为空', trigger: 'blur' }
]
}
}
},
computed: {
...mapGetters([
'imagesUploadApi',
'baseApi'
])
},
mounted() {
const _this = this
var editor = new E(this.$refs.editor)
//
editor.config.zIndex = 10
//
editor.config.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.config.onchange = (html) => {
this.form.content = html
}
editor.create()
},
methods: {
doSubmit() {
this.$refs['form'].validate((valid) => {
if (valid) {
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>

View File

@ -3,19 +3,18 @@
<el-tab-pane label="本地存储" name="first"> <el-tab-pane label="本地存储" name="first">
<Local ref="local" /> <Local ref="local" />
</el-tab-pane> </el-tab-pane>
<!-- <el-tab-pane label="七牛云存储" name="second">--> <el-tab-pane label="七牛云存储" name="second">
<!-- <QiNiu ref="qiNiu" />--> <QiNiu ref="qiNiu" />
<!-- </el-tab-pane>--> </el-tab-pane>
</el-tabs> </el-tabs>
</template> </template>
<script> <script>
// import QiNiu from './qiniu/index' import QiNiu from './qiniu/index'
import Local from './local/index' import Local from './local/index'
export default { export default {
name: 'Storage', name: 'Storage',
components: { Local }, components: { QiNiu, Local },
// components: { QiNiu, Local },
data() { data() {
return { return {
activeName: 'first' activeName: 'first'

View File

@ -0,0 +1,98 @@
<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>

View File

@ -0,0 +1,189 @@
<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>

View File

@ -176,7 +176,7 @@ recommend that a file or class name and description of purpose be included on
the same "printed page" as the copyright notice for easier identification within the same "printed page" as the copyright notice for easier identification within
third-party archives. third-party archives.
Copyright 2019-2025 Tz Copyright 2019-2025 Zheng Jie
Licensed under the Apache License, Version 2.0 (the "License"); Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. you may not use this file except in compliance with the License.

View File

@ -1,17 +1,26 @@
<h1 style="text-align: center">区块链技术的隐私保护和执法数据管理系统</h1> <h1 style="text-align: center">ELADMIN 后台管理系统</h1>
#### 项目简介 #### 项目简介
一个基于 Spring Boot 2.7.18 、 Mybatis-Plus、 JWT、Spring Security、Redis、Vue的前后端分离的后台管理系统 一个基于 Spring Boot 2.7.18 、 Mybatis-Plus、 JWT、Spring Security、Redis、Vue的前后端分离的后台管理系统
**开发文档:** [https://eladmin.vip](https://eladmin.vip)
**体验地址:** [https://eladmin.vip/demo](https://eladmin.vip/demo)
**账号密码:** `admin / 123456` **账号密码:** `admin / 123456`
#### 项目结构 #### 项目源码
项目采用按功能分模块的开发方式,结构如下
- `eladmin-common` 为系统的公共模块,各种工具类,公共配置存在该模块 | github | gitee |
|--------------------------------------| --- |
| https://github.com/elunez/eladmin-mp | https://gitee.com/elunez/eladmin-mp |
- `eladmin-system` 为系统核心模块也是项目入口模块,也是最终需要打包部署的模块 #### VPS推荐
<a href="https://bwh81.net/aff.php?aff=70876" target="_blank">
<img src="https://eladmin.vip/images/banner/side.jpeg" style="width: 435px;border-radius: 2px;" alt="帮瓦工">
</a>
使用优惠码: `BWHNCXNVXV`,可获得 6.81% 的折扣, [查看介绍](https://eladmin.vip/pages/040101/)
#### 主要特性 #### 主要特性
- 使用最新技术栈,社区资源丰富。 - 使用最新技术栈,社区资源丰富。
- 高效率开发,代码生成器可一键生成前后端代码 - 高效率开发,代码生成器可一键生成前后端代码
@ -32,7 +41,14 @@
- 岗位管理:配置各个部门的职位 - 岗位管理:配置各个部门的职位
- 字典管理:可维护常用一些固定的数据,如:状态,性别等 - 字典管理:可维护常用一些固定的数据,如:状态,性别等
- 系统日志:记录用户操作日志与异常日志,方便开发人员定位排错 - 系统日志:记录用户操作日志与异常日志,方便开发人员定位排错
- 执法数据:对执法信息的上链保护已经链路溯源 - SQL监控采用druid 监控数据库访问性能默认用户名admin密码123456
- 定时任务整合Quartz做定时任务加入任务日志任务运行情况一目了然
- 代码生成:高灵活度生成前后端代码,减少大量重复的工作任务
- 邮件工具配合富文本发送html格式的邮件
- 七牛云存储:可同步七牛云存储的数据到系统,无需登录七牛云直接操作云数据
- 支付宝支付:整合了支付宝支付并且提供了测试账号,可自行测试
- 服务监控:监控服务器的负载情况
- 运维管理:一键部署你的应用
#### 项目结构 #### 项目结构
项目采用按功能分模块的开发方式,结构如下 项目采用按功能分模块的开发方式,结构如下
@ -41,6 +57,12 @@
- `eladmin-system` 为系统核心模块也是项目入口模块,也是最终需要打包部署的模块 - `eladmin-system` 为系统核心模块也是项目入口模块,也是最终需要打包部署的模块
- `eladmin-logging` 为系统的日志模块,其他模块如果需要记录日志需要引入该模块
- `eladmin-tools` 为第三方工具模块,包含:邮件、七牛云存储、本地存储、支付宝
- `eladmin-generator` 为系统的代码生成模块支持生成前后端CRUD代码
#### 详细结构 #### 详细结构
``` ```
@ -65,5 +87,28 @@
- FileUtil 文件工具类 - FileUtil 文件工具类
- eladmin-system 系统核心模块(系统启动入口) - eladmin-system 系统核心模块(系统启动入口)
- sysrunner 程序启动后处理数据 - sysrunner 程序启动后处理数据
- modules 系统相关模块(登录授权、系统模块、运维模块) - modules 系统相关模块(登录授权、系统监控、定时任务、系统模块、运维模块)
- eladmin-logging 系统日志模块
- eladmin-tools 系统第三方工具模块
- email 邮件工具
- qiniu 七牛云存储工具
- alipay 支付宝支付工具
- local-storage 本地存储工具
- eladmin-generator 系统代码生成模块
``` ```
#### 特别鸣谢
- 感谢 [PanJiaChen](https://github.com/PanJiaChen/vue-element-admin) 大佬提供的前端模板
- 感谢 [Moxun](https://github.com/moxun1639) 大佬提供的前端 Curd 通用组件
- 感谢 [zhy6599](https://gitee.com/zhy6599) 大佬提供的后端运维管理相关功能
- 感谢 [j.yao.SUSE](https://github.com/everhopingandwaiting) 大佬提供的匿名接口与Redis限流等功能
#### 项目捐赠
项目的发展离不开你的支持,请作者喝杯咖啡吧☕ [Donate](https://eladmin.vip/pages/030101/)
#### 反馈交流
- QQ交流群891137268 、947578238、659622532

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2019-2025 Tz * Copyright 2019-2025 Zheng Jie
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2019-2025 Tz * Copyright 2019-2025 Zheng Jie
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2019-2025 Tz * Copyright 2019-2025 Zheng Jie
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2019-2025 Tz * Copyright 2019-2025 Zheng Jie
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2019-2025 Tz * Copyright 2019-2025 Zheng Jie
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -30,7 +30,7 @@ import java.sql.Timestamp;
/** /**
* 通用字段 is_del 根据需求自行添加 * 通用字段 is_del 根据需求自行添加
* @author Tz * @author Zheng Jie
* @date 2019年10月24日20:46:32 * @date 2019年10月24日20:46:32
*/ */
@Getter @Getter

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2019-2025 Tz * Copyright 2019-2025 Zheng Jie
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -26,7 +26,7 @@ import java.util.concurrent.atomic.AtomicInteger;
/** /**
* 创建自定义的线程池 * 创建自定义的线程池
* @author Tz * @author Zheng Jie
* @description * @description
* @date 2023-06-08 * @date 2023-06-08
**/ **/

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2019-2025 Tz * Copyright 2019-2025 Zheng Jie
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -23,7 +23,7 @@ import java.util.List;
import java.util.stream.Collectors; import java.util.stream.Collectors;
/** /**
* @author Tz * @author Zheng Jie
*/ */
@Service(value = "el") @Service(value = "el")
public class AuthorityConfig { public class AuthorityConfig {

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2019-2025 Tz * Copyright 2019-2025 Zheng Jie
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -20,8 +20,6 @@ import com.alibaba.fastjson2.JSONFactory;
import com.alibaba.fastjson2.JSONWriter; import com.alibaba.fastjson2.JSONWriter;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.digest.MurmurHash3; import org.apache.commons.codec.digest.MurmurHash3;
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
import org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration;
import org.springframework.cache.Cache; import org.springframework.cache.Cache;
import org.springframework.cache.annotation.CachingConfigurerSupport; import org.springframework.cache.annotation.CachingConfigurerSupport;
import org.springframework.cache.annotation.EnableCaching; import org.springframework.cache.annotation.EnableCaching;
@ -44,13 +42,12 @@ import java.util.HashMap;
import java.util.Map; import java.util.Map;
/** /**
* @author Tz * @author Zheng Jie
* @date 2025-01-13 * @date 2025-01-13
*/ */
@Slf4j @Slf4j
@Configuration @Configuration
@EnableCaching @EnableCaching
@AutoConfigureBefore(RedisAutoConfiguration.class)
public class RedisConfiguration extends CachingConfigurerSupport { public class RedisConfiguration extends CachingConfigurerSupport {
// 自动识别json对象白名单配置仅允许解析的包名范围越小越安全 // 自动识别json对象白名单配置仅允许解析的包名范围越小越安全

View File

@ -6,14 +6,11 @@ import org.redisson.Redisson;
import org.redisson.api.RedissonClient; import org.redisson.api.RedissonClient;
import org.redisson.config.Config; import org.redisson.config.Config;
import org.springframework.beans.factory.annotation.Value; import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
import org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
@Data @Data
@Configuration @Configuration
@AutoConfigureBefore(RedisAutoConfiguration.class)
public class RedissonConfiguration { public class RedissonConfiguration {
@Value("${spring.redis.host}") @Value("${spring.redis.host}")

View File

@ -15,7 +15,7 @@ import javax.servlet.http.HttpServletResponse;
import java.io.IOException; import java.io.IOException;
/** /**
* @author Tz * @author Zheng Jie
* @description * @description
* @date 2025-01-11 * @date 2025-01-11
**/ **/

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2019-2025 Tz * Copyright 2019-2025 Zheng Jie
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -20,7 +20,7 @@ import com.p6spy.engine.spy.appender.MessageFormattingStrategy;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
/** /**
* @author Tz * @author Zheng Jie
* @description 自定义 p6spy sql输出格式 * @description 自定义 p6spy sql输出格式
* @date 2024-12-26 * @date 2024-12-26
**/ **/

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2019-2025 Tz * Copyright 2019-2025 Zheng Jie
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -23,7 +23,7 @@ import org.springframework.stereotype.Component;
import java.sql.Timestamp; import java.sql.Timestamp;
/** /**
* @author Tz * @author Zheng Jie
* @description * @description
* @date 2023-06-13 * @date 2023-06-13
**/ **/

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2019-2025 Tz * Copyright 2019-2025 Zheng Jie
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -22,7 +22,7 @@ import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
/** /**
* @author Tz * @author Zheng Jie
* @description * @description
* @date 2023-06-12 * @date 2023-06-12
**/ **/

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2019-2025 Tz * Copyright 2019-2025 Zheng Jie
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -21,7 +21,7 @@ import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
/** /**
* @author Tz * @author Zheng Jie
*/ */
@Data @Data
@Configuration @Configuration

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2019-2025 Tz * Copyright 2019-2025 Zheng Jie
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -20,7 +20,7 @@ import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
/** /**
* @author Tz * @author Zheng Jie
* @website <a href="https://eladmin.vip">...</a> * @website <a href="https://eladmin.vip">...</a>
* @description * @description
* @date 2020-05-18 * @date 2020-05-18

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2019-2025 Tz * Copyright 2019-2025 Zheng Jie
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -37,7 +37,7 @@ import java.util.List;
/** /**
* WebMvcConfigurer * WebMvcConfigurer
* *
* @author Tz * @author Zheng Jie
* @date 2018-11-30 * @date 2018-11-30
*/ */
@Configuration @Configuration

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2019-2025 Tz * Copyright 2019-2025 Zheng Jie
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2019-2023 Tz * Copyright 2019-2023 Zheng Jie
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2019-2025 Tz * Copyright 2019-2025 Zheng Jie
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -47,7 +47,7 @@ import java.util.stream.Collectors;
/** /**
* api页面 /doc.html * api页面 /doc.html
* @author Tz * @author Zheng Jie
* @date 2018-11-23 * @date 2018-11-23
*/ */
@Configuration @Configuration

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2019-2025 Tz * Copyright 2019-2025 Zheng Jie
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -20,7 +20,7 @@ import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.server.standard.ServerEndpointExporter; import org.springframework.web.socket.server.standard.ServerEndpointExporter;
/** /**
* @author Tz * @author ZhangHouYing
* @date 2019-08-24 15:44 * @date 2019-08-24 15:44
*/ */
@Configuration @Configuration

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2019-2025 Tz * Copyright 2019-2025 Zheng Jie
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -20,7 +20,7 @@ import org.springframework.http.HttpStatus;
import static org.springframework.http.HttpStatus.BAD_REQUEST; import static org.springframework.http.HttpStatus.BAD_REQUEST;
/** /**
* @author Tz * @author Zheng Jie
* @date 2018-11-23 * @date 2018-11-23
* 统一异常处理 * 统一异常处理
*/ */

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2019-2025 Tz * Copyright 2019-2025 Zheng Jie
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -18,7 +18,7 @@ package me.zhengjie.exception;
import org.springframework.util.StringUtils; import org.springframework.util.StringUtils;
/** /**
* @author Tz * @author Zheng Jie
* @date 2018-11-23 * @date 2018-11-23
*/ */
public class EntityExistException extends RuntimeException { public class EntityExistException extends RuntimeException {

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2019-2025 Tz * Copyright 2019-2025 Zheng Jie
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -18,7 +18,7 @@ package me.zhengjie.exception;
import org.springframework.util.StringUtils; import org.springframework.util.StringUtils;
/** /**
* @author Tz * @author Zheng Jie
* @date 2018-11-23 * @date 2018-11-23
*/ */
public class EntityNotFoundException extends RuntimeException { public class EntityNotFoundException extends RuntimeException {

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2019-2025 Tz * Copyright 2019-2025 Zheng Jie
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -18,7 +18,7 @@ package me.zhengjie.exception.handler;
import lombok.Data; import lombok.Data;
/** /**
* @author Tz * @author Zheng Jie
* @date 2018-11-23 * @date 2018-11-23
*/ */
@Data @Data

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2019-2025 Tz * Copyright 2019-2025 Zheng Jie
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -31,7 +31,7 @@ import org.springframework.web.bind.annotation.RestControllerAdvice;
import static org.springframework.http.HttpStatus.*; import static org.springframework.http.HttpStatus.*;
/** /**
* @author Tz * @author Zheng Jie
* @date 2018-11-23 * @date 2018-11-23
*/ */
@Slf4j @Slf4j

View File

@ -25,7 +25,7 @@ import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandl
import java.util.*; import java.util.*;
/** /**
* @author Tz * @author Zheng Jie
* @description 匿名标记工具 * @description 匿名标记工具
* @date 2025-01-13 * @date 2025-01-13
**/ **/

View File

@ -19,7 +19,7 @@ import java.math.BigDecimal;
import java.math.RoundingMode; import java.math.RoundingMode;
/** /**
* @author Tz * @author Zheng Jie
* @description 计算类 * @description 计算类
* @date 2024-12-27 * @date 2024-12-27
**/ **/

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2019-2025 Tz * Copyright 2019-2025 Zheng Jie
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -18,7 +18,7 @@ package me.zhengjie.utils;
import java.io.Closeable; import java.io.Closeable;
/** /**
* @author Tz * @author Zheng Jie
* @description 用于关闭各种连接缺啥补啥 * @description 用于关闭各种连接缺啥补啥
* @date 2021-03-05 * @date 2021-03-05
**/ **/

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2019-2025 Tz * Copyright 2019-2025 Zheng Jie
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -18,7 +18,7 @@ package me.zhengjie.utils;
/** /**
* 常用静态常量 * 常用静态常量
* *
* @author Tz * @author Zheng Jie
* @date 2018-12-26 * @date 2018-12-26
*/ */
public class ElConstant { public class ElConstant {

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2019-2025 Tz * Copyright 2019-2025 Zheng Jie
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -24,7 +24,7 @@ import java.nio.charset.StandardCharsets;
/** /**
* 加密 * 加密
* @author Tz * @author Zheng Jie
* @date 2018-11-23 * @date 2018-11-23
*/ */
public class EncryptUtils { public class EncryptUtils {

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2019-2025 Tz * Copyright 2019-2025 Zheng Jie
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -38,7 +38,7 @@ import java.util.stream.Collectors;
/** /**
* File工具类扩展 hutool 工具包 * File工具类扩展 hutool 工具包
* *
* @author Tz * @author Zheng Jie
* @date 2018-12-27 * @date 2018-12-27
*/ */
@Slf4j @Slf4j
@ -213,7 +213,7 @@ public class FileUtil extends cn.hutool.core.io.FileUtil {
BigExcelWriter writer = ExcelUtil.getBigWriter(file); BigExcelWriter writer = ExcelUtil.getBigWriter(file);
// 处理数据以防止CSV注入 // 处理数据以防止CSV注入
List<Map<String, Object>> sanitizedList = list.parallelStream().map(map -> { List<Map<String, Object>> sanitizedList = list.parallelStream().map(map -> {
Map<String, Object> sanitizedMap = new LinkedHashMap<>(); Map<String, Object> sanitizedMap = new HashMap<>();
map.forEach((key, value) -> { map.forEach((key, value) -> {
if (value instanceof String) { if (value instanceof String) {
String strValue = (String) value; String strValue = (String) value;

View File

@ -6,7 +6,7 @@ import java.util.List;
/** /**
* 分页结果封装类 * 分页结果封装类
* @author Tz * @author Zheng Jie
* @date 2018-11-23 * @date 2018-11-23
* @param <T> * @param <T>
*/ */

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2019-2025 Tz * Copyright 2019-2025 Zheng Jie
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -20,7 +20,7 @@ import java.util.*;
/** /**
* 分页工具 * 分页工具
* @author Tz * @author Zheng Jie
* @date 2018-12-10 * @date 2018-12-10
*/ */
public class PageUtil extends cn.hutool.core.util.PageUtil { public class PageUtil extends cn.hutool.core.util.PageUtil {

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2019-2025 Tz * Copyright 2019-2025 Zheng Jie
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2019-2025 Tz * Copyright 2019-2025 Zheng Jie
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -22,7 +22,7 @@ import java.util.Objects;
/** /**
* 获取 HttpServletRequest * 获取 HttpServletRequest
* @author Tz * @author Zheng Jie
* @date 2018-11-24 * @date 2018-11-24
*/ */
public class RequestHolder { public class RequestHolder {

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2019-2025 Tz * Copyright 2019-2025 Zheng Jie
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -35,7 +35,7 @@ import java.util.Objects;
/** /**
* 获取当前登录的用户 * 获取当前登录的用户
* @author Tz * @author Zheng Jie
* @date 2019-01-17 * @date 2019-01-17
*/ */
@Slf4j @Slf4j

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2019-2025 Tz * Copyright 2019-2025 Zheng Jie
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2019-2025 Tz * Copyright 2019-2025 Zheng Jie
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -28,7 +28,7 @@ import java.net.UnknownHostException;
import java.util.*; import java.util.*;
/** /**
* @author Tz * @author Zheng Jie
* 字符串工具类, 继承org.apache.commons.lang3.StringUtils类 * 字符串工具类, 继承org.apache.commons.lang3.StringUtils类
*/ */
@Slf4j @Slf4j

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2019-2025 Tz * Copyright 2019-2025 Zheng Jie
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -20,7 +20,7 @@ import java.io.StringWriter;
/** /**
* 异常工具 2019-01-06 * 异常工具 2019-01-06
* @author Tz * @author Zheng Jie
*/ */
public class ThrowableUtil { public class ThrowableUtil {

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2019-2025 Tz * Copyright 2019-2025 Zheng Jie
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -22,7 +22,7 @@ import lombok.Getter;
* <p> * <p>
* 验证码业务场景 * 验证码业务场景
* </p> * </p>
* @author Tz * @author Zheng Jie
* @date 2020-05-02 * @date 2020-05-02
*/ */
@Getter @Getter

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2019-2025 Tz * Copyright 2019-2025 Zheng Jie
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -22,7 +22,7 @@ import lombok.Getter;
* <p> * <p>
* 验证码业务场景对应的 Redis 中的 key * 验证码业务场景对应的 Redis 中的 key
* </p> * </p>
* @author Tz * @author Zheng Jie
* @date 2020-05-02 * @date 2020-05-02
*/ */
@Getter @Getter

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2019-2025 Tz * Copyright 2019-2025 Zheng Jie
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -22,7 +22,7 @@ import lombok.Getter;
* <p> * <p>
* 数据权限枚举 * 数据权限枚举
* </p> * </p>
* @author Tz * @author Zheng Jie
* @date 2020-05-07 * @date 2020-05-07
*/ */
@Getter @Getter

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2019-2025 Tz * Copyright 2019-2025 Zheng Jie
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -19,7 +19,7 @@ import lombok.AllArgsConstructor;
import lombok.Getter; import lombok.Getter;
/** /**
* @author Tz * @author Zheng Jie
* @website https://eladmin.vip * @website https://eladmin.vip
* @description * @description
* @date 2020-06-10 * @date 2020-06-10

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2019-2025 Tz * Copyright 2019-2025 Zheng Jie
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -26,7 +26,7 @@ import java.io.Serializable;
/** /**
* 列的数据信息 * 列的数据信息
* @author Tz * @author Zheng Jie
* @date 2019-01-02 * @date 2019-01-02
*/ */
@Getter @Getter

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2019-2025 Tz * Copyright 2019-2025 Zheng Jie
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -28,7 +28,7 @@ import java.io.Serializable;
/** /**
* 代码生成配置 * 代码生成配置
* @author Tz * @author Zheng Jie
* @date 2019-01-03 * @date 2019-01-03
*/ */
@Getter @Getter

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2019-2025 Tz * Copyright 2019-2025 Zheng Jie
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -23,7 +23,7 @@ import lombok.NoArgsConstructor;
/** /**
* 表的数据信息 * 表的数据信息
* @author Tz * @author Zheng Jie
* @date 2019-01-02 * @date 2019-01-02
*/ */
@Data @Data

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2019-2025 Tz * Copyright 2019-2025 Zheng Jie
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -25,7 +25,7 @@ import org.apache.ibatis.annotations.Param;
import java.util.List; import java.util.List;
/** /**
* @author Tz * @author Zheng Jie
* @date 2023-06-26 * @date 2023-06-26
*/ */
@Mapper @Mapper

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2019-2025 Tz * Copyright 2019-2025 Zheng Jie
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -21,7 +21,7 @@ import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param; import org.apache.ibatis.annotations.Param;
/** /**
* @author Tz * @author Zheng Jie
* @date 2023-06-26 * @date 2023-06-26
*/ */
@Mapper @Mapper

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2019-2025 Tz * Copyright 2019-2025 Zheng Jie
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -26,7 +26,7 @@ import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.*;
/** /**
* @author Tz * @author Zheng Jie
* @date 2019-01-14 * @date 2019-01-14
*/ */
@RestController @RestController

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2019-2025 Tz * Copyright 2019-2025 Zheng Jie
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -35,7 +35,7 @@ import javax.servlet.http.HttpServletResponse;
import java.util.List; import java.util.List;
/** /**
* @author Tz * @author Zheng Jie
* @date 2019-01-02 * @date 2019-01-02
*/ */
@RestController @RestController

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2019-2025 Tz * Copyright 2019-2025 Zheng Jie
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -19,7 +19,7 @@ import com.baomidou.mybatisplus.extension.service.IService;
import me.zhengjie.domain.GenConfig; import me.zhengjie.domain.GenConfig;
/** /**
* @author Tz * @author Zheng Jie
* @date 2019-01-14 * @date 2019-01-14
*/ */
public interface GenConfigService extends IService<GenConfig> { public interface GenConfigService extends IService<GenConfig> {

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2019-2025 Tz * Copyright 2019-2025 Zheng Jie
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -27,7 +27,7 @@ import javax.servlet.http.HttpServletResponse;
import java.util.List; import java.util.List;
/** /**
* @author Tz * @author Zheng Jie
* @date 2019-01-02 * @date 2019-01-02
*/ */
public interface GeneratorService extends IService<ColumnInfo> { public interface GeneratorService extends IService<ColumnInfo> {

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2019-2025 Tz * Copyright 2019-2025 Zheng Jie
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -24,7 +24,7 @@ import org.springframework.stereotype.Service;
import java.io.File; import java.io.File;
/** /**
* @author Tz * @author Zheng Jie
* @date 2019-01-14 * @date 2019-01-14
*/ */
@Service @Service

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2019-2025 Tz * Copyright 2019-2025 Zheng Jie
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -41,7 +41,7 @@ import java.util.Map;
import java.util.stream.Collectors; import java.util.stream.Collectors;
/** /**
* @author Tz * @author Zheng Jie
* @date 2019-01-02 * @date 2019-01-02
*/ */
@Slf4j @Slf4j

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2019-2025 Tz * Copyright 2019-2025 Zheng Jie
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -22,7 +22,7 @@ import org.slf4j.LoggerFactory;
/** /**
* sql字段转java * sql字段转java
* *
* @author Tz * @author Zheng Jie
* @date 2019-01-03 * @date 2019-01-03
*/ */
public class ColUtil { public class ColUtil {

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2019-2025 Tz * Copyright 2019-2025 Zheng Jie
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -32,7 +32,7 @@ import static me.zhengjie.utils.FileUtil.SYS_TEM_DIR;
/** /**
* 代码生成 * 代码生成
* *
* @author Tz * @author Zheng Jie
* @date 2019-01-02 * @date 2019-01-02
*/ */
@Slf4j @Slf4j

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2019-2025 Tz * Copyright 2019-2025 Zheng Jie
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2019-2025 Tz * Copyright 2019-2025 Zheng Jie
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2019-2025 Tz * Copyright 2019-2025 Zheng Jie
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2019-2025 Tz * Copyright 2019-2025 Zheng Jie
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2019-2025 Tz * Copyright 2019-2025 Zheng Jie
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2019-2025 Tz * Copyright 2019-2025 Zheng Jie
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -75,7 +75,7 @@ public class ${className}ServiceImpl extends ServiceImpl<${className}Mapper, ${c
public void update(${className} resources) { public void update(${className} resources) {
${className} ${changeClassName} = getById(resources.get${pkCapitalColName}()); ${className} ${changeClassName} = getById(resources.get${pkCapitalColName}());
${changeClassName}.copy(resources); ${changeClassName}.copy(resources);
${changeClassName}Mapper.updateById(${changeClassName}); ${changeClassName}Mapper.update(${changeClassName});
} }
@Override @Override

Some files were not shown because too many files have changed in this diff Show More