Commit fbc2862e authored by trumansdo's avatar trumansdo
Browse files

完成功能点管理

补充路由刷新功能,利用空白页面和Vue-Router 的导航守卫hook做中间跳转
parent e3c1e9f2
......@@ -13,11 +13,13 @@ import com.ibeetl.admin.core.entity.CoreRoleMenu;
import com.ibeetl.admin.core.rbac.tree.FunctionItem;
import com.ibeetl.admin.core.service.CoreBaseService;
import com.ibeetl.admin.core.service.CorePlatformService;
import com.ibeetl.admin.core.util.FormFieldException;
import com.ibeetl.admin.core.util.PlatformException;
import com.ibeetl.admin.core.util.enums.DelFlagEnum;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
import javax.validation.constraints.NotNull;
import org.beetl.sql.core.engine.PageQuery;
......@@ -47,6 +49,9 @@ public class FunctionConsoleService extends CoreBaseService<CoreFunction> {
@Autowired
CorePlatformService corePlatformService;
/**
* @return 返回功能点构成的树结构
*/
public List<CoreFunction> getFuncTree() {
List<CoreFunction> coreFunctionList = functionConsoleDao.getSQLManager()
......@@ -63,12 +68,9 @@ public class FunctionConsoleService extends CoreBaseService<CoreFunction> {
/**
* 深度优先算法递归构建功能点树
*
* @param root
* @param allNodes
* @return
*/
private void buildTree(CoreFunction root, @NotNull List<CoreFunction> allNodes) {
if (CollUtil.isEmpty(allNodes)) {
return;
}
......@@ -104,11 +106,31 @@ public class FunctionConsoleService extends CoreBaseService<CoreFunction> {
public Long saveFunction(CoreFunction function) {
String code = function.getCode();
CoreFunction dbFunction = this.getFunction(code);
if (dbFunction != null) {
throw new FormFieldException(CoreFunction.class.getName(), "code", "已经存在");
}
Long parentId = Optional.ofNullable(function.getParent()).map(CoreFunction::getId).orElse(-1L);
function.setParentId(parentId);
function.setCreateTime(new Date());
functionConsoleDao.insert(function, true);
corePlatformService.clearFunctionCache();
return function.getId();
}
public void updateFunction(CoreFunction function) {
CoreFunction dbFunction = this.getFunction(function.getCode());
if (dbFunction != null && !dbFunction.getId().equals(function.getId())) {
throw new FormFieldException(CoreFunction.class.getName(), "code", "不存在此功能点");
}
Long parentId = Optional.ofNullable(function.getParent()).map(CoreFunction::getId).orElse(-1L);
function.setParentId(parentId);
functionConsoleDao.updateById(function);
corePlatformService.clearFunctionCache();
}
/**
* 删除功能点,跟菜单有关联的无法删除,删除功能点导致所有缓存都需要更新
*/
......@@ -126,11 +148,6 @@ public class FunctionConsoleService extends CoreBaseService<CoreFunction> {
corePlatformService.clearFunctionCache();
}
public void updateFunction(CoreFunction function) {
functionConsoleDao.updateById(function);
corePlatformService.clearFunctionCache();
}
public CoreFunction getFunction(Long functionId) {
......
......@@ -44,14 +44,19 @@ public class FunctionController {
private final Log log = LogFactory.getLog(this.getClass());
private static final String MODEL = "/admin/function";
@Autowired CorePlatformService platformService;
@Autowired private FunctionConsoleService functionConsoleService;
@Autowired
CorePlatformService platformService;
@Autowired
private FunctionConsoleService functionConsoleService;
/*页面*/
@GetMapping(MODEL + "/index.do")
@Function("function")
public ModelAndView index() {
ModelAndView view = new ModelAndView("/admin/function/index.html");
view.addObject("search", FunctionQuery.class.getName());
return view;
......@@ -60,6 +65,7 @@ public class FunctionController {
@GetMapping(MODEL + "/add.do")
@Function("function.add")
public ModelAndView add() {
ModelAndView view = new ModelAndView("/admin/function/add.html");
return view;
}
......@@ -67,6 +73,7 @@ public class FunctionController {
@GetMapping(MODEL + "/edit.do")
@Function("function.edit")
public ModelAndView edit(Integer id) {
ModelAndView view = new ModelAndView("/admin/function/edit.html");
CoreFunction function = functionConsoleService.queryById(id);
view.addObject("function", function);
......@@ -80,6 +87,7 @@ public class FunctionController {
@ResponseBody
public JsonResult<CoreFunction> addFunction(
@Validated(ValidateConfig.ADD.class) CoreFunction function) {
String code = function.getCode();
CoreFunction dbFunction = functionConsoleService.getFunction(code);
if (dbFunction != null) {
......@@ -87,7 +95,7 @@ public class FunctionController {
}
if (function.getParentId() == null) {
function.setParentId(0l);
function.setParentId(0L);
}
function.setCreateTime(new Date());
functionConsoleService.saveFunction(function);
......@@ -99,13 +107,14 @@ public class FunctionController {
@ResponseBody
public JsonResult<?> updateFunction(
@Validated(ValidateConfig.UPDATE.class) CoreFunction function) {
CoreFunction dbFunction = functionConsoleService.getFunction(function.getCode());
if (dbFunction != null && !dbFunction.getId().equals(function.getId())) {
throw new FormFieldException(CoreFunction.class.getName(), "code", "已经存在");
}
if (function.getParentId() == null) {
function.setParentId(0l);
function.setParentId(0L);
}
// function.setCreateTime(dbFunction.getCreateTime());
functionConsoleService.updateFunction(function);
......@@ -116,6 +125,7 @@ public class FunctionController {
@Function("function.query")
@ResponseBody
public JsonResult<CoreFunction> getFunction(Long id) {
CoreFunction function = functionConsoleService.getFunction(id);
if (function.hasParent()) {
......@@ -132,6 +142,7 @@ public class FunctionController {
@Function("function.delete")
@ResponseBody
public JsonResult deleteFunction(Long id) {
CoreFunction fun = functionConsoleService.queryById(id);
if (fun == null) {
throw new PlatformException("删除失败,没有找到Function " + id + "!");
......@@ -143,9 +154,6 @@ public class FunctionController {
/**
* 字典列表 分页
*
* @param condtion
* @return
*/
@RequestMapping(MODEL + "/list.json")
@Function("function.query")
......@@ -161,6 +169,7 @@ public class FunctionController {
@Function("function.query")
@ResponseBody
public JsonResult<List<Map<String, Object>>> listCondtion() {
List<Map<String, Object>> list =
AnnotationUtil.getInstance().getAnnotations(Query.class, FunctionQuery.class);
return JsonResult.success(list);
......@@ -178,21 +187,24 @@ public class FunctionController {
@Function("function.delete")
@ResponseBody
public JsonResult batchDel(String ids) {
List<Long> dels = ConvertUtil.str2longs(ids);
functionConsoleService.batchDeleteFunction(dels);
return new JsonResult().success();
return JsonResult.success();
}
@PostMapping(MODEL + "/tree.json")
@Function("function.query")
@ResponseBody
public JsonResult<List<FunctionNodeView>> tree() {
FunctionItem root = this.platformService.buildFunction();
List<FunctionNodeView> tree = buildFunctionTree(root);
return JsonResult.success(tree);
}
private List<FunctionNodeView> buildFunctionTree(FunctionItem node) {
List<FunctionItem> list = node.getChildren();
if (list.size() == 0) {
return Collections.EMPTY_LIST;
......@@ -210,4 +222,5 @@ public class FunctionController {
}
return views;
}
}
......@@ -2,13 +2,22 @@ package com.ibeetl.admin.console.web;
import com.ibeetl.admin.console.service.FunctionConsoleService;
import com.ibeetl.admin.core.annotation.Function;
import com.ibeetl.admin.core.annotation.RequestBodyPlus;
import com.ibeetl.admin.core.entity.CoreFunction;
import com.ibeetl.admin.core.service.CorePlatformService;
import com.ibeetl.admin.core.util.ValidateConfig;
import com.ibeetl.admin.core.web.JsonResult;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import lombok.extern.slf4j.Slf4j;
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.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.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
......@@ -41,4 +50,30 @@ public class FunctionElController {
return JsonResult.success(functionTreeNodes);
}
@PostMapping
@Function("function.add")
public JsonResult<CoreFunction> addFunction(
@Validated(ValidateConfig.ADD.class) @RequestBody CoreFunction function) {
functionConsoleService.saveFunction(function);
return JsonResult.success(function);
}
@PutMapping
@Function("function.update")
public JsonResult updateFunction(
@Validated(ValidateConfig.UPDATE.class) @RequestBody CoreFunction function) {
functionConsoleService.updateFunction(function);
return JsonResult.success();
}
@DeleteMapping
@Function("function.delete")
public JsonResult deleteFunction(@RequestBodyPlus("ids") Long[] ids) {
// 删除功能和所有子功能
functionConsoleService.batchDeleteFunction(Arrays.asList(ids));
return JsonResult.success();
}
}
......@@ -36,6 +36,8 @@ public class CoreFunction extends BaseEntity {
@NotBlank
private Long parentId;
private CoreFunction parent;
@UpdateIgnore
private Date createTime;
......
/*
* @Author: 一日看尽长安花
* @since: 2020-05-31 14:38:23
* @LastEditTime: 2020-05-31 14:45:16
* @LastEditTime: 2020-06-07 18:30:54
* @LastEditors: 一日看尽长安花
* @Description:
*/
import request from '@/utils/request';
/**
* 用户管理的数据
* 功能点管理的数据
* @param {*} params
*/
export function funcs(params) {
......@@ -18,3 +18,37 @@ export function funcs(params) {
params
});
}
/**
* 功能点管理的数据
* @param {*} params
*/
export function createFuncNode(params) {
return request({
url: '/functions',
method: 'post',
params
});
}
/**
* 功能点管理的数据
* @param {*} params
*/
export function updateFuncNode(params) {
return request({
url: '/functions',
method: 'put',
params
});
}
/**
* 功能点管理的数据
* @param {*} params
*/
export function delFuncNodesByParent(params) {
return request({
url: '/functions',
method: 'delete',
params
});
}
<!--
* @Author: 一日看尽长安花
* @since: 2020-06-07 14:41:55
* @LastEditTime: 2020-06-07 14:45:23
* @LastEditors: 一日看尽长安花
* @Description:
-->
<script>
export default {
name: 'Refresh',
beforeRouteEnter(to, from, next) {
// 在渲染该组件的对应路由被 confirm 前调用
// 不!能!获取组件实例 `this`
// 因为当守卫执行前,组件实例还没被创建
next(vm => {
vm.$router.replace(from.path);
// 跳到该路由页面后,再替换为from.path来源路径
});
}
};
</script>
# replace default config
#replace default config
# multipass: true
# full: true
#multipass: true
#full: true
plugins:
......
/*
* @Author: 一日看尽长安花
* @since: 2019-09-04 20:55:14
* @LastEditTime: 2019-10-29 21:31:55
* @LastEditTime: 2020-06-07 14:12:42
* @LastEditors: 一日看尽长安花
* @Description:
*/
......
import Vue from 'vue'
import Router from 'vue-router'
import Vue from 'vue';
import Router from 'vue-router';
Vue.use(Router)
Vue.use(Router);
/* Layout */
import Layout from '@/layout'
import Layout from '@/layout';
/**
* constantRoutes
* a base page that does not have permission requirements
* all roles can be accessed
* 这个常驻的路由不能拆分至route_map 中,也许是因为import是异步的?
* 所以导致了第一时间内路由中没有component
*/
// refresh 是为了需要刷新当前路由创建的
export const constantRoutes = [
{
path: '/refresh',
component: Layout,
hidden: true,
children: [
{
path: '/refresh',
component: () => import('@/components/Refresh/index')
}
]
},
{
path: '/redirect',
component: Layout,
......@@ -97,21 +107,21 @@ export const constantRoutes = [
}
]
}
]
];
const createRouter = () =>
new Router({
// mode: 'history', // require service support
scrollBehavior: () => ({ y: 0 }),
routes: constantRoutes
})
});
const router = createRouter()
const router = createRouter();
// Detail see: https://github.com/vuejs/vue-router/issues/1234#issuecomment-357941465
export function resetRouter() {
const newRouter = createRouter()
router.matcher = newRouter.matcher // reset router
const newRouter = createRouter();
router.matcher = newRouter.matcher; // reset router
}
export default router
export default router;
<!--
* @Author: 一日看尽长安花
* @since: 2020-05-30 12:53:38
* @LastEditTime: 2020-06-02 20:58:23
* @LastEditTime: 2020-06-07 19:37:11
* @LastEditors: 一日看尽长安花
* @Description:
-->
......@@ -17,7 +17,7 @@
:data="treeData"
node-key="id"
default-expand-all
:expand-on-click-node="true"
:expand-on-click-node="false"
:filter-node-method="filterNode"
>
<template v-slot="{ node: node, data: data }">
......@@ -56,27 +56,48 @@
</el-tree>
</div>
<div class="sp-side_panel--right">
<el-form key="formKey" ref="form" :model="formModel" label-width="80px">
<el-form-item label="功能名">
<el-input v-model="formModel.name"></el-input>
<el-form
key="formKey"
ref="nodeForm"
:rules="rules"
:model="formModel"
label-width="80px"
>
<el-form-item label="功能名" prop="name">
<el-input
v-model="formModel.name"
placeholder="请输入功能点名称"
></el-input>
</el-form-item>
<el-form-item label="功能代码">
<el-input v-model="formModel.code"></el-input>
<el-form-item label="功能代码" prop="code">
<el-input
v-model="formModel.code"
placeholder="请输入系统唯一功能点代码"
></el-input>
</el-form-item>
<el-form-item label="功能地址">
<el-form-item label="路由地址" prop="access_url">
<el-input
v-model="formModel.access_url"
:disabled="actType === 'editor'"
placeholder="请输入路由地址,可以输入动态路由"
></el-input>
<!-- todo :disabled="actType === 'editor'" 理论上应该在创建后就禁止修改,但是开发时方便一下-->
</el-form-item>
<el-form-item label="组件位置">
<el-input
v-model="formModel.component"
placeholder="请输入在前端中的组件地址,非页面可不填"
></el-input>
<!-- todo :disabled="actType === 'editor'" 理论上应该在创建后就禁止修改,但是开发时方便一下-->
</el-form-item>
<el-form-item label="父功能">
<el-form-item label="父功能" prop="parent">
<el-input
v-model="formModel.parent.name"
placeholder="点击选择上一级功能点"
readonly
@focus="openSelectParentNodeLayer"
></el-input>
</el-form-item>
<el-form-item label="功能类型">
<el-form-item label="功能类型" prop="type">
<el-select v-model="formModel.type" placeholder="请选择功能类型">
<el-option label="导航访问" value="FN0"></el-option>
<el-option label="功能点访问" value="FN1"></el-option>
......@@ -84,11 +105,7 @@
</el-select>
</el-form-item>
<el-form-item>
<el-button
type="primary"
@click="actType === 'create' ? createNode : updateNode"
>保存</el-button
>
<el-button type="primary" @click="saveNode">保存</el-button>
<el-button>取消</el-button>
</el-form-item>
</el-form>
......@@ -104,7 +121,12 @@
</template>
<script>
/** 功能点管理 */
import { funcs } from '@/api/func';
import {
funcs,
createFuncNode,
updateFuncNode,
delFuncNodesByParent
} from '@/api/func';
import SelFuncDialog from './select_dialog';
export default {
......@@ -122,7 +144,29 @@ export default {
}
},
actType: 'create',
dialogVisible: false
dialogVisible: false,
rules: {
name: { required: true, message: '请输入名称', trigger: 'blur' },
code: { required: true, message: '请输入代码点', trigger: 'blur' },
access_url: {
required: true,
message: '请输入访问路由,可使用动态路由',
trigger: 'blur'
},
parent: {
type: 'object',
required: true,
fields: {
name: { type: 'string', message: '请选择父功能', required: true }
}
},
type: {
type: 'string',
required: true,
message: '请选择访问类型',
trigger: 'change'
}
}
};
},
watch: {
......@@ -158,9 +202,98 @@ export default {
this.formModel.parent = node.parent.data;
this.actType = 'editor';
},
removeNode(node, data) {},
createNode() {},
updateNode() {},
removeNode(node, data) {
const ids = this.getTreeBranchIds(node);
this.$confirm('此操作将永久删除该功能点及其子功能点, 是否继续?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
})
.then(() => {
delFuncNodesByParent({ ids: ids }).then(response => {
const { code, message, data } = { ...response };
const loading = this.$loading({
lock: true,
text: 'Loading',
spinner: 'el-icon-loading',
background: 'rgba(0, 0, 0, 0.7)'
});
const _that = this;
this.$message({
message: '删除成功',
type: 'success',
onClose: function(_instance) {
_that.$router.replace('/refresh');
loading.close();
}
});
});
})
.catch(() => {});
},
getTreeBranchIds(node) {
let ids = [];
ids.push(node.data.id);
const _children = node.childNodes;
for (let i = 0; i < _children.length; i++) {
const child = _children[i];
let _child_ids = this.getTreeBranchIds(child);
ids = ids.concat(_child_ids);
}
return ids;
},
saveNode() {
const _that = this;
_that.$refs.nodeForm.validate(valid => {
if (!valid) {
_that.$message.error('数据请填写完成');
return false;
}
// 解除循环引用
delete _that.formModel.parent.children;
if (_that.actType === 'create') {
createFuncNode(_that.formModel).then(response => {
const { code, message, data } = { ...response };
const _that = this;
const loading = this.$loading({
lock: true,
text: 'Loading',
spinner: 'el-icon-loading',
background: 'rgba(0, 0, 0, 0.7)'
});
this.$message({
message: '创建功能点成功',
type: 'success',
onClose: function(_instance) {
// todo 可以用组件Mixin改写,或者直接挂载到Router原型上
_that.$router.replace('/refresh');
loading.close();
}
});
});
} else {
updateFuncNode(_that.formModel).then(response => {
const { code, message, data } = { ...response };
const _that = this;
const loading = this.$loading({
lock: true,
text: 'Loading',
spinner: 'el-icon-loading',
background: 'rgba(0, 0, 0, 0.7)'
});
this.$message({
message: '更新功能点成功',
type: 'success',
onClose: function(_instance) {
// todo 可以用组件Mixin改写,或者直接挂载到Router原型上
_that.$router.replace('/refresh');
loading.close();
}
});
});
}
});
},
openSelectParentNodeLayer() {
this.dialogVisible = true;
}
......
<!--
* @Author: 一日看尽长安花
* @since: 2020-05-30 12:53:38
* @LastEditTime: 2020-06-02 21:01:15
* @LastEditTime: 2020-06-06 18:44:44
* @LastEditors: 一日看尽长安花
* @Description:
-->
......@@ -13,7 +13,12 @@
:visible="visible"
@update:visible="$emit('update:visible', $event)"
>
<el-input v-model="filterText" placeholder="输入关键字进行过滤"> </el-input>
<el-input
v-model="filterText"
placeholder="输入关键字进行过滤"
@input="filterInput"
>
</el-input>
<el-tree
:key="Math.random()"
ref="tree"
......@@ -77,15 +82,11 @@ export default {
filterText: ''
};
},
watch: {
filterText(val) {
debugger;
this.$refs.tree.filter(val);
}
},
methods: {
filterInput(value) {
this.$refs.tree.filter(value);
},
filterNode(value, data) {
debugger;
if (!value) return true;
return data.name.indexOf(value) !== -1;
},
......@@ -109,7 +110,6 @@ export default {
this.$lodash.set(resObj, _label, _node.data);
_node = _node.parent;
}
debugger;
const updateValue = this.$lodash.assignIn({}, this.value, resObj);
this.$emit('updateValue', updateValue);
this.$emit('update:visible', false);
......
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