Commit 6833044a authored by trumansdo's avatar trumansdo
Browse files

完成字典数据管理

parent 875339d5
......@@ -3,8 +3,8 @@
用户管理 - 已完成
组织机构管理
角色管理
菜单项 - (需要功能点做前置)
功能点管理 - 进行中
菜单项 - 已完成
功能点管理 - 已完成
字典数据管理
角色功能授权
角色数据授权
......
......@@ -5,6 +5,7 @@ import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.validation.constraints.NotEmpty;
import org.apache.poi.ss.util.CellReference;
import org.beetl.sql.core.engine.PageQuery;
import org.springframework.beans.factory.annotation.Autowired;
......@@ -18,6 +19,7 @@ import com.ibeetl.admin.core.entity.CoreUser;
import com.ibeetl.admin.core.service.CoreBaseService;
import com.ibeetl.admin.core.util.ExcelError;
import com.ibeetl.admin.core.util.PlatformException;
import org.springframework.validation.annotation.Validated;
/** CoreDict Service */
@Service
......@@ -32,9 +34,10 @@ public class DictConsoleService extends CoreBaseService<CoreDict> {
return ret;
}
public void batchDelCoreDict(List<Long> ids) {
@Validated
public void batchDelCoreDict(@NotEmpty List<Long> ids) {
try {
// TODO,找到数据字典所有子类,设置删除标记
// TODO,找到数据字典所有子类,设置删除标记、可以从缓存中遍历字典树得到id
dictDao.batchDelCoreDictByIds(ids);
} catch (Exception e) {
throw new PlatformException("批量删除CoreDict失败", e);
......
......@@ -100,7 +100,7 @@ public class DictConsoleController {
dict.setCreateTime(new Date());
dictService.save(dict);
platformService.clearDictCache();
return new JsonResult().success();
return JsonResult.success();
}
@PostMapping(MODEL + "/update.json")
......@@ -110,7 +110,7 @@ public class DictConsoleController {
boolean success = dictService.update(dict);
if (success) {
platformService.clearDictCache();
return new JsonResult().success();
return JsonResult.success();
} else {
return JsonResult.failMessage("保存失败");
}
......@@ -131,7 +131,7 @@ public class DictConsoleController {
List<Long> dels = ConvertUtil.str2longs(ids);
dictService.batchDelCoreDict(dels);
platformService.clearDictCache();
return new JsonResult().success();
return JsonResult.success();
}
@PostMapping(MODEL + "/excel/export.json")
......
package com.ibeetl.admin.console.web;
import com.ibeetl.admin.console.service.DictConsoleService;
import com.ibeetl.admin.console.web.dto.DictExcelImportData;
import com.ibeetl.admin.console.web.query.CoreDictQuery;
import com.ibeetl.admin.core.annotation.Function;
import com.ibeetl.admin.core.annotation.RequestBodyPlus;
import com.ibeetl.admin.core.entity.CoreDict;
import com.ibeetl.admin.core.entity.CoreUser;
import com.ibeetl.admin.core.file.FileItem;
import com.ibeetl.admin.core.file.FileService;
import com.ibeetl.admin.core.service.CorePlatformService;
import com.ibeetl.admin.core.util.PlatformException;
import com.ibeetl.admin.core.util.ValidateConfig;
import com.ibeetl.admin.core.web.JsonResult;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.servlet.http.HttpServletResponse;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;
import lombok.extern.slf4j.Slf4j;
import org.beetl.sql.core.engine.PageQuery;
import org.jxls.common.Context;
import org.jxls.reader.ReaderBuilder;
import org.jxls.reader.ReaderConfig;
import org.jxls.reader.XLSReadMessage;
import org.jxls.reader.XLSReadStatus;
import org.jxls.reader.XLSReader;
import org.jxls.util.JxlsHelper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
/**
* 字典数据管理接口
*/
@Slf4j
@RequestMapping("dicts")
@RestController
public class DictConsoleElController {
@Autowired
private DictConsoleService dictService;
@Autowired
FileService fileService;
@Autowired
CorePlatformService platformService = null;
@GetMapping("/list")
@Function("dict.query")
public JsonResult<PageQuery> list(CoreDictQuery condtion) {
PageQuery page = condtion.getPageQuery();
dictService.queryByCondition(page);
return JsonResult.success(page);
}
@PostMapping("/add")
@Function("dict.add")
public JsonResult add(@RequestBody @Validated(ValidateConfig.ADD.class) CoreDict dict) {
dict.setCreateTime(new Date());
dictService.save(dict);
platformService.clearDictCache();
return JsonResult.success();
}
@PutMapping("/update")
@Function("dict.update")
public JsonResult<String> update(
@RequestBody @Validated(ValidateConfig.UPDATE.class) CoreDict dict) {
boolean success = dictService.update(dict);
if (success) {
platformService.clearDictCache();
return JsonResult.success();
} else {
return JsonResult.failMessage("保存失败");
}
}
@GetMapping("/view/{id}")
@Function("dict.query")
public JsonResult<CoreDict> queryInfo(@PathVariable("id") @NotNull Long id) {
CoreDict dict = dictService.queryById(id);
return JsonResult.success(dict);
}
@DeleteMapping("/delete")
@Function("dict.delete")
public JsonResult delete(@NotEmpty @RequestBodyPlus("ids") List<Long> ids) {
dictService.batchDelCoreDict(ids);
platformService.clearDictCache();
return JsonResult.success();
}
@GetMapping("/excel/export")
@Function("dict.export")
public JsonResult<String> export(CoreDictQuery condtion,
HttpServletResponse response) {
String excelTemplate = "excelTemplates/admin/dict/dict_collection_template.xls";
PageQuery<CoreUser> page = condtion.getPageQuery();
// 取出全部符合条件的
page.setPageSize(Integer.MAX_VALUE);
page.setPageNumber(1);
page.setTotalRow(Integer.MAX_VALUE);
List<CoreDict> dicts = dictService.queryExcel(page);
try (InputStream is =
Thread.currentThread().getContextClassLoader().getResourceAsStream(excelTemplate)) {
if (is == null) {
throw new PlatformException("模板资源不存在:" + excelTemplate);
}
FileItem item = fileService.createFileTemp("dict_collection.xls");
OutputStream os = item.openOutpuStream();
Context context = new Context();
context.putVar("dicts", dicts);
JxlsHelper.getInstance().processTemplate(is, os, context);
os.close();
// 下载参考FileSystemContorller
return JsonResult.success(item.getPath());
} catch (IOException e) {
throw new PlatformException(e.getMessage());
}
}
@PostMapping("/excel/import")
@Function("dict.import")
public JsonResult importExcel(@RequestParam("file") MultipartFile file) throws Exception {
if (file.isEmpty()) {
return JsonResult.fail();
}
InputStream ins = file.getInputStream();
InputStream inputXML =
Thread.currentThread()
.getContextClassLoader()
.getResourceAsStream("excelTemplates/admin/dict/dict_mapping.xml");
XLSReader mainReader = ReaderBuilder.buildFromXML(inputXML);
InputStream inputXLS = ins;
List<DictExcelImportData> dicts = new ArrayList<DictExcelImportData>();
Map beans = new HashMap();
beans.put("list", dicts);
ReaderConfig.getInstance().setSkipErrors(true);
XLSReadStatus readStatus = mainReader.read(inputXLS, beans);
List<XLSReadMessage> errors = readStatus.getReadMessages();
if (!errors.isEmpty()) {
StringBuilder sb = new StringBuilder();
for (XLSReadMessage msg : errors) {
sb.append(parseXLSReadMessage(msg));
sb.append(",");
}
sb.setLength(sb.length() - 1);
return JsonResult.failMessage("解析excel出错:" + sb.toString());
}
// this.dictService.batchInsert(dicts);//layui对话框不能正确处理http 500错误,改成下面方式
// return JsonResult.success();
try {
this.dictService.batchInsert(dicts);
return JsonResult.success();
} catch (Exception ex) {
return JsonResult.failMessage(ex.getMessage());
}
}
/*xlsReader 设计有问题,还需要通过解析msg知道错误位置在哪里*/
private String parseXLSReadMessage(XLSReadMessage msg) {
// String message = "Can't read cell " + getCellName(mapping, rowShift) + " on " +
// cursor.getSheetName() + " spreadsheet";
String str = msg.getMessage();
int start = "Can't read cell ".length();
int end = str.indexOf("on");
return str.substring(start, end);
}
}
......@@ -29,7 +29,7 @@ import org.springframework.web.bind.annotation.RestController;
*/
@Slf4j
@RestController
@RequestMapping("/functions")
@RequestMapping("functions")
public class FunctionElController {
@Autowired
......
......@@ -40,7 +40,7 @@ import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
@Validated
@RequestMapping("/users")
@RequestMapping("users")
@RestController
public class UserConsoleElController {
......
# --------自定义应用属性
app:
name: SpringBoot-Plus
arrs:
- 1
- 2
#打开审计功能,开发模式应该关闭
audit:
enable: false
......
......@@ -33,5 +33,5 @@ batchDelCoreDictByIds
* 批量逻辑删除
update core_dict set del_flag = 1 where id in( #join(ids)#)
update core_dict set del_flag = 1 where id in ( #join(ids)#)
......@@ -57,11 +57,9 @@ public class ServiceValidationAop {
target.getClass().getDeclaredMethod(signature.getName(), targetMethod.getParameterTypes());
Object[] args = point.getArgs();
/*获取验证组*/
Class[] groups;
groups =
Optional.ofNullable(realMethod.getAnnotation(Validated.class))
.map(Validated::value)
.orElse(new Class[0]);
Class[] groups = Optional.ofNullable(realMethod.getAnnotation(Validated.class))
.map(Validated::value)
.orElse(new Class[0]);
/*使用hibernate-validator验证*/
Set<ConstraintViolation<Object>> constraintViolations =
ValidateUtils.validateMethod(target, realMethod, args, groups);
......
/*
* @Author: 一日看尽长安花
* @since: 2019-09-04 20:55:14
* @LastEditTime: 2020-07-26 15:22:32
* @LastEditors: 一日看尽长安花
* @Description:
*/
import request from '@/utils/request';
/**
* 字典数据管理页的数据
* @param {*} params
*/
export function getDicts(params) {
return request({
url: '/dicts/list',
method: 'get',
params
});
}
/**
* 通过字典数据id获取指定字典数据数据
* @param {*} params
*/
export function getDictById(params) {
return request({
url: `/dicts/${params.id}`,
method: 'get'
});
}
export function saveDictData(data) {
return request({
url: '/dicts/add',
method: 'post',
data
});
}
export function updateDictData(data) {
return request({
url: '/dicts/update',
method: 'put',
data
});
}
/**
* 删除字典数据管理页面的数据
* @param {*} data
*/
export function deleteDictData(data) {
return request({
url: '/dicts/delete',
method: 'delete',
data
});
}
export function exportDictExcel(data) {
return request({
url: '/dicts/excel/export',
method: 'get',
data
});
}
export function importExcel(data) {
return request({
url: '/dicts/excel/import',
method: 'post',
data
});
}
<!--
* @Author: 一日看尽长安花
* @since: 2020-07-19 16:33:05
* @LastEditTime: 2020-07-26 14:43:29
* @LastEditors: 一日看尽长安花
* @Description:
-->
<template>
<!-- vue实例外创建 -->
<div class="sp-edit-form-popup">
<el-dialog
ref="editDialog"
:title="title"
:visible.sync="visible"
:destroy-on-close="true"
:close-on-click-modal="false"
:close-on-press-escape="false"
:show-close="false"
@open="initDialog"
>
<div class="sp-edit-form">
<el-form
ref="editPopupForm"
:model="data_"
:rules="rules"
label-width="120px"
>
<el-form-item label="字典名称" required prop="name">
<el-input
v-model="data_.name"
placeholder="请输入字典名称"
></el-input>
</el-form-item>
<el-form-item label="字典值" required prop="value">
<el-input
v-model="data_.value"
placeholder="请输入字典值"
></el-input>
</el-form-item>
<el-form-item label="字典类型名称" required prop="type_name">
<el-input
v-model="data_.type_name"
placeholder="请输入字典类型名称"
></el-input>
</el-form-item>
<el-form-item label="字典类型" required prop="type">
<el-input
v-model="data_.type"
placeholder="请输入字典类型"
></el-input>
</el-form-item>
<el-form-item label="上级字典" prop="parent">
<el-input
v-model.number="data_.parent"
placeholder="请输入上级字典id"
type="number"
></el-input>
</el-form-item>
<el-form-item label="序号" prop="sort">
<el-input
v-model.number="data_.sort"
placeholder="请输入序号"
type="number"
></el-input>
</el-form-item>
<el-form-item label="备注" prop="remark">
<el-input
v-model="data_.remark"
placeholder="请输入备注"
></el-input>
</el-form-item>
</el-form>
</div>
<template #footer>
<div class="sp-edit-form-btn">
<el-button @click="close">取 消</el-button>
<el-button type="primary" @click="submit">
确 定
</el-button>
</div>
</template>
</el-dialog>
</div>
</template>
<script>
import { saveDictData, updateDictData } from '@/api/dicts';
export default {
name: 'DictEditPopup',
components: {},
props: {
visible: {
type: Boolean,
default: false
},
title: {
type: String,
default: '编辑'
},
data: {
type: Object,
default: function() {
return {};
}
}
},
data() {
return {
data_: {},
rules: {
name: [{ required: true, message: '请输入字典名称' }],
value: [{ required: true, message: '请输入字典值' }],
type: [{ required: true, message: '请输入字典类型名称' }],
type_name: [{ required: true, message: '请输入字典类型' }],
sort: [{ type: 'number', message: '序号必须是数字' }]
}
};
},
methods: {
initDialog() {
this.data_ = this.data;
if (this.data_.id) {
this.title = '编辑';
} else {
this.title = '新增';
}
},
submit() {
this.$refs['editPopupForm'].validate(valid => {
if (valid) {
if (this.data_.id) {
this.updateData();
} else {
this.addData();
}
} else {
return false;
}
});
},
addData() {
const _that = this;
saveDictData(this.data_).then(res => {
const { code, message, data } = { ...res };
// 通过中间路由刷新当前路由
_that.$nextTick(() => {
_that.$notify({
title: '成功',
message: '添加成功',
type: 'success',
duration: 2000,
onClose: function() {
_that.$router.replace('/refresh');
}
});
});
});
},
updateData() {
const _that = this;
updateDictData(this.data_).then(res => {
const { code, message, data } = { ...res };
// 通过中间路由刷新当前路由
_that.$nextTick(() => {
_that.$notify({
title: '成功',
message: '修改成功',
type: 'success',
duration: 2000,
onClose: function() {
_that.$router.replace('/refresh');
}
});
});
});
},
close() {
this.$emit('update:visible', false);
}
}
};
</script>
<!--
* @Author: 一日看尽长安花
* @since: 2020-07-12 16:32:51
* @LastEditTime: 2020-07-26 17:18:21
* @LastEditors: 一日看尽长安花
* @Description:
-->
<template>
<div class="sp-view-page">
<div class="sp-search-inline-pane">
<el-form :inline="true" :model="searchData">
<el-form-item label="字典值">
<el-input
v-model="searchData.value"
placeholder="请输入字典值"
></el-input>
</el-form-item>
<el-form-item label="字典名称">
<el-input
v-model="searchData.name"
placeholder="请输入字典名称"
></el-input>
</el-form-item>
<el-form-item label="字典类型">
<el-input
v-model="searchData.typeName"
placeholder="请输入字典类型"
></el-input>
</el-form-item>
<el-form-item label="上级字典">
<el-input
v-model.number="searchData.parent"
placeholder="请输入上级字典"
></el-input>
</el-form-item>
</el-form>
</div>
<div class="sp-opr-btn-group">
<div class="sp-func-btn">
<el-button class="el-icon-plus" type="primary" @click="addRecord">
增加
</el-button>
</div>
<div class="sp-func-btn">
<el-button
class="el-icon-delete-solid"
type="primary"
@click="delRecord"
>
删除
</el-button>
</div>
<div class="sp-func-btn">
<file-upload
class="upload-demo"
action="/dicts/excel/import"
:show-file-list="false"
:auto-upload="true"
>
<el-button size="mini" class="el-icon-download" type="primary">
导入
</el-button>
</file-upload>
</div>
<div class="sp-func-btn">
<el-button class="el-icon-download" type="primary" @click="exportExcel">
导出
</el-button>
</div>
<div class="sp-search-btn">
<el-button class="el-icon-search" type="primary" @click="onSearch">
查询
</el-button>
</div>
</div>
<el-table
ref="dataTable"
:data="tableData"
border
fit
highlight-current-row
>
<el-table-column label="#" type="selection"> </el-table-column>
<el-table-column prop="id" label="id"> </el-table-column>
<el-table-column prop="name" label="字典名称"> </el-table-column>
<el-table-column prop="value" label="字典值"> </el-table-column>
<el-table-column prop="type_name" label="字典类型名称"> </el-table-column>
<el-table-column prop="type" label="字典类型值"> </el-table-column>
<el-table-column prop="sort" label="排序"> </el-table-column>
<el-table-column prop="parent" label="父级id"> </el-table-column>
<el-table-column prop="remark" label="备注"> </el-table-column>
<el-table-column label="操作" width="150">
<template slot-scope="scope">
<el-button size="mini" @click="handleEdit(scope.$index, scope.row)">
编辑
</el-button>
<el-button
size="mini"
type="danger"
@click="handleDelete(scope.$index, scope.row)"
>
删除
</el-button>
</template>
</el-table-column>
</el-table>
<pagination
v-show="pageQuery.total > 0"
:total="pageQuery.total"
:page.sync="pageQuery.page"
:limit.sync="pageQuery.limit"
@pagination="getList"
/>
<edit-popup :visible.sync="editVisible" :data="rowData"></edit-popup>
</div>
</template>
<script>
import FileUpload from '@/components/Upload/FileUpload';
import Pagination from '@/components/Pagination'; // secondary package based on el-pagination
import EditPopup from './edit_popup';
import {
getDicts,
getDictById,
deleteDictData,
exportDictExcel,
importExcel
} from '@/api/dicts';
import { download } from '@/api/file';
export default {
name: 'DictManager',
components: { Pagination, EditPopup, FileUpload },
props: {},
data() {
return {
searchData: {},
tableData: [],
loading: true,
pageQuery: { page: 1, limit: 10, total: 0 },
editVisible: false,
rowData: {}
};
},
mounted() {
this.getList();
},
methods: {
getList() {
const queryParam = Object.assign({}, this.searchData, this.pageQuery);
getDicts(queryParam).then(res => {
const { code, message, data, count, total } = { ...res };
this.pageQuery.total = total;
this.tableData = data;
});
},
onSearch() {
this.getList();
},
addRecord() {
this.rowData = {};
this.editVisible = true;
},
handleEdit(index, row) {
this.rowData = row;
this.editVisible = true;
},
handleDelete(index, row) {
const Vue = this;
this.$confirm('确定删除该字典?', '删除', {
type: 'warning '
})
.then(() => {
deleteDictData({ ids: [row.id] })
.then(result => {
this.$nextTick(() => {
this.$notify({
title: '成功',
message: '删除字典数据成功',
type: 'success',
duration: 2000,
onClose: function() {
Vue.$router.replace('/refresh');
}
});
});
})
.catch(err => {
this.$nextTick(() => {
this.$notify({
title: '失败',
message: '删除字典数据失败',
type: 'error',
duration: 2000
});
});
});
})
.catch(action => {});
},
delRecord() {
const _table = this.$refs.dataTable;
const isSelection = _table.selection.length > 0 ? true : false;
if (!isSelection) {
this.$message({
type: 'warning',
message: '请选择数据'
});
return;
}
this.$confirm('确定删除所选字典?', '删除', {
type: 'warning '
}).then(() => {
const _selList = _table.selection;
const ids = _selList.map(item => item.id);
deleteDictData({ ids: ids }).then(response => {
const { code, message, data } = { ...response };
this.onSearch();
});
});
},
importExcel() {},
exportExcel() {
/**
* 导出Excel文件的两步:
* 1、通过查询条件由后台生成Excel临时文件,返回临时文件path
* 2、通过path去下载该文件
*/
exportDictExcel(this.searchData).then(res => {
const { code, data, message } = { ...res };
console.log(`...download path is ${data}`);
download({ path: data });
});
}
}
};
</script>
<style scoped>
.sp-view-page {
padding: 5px 10px;
}
.sp-opr-btn-group {
display: flex;
align-items: center;
justify-content: flex-start;
padding: 3px 0;
column-gap: 5px;
}
.sp-func-btn {
}
.sp-search-btn {
position: absolute;
right: 5px;
}
</style>
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment