This commit is contained in:
tangzh 2025-05-11 21:16:30 +08:00
parent 1154eaab0b
commit 5bc72e6f3b
295 changed files with 3016 additions and 8521 deletions

View File

@ -1,26 +1,17 @@
<h1 style="text-align: center">ELADMIN 后台管理系统</h1>
<h1 style="text-align: center">区块链技术的隐私保护和执法数据管理系统</h1>
#### 项目简介
一个基于 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`
#### 项目源码
#### 项目结构
项目采用按功能分模块的开发方式,结构如下
| github | gitee |
|--------------------------------------| --- |
| https://github.com/elunez/eladmin-mp | https://gitee.com/elunez/eladmin-mp |
- `eladmin-common` 为系统的公共模块,各种工具类,公共配置存在该模块
#### 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>
- `eladmin-system` 为系统核心模块也是项目入口模块,也是最终需要打包部署的模块
使用优惠码: `BWHNCXNVXV`,可获得 6.81% 的折扣, [查看介绍](https://eladmin.vip/pages/040101/)
#### 主要特性
- 使用最新技术栈,社区资源丰富。
- 高效率开发,代码生成器可一键生成前后端代码
@ -41,14 +32,7 @@
- 岗位管理:配置各个部门的职位
- 字典管理:可维护常用一些固定的数据,如:状态,性别等
- 系统日志:记录用户操作日志与异常日志,方便开发人员定位排错
- SQL监控采用druid 监控数据库访问性能默认用户名admin密码123456
- 定时任务整合Quartz做定时任务加入任务日志任务运行情况一目了然
- 代码生成:高灵活度生成前后端代码,减少大量重复的工作任务
- 邮件工具配合富文本发送html格式的邮件
- 七牛云存储:可同步七牛云存储的数据到系统,无需登录七牛云直接操作云数据
- 支付宝支付:整合了支付宝支付并且提供了测试账号,可自行测试
- 服务监控:监控服务器的负载情况
- 运维管理:一键部署你的应用
- 执法数据:对执法信息的上链保护已经链路溯源
#### 项目结构
项目采用按功能分模块的开发方式,结构如下
@ -57,12 +41,6 @@
- `eladmin-system` 为系统核心模块也是项目入口模块,也是最终需要打包部署的模块
- `eladmin-logging` 为系统的日志模块,其他模块如果需要记录日志需要引入该模块
- `eladmin-tools` 为第三方工具模块,包含:邮件、七牛云存储、本地存储、支付宝
- `eladmin-generator` 为系统的代码生成模块支持生成前后端CRUD代码
#### 详细结构
```
@ -87,28 +65,5 @@
- FileUtil 文件工具类
- eladmin-system 系统核心模块(系统启动入口)
- sysrunner 程序启动后处理数据
- modules 系统相关模块(登录授权、系统监控、定时任务、系统模块、运维模块)
- eladmin-logging 系统日志模块
- eladmin-tools 系统第三方工具模块
- email 邮件工具
- qiniu 七牛云存储工具
- alipay 支付宝支付工具
- local-storage 本地存储工具
- eladmin-generator 系统代码生成模块
- modules 系统相关模块(登录授权、系统模块、运维模块)
```
#### 特别鸣谢
- 感谢 [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",
"license": "Apache-2.0",
"scripts": {
"dev": "vue-cli-service serve",
"dev": "SET NODE_OPTIONS=--openssl-legacy-provider && vue-cli-service serve",
"build:prod": "vue-cli-service build",
"build:stage": "vue-cli-service build --mode staging",
"preview": "node build/index.js --preview",

View File

@ -0,0 +1,34 @@
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>
<div>
<div style="display: inline-block">
<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">
<p>{{ msg }}</p>

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -2,7 +2,7 @@
<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">
<h3 class="title">
ELADMIN 后台管理系统
数据安全管理中心
</h3>
<el-form-item prop="username">
<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 Cookies from 'js-cookie'
import qs from 'qs'
import Background from '@/assets/images/background.jpeg'
import Background from '@/assets/images/background2.jpeg'
export default {
name: 'Login',
data() {

View File

@ -1,144 +0,0 @@
<template>
<div class="app-container">
<!--工具栏-->
<div class="head-container">
<div v-if="crud.props.searchToggle">
<!-- 搜索 -->
<el-input v-model="query.name" clearable placeholder="输入名称搜索" style="width: 200px" class="filter-item" @keyup.enter.native="crud.toQuery" />
<date-range-picker v-model="query.createTime" class="date-item" />
<rrOperation />
</div>
<crudOperation :permission="permission">
<el-button
slot="left"
v-permission="['admin','app:add']"
:disabled="!currentRow"
class="filter-item"
size="mini"
type="primary"
icon="el-icon-plus"
@click="copy"
>复制</el-button>
</crudOperation>
</div>
<!--表单组件-->
<el-dialog append-to-body :close-on-click-modal="false" :before-close="crud.cancelCU" :visible.sync="crud.status.cu > 0" :title="crud.status.title" width="800px">
<el-form ref="form" :model="form" :rules="rules" size="small" label-width="100px">
<el-form-item label="应用名称" prop="name">
<el-input v-model="form.name" style="width: 670px" placeholder="部署后的文件或者目录名称,用于备份" />
</el-form-item>
<el-form-item label="应用端口" prop="port">
<el-input-number v-model.number="form.port" placeholder="例如8080" />
</el-form-item>
<el-form-item label="上传目录" prop="uploadPath">
<el-input v-model="form.uploadPath" style="width: 670px" placeholder="例如: /opt/upload" />
</el-form-item>
<el-form-item label="部署目录" prop="deployPath">
<el-input v-model="form.deployPath" style="width: 670px" placeholder="例如: /opt/app" />
</el-form-item>
<el-form-item label="备份目录" prop="backupPath">
<el-input v-model="form.backupPath" style="width: 670px" placeholder="例如: /opt/backup" />
</el-form-item>
<el-form-item label="部署脚本" prop="deployScript">
<el-input v-model="form.deployScript" :rows="3" type="textarea" autosize style="width: 670px" placeholder="" />
</el-form-item>
<el-form-item label="启动脚本" prop="startScript">
<el-input v-model="form.startScript" :rows="3" type="textarea" autosize style="width: 670px" placeholder="" />
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button type="text" @click="crud.cancelCU">取消</el-button>
<el-button :loading="crud.status.cu === 2" type="primary" @click="crud.submitCU">确认</el-button>
</div>
</el-dialog>
<!--表格渲染-->
<el-table ref="table" v-loading="crud.loading" :data="crud.data" highlight-current-row style="width: 100%" @selection-change="crud.selectionChangeHandler" @current-change="handleCurrentChange">
<el-table-column type="selection" width="55" />
<el-table-column prop="name" label="应用名称" />
<el-table-column prop="port" label="端口号" />
<el-table-column prop="uploadPath" label="上传目录" />
<el-table-column prop="deployPath" label="部署目录" />
<el-table-column prop="backupPath" label="备份目录" />
<el-table-column prop="createTime" label="创建日期" />
<el-table-column v-if="checkPer(['admin','app:edit','app:del'])" label="操作" width="150px" align="center">
<template slot-scope="scope">
<udOperation
:data="scope.row"
:permission="permission"
/>
</template>
</el-table-column>
</el-table>
<!--分页组件-->
<pagination />
</div>
</template>
<script>
import crudApp from '@/api/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

@ -1,86 +0,0 @@
<template>
<el-dialog append-to-body :close-on-click-modal="false" :visible.sync="dialog" title="执行脚本" width="400px">
<el-form ref="form" :rules="rules" size="small">
<el-upload
:action="databaseUploadApi"
:data="databaseInfo"
:headers="headers"
:on-success="handleSuccess"
:on-error="handleError"
class="upload-demo"
drag
>
<i class="el-icon-upload" />
<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

@ -1,148 +0,0 @@
<template>
<div class="app-container">
<!--工具栏-->
<div class="head-container">
<div v-if="crud.props.searchToggle">
<!-- 搜索 -->
<el-input v-model="query.blurry" clearable placeholder="模糊搜索" style="width: 200px" class="filter-item" @keyup.enter.native="crud.toQuery" />
<date-range-picker v-model="query.createTime" class="date-item" />
<rrOperation />
</div>
<crudOperation :permission="permission">
<el-button
slot="right"
v-permission="['admin','database:add']"
:disabled="!selectIndex"
class="filter-item"
size="mini"
type="warning"
icon="el-icon-upload"
@click="execute"
>执行脚本
</el-button>
</crudOperation>
</div>
<!--表单组件-->
<eForm ref="execute" :database-info="currentRow" />
<el-dialog append-to-body :close-on-click-modal="false" :before-close="crud.cancelCU" :visible.sync="crud.status.cu > 0" :title="crud.status.title" width="530px">
<el-form ref="form" :model="form" :rules="rules" size="small" label-width="100px">
<el-form-item label="连接名称" prop="name">
<el-input v-model="form.name" style="width: 370px" />
</el-form-item>
<el-form-item label="JDBC地址" prop="jdbcUrl">
<el-input v-model="form.jdbcUrl" style="width: 300px" />
<el-button :loading="loading" type="success" @click="testConnectDatabase">测试</el-button>
</el-form-item>
<el-form-item label="用户" prop="userName">
<el-input v-model="form.userName" style="width: 370px" />
</el-form-item>
<el-form-item label="密码" prop="pwd">
<el-input v-model="form.pwd" type="password" style="width: 370px" />
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button type="text" @click="crud.cancelCU">取消</el-button>
<el-button :loading="crud.status.cu === 2" type="primary" @click="crud.submitCU">确认</el-button>
</div>
</el-dialog>
<!--表格渲染-->
<el-table ref="table" v-loading="crud.loading" :data="crud.data" highlight-current-row stripe style="width: 100%" @selection-change="handleCurrentChange">
<el-table-column type="selection" width="55" />
<el-table-column prop="name" width="130px" label="数据库名称" />
<el-table-column prop="jdbcUrl" label="连接地址" />
<el-table-column prop="userName" width="200px" label="用户名" />
<el-table-column prop="createTime" width="200px" label="创建日期" />
<el-table-column v-if="checkPer(['admin','database:edit','database:del'])" label="操作" width="150px" align="center">
<template slot-scope="scope">
<udOperation
:data="scope.row"
:permission="permission"
/>
</template>
</el-table-column>
</el-table>
<!--分页组件-->
<pagination />
</div>
</template>
<script>
import crudDatabase from '@/api/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

@ -1,190 +0,0 @@
<template>
<el-dialog append-to-body :close-on-click-modal="false" :visible.sync="dialog" title="应用部署" width="400px">
<el-form ref="form" :model="form" :rules="rules" size="small">
<el-upload
:action="deployUploadApi"
:data="deployInfo"
:headers="headers"
:on-success="handleSuccess"
:on-error="handleError"
class="upload-demo"
drag
>
<i class="el-icon-upload" />
<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

@ -1,229 +0,0 @@
<template>
<div class="app-container">
<!--工具栏-->
<div class="head-container">
<div v-if="crud.props.searchToggle">
<!-- 搜索 -->
<el-input v-model="query.appName" clearable placeholder="输入应用名称查询" style="width: 200px" class="filter-item" @keyup.enter.native="crud.toQuery" />
<date-range-picker v-model="query.createTime" class="date-item" />
<rrOperation />
</div>
<crudOperation :permission="permission">
<template slot="right">
<el-button
v-permission="['admin','deploy:add']"
:disabled="!selectIndex"
class="filter-item"
size="mini"
type="primary"
icon="el-icon-upload"
@click="sysRestore"
>系统还原
</el-button>
<el-button
v-permission="['admin','deploy:add']"
:disabled="!selectIndex"
class="filter-item"
size="mini"
type="primary"
icon="el-icon-upload"
@click="serverStatus"
>状态查询
</el-button>
<el-button
v-permission="['admin','deploy:add']"
:disabled="!selectIndex"
class="filter-item"
size="mini"
type="success"
icon="el-icon-upload"
@click="startServer"
>启动
</el-button>
<el-button
v-permission="['admin','deploy:add']"
:disabled="!selectIndex"
class="filter-item"
size="mini"
type="danger"
icon="el-icon-upload"
@click="stopServer"
>停止
</el-button>
<el-button
v-permission="['admin','deploy:add']"
:disabled="!selectIndex"
class="filter-item"
size="mini"
type="warning"
icon="el-icon-upload"
@click="deploy"
>一键部署
</el-button>
</template>
</crudOperation>
</div>
<!--表单组件-->
<el-dialog append-to-body :close-on-click-modal="false" :before-close="crud.cancelCU" :visible.sync="crud.status.cu > 0" :title="crud.status.title" width="500px">
<el-form ref="form" :model="form" :rules="rules" size="small" label-width="80px">
<el-form-item label="应用" prop="app.id">
<el-select v-model.number="form.app.id" placeholder="请选择" style="width: 370px">
<el-option v-for="item in apps" :key="item.id" :label="item.name" :value="item.id" />
</el-select>
</el-form-item>
<el-form-item label="服务器" prop="deploys">
<el-select v-model="form.deploys" multiple placeholder="请选择" style="width: 370px">
<el-option v-for="item in servers" :key="item.id" :label="item.name" :value="item.id" />
</el-select>
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button type="text" @click="crud.cancelCU">取消</el-button>
<el-button :loading="crud.status.cu === 2" type="primary" @click="crud.submitCU">确认</el-button>
</div>
</el-dialog>
<!--统还原组件-->
<fForm ref="sysRestore" :key="times" :app-name="appName" />
<dForm ref="deploy" />
<!--表格渲染-->
<el-table ref="table" v-loading="crud.loading" :data="crud.data" highlight-current-row stripe style="width: 100%" @selection-change="handleCurrentChange">
<el-table-column type="selection" width="55" />
<el-table-column prop="app.name" label="应用名称" />
<el-table-column prop="servers" label="服务器列表" />
<el-table-column prop="createTime" label="部署日期" />
<el-table-column v-if="checkPer(['admin','deploy:edit','deploy:del'])" label="操作" width="150px" align="center">
<template slot-scope="scope">
<udOperation
:data="scope.row"
:permission="permission"
/>
</template>
</el-table-column>
</el-table>
<!--分页组件-->
<pagination />
</div>
</template>
<script>
import crudDeploy from '@/api/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

@ -1,107 +0,0 @@
<template>
<el-dialog append-to-body :close-on-click-modal="false" :visible.sync="dialog" title="系统还原" width="800px">
<!--工具栏-->
<div class="head-container">
<date-range-picker v-model="query.createTime" class="date-item" />
<el-button class="filter-item" size="mini" type="success" icon="el-icon-search" @click="toQuery">搜索</el-button>
</div>
<el-form size="small" label-width="80px">
<!--表格渲染-->
<el-table v-loading="loading" :data="data" style="width: 100%" @row-click="showRow">
<el-table-column width="30px">
<template slot-scope="scope">
<el-radio v-model="radio" :label="scope.$index" />
</template>
</el-table-column>
<el-table-column prop="appName" label="应用名称" />
<el-table-column prop="ip" label="部署IP" />
<el-table-column prop="deployDate" label="部署时间" />
<el-table-column prop="deployUser" label="部署人员" />
</el-table>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button type="text" @click="cancel">取消</el-button>
<el-button v-permission="['admin','deploy:add']" :loading="submitLoading" type="primary" @click="doSubmit">确认</el-button>
</div>
<!--分页组件-->
<el-pagination
:total="total"
:current-page="page"
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

@ -1,93 +0,0 @@
<template>
<div class="app-container">
<!--工具栏-->
<div class="head-container">
<div v-if="crud.props.searchToggle">
<!-- 搜索 -->
<el-input v-model="query.blurry" clearable placeholder="输入搜索内容" style="width: 200px" class="filter-item" @keyup.enter.native="crud.toQuery" />
<date-range-picker v-model="query.deployDate" class="date-item" />
<rrOperation />
</div>
<crudOperation :permission="permission" />
</div>
<!--表格渲染-->
<el-table ref="table" v-loading="crud.loading" :data="crud.data" style="width: 100%" @selection-change="crud.selectionChangeHandler">
<el-table-column type="selection" width="55" />
<el-table-column prop="appName" label="应用名称" />
<el-table-column prop="ip" label="部署IP" />
<el-table-column prop="deployUser" label="部署人员" />
<el-table-column prop="deployDate" label="部署时间" />
<el-table-column v-if="checkPer(['admin','deployHistory:del'])" label="操作" width="100px" align="center">
<template slot-scope="scope">
<el-popover
:ref="scope.row.id"
v-permission="['admin','deployHistory:del']"
placement="top"
width="180"
>
<p>确定删除本条数据吗</p>
<div style="text-align: right; margin: 0">
<el-button size="mini" type="text" @click="$refs[scope.row.id].doClose()">取消</el-button>
<el-button :loading="delLoading" type="primary" size="mini" @click="delMethod(scope.row.id)">确定</el-button>
</div>
<el-button slot="reference" type="danger" icon="el-icon-delete" size="mini" />
</el-popover>
</template>
</el-table-column>
</el-table>
<!--分页组件-->
<pagination />
</div>
</template>
<script>
import { del } from '@/api/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

@ -1,136 +0,0 @@
<template>
<div class="app-container">
<!--工具栏-->
<div class="head-container">
<div v-if="crud.props.searchToggle">
<!-- 搜索 -->
<el-input v-model="query.blurry" clearable placeholder="输入名称或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

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

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

View File

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

View File

@ -0,0 +1,361 @@
<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">
<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="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="email" /> 用户邮箱 <div class="user-right">{{ user.email }}</div></li>
<li>

View File

@ -1,98 +0,0 @@
<template>
<el-form ref="form" :model="form" :rules="rules" style="margin-top: 6px;" size="small" label-width="100px">
<el-form-item label="appID" prop="appId">
<el-input v-model="form.appId" style="width: 40%" />
<span style="color: #C0C0C0;margin-left: 10px;">应用APPID,收款账号既是APPID对应支付宝账号</span>
</el-form-item>
<el-form-item label="商家账号" prop="sysServiceProviderId">
<el-input v-model="form.sysServiceProviderId" style="width: 40%;" />
<span style="color: #C0C0C0;margin-left: 10px;">商家账号</span>
</el-form-item>
<el-form-item label="商户私钥" prop="privateKey">
<el-input v-model="form.privateKey" type="password" style="width: 40%;" />
<span style="color: #C0C0C0;margin-left: 10px;">商户私钥你的PKCS8格式RSA2私钥</span>
</el-form-item>
<el-form-item label="支付宝公钥" prop="publicKey">
<el-input v-model="form.publicKey" type="password" style="width: 40%;" />
<span style="color: #C0C0C0;margin-left: 10px;">支付宝公钥</span>
</el-form-item>
<el-form-item label="回调地址" prop="returnUrl">
<el-input v-model="form.returnUrl" style="width: 40%;" />
<span style="color: #C0C0C0;margin-left: 10px;">订单完成后返回的地址</span>
</el-form-item>
<el-form-item label="异步通知" prop="notifyUrl">
<el-input v-model="form.notifyUrl" style="width: 40%;" />
<span style="color: #C0C0C0;margin-left: 10px;">支付结果异步通知地址</span>
</el-form-item>
<el-form-item label="">
<el-button :loading="loading" size="medium" type="primary" @click="doSubmit">保存配置</el-button>
</el-form-item>
</el-form>
</template>
<script>
import { get, update } from '@/api/tools/alipay'
export default {
name: 'Config',
data() {
return {
loading: false,
form: { appId: '', sysServiceProviderId: '', privateKey: '', publicKey: '', returnUrl: '', notifyUrl: '' },
rules: {
appId: [
{ required: true, message: '请输入appID', trigger: 'blur' }
],
sysServiceProviderId: [
{ required: true, message: '请输入商家账号', trigger: 'blur' }
],
privateKey: [
{ required: true, message: '商户私钥不能为空', trigger: 'blur' }
],
publicKey: [
{ required: true, message: '支付宝公钥不能为空', trigger: 'blur' }
],
returnUrl: [
{ required: true, message: '回调地址不能为空', trigger: 'blur' }
],
notifyUrl: [
{ required: true, message: '回调地址不能为空', trigger: 'blur' }
]
}
}
},
created() {
this.init()
},
methods: {
init() {
get().then(res => {
this.form = res
})
},
doSubmit() {
this.$refs['form'].validate((valid) => {
if (valid) {
this.loading = true
update(this.form).then(res => {
this.$notify({
title: '修改成功',
type: 'success',
duration: 2500
})
this.loading = false
}).catch(err => {
this.loading = false
console.log(err.response.data.message)
})
} else {
return false
}
})
}
}
}
</script>
<style scoped>
</style>

View File

@ -1,48 +0,0 @@
<template>
<el-tabs v-model="activeName" style="padding-left: 5px;">
<el-tab-pane label="参数配置" name="first">
<Config />
</el-tab-pane>
<el-tab-pane label="支付测试" name="second">
<ToPay />
</el-tab-pane>
<el-tab-pane label="使用说明" name="third">
<div>
<blockquote class="my-blockquote">注意</blockquote>
<pre class="my-code">
测试所用参数都是沙箱环境仅供测试使用申请地址<a style="color: #00a0e9" href="https://openhome.alipay.com/platform/appDaily.htm?tab=info" target="_blank">支付宝开发平台</a>
如需付款测试请使用
账号uuxesw9745@sandbox.com
密码与支付密码111111</pre>
<blockquote class="my-blockquote"> 支付设置</blockquote>
<pre class="my-code">
//
// PC使
if (/(Android)/i.test(navigator.userAgent)){ // Android
url = "/aliPay/toPayAsWeb"
}else if(/(iPhone|iPad|iPod|iOS)/i.test(navigator.userAgent)){ //
url = "/aliPay/toPayAsWeb"
} else {
url = "/aliPay/toPayAsPC"
}</pre>
</div>
</el-tab-pane>
</el-tabs>
</template>
<script>
import Config from './config'
import ToPay from './toPay'
export default {
name: 'AliPay',
components: { Config, ToPay },
data() {
return {
activeName: 'second'
}
}
}
</script>
<style scoped>
</style>

View File

@ -1,86 +0,0 @@
<template>
<div>
<el-form ref="form" :model="form" :rules="rules" style="margin-top: 6px;" size="small" label-width="90px">
<el-form-item label="商品名称" prop="subject">
<el-input v-model="form.subject" style="width: 35%" />
</el-form-item>
<el-form-item label="商品价格" prop="totalAmount">
<el-input v-model="form.totalAmount" style="width: 35%" />
<span style="color: #C0C0C0;margin-left: 10px;">测试允许区间(0,5000]</span>
</el-form-item>
<el-form-item label="商品描述" prop="body">
<el-input v-model="form.body" style="width: 35%" rows="8" type="textarea" />
</el-form-item>
<el-form-item label="">
<el-button :loading="loading" size="medium" type="primary" @click="doSubmit">去支付</el-button>
</el-form-item>
</el-form>
</div>
</template>
<script>
import { toAliPay } from '@/api/tools/alipay'
export default {
data() {
return {
url: '',
//
newWin: null,
loading: false, form: { subject: '', totalAmount: '', body: '' },
rules: {
subject: [
{ required: true, message: '商品名称不能为空', trigger: 'blur' }
],
totalAmount: [
{ required: true, message: '商品价格不能为空', trigger: 'blur' }
],
body: [
{ required: true, message: '商品描述不能为空', trigger: 'blur' }
]
}
}
},
watch: {
url(newVal, oldVal) {
if (newVal && this.newWin) {
this.newWin.sessionStorage.clear()
this.newWin.location.href = newVal
// urlnewWin
this.url = ''
this.newWin = null
}
}
},
methods: {
doSubmit() {
this.$refs['form'].validate((valid) => {
if (valid) {
this.loading = true
//
this.newWin = window.open()
let url = ''
if (/(Android)/i.test(navigator.userAgent)) { // Android
url = 'aliPay/toPayAsWeb'
} else if (/(iPhone|iPad|iPod|iOS)/i.test(navigator.userAgent)) { //
url = 'aliPay/toPayAsWeb'
} else {
url = 'aliPay/toPayAsPC'
}
toAliPay(url, this.form).then(res => {
this.loading = false
this.url = res
}).catch(err => {
this.loading = false
console.log(err.response.data.message)
})
} else {
return false
}
})
}
}
}
</script>
<style scoped>
</style>

View File

@ -1,91 +0,0 @@
<template>
<el-form ref="form" :model="form" :rules="rules" style="margin-top: 6px;" size="small" label-width="100px">
<el-form-item label="发件人邮箱" prop="fromUser">
<el-input v-model="form.fromUser" style="width: 40%" />
<span style="color: #C0C0C0;margin-left: 10px;">Sender mailbox</span>
</el-form-item>
<el-form-item label="发件用户名" prop="user">
<el-input v-model="form.user" style="width: 40%;" />
<span style="color: #C0C0C0;margin-left: 10px;">Sender usernamex</span>
</el-form-item>
<el-form-item label="邮箱密码" prop="pass">
<el-input v-model="form.pass" type="password" style="width: 40%;" />
<span style="color: #C0C0C0;margin-left: 10px;">email Password</span>
</el-form-item>
<el-form-item label="SMTP地址" prop="host">
<el-input v-model="form.host" style="width: 40%;" />
<span style="color: #C0C0C0;margin-left: 10px;">SMTP address</span>
</el-form-item>
<el-form-item label="SMTP端口" prop="port">
<el-input v-model="form.port" style="width: 40%;" />
<span style="color: #C0C0C0;margin-left: 10px;">SMTP port</span>
</el-form-item>
<el-form-item label="">
<el-button :loading="loading" size="medium" type="primary" @click="doSubmit">保存配置</el-button>
</el-form-item>
</el-form>
</template>
<script>
import { get, update } from '@/api/tools/email'
export default {
name: 'Config',
data() {
return {
loading: false, form: { id: 1, fromUser: '', user: '', pass: '', host: '', port: '', sslEnable: '' },
rules: {
fromUser: [
{ required: true, message: '请输入发件人邮箱', trigger: 'blur' },
{ type: 'email', message: '请输入正确的邮箱地址', trigger: 'blur' }
],
user: [
{ required: true, message: '请输入发件用户名', trigger: 'blur' }
],
pass: [
{ required: true, message: '密码不能为空', trigger: 'blur' }
],
host: [
{ required: true, message: 'SMTP地址不能为空', trigger: 'blur' }
],
port: [
{ required: true, message: 'SMTP端口不能为空', trigger: 'blur' }
]
}
}
},
created() {
this.init()
},
methods: {
init() {
get().then(res => {
this.form = res
})
},
doSubmit() {
this.$refs['form'].validate((valid) => {
if (valid) {
this.loading = true
update(this.form).then(res => {
this.$notify({
title: '修改成功',
type: 'success',
duration: 2500
})
this.loading = false
}).catch(err => {
this.loading = false
console.log(err.response.data.message)
})
} else {
return false
}
})
}
}
}
</script>
<style scoped>
</style>

View File

@ -1,41 +0,0 @@
<template>
<el-tabs v-model="activeName" style="padding-left: 8px;">
<el-tab-pane label="邮箱配置" name="first">
<Config />
</el-tab-pane>
<el-tab-pane label="发送邮件" name="second">
<Send />
</el-tab-pane>
<el-tab-pane label="使用说明" name="third">
<div>
<blockquote class="my-blockquote"> 邮件服务器配置</blockquote>
<pre class="my-code">
# 邮件服务器的SMTP地址可选默认为smtp
# 邮件服务器的SMTP端口可选默认465或者25
# 发件人必须正确否则发送失败
# 用户名默认为发件人邮箱前缀
# 密码注意某些邮箱需要为SMTP服务单独设置密码如QQ和163等等
# 是否开启ssl默认开启</pre>
<blockquote class="my-blockquote">更多帮助</blockquote>
<pre class="my-code">更多帮助请查看文档<a style="color:#009688" href="http://hutool.mydoc.io/#text_319499" target="_black">hutool工具包</a></pre>
</div>
</el-tab-pane>
</el-tabs>
</template>
<script>
import Config from './config'
import Send from './send'
export default {
name: 'Email',
components: { Config, Send },
data() {
return {
activeName: 'second'
}
}
}
</script>
<style scoped>
</style>

View File

@ -1,98 +0,0 @@
<template>
<div>
<el-form ref="form" :model="form" :rules="rules" style="margin-top: 6px;" size="small" label-width="100px">
<el-form-item label="邮件标题" prop="subject">
<el-input v-model="form.subject" style="width: 646px" 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,18 +3,19 @@
<el-tab-pane label="本地存储" name="first">
<Local ref="local" />
</el-tab-pane>
<el-tab-pane label="七牛云存储" name="second">
<QiNiu ref="qiNiu" />
</el-tab-pane>
<!-- <el-tab-pane label="七牛云存储" name="second">-->
<!-- <QiNiu ref="qiNiu" />-->
<!-- </el-tab-pane>-->
</el-tabs>
</template>
<script>
import QiNiu from './qiniu/index'
// import QiNiu from './qiniu/index'
import Local from './local/index'
export default {
name: 'Storage',
components: { QiNiu, Local },
components: { Local },
// components: { QiNiu, Local },
data() {
return {
activeName: 'first'

View File

@ -1,98 +0,0 @@
<template>
<el-dialog :visible.sync="dialog" :close-on-click-modal="false" title="七牛云配置" append-to-body width="580px">
<el-form ref="form" :model="form" :rules="rules" style="margin-top: 6px;" size="small" label-width="110px">
<el-form-item label="Access Key" prop="accessKey">
<el-input v-model="form.accessKey" style="width: 95%" placeholder="accessKey在安全中心秘钥管理中查看" />
</el-form-item>
<el-form-item label="Secret Key" prop="secretKey">
<el-input v-model="form.secretKey" type="password" style="width: 95%;" placeholder="secretKey在安全中心秘钥管理中查看" />
</el-form-item>
<el-form-item label="空间名称" prop="bucket">
<el-input v-model="form.bucket" style="width: 95%;" placeholder="存储空间名称作为唯一的 Bucket 识别符" />
</el-form-item>
<el-form-item label="外链域名" prop="host">
<el-input v-model="form.host" style="width: 95%;" placeholder="外链域名,可自定义,需在七牛云绑定" />
</el-form-item>
<el-form-item label="存储区域">
<el-select v-model="form.zone" placeholder="请选择存储区域">
<el-option
v-for="item in zones"
:key="item"
:label="item"
:value="item"
/>
</el-select>
</el-form-item>
<el-form-item label="空间类型" prop="type">
<el-radio v-model="form.type" label="公开">公开</el-radio>
<el-radio v-model="form.type" label="私有">私有</el-radio>
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button type="text" @click="dialog = false">取消</el-button>
<el-button :loading="loading" type="primary" @click="doSubmit">确认</el-button>
</div>
</el-dialog>
</template>
<script>
import { get, update } from '@/api/tools/qiniu'
export default {
data() {
return {
zones: ['华东', '华北', '华南', '北美', '东南亚'], dialog: false,
loading: false, form: { accessKey: '', secretKey: '', bucket: '', host: '', zone: '', type: '' },
rules: {
accessKey: [
{ required: true, message: '请输入accessKey', trigger: 'blur' }
],
secretKey: [
{ required: true, message: '请输入secretKey', trigger: 'blur' }
],
bucket: [
{ required: true, message: '请输入空间名称', trigger: 'blur' }
],
host: [
{ required: true, message: '请输入外链域名', trigger: 'blur' }
],
type: [
{ required: true, message: '空间类型不能为空', trigger: 'blur' }
]
}
}
},
methods: {
init() {
get().then(res => {
this.form = res
})
},
doSubmit() {
this.$refs['form'].validate((valid) => {
if (valid) {
this.loading = true
update(this.form).then(res => {
this.$notify({
title: '修改成功',
type: 'success',
duration: 2500
})
this.$parent.crud.toQuery()
this.loading = false
this.dialog = false
}).catch(err => {
this.loading = false
console.log(err.response.data.message)
})
} else {
return false
}
})
}
}
}
</script>
<style scoped>
</style>

View File

@ -1,189 +0,0 @@
<template>
<div class="app-container" style="padding: 8px;">
<!--表单组件-->
<eForm ref="form" />
<!-- 工具栏 -->
<div class="head-container">
<div v-if="crud.props.searchToggle">
<!-- 搜索 -->
<el-input v-model="query.key" clearable size="small" placeholder="输入文件名称搜索" style="width: 200px;" class="filter-item" @keyup.enter.native="toQuery" />
<date-range-picker v-model="query.createTime" class="date-item" />
<rrOperation />
</div>
<crudOperation :permission="permission">
<template slot="left">
<!-- 上传 -->
<el-button class="filter-item" size="mini" type="primary" icon="el-icon-upload" @click="dialog = true">上传</el-button>
<!-- 同步 -->
<el-button :icon="icon" class="filter-item" size="mini" type="warning" @click="synchronize">同步</el-button>
<!-- 配置 -->
<el-button
class="filter-item"
size="mini"
type="success"
icon="el-icon-s-tools"
@click="doConfig"
>配置</el-button>
</template>
</crudOperation>
<!-- 文件上传 -->
<el-dialog :visible.sync="dialog" :close-on-click-modal="false" append-to-body width="500px" @close="doSubmit">
<el-upload
:before-remove="handleBeforeRemove"
:on-success="handleSuccess"
:on-error="handleError"
:file-list="fileList"
:headers="headers"
:action="qiNiuUploadApi"
class="upload-demo"
multiple
>
<el-button size="small" type="primary">点击上传</el-button>
<div slot="tip" style="display: block;" class="el-upload__tip">请勿上传违法文件且文件不超过15M</div>
</el-upload>
<div slot="footer" class="dialog-footer">
<el-button type="primary" @click="doSubmit">确认</el-button>
</div>
</el-dialog>
<!--表格渲染-->
<el-table ref="table" v-loading="crud.loading" :data="crud.data" style="width: 100%;" @selection-change="crud.selectionChangeHandler">
<el-table-column type="selection" width="55" />
<el-table-column prop="name" :show-overflow-tooltip="true" label="文件名">
<template slot-scope="scope">
<a href="JavaScript:" class="el-link el-link--primary" target="_blank" type="primary" @click="download(scope.row.id)">{{ scope.row.key }}</a>
</template>
</el-table-column>
<el-table-column :show-overflow-tooltip="true" prop="suffix" label="文件类型" @selection-change="crud.selectionChangeHandler" />
<el-table-column prop="bucket" label="空间名称" />
<el-table-column prop="size" label="文件大小" />
<el-table-column prop="type" label="空间类型" />
<el-table-column prop="updateTime" label="创建日期" />
</el-table>
<!--分页组件-->
<pagination />
</div>
</div>
</template>
<script>
import crudQiNiu from '@/api/tools/qiniu'
import { mapGetters } from 'vuex'
import { getToken } from '@/utils/auth'
import eForm from './form'
import CRUD, { presenter, header, crud } from '@crud/crud'
import rrOperation from '@crud/RR.operation'
import crudOperation from '@crud/CRUD.operation'
import pagination from '@crud/Pagination'
import DateRangePicker from '@/components/DateRangePicker'
export default {
components: { eForm, pagination, crudOperation, rrOperation, DateRangePicker },
cruds() {
return CRUD({ title: '七牛云文件', url: 'api/qiNiuContent', crudMethod: { ...crudQiNiu }})
},
mixins: [presenter(), header(), crud()],
data() {
return {
permission: {
del: ['admin', 'storage:del']
},
title: '文件', dialog: false,
icon: 'el-icon-refresh',
url: '', headers: { 'Authorization': getToken() },
dialogImageUrl: '', dialogVisible: false, fileList: [], files: [], newWin: null
}
},
computed: {
...mapGetters([
'qiNiuUploadApi'
])
},
watch: {
url(newVal, oldVal) {
if (newVal && this.newWin) {
this.newWin.sessionStorage.clear()
this.newWin.location.href = newVal
// urlnewWin
this.url = ''
this.newWin = null
}
}
},
created() {
this.crud.optShow.add = false
this.crud.optShow.edit = false
},
methods: {
//
doConfig() {
const _this = this.$refs.form
_this.init()
_this.dialog = true
},
handleSuccess(response, file, fileList) {
const uid = file.uid
const id = response.id
this.files.push({ uid, id })
},
handleBeforeRemove(file, fileList) {
for (let i = 0; i < this.files.length; i++) {
if (this.files[i].uid === file.uid) {
crudQiNiu.del([this.files[i].id]).then(res => {})
return true
}
}
},
handlePictureCardPreview(file) {
this.dialogImageUrl = file.url
this.dialogVisible = true
},
//
doSubmit() {
this.fileList = []
this.dialogVisible = false
this.dialogImageUrl = ''
this.dialog = false
this.crud.toQuery()
},
//
handleError(e, file, fileList) {
const msg = JSON.parse(e.message)
this.crud.notify(msg.message, CRUD.NOTIFICATION_TYPE.ERROR)
},
//
download(id) {
this.downloadLoading = true
//
this.newWin = window.open()
crudQiNiu.download(id).then(res => {
this.downloadLoading = false
this.url = res.url
}).catch(err => {
this.downloadLoading = false
console.log(err.response.data.message)
})
},
//
synchronize() {
this.icon = 'el-icon-loading'
crudQiNiu.sync().then(res => {
this.icon = 'el-icon-refresh'
this.$message({
showClose: true,
message: '数据同步成功',
type: 'success',
duration: 1500
})
this.crud.toQuery()
}).catch(err => {
this.icon = 'el-icon-refresh'
console.log(err.response.data.message)
})
}
}
}
</script>
<style scoped>
</style>

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
third-party archives.
Copyright 2019-2025 Zheng Jie
Copyright 2019-2025 Tz
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.

View File

@ -1,26 +1,17 @@
<h1 style="text-align: center">ELADMIN 后台管理系统</h1>
<h1 style="text-align: center">区块链技术的隐私保护和执法数据管理系统</h1>
#### 项目简介
一个基于 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`
#### 项目源码
#### 项目结构
项目采用按功能分模块的开发方式,结构如下
| github | gitee |
|--------------------------------------| --- |
| https://github.com/elunez/eladmin-mp | https://gitee.com/elunez/eladmin-mp |
- `eladmin-common` 为系统的公共模块,各种工具类,公共配置存在该模块
#### 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>
- `eladmin-system` 为系统核心模块也是项目入口模块,也是最终需要打包部署的模块
使用优惠码: `BWHNCXNVXV`,可获得 6.81% 的折扣, [查看介绍](https://eladmin.vip/pages/040101/)
#### 主要特性
- 使用最新技术栈,社区资源丰富。
- 高效率开发,代码生成器可一键生成前后端代码
@ -41,14 +32,7 @@
- 岗位管理:配置各个部门的职位
- 字典管理:可维护常用一些固定的数据,如:状态,性别等
- 系统日志:记录用户操作日志与异常日志,方便开发人员定位排错
- SQL监控采用druid 监控数据库访问性能默认用户名admin密码123456
- 定时任务整合Quartz做定时任务加入任务日志任务运行情况一目了然
- 代码生成:高灵活度生成前后端代码,减少大量重复的工作任务
- 邮件工具配合富文本发送html格式的邮件
- 七牛云存储:可同步七牛云存储的数据到系统,无需登录七牛云直接操作云数据
- 支付宝支付:整合了支付宝支付并且提供了测试账号,可自行测试
- 服务监控:监控服务器的负载情况
- 运维管理:一键部署你的应用
- 执法数据:对执法信息的上链保护已经链路溯源
#### 项目结构
项目采用按功能分模块的开发方式,结构如下
@ -57,12 +41,6 @@
- `eladmin-system` 为系统核心模块也是项目入口模块,也是最终需要打包部署的模块
- `eladmin-logging` 为系统的日志模块,其他模块如果需要记录日志需要引入该模块
- `eladmin-tools` 为第三方工具模块,包含:邮件、七牛云存储、本地存储、支付宝
- `eladmin-generator` 为系统的代码生成模块支持生成前后端CRUD代码
#### 详细结构
```
@ -87,28 +65,5 @@
- FileUtil 文件工具类
- eladmin-system 系统核心模块(系统启动入口)
- sysrunner 程序启动后处理数据
- modules 系统相关模块(登录授权、系统监控、定时任务、系统模块、运维模块)
- eladmin-logging 系统日志模块
- eladmin-tools 系统第三方工具模块
- email 邮件工具
- qiniu 七牛云存储工具
- alipay 支付宝支付工具
- local-storage 本地存储工具
- eladmin-generator 系统代码生成模块
- modules 系统相关模块(登录授权、系统模块、运维模块)
```
#### 特别鸣谢
- 感谢 [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 Zheng Jie
* Copyright 2019-2025 Tz
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.

View File

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

View File

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

View File

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

View File

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

View File

@ -1,5 +1,5 @@
/*
* Copyright 2019-2025 Zheng Jie
* Copyright 2019-2025 Tz
*
* Licensed under the Apache License, Version 2.0 (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 Zheng Jie
* @author Tz
* @description
* @date 2023-06-08
**/

View File

@ -1,5 +1,5 @@
/*
* Copyright 2019-2025 Zheng Jie
* Copyright 2019-2025 Tz
*
* Licensed under the Apache License, Version 2.0 (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;
/**
* @author Zheng Jie
* @author Tz
*/
@Service(value = "el")
public class AuthorityConfig {

View File

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

View File

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

View File

@ -1,5 +1,5 @@
/*
* Copyright 2019-2025 Zheng Jie
* Copyright 2019-2025 Tz
*
* Licensed under the Apache License, Version 2.0 (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;
/**
* @author Zheng Jie
* @author Tz
* @description 自定义 p6spy sql输出格式
* @date 2024-12-26
**/

View File

@ -1,5 +1,5 @@
/*
* Copyright 2019-2025 Zheng Jie
* Copyright 2019-2025 Tz
*
* Licensed under the Apache License, Version 2.0 (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;
/**
* @author Zheng Jie
* @author Tz
* @description
* @date 2023-06-13
**/

View File

@ -1,5 +1,5 @@
/*
* Copyright 2019-2025 Zheng Jie
* Copyright 2019-2025 Tz
*
* Licensed under the Apache License, Version 2.0 (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;
/**
* @author Zheng Jie
* @author Tz
* @description
* @date 2023-06-12
**/

View File

@ -1,5 +1,5 @@
/*
* Copyright 2019-2025 Zheng Jie
* Copyright 2019-2025 Tz
*
* Licensed under the Apache License, Version 2.0 (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;
/**
* @author Zheng Jie
* @author Tz
*/
@Data
@Configuration

View File

@ -1,5 +1,5 @@
/*
* Copyright 2019-2025 Zheng Jie
* Copyright 2019-2025 Tz
*
* Licensed under the Apache License, Version 2.0 (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;
/**
* @author Zheng Jie
* @author Tz
* @website <a href="https://eladmin.vip">...</a>
* @description
* @date 2020-05-18

View File

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

View File

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

View File

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

View File

@ -1,5 +1,5 @@
/*
* Copyright 2019-2025 Zheng Jie
* Copyright 2019-2025 Tz
*
* Licensed under the Apache License, Version 2.0 (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
* @author Zheng Jie
* @author Tz
* @date 2018-11-23
*/
@Configuration

View File

@ -1,5 +1,5 @@
/*
* Copyright 2019-2025 Zheng Jie
* Copyright 2019-2025 Tz
*
* Licensed under the Apache License, Version 2.0 (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;
/**
* @author ZhangHouYing
* @author Tz
* @date 2019-08-24 15:44
*/
@Configuration

View File

@ -1,5 +1,5 @@
/*
* Copyright 2019-2025 Zheng Jie
* Copyright 2019-2025 Tz
*
* Licensed under the Apache License, Version 2.0 (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;
/**
* @author Zheng Jie
* @author Tz
* @date 2018-11-23
* 统一异常处理
*/

View File

@ -1,5 +1,5 @@
/*
* Copyright 2019-2025 Zheng Jie
* Copyright 2019-2025 Tz
*
* Licensed under the Apache License, Version 2.0 (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;
/**
* @author Zheng Jie
* @author Tz
* @date 2018-11-23
*/
public class EntityExistException extends RuntimeException {

View File

@ -1,5 +1,5 @@
/*
* Copyright 2019-2025 Zheng Jie
* Copyright 2019-2025 Tz
*
* Licensed under the Apache License, Version 2.0 (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;
/**
* @author Zheng Jie
* @author Tz
* @date 2018-11-23
*/
public class EntityNotFoundException extends RuntimeException {

View File

@ -1,5 +1,5 @@
/*
* Copyright 2019-2025 Zheng Jie
* Copyright 2019-2025 Tz
*
* Licensed under the Apache License, Version 2.0 (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;
/**
* @author Zheng Jie
* @author Tz
* @date 2018-11-23
*/
@Data

View File

@ -1,5 +1,5 @@
/*
* Copyright 2019-2025 Zheng Jie
* Copyright 2019-2025 Tz
*
* Licensed under the Apache License, Version 2.0 (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.*;
/**
* @author Zheng Jie
* @author Tz
* @date 2018-11-23
*/
@Slf4j

View File

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

View File

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

View File

@ -1,5 +1,5 @@
/*
* Copyright 2019-2025 Zheng Jie
* Copyright 2019-2025 Tz
*
* Licensed under the Apache License, Version 2.0 (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;
/**
* @author Zheng Jie
* @author Tz
* @description 用于关闭各种连接缺啥补啥
* @date 2021-03-05
**/

View File

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

View File

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

View File

@ -1,5 +1,5 @@
/*
* Copyright 2019-2025 Zheng Jie
* Copyright 2019-2025 Tz
*
* Licensed under the Apache License, Version 2.0 (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 工具包
*
* @author Zheng Jie
* @author Tz
* @date 2018-12-27
*/
@Slf4j

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,5 +1,5 @@
/*
* Copyright 2019-2025 Zheng Jie
* Copyright 2019-2025 Tz
*
* Licensed under the Apache License, Version 2.0 (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.*;
/**
* @author Zheng Jie
* @author Tz
* 字符串工具类, 继承org.apache.commons.lang3.StringUtils类
*/
@Slf4j

View File

@ -1,5 +1,5 @@
/*
* Copyright 2019-2025 Zheng Jie
* Copyright 2019-2025 Tz
*
* Licensed under the Apache License, Version 2.0 (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
* @author Zheng Jie
* @author Tz
*/
public class ThrowableUtil {

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,5 +1,5 @@
/*
* Copyright 2019-2025 Zheng Jie
* Copyright 2019-2025 Tz
*
* Licensed under the Apache License, Version 2.0 (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;
/**
* @author Zheng Jie
* @author Tz
* @date 2023-06-26
*/
@Mapper

View File

@ -1,5 +1,5 @@
/*
* Copyright 2019-2025 Zheng Jie
* Copyright 2019-2025 Tz
*
* Licensed under the Apache License, Version 2.0 (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;
/**
* @author Zheng Jie
* @author Tz
* @date 2023-06-26
*/
@Mapper

View File

@ -1,5 +1,5 @@
/*
* Copyright 2019-2025 Zheng Jie
* Copyright 2019-2025 Tz
*
* Licensed under the Apache License, Version 2.0 (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.*;
/**
* @author Zheng Jie
* @author Tz
* @date 2019-01-14
*/
@RestController

View File

@ -1,5 +1,5 @@
/*
* Copyright 2019-2025 Zheng Jie
* Copyright 2019-2025 Tz
*
* Licensed under the Apache License, Version 2.0 (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;
/**
* @author Zheng Jie
* @author Tz
* @date 2019-01-02
*/
@RestController

View File

@ -1,5 +1,5 @@
/*
* Copyright 2019-2025 Zheng Jie
* Copyright 2019-2025 Tz
*
* Licensed under the Apache License, Version 2.0 (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;
/**
* @author Zheng Jie
* @author Tz
* @date 2019-01-14
*/
public interface GenConfigService extends IService<GenConfig> {

View File

@ -1,5 +1,5 @@
/*
* Copyright 2019-2025 Zheng Jie
* Copyright 2019-2025 Tz
*
* Licensed under the Apache License, Version 2.0 (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;
/**
* @author Zheng Jie
* @author Tz
* @date 2019-01-02
*/
public interface GeneratorService extends IService<ColumnInfo> {

View File

@ -1,5 +1,5 @@
/*
* Copyright 2019-2025 Zheng Jie
* Copyright 2019-2025 Tz
*
* Licensed under the Apache License, Version 2.0 (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;
/**
* @author Zheng Jie
* @author Tz
* @date 2019-01-14
*/
@Service

View File

@ -1,5 +1,5 @@
/*
* Copyright 2019-2025 Zheng Jie
* Copyright 2019-2025 Tz
*
* Licensed under the Apache License, Version 2.0 (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;
/**
* @author Zheng Jie
* @author Tz
* @date 2019-01-02
*/
@Slf4j

View File

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

View File

@ -1,5 +1,5 @@
/*
* Copyright 2019-2025 Zheng Jie
* Copyright 2019-2025 Tz
*
* Licensed under the Apache License, Version 2.0 (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 Zheng Jie
* @author Tz
* @date 2019-01-02
*/
@Slf4j

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,5 +1,5 @@
/*
* Copyright 2019-2025 Zheng Jie
* Copyright 2019-2025 Tz
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -21,7 +21,7 @@ import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* @author Zheng Jie
* @author Tz
* @date 2018-11-24
*/
@Target(ElementType.METHOD)

View File

@ -1,5 +1,5 @@
/*
* Copyright 2019-2025 Zheng Jie
* Copyright 2019-2025 Tz
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -32,7 +32,7 @@ import org.springframework.stereotype.Component;
import javax.servlet.http.HttpServletRequest;
/**
* @author Zheng Jie
* @author Tz
* @date 2018-11-24
*/
@Component

View File

@ -1,5 +1,5 @@
/*
* Copyright 2019-2025 Zheng Jie
* Copyright 2019-2025 Tz
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -26,7 +26,7 @@ import java.io.Serializable;
import java.sql.Timestamp;
/**
* @author Zheng Jie
* @author Tz
* @date 2018-11-24
*/
@Getter

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