增加用户管理功能。管理员可以添加删除用户、修改用户密码、重置pushkey
| | |
| | | package com.genersoft.iot.vmp.service; |
| | | |
| | | import com.genersoft.iot.vmp.storager.dao.dto.User; |
| | | import com.github.pagehelper.PageInfo; |
| | | |
| | | import java.util.List; |
| | | |
| | |
| | | int updateUsers(User user); |
| | | |
| | | boolean checkPushAuthority(String callId, String sign); |
| | | |
| | | PageInfo<User> getUsers(int page, int count); |
| | | |
| | | int resetPushKey(int id); |
| | | } |
| | |
| | | import com.genersoft.iot.vmp.service.IUserService; |
| | | import com.genersoft.iot.vmp.storager.dao.UserMapper; |
| | | import com.genersoft.iot.vmp.storager.dao.dto.User; |
| | | import com.github.pagehelper.PageHelper; |
| | | import com.github.pagehelper.PageInfo; |
| | | import org.springframework.beans.factory.annotation.Autowired; |
| | | import org.springframework.stereotype.Service; |
| | | import org.springframework.util.StringUtils; |
| | |
| | | |
| | | @Service |
| | | public class UserServiceImpl implements IUserService { |
| | | |
| | | |
| | | @Autowired |
| | | private UserMapper userMapper; |
| | | |
| | |
| | | return userMapper.checkPushAuthorityByCallIdAndSign(callId, sign).size() > 0; |
| | | } |
| | | } |
| | | |
| | | @Override |
| | | public PageInfo<User> getUsers(int page, int count) { |
| | | PageHelper.startPage(page, count); |
| | | List<User> users = userMapper.getUsers(); |
| | | return new PageInfo<>(users); |
| | | } |
| | | |
| | | @Override |
| | | public int resetPushKey(int id) { |
| | | return userMapper.resetPushKey(id); |
| | | } |
| | | } |
| | |
| | | |
| | | @Select("select * from user where md5(pushKey) = '${sign}'") |
| | | List<User> checkPushAuthorityByCallId(String sign); |
| | | |
| | | @Select("select u.idu.username,u.pushKey,u.roleId, r.id as roleID, r.name as roleName, r.authority as roleAuthority , r.createTime as roleCreateTime , r.updateTime as roleUpdateTime FROM user u join user_role r on u.roleId=r.id") |
| | | @ResultMap(value="roleMap") |
| | | List<User> getUsers(); |
| | | |
| | | @Delete("update user set pushKey=MD5(NOW()+#{id}) where id=#{id}") |
| | | int resetPushKey(int id); |
| | | } |
| | |
| | | import com.genersoft.iot.vmp.storager.dao.dto.User; |
| | | import com.genersoft.iot.vmp.utils.DateUtil; |
| | | import com.genersoft.iot.vmp.vmanager.bean.WVPResult; |
| | | import com.github.pagehelper.PageInfo; |
| | | import io.swagger.annotations.Api; |
| | | import io.swagger.annotations.ApiImplicitParam; |
| | | import io.swagger.annotations.ApiImplicitParams; |
| | |
| | | result.setData(allUsers); |
| | | return new ResponseEntity<>(result, HttpStatus.OK); |
| | | } |
| | | |
| | | /** |
| | | * 分页查询用户 |
| | | * |
| | | * @param page 当前页 |
| | | * @param count 每页查询数量 |
| | | * @return 分页用户列表 |
| | | */ |
| | | @ApiOperation("分页查询用户") |
| | | @ApiImplicitParams({ |
| | | @ApiImplicitParam(name = "page", value = "当前页", required = true, dataTypeClass = Integer.class), |
| | | @ApiImplicitParam(name = "count", value = "每页查询数量", required = true, dataTypeClass = Integer.class), |
| | | }) |
| | | @GetMapping("/users") |
| | | public PageInfo<User> users(int page, int count) { |
| | | return userService.getUsers(page, count); |
| | | } |
| | | |
| | | @ApiOperation("重置pushkey") |
| | | @ApiImplicitParams({ |
| | | @ApiImplicitParam(name = "id", required = true, value = "用户Id", dataTypeClass = Integer.class), |
| | | }) |
| | | @RequestMapping("/resetPushKey") |
| | | public ResponseEntity<WVPResult<String>> resetPushKey(@RequestParam Integer id) { |
| | | // 获取当前登录用户id |
| | | int currenRoleId = SecurityUtils.getUserInfo().getRole().getId(); |
| | | WVPResult<String> result = new WVPResult<>(); |
| | | if (currenRoleId != 1) { |
| | | // 只用角色id为0才可以删除和添加用户 |
| | | result.setCode(-1); |
| | | result.setMsg("用户无权限"); |
| | | return new ResponseEntity<>(result, HttpStatus.FORBIDDEN); |
| | | } |
| | | int resetPushKeyResult = userService.resetPushKey(id); |
| | | |
| | | result.setCode(resetPushKeyResult > 0 ? 0 : -1); |
| | | result.setMsg(resetPushKeyResult > 0 ? "success" : "fail"); |
| | | return new ResponseEntity<>(result, HttpStatus.OK); |
| | | } |
| | | |
| | | @ApiOperation("管理员修改普通用户密码") |
| | | @ApiImplicitParams({ |
| | | @ApiImplicitParam(name = "adminId", required = true, value = "管理员id", dataTypeClass = String.class), |
| | | @ApiImplicitParam(name = "userId", required = true, value = "用户id", dataTypeClass = String.class), |
| | | @ApiImplicitParam(name = "password", required = true, value = "新密码(未md5加密的密码)", dataTypeClass = String.class), |
| | | }) |
| | | @PostMapping("/changePasswordForAdmin") |
| | | public String changePasswordForAdmin(@RequestParam int userId, @RequestParam String password) { |
| | | // 获取当前登录用户id |
| | | LoginUser userInfo = SecurityUtils.getUserInfo(); |
| | | if (userInfo == null) { |
| | | return "fail"; |
| | | } |
| | | Role role = userInfo.getRole(); |
| | | if (role != null && role.getId() == 1) { |
| | | boolean result = userService.changePassword(userId, DigestUtils.md5DigestAsHex(password.getBytes())); |
| | | if (result) { |
| | | return "success"; |
| | | } |
| | | } |
| | | |
| | | return "fail"; |
| | | } |
| | | } |
| | |
| | | }).then(function (res) { |
| | | console.log(JSON.stringify(res)); |
| | | if (res.data.code == 0 && res.data.msg == "success") { |
| | | that.$cookies.set("session", {"username": that.username}) ; |
| | | that.$cookies.set("session", {"username": that.username,"roleId":res.data.data.role.id}) ; |
| | | //登录成功后 |
| | | that.cancelEnterkeyDefaultAction(); |
| | | that.$router.push('/'); |
New file |
| | |
| | | <template> |
| | | |
| | | <div id="app" style="width: 100%"> |
| | | <div class="page-header"> |
| | | |
| | | <div class="page-title">用户列表</div> |
| | | <div class="page-header-btn"> |
| | | <el-button icon="el-icon-plus" size="mini" style="margin-right: 1rem;" type="primary" @click="addUser"> |
| | | 添加用户 |
| | | </el-button> |
| | | |
| | | </div> |
| | | </div> |
| | | <!--用户列表--> |
| | | <el-table :data="userList" style="width: 100%;font-size: 12px;" :height="winHeight" |
| | | header-row-class-name="table-header"> |
| | | <el-table-column prop="username" label="用户名" min-width="160"/> |
| | | <el-table-column prop="pushKey" label="pushkey" min-width="160"/> |
| | | <el-table-column prop="role.name" label="类型" min-width="160"/> |
| | | <el-table-column label="操作" min-width="450" fixed="right"> |
| | | <template slot-scope="scope"> |
| | | <el-button size="medium" icon="el-icon-edit" type="text" @click="edit(scope.row)">修改密码</el-button> |
| | | <el-divider direction="vertical"></el-divider> |
| | | <el-button size="medium" icon="el-icon-refresh" type="text" @click="resetPushKey(scope.row)">重置pushkey</el-button> |
| | | <el-divider direction="vertical"></el-divider> |
| | | <el-button size="medium" icon="el-icon-delete" type="text" @click="deleteUser(scope.row)" |
| | | style="color: #f56c6c">删除 |
| | | </el-button> |
| | | </template> |
| | | </el-table-column> |
| | | </el-table> |
| | | <changePasswordForAdmin ref="changePasswordForAdmin"></changePasswordForAdmin> |
| | | <addUser ref="addUser"></addUser> |
| | | <el-pagination |
| | | style="float: right" |
| | | @size-change="handleSizeChange" |
| | | @current-change="currentChange" |
| | | :current-page="currentPage" |
| | | :page-size="count" |
| | | :page-sizes="[15, 25, 35, 50]" |
| | | layout="total, sizes, prev, pager, next" |
| | | :total="total"> |
| | | </el-pagination> |
| | | </div> |
| | | </template> |
| | | |
| | | <script> |
| | | import uiHeader from '../layout/UiHeader.vue' |
| | | import changePasswordForAdmin from './dialog/changePasswordForAdmin.vue' |
| | | import addUser from '../components/dialog/addUser.vue' |
| | | |
| | | export default { |
| | | name: 'userManager', |
| | | components: { |
| | | uiHeader, |
| | | changePasswordForAdmin, |
| | | addUser |
| | | }, |
| | | data() { |
| | | return { |
| | | userList: [], //设备列表 |
| | | currentUser: {}, //当前操作设备对象 |
| | | |
| | | videoComponentList: [], |
| | | updateLooper: 0, //数据刷新轮训标志 |
| | | currentUserLenth: 0, |
| | | winHeight: window.innerHeight - 200, |
| | | currentPage: 1, |
| | | count: 15, |
| | | total: 0, |
| | | getUserListLoading: false |
| | | }; |
| | | }, |
| | | mounted() { |
| | | this.initData(); |
| | | this.updateLooper = setInterval(this.initData, 10000); |
| | | }, |
| | | destroyed() { |
| | | this.$destroy('videojs'); |
| | | clearTimeout(this.updateLooper); |
| | | }, |
| | | methods: { |
| | | initData: function () { |
| | | this.getUserList(); |
| | | }, |
| | | currentChange: function (val) { |
| | | this.currentPage = val; |
| | | this.getUserList(); |
| | | }, |
| | | handleSizeChange: function (val) { |
| | | this.count = val; |
| | | this.getUserList(); |
| | | }, |
| | | getUserList: function () { |
| | | let that = this; |
| | | this.getUserListLoading = true; |
| | | this.$axios({ |
| | | method: 'get', |
| | | url: `/api/user/users`, |
| | | params: { |
| | | page: that.currentPage, |
| | | count: that.count |
| | | } |
| | | }).then(function (res) { |
| | | that.total = res.data.total; |
| | | that.userList = res.data.list; |
| | | that.getUserListLoading = false; |
| | | }).catch(function (error) { |
| | | that.getUserListLoading = false; |
| | | }); |
| | | |
| | | }, |
| | | edit: function (row) { |
| | | this.$refs.changePasswordForAdmin.openDialog(row, () => { |
| | | this.$refs.changePasswordForAdmin.close(); |
| | | this.$message({ |
| | | showClose: true, |
| | | message: "密码修改成功", |
| | | type: "success", |
| | | }); |
| | | setTimeout(this.getDeviceList, 200) |
| | | |
| | | }) |
| | | }, |
| | | deleteUser: function (row) { |
| | | let msg = "确定删除此用户?" |
| | | if (row.online !== 0) { |
| | | msg = "<strong>确定删除此用户?</strong>" |
| | | } |
| | | this.$confirm(msg, '提示', { |
| | | dangerouslyUseHTMLString: true, |
| | | confirmButtonText: '确定', |
| | | cancelButtonText: '取消', |
| | | center: true, |
| | | type: 'warning' |
| | | }).then(() => { |
| | | this.$axios({ |
| | | method: 'delete', |
| | | url: `/api/user/delete?id=${row.id}` |
| | | }).then((res) => { |
| | | this.getUserList(); |
| | | }).catch((error) => { |
| | | console.error(error); |
| | | }); |
| | | }).catch(() => { |
| | | |
| | | }); |
| | | |
| | | |
| | | }, |
| | | resetPushKey: function (row) { |
| | | let msg = "确定重置pushkey?" |
| | | if (row.online !== 0) { |
| | | msg = "<strong>确定重置pushkey?</strong>" |
| | | } |
| | | this.$confirm(msg, '提示', { |
| | | dangerouslyUseHTMLString: true, |
| | | confirmButtonText: '确定', |
| | | cancelButtonText: '取消', |
| | | center: true, |
| | | type: 'warning' |
| | | }).then(() => { |
| | | this.$axios({ |
| | | method: 'get', |
| | | url: `/api/user/resetPushKey?id=${row.id}` |
| | | }).then((res) => { |
| | | this.getUserList(); |
| | | }).catch((error) => { |
| | | console.error(error); |
| | | }); |
| | | }).catch(() => { |
| | | |
| | | }); |
| | | |
| | | |
| | | }, |
| | | addUser: function () { |
| | | this.$refs.addUser.openDialog() |
| | | } |
| | | } |
| | | } |
| | | </script> |
| | | <style> |
| | | .videoList { |
| | | display: flex; |
| | | flex-wrap: wrap; |
| | | align-content: flex-start; |
| | | } |
| | | |
| | | .video-item { |
| | | position: relative; |
| | | width: 15rem; |
| | | height: 10rem; |
| | | margin-right: 1rem; |
| | | background-color: #000000; |
| | | } |
| | | |
| | | .video-item-img { |
| | | position: absolute; |
| | | top: 0; |
| | | bottom: 0; |
| | | left: 0; |
| | | right: 0; |
| | | margin: auto; |
| | | width: 100%; |
| | | height: 100%; |
| | | } |
| | | |
| | | .video-item-img:after { |
| | | content: ""; |
| | | display: inline-block; |
| | | position: absolute; |
| | | z-index: 2; |
| | | top: 0; |
| | | bottom: 0; |
| | | left: 0; |
| | | right: 0; |
| | | margin: auto; |
| | | width: 3rem; |
| | | height: 3rem; |
| | | background-image: url("../assets/loading.png"); |
| | | background-size: cover; |
| | | background-color: #000000; |
| | | } |
| | | |
| | | .video-item-title { |
| | | position: absolute; |
| | | bottom: 0; |
| | | color: #000000; |
| | | background-color: #ffffff; |
| | | line-height: 1.5rem; |
| | | padding: 0.3rem; |
| | | width: 14.4rem; |
| | | } |
| | | |
| | | </style> |
New file |
| | |
| | | <template> |
| | | <div id="addUser" v-loading="isLoging"> |
| | | <el-dialog |
| | | title="添加用户" |
| | | width="40%" |
| | | top="2rem" |
| | | :close-on-click-modal="false" |
| | | :visible.sync="showDialog" |
| | | :destroy-on-close="true" |
| | | @close="close()" |
| | | > |
| | | <div id="shared" style="margin-right: 20px;"> |
| | | <el-form ref="passwordForm" :rules="rules" status-icon label-width="80px"> |
| | | <el-form-item label="用户名" prop="username"> |
| | | <el-input v-model="username" autocomplete="off"></el-input> |
| | | </el-form-item> |
| | | <el-form-item label="用户类型" prop="roleId"> |
| | | <el-select v-model="roleId" placeholder="请选择"> |
| | | <el-option |
| | | v-for="item in options" |
| | | :key="item.id" |
| | | :label="item.name" |
| | | :value="item.id"> |
| | | </el-option> |
| | | </el-select> |
| | | </el-form-item> |
| | | <el-form-item label="密码" prop="password"> |
| | | <el-input v-model="password" autocomplete="off"></el-input> |
| | | </el-form-item> |
| | | <el-form-item label="确认密码" prop="confirmPassword"> |
| | | <el-input v-model="confirmPassword" autocomplete="off"></el-input> |
| | | </el-form-item> |
| | | |
| | | <el-form-item> |
| | | <div style="float: right;"> |
| | | <el-button type="primary" @click="onSubmit">保存</el-button> |
| | | <el-button @click="close">取消</el-button> |
| | | </div> |
| | | </el-form-item> |
| | | </el-form> |
| | | </div> |
| | | </el-dialog> |
| | | </div> |
| | | </template> |
| | | |
| | | <script> |
| | | |
| | | export default { |
| | | name: "addUser", |
| | | props: {}, |
| | | computed: {}, |
| | | created() { |
| | | this.getAllRole(); |
| | | }, |
| | | data() { |
| | | let validatePass1 = (rule, value, callback) => { |
| | | if (value === '') { |
| | | callback(new Error('请输入新密码')); |
| | | } else { |
| | | if (this.confirmPassword !== '') { |
| | | this.$refs.passwordForm.validateField('confirmPassword'); |
| | | } |
| | | callback(); |
| | | } |
| | | }; |
| | | let validatePass2 = (rule, value, callback) => { |
| | | if (this.confirmPassword === '') { |
| | | callback(new Error('请再次输入密码')); |
| | | } else if (this.confirmPassword !== this.password) { |
| | | callback(new Error('两次输入密码不一致!')); |
| | | } else { |
| | | callback(); |
| | | } |
| | | }; |
| | | return { |
| | | value:"", |
| | | options: [], |
| | | loading: false, |
| | | username: null, |
| | | password: null, |
| | | roleId: null, |
| | | confirmPassword: null, |
| | | listChangeCallback: null, |
| | | showDialog: false, |
| | | isLoging: false, |
| | | rules: { |
| | | newPassword: [{required: true, validator: validatePass1, trigger: "blur"}, { |
| | | pattern: /^(?=.*[a-zA-Z])(?=.*\d)(?=.*[~!@#$%^&*()_+`\-={}:";'<>?,.\/]).{8,20}$/, |
| | | message: "密码长度在8-20位之间,由字母+数字+特殊字符组成", |
| | | },], |
| | | confirmPassword: [{required: true, validator: validatePass2, trigger: "blur"}], |
| | | }, |
| | | }; |
| | | }, |
| | | methods: { |
| | | openDialog: function (callback) { |
| | | this.listChangeCallback = callback; |
| | | this.showDialog = true; |
| | | }, |
| | | onSubmit: function () { |
| | | this.$axios({ |
| | | method: 'post', |
| | | url: "/api/user/add", |
| | | params: { |
| | | username: this.username, |
| | | password: this.password, |
| | | roleId: this.roleId |
| | | } |
| | | }).then((res) => { |
| | | if (res.data.code === 0) { |
| | | this.$message({ |
| | | showClose: true, |
| | | message: '添加成功', |
| | | type: 'success', |
| | | |
| | | }); |
| | | this.showDialog = false; |
| | | this.listChangeCallback() |
| | | |
| | | } else { |
| | | this.$message({ |
| | | showClose: true, |
| | | message: res.data.msg, |
| | | type: 'error' |
| | | }); |
| | | } |
| | | }).catch((error) => { |
| | | console.error(error) |
| | | }); |
| | | }, |
| | | close: function () { |
| | | this.showDialog = false; |
| | | this.password = null; |
| | | this.confirmPassword = null; |
| | | this.username = null; |
| | | this.roleId = null; |
| | | }, |
| | | getAllRole:function () { |
| | | |
| | | this.$axios({ |
| | | method: 'get', |
| | | url: "/api/role/all" |
| | | }).then((res) => { |
| | | this.loading = true; |
| | | console.info(res) |
| | | res.data |
| | | console.info(res.data.code) |
| | | if (res.data.code === 0) { |
| | | console.info(res.data.data) |
| | | this.options=res.data.data |
| | | |
| | | } |
| | | }).catch((error) => { |
| | | console.error(error) |
| | | }); |
| | | } |
| | | }, |
| | | }; |
| | | </script> |
New file |
| | |
| | | <template> |
| | | <div id="changePassword" v-loading="isLoging"> |
| | | <el-dialog |
| | | title="修改密码" |
| | | width="40%" |
| | | top="2rem" |
| | | :close-on-click-modal="false" |
| | | :visible.sync="showDialog" |
| | | :destroy-on-close="true" |
| | | @close="close()" |
| | | > |
| | | <div id="shared" style="margin-right: 20px;"> |
| | | <el-form ref="passwordForm" :rules="rules" status-icon label-width="80px"> |
| | | <el-form-item label="新密码" prop="newPassword" > |
| | | <el-input v-model="newPassword" autocomplete="off"></el-input> |
| | | </el-form-item> |
| | | <el-form-item label="确认密码" prop="confirmPassword"> |
| | | <el-input v-model="confirmPassword" autocomplete="off"></el-input> |
| | | </el-form-item> |
| | | |
| | | <el-form-item> |
| | | <div style="float: right;"> |
| | | <el-button type="primary" @click="onSubmit">保存</el-button> |
| | | <el-button @click="close">取消</el-button> |
| | | </div> |
| | | </el-form-item> |
| | | </el-form> |
| | | </div> |
| | | </el-dialog> |
| | | </div> |
| | | </template> |
| | | |
| | | <script> |
| | | export default { |
| | | name: "changePasswordForAdmin", |
| | | props: {}, |
| | | computed: {}, |
| | | created() {}, |
| | | data() { |
| | | let validatePass1 = (rule, value, callback) => { |
| | | if (value === '') { |
| | | callback(new Error('请输入新密码')); |
| | | } else { |
| | | if (this.confirmPassword !== '') { |
| | | this.$refs.passwordForm.validateField('confirmPassword'); |
| | | } |
| | | callback(); |
| | | } |
| | | }; |
| | | let validatePass2 = (rule, value, callback) => { |
| | | if (this.confirmPassword === '') { |
| | | callback(new Error('请再次输入密码')); |
| | | } else if (this.confirmPassword !== this.newPassword) { |
| | | callback(new Error('两次输入密码不一致!')); |
| | | } else { |
| | | callback(); |
| | | } |
| | | }; |
| | | return { |
| | | newPassword: null, |
| | | confirmPassword: null, |
| | | userId: null, |
| | | showDialog: false, |
| | | isLoging: false, |
| | | listChangeCallback: null, |
| | | form: {}, |
| | | rules: { |
| | | newPassword: [{ required: true, validator: validatePass1, trigger: "blur" }, { |
| | | pattern: /^(?=.*[a-zA-Z])(?=.*\d)(?=.*[~!@#$%^&*()_+`\-={}:";'<>?,.\/]).{8,20}$/, |
| | | message: "密码长度在8-20位之间,由字母+数字+特殊字符组成", |
| | | },], |
| | | confirmPassword: [{ required: true, validator: validatePass2, trigger: "blur" }], |
| | | }, |
| | | }; |
| | | }, |
| | | methods: { |
| | | openDialog: function (row, callback) { |
| | | console.log(row) |
| | | this.showDialog = true; |
| | | this.listChangeCallback = callback; |
| | | if (row != null) { |
| | | this.form = row; |
| | | } |
| | | }, |
| | | onSubmit: function () { |
| | | this.$axios({ |
| | | method: 'post', |
| | | url:"/api/user/changePasswordForAdmin", |
| | | params: { |
| | | password: this.newPassword, |
| | | userId: this.form.id, |
| | | } |
| | | }).then((res)=> { |
| | | if (res.data === "success"){ |
| | | this.$message({ |
| | | showClose: true, |
| | | message: '修改成功', |
| | | type: 'success' |
| | | }); |
| | | this.showDialog = false; |
| | | }else { |
| | | this.$message({ |
| | | showClose: true, |
| | | message: '修改密码失败,是否已登录(接口鉴权关闭无法修改密码)', |
| | | type: 'error' |
| | | }); |
| | | } |
| | | }).catch((error)=> { |
| | | console.error(error) |
| | | }); |
| | | }, |
| | | close: function () { |
| | | this.showDialog = false; |
| | | this.newPassword = null; |
| | | this.confirmPassword = null; |
| | | this.userId=null; |
| | | this.adminId=null; |
| | | }, |
| | | }, |
| | | }; |
| | | </script> |
| | |
| | | <el-menu-item index="/cloudRecord">云端录像</el-menu-item> |
| | | <el-menu-item index="/mediaServerManger">节点管理</el-menu-item> |
| | | <el-menu-item index="/parentPlatformList/15/1">国标级联</el-menu-item> |
| | | <el-menu-item v-if="editUser" index="/userManager">用户管理</el-menu-item> |
| | | |
| | | <!-- <el-submenu index="/setting">--> |
| | | <!-- <template slot="title">系统设置</template>--> |
| | |
| | | alarmNotify: false, |
| | | sseSource: null, |
| | | activeIndex: this.$route.path, |
| | | editUser: this.$cookies.get("session").roleId==1 |
| | | }; |
| | | }, |
| | | created() { |
| | | console.log(this.$cookies.get("session")) |
| | | if (this.$route.path.startsWith("/channelList")) { |
| | | this.activeIndex = "/deviceList" |
| | | } |
| | |
| | | import media from '../components/setting/Media.vue' |
| | | import live from '../components/live.vue' |
| | | import deviceTree from '../components/common/DeviceTree.vue' |
| | | import userManager from '../components/UserManager.vue' |
| | | |
| | | import wasmPlayer from '../components/common/jessibuca.vue' |
| | | import rtcPlayer from '../components/dialog/rtcPlayer.vue' |
| | |
| | | name: 'map', |
| | | component: map, |
| | | }, |
| | | { |
| | | path: '/userManager', |
| | | name: 'userManager', |
| | | component: userManager, |
| | | } |
| | | ] |
| | | }, |
| | | { |