Quellcode durchsuchen

devops-manager 更新用户管理接口和页面

reghao vor 2 Jahren
Ursprung
Commit
a1b008b057

+ 21 - 0
manager/src/main/java/cn/reghao/devops/manager/rbac/controller/UserController.java

@@ -11,6 +11,7 @@ import org.springframework.http.MediaType;
 import org.springframework.security.access.prepost.PreAuthorize;
 import org.springframework.validation.annotation.Validated;
 import org.springframework.web.bind.annotation.*;
+import org.springframework.web.multipart.MultipartFile;
 
 import javax.validation.constraints.NotNull;
 import java.util.List;
@@ -41,13 +42,33 @@ public class UserController {
         return WebResult.success();
     }
 
+    @PreAuthorize("hasRole('ROLE_ADMIN')")
+    @ApiOperation(value = "批量创建用户")
+    @PostMapping(value = "/batch", produces = MediaType.APPLICATION_JSON_VALUE)
+    public String batchAdd(MultipartFile file) {
+        return WebResult.success();
+    }
+
+    @PostMapping(value = "/avatar", produces = MediaType.APPLICATION_JSON_VALUE)
+    public String userAvatar(MultipartFile file) {
+        return WebResult.success();
+    }
+
     @ApiOperation(value = "修改用户信息")
     @PostMapping(value = "/modify", produces = MediaType.APPLICATION_JSON_VALUE)
+    @Deprecated
     public String modifyUserInfo(@Validated UserInfo userInfo) {
         userService.modifyUserInfo(userInfo);
         return WebResult.success();
     }
 
+    @ApiOperation(value = "修改用户信息")
+    @PostMapping(value = "/edit", produces = MediaType.APPLICATION_JSON_VALUE)
+    public String editUserInfo(@Validated UserInfo userInfo) {
+        //userService.modifyUserInfo(userInfo);
+        return WebResult.success();
+    }
+
     @PreAuthorize("hasRole('ROLE_ADMIN')")
     @ApiOperation(value = "删除用户")
     @DeleteMapping(value = "/{id}", produces = MediaType.APPLICATION_JSON_VALUE)

+ 11 - 0
manager/src/main/java/cn/reghao/devops/manager/rbac/controller/page/UserPageController.java

@@ -12,6 +12,8 @@ import io.swagger.annotations.ApiOperation;
 import org.springframework.data.domain.Page;
 import org.springframework.data.domain.PageImpl;
 import org.springframework.data.domain.PageRequest;
+import org.springframework.security.core.Authentication;
+import org.springframework.security.core.context.SecurityContextHolder;
 import org.springframework.stereotype.Controller;
 import org.springframework.ui.Model;
 import org.springframework.web.bind.annotation.*;
@@ -71,6 +73,7 @@ public class UserPageController {
 
     @ApiOperation(value = "用户信息编辑页面")
     @GetMapping("/edit/{id}")
+    @Deprecated
     public String editUserPage(@PathVariable("id") User user, Model model) {
         Set<Role> allRoles = new HashSet<>(roleQuery.findAll());
         Set<Role> userRoles = userQuery.getUserRoles(user);
@@ -93,6 +96,14 @@ public class UserPageController {
         return "/rbac/user/detail";
     }
 
+    @GetMapping("/profile")
+    public String userInfoPage(Model model) {
+        Authentication authToken = SecurityContextHolder.getContext().getAuthentication();
+        User user = (User) authToken.getDetails();
+        model.addAttribute("user", user);
+        return "/rbac/user/userinfo";
+    }
+
     @ApiOperation(value = "用户修改密码页面")
     @GetMapping("/passwd/{id}")
     public String modifyPasswordPage(@PathVariable("id") Integer id, Model model) {

+ 1 - 0
manager/src/main/java/cn/reghao/devops/manager/rbac/model/dto/UserInfo.java

@@ -18,4 +18,5 @@ public class UserInfo implements Serializable {
     // TODO 验证邮箱和手机号码是否有效
     private String mobilePhone;
     private String email;
+    private Integer gender;
 }

+ 15 - 0
manager/src/main/resources/static/js/main.js

@@ -426,6 +426,21 @@ layui.use(['element', 'form', 'layer', 'upload'], function () {
         $("[data-field='"+ field +"']").addClass(isAsc);
     }
 
+    /* 上传文件操作 */
+    upload.render({
+        elem: '.upload-file' //绑定元素
+        ,url: $('.upload-file').attr('up-url') //上传接口
+        ,field: 'file' //文件域的字段名
+        ,accept: 'file'
+        //,field: 'image' //文件域的字段名
+        //,acceptMime: 'image/*' //选择文件类型
+        //,exts: 'jpg|jpeg|png|gif' //支持的图片格式
+        ,multiple: true //开启多文件选择
+        ,done: function(res, index, upload){
+            console.log(res)
+        }
+    });
+
     /* 上传图片操作 */
     upload.render({
         elem: '.upload-image' //绑定元素

+ 2 - 3
manager/src/main/resources/templates/main.html

@@ -31,7 +31,7 @@
                 <div class="layui-nav-child">
                     <div class="timo-nav-child-box">
                         <div>
-                            <a class="open-popup" data-title="个人信息" th:attr="data-url=@{/userInfo}" data-size="680,464">
+                            <a class="open-popup" data-title="个人信息" th:attr="data-url=@{/rbac/user/profile}" data-size="680,464">
                                 <i class="fa fa-user-o"></i>个人信息</a>
                         </div>
                         <div>
@@ -51,8 +51,7 @@
         <div class="layui-side-scroll">
             <!-- 用户区域 -->
             <div class="layui-side-user">
-                <img class="layui-side-user-avatar open-popup" th:attr="data-url=@{/userInfo}" data-size="680,464"
-                     th:src="@{${user.avatarUrl}}" alt="头像">
+                <img class="layui-side-user-avatar" data-size="680,464" th:src="@{${user.avatarUrl}}" alt="头像">
                 <div>
                     <p class="layui-side-user-name" th:text="${user.nickname}">DevOps</p>
                     <p class="layui-side-user-designation">在线</p>

+ 4 - 0
manager/src/main/resources/templates/rbac/user/index.html

@@ -30,6 +30,10 @@
                                 data-size="auto">
                             <i class="fa fa-plus"></i> 添加
                         </button>
+                        <!--<button class="layui-btn upload-file" data-title=""
+                                name="file[]" th:attr="up-url=@{/api/rbac/user/batch}" data-size="auto">
+                            <i class="fa fa-plus"></i> 批量添加
+                        </button>-->
                     </div>
                 </div>
             </div>

+ 196 - 0
manager/src/main/resources/templates/rbac/user/userinfo.html

@@ -0,0 +1,196 @@
+<!DOCTYPE html>
+<html xmlns:th="http://www.thymeleaf.org">
+<head th:replace="/common/template :: header(~{::title},~{::link},~{::style})">
+</head>
+<body>
+<div class="layui-form timo-compile user-info-page">
+    <div class="user-info">
+        <div class="user-avatar-box">
+            <img class="user-avatar" th:src="@{${user.avatarUrl}}" alt="头像">
+            <span class="edit-avatar" th:attr="data-url=@{/api/rbac/user/avatar}">修改头像</span>
+        </div>
+        <ul class="detail-info">
+            <li>账号:<span th:text="${user.username}" th:title="${user.username}"></span></li>
+            <li>昵称:<span th:text="${user.nickname}" th:title="${user.nickname}"></span></li>
+            <li>性别:<span th:text="${user.gender}"
+                         th:title="${user.gender}"></span></li>
+            <li>电话:<span th:text="${user.mobilePhone}" th:title="${user.mobilePhone}"></span></li>
+            <li>邮箱:<span th:text="${user.email}" th:title="${user.email}"></span></li>
+        </ul>
+    </div>
+    <form class="user-edit" th:action="@{/api/rbac/user/edit}">
+        <input type="hidden" name="userId" th:value="${user.id}"/>
+        <div class="layui-form-item">
+            <label class="layui-form-label">用户昵称</label>
+            <div class="layui-input-inline">
+                <input class="layui-input" type="text" name="nickname" placeholder="请输入用户昵称" th:value="${user.nickname}">
+            </div>
+        </div>
+        <div class="layui-form-item">
+            <label class="layui-form-label">电话号码</label>
+            <div class="layui-input-inline">
+                <input class="layui-input" type="text" name="mobilePhone" placeholder="请输入电话号码" th:value="${user.mobilePhone}">
+            </div>
+        </div>
+        <div class="layui-form-item">
+            <label class="layui-form-label">邮箱</label>
+            <div class="layui-input-inline">
+                <input class="layui-input" type="text" name="email" placeholder="请输入邮箱" th:value="${user.email}">
+            </div>
+        </div>
+        <div class="layui-form-item">
+            <label class="layui-form-label">选择性别</label>
+            <div class="layui-input-inline">
+                <input type="radio" name="gender" value="1" title="男" checked><div class="layui-unselect layui-form-radio layui-form-radioed"><i class="layui-anim layui-icon"></i><div>男</div></div>
+                <input type="radio" name="gender" value="2" title="女" th:checked="${user.gender} eq 2"><div class="layui-unselect layui-form-radio"><i class="layui-anim layui-icon"></i><div>女</div></div>
+            </div>
+        </div>
+        <div class="layui-form-item timo-finally">
+            <button class="layui-btn ajax-submit"><i class="fa fa-check-circle"></i> 保存</button>
+            <a class="layui-btn btn-secondary close-popup"><i class="fa fa-times-circle"></i> 关闭</a>
+        </div>
+    </form>
+    <!-- 编辑头像面板 -->
+    <div class="canvas-panel">
+        <img class="canvas-bg"/>
+        <div class="canvas-shade"></div>
+        <canvas class="canvas-crop"></canvas>
+    </div>
+    <div class="canvas-group layui-btn-group">
+        <button class="upload-close layui-btn layui-btn-primary layui-btn-sm">取消</button>
+        <button class="upload-btn layui-btn layui-btn-primary layui-btn-sm">保存</button>
+    </div>
+</div>
+<script th:replace="/common/template :: script"></script>
+<script type="text/javascript" th:src="@{/js/plugins/jquery-2.2.4.min.js}"></script>
+<script type="text/javascript" th:src="@{/js/plugins/jquery.mousewheel.min.js}"></script>
+<script>
+    layui.use(['jquery','upload'], function () {
+        var $ = layui.jquery;
+        var upload = layui.upload;
+
+        $(".user-edit").on("mousedown", function () {
+            $(this).css("opacity", 1);
+        });
+
+        /* 修改头像 */
+        var image = new Image();
+        var panel = $(".canvas-panel");
+        var bgImg = $(".canvas-bg");
+        var canvas = $(".canvas-crop");
+
+        // 激活或停止移动
+        var moveEvent = false;
+        var screenX = 0, screenY = 0;
+        var moveTop = 0, moveLeft = 0;
+        panel.on("mousedown",function (e) {
+            screenX = e.screenX;
+            screenY = e.screenY;
+            moveTop = parseFloat(bgImg.css("top"));
+            moveLeft = parseFloat(bgImg.css("left"));
+            moveEvent = true;
+        });
+        panel.on("mouseup",function (e) {
+            moveEvent = false;
+        });
+        panel.on("mousemove", function (e) {
+            if (moveEvent){
+                bgImg.css("left", moveLeft + e.screenX - screenX);
+                bgImg.css("top", moveTop + e.screenY - screenY);
+                renderPanel();
+            }
+        });
+        panel.on("mousewheel", function(event, delta) {
+            var dir = delta > 0 ? 'Up' : 'Down';
+            var width = parseFloat(bgImg.css("width"));
+            var height = parseFloat(bgImg.css("height"));
+            if (dir == 'Up') {
+                delta = 1;
+            } else {
+                delta = -1;
+            }
+            bgImg.css("width", width * (1 + 0.1 * delta));
+            bgImg.css("height", height * (1 + 0.1 * delta));
+            bgImg.css("left", parseFloat(bgImg.css("left")) - (width * 0.1 / 2) * delta);
+            bgImg.css("top", parseFloat(bgImg.css("top")) - (height * 0.1 / 2) * delta);
+            renderPanel();
+            return false;
+        });
+
+        // 渲染画布面板
+        function renderPanel() {
+            canvas[0].width = 256;
+            canvas[0].height = 256;
+            var imgScale = image.width / bgImg.width();
+            var context = canvas[0].getContext('2d');
+            var sx = (bgImg.width() * imgScale / 2 ) - canvas.width() / 2 * imgScale,
+                sy = (bgImg.height() * imgScale / 2) - canvas.height() / 2 * imgScale,
+                sw = canvas.width() * imgScale, sh = canvas.height() * imgScale;
+            var moveX = panel.width() / 2 - parseFloat(bgImg.css("left")) - bgImg.width() / 2;
+            var moveY = panel.height() / 2 - parseFloat(bgImg.css("top")) - bgImg.height() / 2;
+            context.drawImage(image, sx + moveX * imgScale, sy + moveY * imgScale, sw, sh, 0, 0, canvas[0].width, canvas[0].height);
+        }
+
+        var files = [];
+        var uploadInst = upload.render({
+            elem: '.edit-avatar'
+            ,field: 'picture'
+            ,url: $('.edit-avatar').data('url')
+            ,exts: 'jpg|png|gif|jpeg'
+            ,auto: false
+            ,bindAction: ".upload-btn"
+            // 选择文件回调
+            ,choose: function(obj){
+                obj.preview(function(index, file, result){
+                    panel.show();
+                    $(".canvas-group").show();
+                    image.src = result;
+                    image.onload = function(){
+                        bgImg.attr("src", result);
+                        if(bgImg.width() >= bgImg.height()){
+                            bgImg.css("height", canvas.width());
+                        }else {
+                            bgImg.css("width", canvas.height());
+                        }
+                        bgImg.css("top", (panel.height() - bgImg.height()) / 2);
+                        bgImg.css("left", (panel.width() - bgImg.width()) / 2);
+                        renderPanel();
+                    }
+                });
+            }
+            ,before: function(obj){
+                files = obj.pushFile();
+                var index, file;
+                for(index in files) {
+                    file = files[index];
+                }
+                var dataurl = canvas[0].toDataURL(file.type, 0.92);
+                var arr = dataurl.split(','), mime = arr[0].match(/:(.*?);/)[1],
+                    bstr = atob(arr[1]), n = bstr.length, u8arr = new Uint8Array(n);
+                while(n--){
+                    u8arr[n] = bstr.charCodeAt(n);
+                }
+                files[index] = new File([u8arr], file.name, {type:mime});
+            }
+            ,done: function(res, index){
+                if(res.code === 0){
+                    panel.hide();
+                    $(".canvas-group").hide();
+                    layer.msg("修改头像成功", {offset: '15px', time: 3000, icon: 1});
+                    $(".user-avatar").attr("src", canvas[0].toDataURL());
+                    delete files[index];
+                }else {
+                    layer.msg(res.msg, {offset: '15px', time: 3000, icon: 2});
+                }
+            }
+        });
+
+        // 关闭裁切面板及清空文件
+        $(".upload-close").on("click", function () {
+            panel.hide();
+            $(".canvas-group").hide();
+        });
+    });
+</script>
+</body>
+</html>