Commit d7711d96 authored by danfuman's avatar danfuman

Merge branch 'V20230915' of http://192.168.60.201/root/dsk-operate-sys into V20230915

# Conflicts:
#	dsk-operate-ui/src/assets/styles/public.scss
#	dsk-operate-ui/src/views/macro/urban/index.vue
parents b9203304 0ef1f2fc
...@@ -61,6 +61,11 @@ ...@@ -61,6 +61,11 @@
<artifactId>dsk-biz-api</artifactId> <artifactId>dsk-biz-api</artifactId>
</dependency> </dependency>
<dependency>
<groupId>com.dsk</groupId>
<artifactId>dsk-biz-bi</artifactId>
</dependency>
<dependency> <dependency>
<groupId>org.springframework.boot</groupId> <groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId> <artifactId>spring-boot-starter-test</artifactId>
...@@ -84,6 +89,7 @@ ...@@ -84,6 +89,7 @@
<!-- <version>${与你的agent探针版本保持一致}</version>--> <!-- <version>${与你的agent探针版本保持一致}</version>-->
<!-- </dependency>--> <!-- </dependency>-->
</dependencies> </dependencies>
<build> <build>
......
...@@ -5,6 +5,7 @@ import com.dsk.common.annotation.Log; ...@@ -5,6 +5,7 @@ import com.dsk.common.annotation.Log;
import com.dsk.common.core.controller.BaseController; import com.dsk.common.core.controller.BaseController;
import com.dsk.common.core.domain.PageQuery; import com.dsk.common.core.domain.PageQuery;
import com.dsk.common.core.domain.R; import com.dsk.common.core.domain.R;
import com.dsk.common.utils.Chinese2PinyinUtils;
import com.dsk.system.domain.SysDept; import com.dsk.system.domain.SysDept;
import com.dsk.system.domain.SysRole; import com.dsk.system.domain.SysRole;
import com.dsk.system.domain.SysUser; import com.dsk.system.domain.SysUser;
...@@ -81,13 +82,16 @@ public class SysRoleController extends BaseController { ...@@ -81,13 +82,16 @@ public class SysRoleController extends BaseController {
@PostMapping @PostMapping
public R<Void> add(@Validated @RequestBody SysRole role) { public R<Void> add(@Validated @RequestBody SysRole role) {
roleService.checkRoleAllowed(role); roleService.checkRoleAllowed(role);
//应产品经理强!烈!要求,让后台自动生成权限字符,为方便后期排查bug,经考虑后将角色名的拼音设置为权限字符
role.setRoleKey(Chinese2PinyinUtils.toLowerPinyin(role.getRoleName()));
if (!roleService.checkRoleNameUnique(role)) { if (!roleService.checkRoleNameUnique(role)) {
return R.fail("新增角色'" + role.getRoleName() + "'失败,角色名称已存在"); return R.fail("新增角色'" + role.getRoleName() + "'失败,角色名称已存在");
} else if (!roleService.checkRoleKeyUnique(role)) { } else if (!roleService.checkRoleKeyUnique(role)) {
return R.fail("新增角色'" + role.getRoleName() + "'失败,角色权限已存在"); return R.fail("新增角色'" + role.getRoleName() + "'失败,角色权限已存在");
} }
return toAjax(roleService.insertRole(role)); return toAjax(roleService.insertRole(role));
} }
/** /**
......
...@@ -3,6 +3,7 @@ package com.dsk.web.controller.system; ...@@ -3,6 +3,7 @@ package com.dsk.web.controller.system;
import cn.dev33.satoken.annotation.SaCheckPermission; import cn.dev33.satoken.annotation.SaCheckPermission;
import cn.dev33.satoken.annotation.SaCheckRole; import cn.dev33.satoken.annotation.SaCheckRole;
import cn.dev33.satoken.annotation.SaMode; import cn.dev33.satoken.annotation.SaMode;
import cn.hutool.core.bean.BeanUtil;
import com.baomidou.lock.annotation.Lock4j; import com.baomidou.lock.annotation.Lock4j;
import com.dsk.common.annotation.Log; import com.dsk.common.annotation.Log;
import com.dsk.common.annotation.RepeatSubmit; import com.dsk.common.annotation.RepeatSubmit;
...@@ -15,9 +16,13 @@ import com.dsk.common.core.validate.AddGroup; ...@@ -15,9 +16,13 @@ import com.dsk.common.core.validate.AddGroup;
import com.dsk.common.core.validate.EditGroup; import com.dsk.common.core.validate.EditGroup;
import com.dsk.common.enums.BusinessType; import com.dsk.common.enums.BusinessType;
import com.dsk.common.tenant.helper.TenantHelper; import com.dsk.common.tenant.helper.TenantHelper;
import com.dsk.common.utils.StringUtils;
import com.dsk.system.domain.SysUser;
import com.dsk.system.domain.bo.SysTenantAdminBo;
import com.dsk.system.domain.bo.SysTenantBo; import com.dsk.system.domain.bo.SysTenantBo;
import com.dsk.system.domain.vo.SysTenantVo; import com.dsk.system.domain.vo.SysTenantVo;
import com.dsk.system.service.ISysTenantService; import com.dsk.system.service.ISysTenantService;
import com.dsk.system.service.ISysUserService;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import org.springframework.validation.annotation.Validated; import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.*;
...@@ -39,11 +44,12 @@ import java.util.Arrays; ...@@ -39,11 +44,12 @@ import java.util.Arrays;
@RequestMapping("/system/tenant") @RequestMapping("/system/tenant")
public class SysTenantController extends BaseController { public class SysTenantController extends BaseController {
private final ISysTenantService tenantService; private final ISysTenantService tenantService;
private final ISysUserService userService;
/** /**
* 查询租户列表 * 查询租户列表
*/ */
@SaCheckRole(value = {TenantConstants.SUPER_ADMIN_ROLE_KEY,TenantConstants.DSK_TENANT_ADMIN_ROLE_KEY},mode = SaMode.OR) @SaCheckRole(value = {TenantConstants.SUPER_ADMIN_ROLE_KEY, TenantConstants.DSK_TENANT_ADMIN_ROLE_KEY}, mode = SaMode.OR)
@SaCheckPermission(value = "system:tenant:list", orRole = "accountAdmin") @SaCheckPermission(value = "system:tenant:list", orRole = "accountAdmin")
@GetMapping("/list") @GetMapping("/list")
public TableDataInfo<SysTenantVo> list(SysTenantBo bo, PageQuery pageQuery) { public TableDataInfo<SysTenantVo> list(SysTenantBo bo, PageQuery pageQuery) {
...@@ -67,7 +73,7 @@ public class SysTenantController extends BaseController { ...@@ -67,7 +73,7 @@ public class SysTenantController extends BaseController {
* *
* @param id 主键 * @param id 主键
*/ */
@SaCheckRole(value = {TenantConstants.SUPER_ADMIN_ROLE_KEY,TenantConstants.DSK_TENANT_ADMIN_ROLE_KEY},mode = SaMode.OR) @SaCheckRole(value = {TenantConstants.SUPER_ADMIN_ROLE_KEY, TenantConstants.DSK_TENANT_ADMIN_ROLE_KEY}, mode = SaMode.OR)
@SaCheckPermission(value = "system:tenant:query", orRole = "accountAdmin") @SaCheckPermission(value = "system:tenant:query", orRole = "accountAdmin")
@GetMapping("/{id}") @GetMapping("/{id}")
public R<SysTenantVo> getInfo(@NotNull(message = "主键不能为空") @PathVariable Long id) { public R<SysTenantVo> getInfo(@NotNull(message = "主键不能为空") @PathVariable Long id) {
...@@ -77,7 +83,7 @@ public class SysTenantController extends BaseController { ...@@ -77,7 +83,7 @@ public class SysTenantController extends BaseController {
/** /**
* 新增租户 * 新增租户
*/ */
@SaCheckRole(value = {TenantConstants.SUPER_ADMIN_ROLE_KEY,TenantConstants.DSK_TENANT_ADMIN_ROLE_KEY},mode = SaMode.OR) @SaCheckRole(value = {TenantConstants.SUPER_ADMIN_ROLE_KEY, TenantConstants.DSK_TENANT_ADMIN_ROLE_KEY}, mode = SaMode.OR)
@SaCheckPermission(value = "system:tenant:add", orRole = "accountAdmin") @SaCheckPermission(value = "system:tenant:add", orRole = "accountAdmin")
@Log(title = "租户", businessType = BusinessType.INSERT) @Log(title = "租户", businessType = BusinessType.INSERT)
@Lock4j @Lock4j
...@@ -90,10 +96,26 @@ public class SysTenantController extends BaseController { ...@@ -90,10 +96,26 @@ public class SysTenantController extends BaseController {
return toAjax(TenantHelper.ignore(() -> tenantService.insertByBo(bo))); return toAjax(TenantHelper.ignore(() -> tenantService.insertByBo(bo)));
} }
/**
* 新增企业普通管理员账号
*/
@SaCheckRole(value = {TenantConstants.SUPER_ADMIN_ROLE_KEY, TenantConstants.DSK_TENANT_ADMIN_ROLE_KEY}, mode = SaMode.OR)
@SaCheckPermission(value = "system:user:add")
@Log(title = "用户管理", businessType = BusinessType.INSERT)
@PostMapping("/addTenantAdmin")
public R<Void> addTenantAdmin(@Validated @RequestBody SysTenantAdminBo tenantAdminBo) {
//校验手机号是否已存在
if (TenantHelper.ignore(()->userService.checkTenantAdminPhoneUnique(tenantAdminBo))) {
return R.fail("新增用户'" + tenantAdminBo.getPhonenumber() + "'失败,手机号码已存在");
}
return toAjax(TenantHelper.ignore(() -> tenantService.addTenantAdmin(tenantAdminBo)));
//return R.ok("手机号验证成功");
}
/** /**
* 修改租户 * 修改租户
*/ */
@SaCheckRole(value = {TenantConstants.SUPER_ADMIN_ROLE_KEY,TenantConstants.DSK_TENANT_ADMIN_ROLE_KEY},mode = SaMode.OR) @SaCheckRole(value = {TenantConstants.SUPER_ADMIN_ROLE_KEY, TenantConstants.DSK_TENANT_ADMIN_ROLE_KEY}, mode = SaMode.OR)
@SaCheckPermission(value = "system:tenant:edit", orRole = "accountAdmin") @SaCheckPermission(value = "system:tenant:edit", orRole = "accountAdmin")
@Log(title = "租户", businessType = BusinessType.UPDATE) @Log(title = "租户", businessType = BusinessType.UPDATE)
@RepeatSubmit() @RepeatSubmit()
...@@ -123,7 +145,7 @@ public class SysTenantController extends BaseController { ...@@ -123,7 +145,7 @@ public class SysTenantController extends BaseController {
* *
* @param ids 主键串 * @param ids 主键串
*/ */
@SaCheckRole(value = {TenantConstants.SUPER_ADMIN_ROLE_KEY,TenantConstants.DSK_TENANT_ADMIN_ROLE_KEY},mode = SaMode.OR) @SaCheckRole(value = {TenantConstants.SUPER_ADMIN_ROLE_KEY, TenantConstants.DSK_TENANT_ADMIN_ROLE_KEY}, mode = SaMode.OR)
@SaCheckPermission(value = "system:tenant:remove", orRole = "accountAdmin") @SaCheckPermission(value = "system:tenant:remove", orRole = "accountAdmin")
@Log(title = "租户", businessType = BusinessType.DELETE) @Log(title = "租户", businessType = BusinessType.DELETE)
@DeleteMapping("/{ids}") @DeleteMapping("/{ids}")
...@@ -146,7 +168,7 @@ public class SysTenantController extends BaseController { ...@@ -146,7 +168,7 @@ public class SysTenantController extends BaseController {
/** /**
* 清除动态租户 * 清除动态租户
*/ */
@SaCheckRole(value = {TenantConstants.SUPER_ADMIN_ROLE_KEY,TenantConstants.DSK_TENANT_ADMIN_ROLE_KEY},mode = SaMode.OR) @SaCheckRole(value = {TenantConstants.SUPER_ADMIN_ROLE_KEY, TenantConstants.DSK_TENANT_ADMIN_ROLE_KEY}, mode = SaMode.OR)
@GetMapping("/dynamic/clear") @GetMapping("/dynamic/clear")
public R<Void> dynamicClear() { public R<Void> dynamicClear() {
TenantHelper.clearDynamic(); TenantHelper.clearDynamic();
...@@ -159,7 +181,7 @@ public class SysTenantController extends BaseController { ...@@ -159,7 +181,7 @@ public class SysTenantController extends BaseController {
* @param tenantId 租户id * @param tenantId 租户id
* @param packageId 套餐id * @param packageId 套餐id
*/ */
@SaCheckRole(value = {TenantConstants.SUPER_ADMIN_ROLE_KEY,TenantConstants.DSK_TENANT_ADMIN_ROLE_KEY},mode = SaMode.OR) @SaCheckRole(value = {TenantConstants.SUPER_ADMIN_ROLE_KEY, TenantConstants.DSK_TENANT_ADMIN_ROLE_KEY}, mode = SaMode.OR)
@SaCheckPermission(value = "system:tenant:edit", orRole = "accountAdmin") @SaCheckPermission(value = "system:tenant:edit", orRole = "accountAdmin")
@Log(title = "租户", businessType = BusinessType.UPDATE) @Log(title = "租户", businessType = BusinessType.UPDATE)
@GetMapping("/syncTenantPackage") @GetMapping("/syncTenantPackage")
......
package com.dsk.web.controller.system; package com.dsk.web.controller.system;
import cn.dev33.satoken.annotation.SaCheckPermission; import cn.dev33.satoken.annotation.SaCheckPermission;
import cn.dev33.satoken.annotation.SaCheckRole;
import cn.dev33.satoken.annotation.SaMode;
import cn.dev33.satoken.secure.BCrypt; import cn.dev33.satoken.secure.BCrypt;
import cn.hutool.core.bean.BeanUtil; import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.lang.tree.Tree; import cn.hutool.core.lang.tree.Tree;
...@@ -9,6 +11,7 @@ import cn.hutool.core.util.ObjectUtil; ...@@ -9,6 +11,7 @@ import cn.hutool.core.util.ObjectUtil;
import com.dsk.biz.utils.ExcelUtils; import com.dsk.biz.utils.ExcelUtils;
import com.dsk.common.annotation.Log; import com.dsk.common.annotation.Log;
import com.dsk.common.constant.GlobalConstants; import com.dsk.common.constant.GlobalConstants;
import com.dsk.common.constant.TenantConstants;
import com.dsk.common.core.controller.BaseController; import com.dsk.common.core.controller.BaseController;
import com.dsk.common.core.domain.PageQuery; import com.dsk.common.core.domain.PageQuery;
import com.dsk.common.core.domain.R; import com.dsk.common.core.domain.R;
...@@ -16,6 +19,7 @@ import com.dsk.common.core.page.TableDataInfo; ...@@ -16,6 +19,7 @@ import com.dsk.common.core.page.TableDataInfo;
import com.dsk.common.enums.BusinessType; import com.dsk.common.enums.BusinessType;
import com.dsk.common.exception.ServiceException; import com.dsk.common.exception.ServiceException;
import com.dsk.common.helper.LoginHelper; import com.dsk.common.helper.LoginHelper;
import com.dsk.common.tenant.helper.TenantHelper;
import com.dsk.common.utils.StreamUtils; import com.dsk.common.utils.StreamUtils;
import com.dsk.common.utils.StringUtils; import com.dsk.common.utils.StringUtils;
import com.dsk.common.utils.poi.ExcelUtil; import com.dsk.common.utils.poi.ExcelUtil;
...@@ -37,6 +41,7 @@ import org.springframework.web.bind.annotation.*; ...@@ -37,6 +41,7 @@ import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile; import org.springframework.web.multipart.MultipartFile;
import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpServletResponse;
import javax.validation.constraints.NotNull;
import java.util.*; import java.util.*;
/** /**
...@@ -55,6 +60,16 @@ public class SysUserController extends BaseController { ...@@ -55,6 +60,16 @@ public class SysUserController extends BaseController {
private final ISysPostService postService; private final ISysPostService postService;
private final ISysDeptService deptService; private final ISysDeptService deptService;
/**
* 根据租户ID查询大司空超管or租户管理员为其创建的企业管理员和管理员账号数量
*/
@SaCheckRole(value = {TenantConstants.SUPER_ADMIN_ROLE_KEY, TenantConstants.DSK_TENANT_ADMIN_ROLE_KEY}, mode = SaMode.OR)
@SaCheckPermission(value = "system:user:query", orRole = "accountAdmin")
@GetMapping("/queryTenantAdminNumCreatedByDSK/{tenantId}")
public R<Long> queryTenantAdminNumCreatedByDSK(@NotNull(message = "租户ID不能为空") @PathVariable Long tenantId) {
return R.ok(TenantHelper.ignore(() -> userService.queryTenantAdminNumCreatedByDSK(tenantId)));
}
/** /**
* 获取用户列表 * 获取用户列表
*/ */
...@@ -121,10 +136,6 @@ public class SysUserController extends BaseController { ...@@ -121,10 +136,6 @@ public class SysUserController extends BaseController {
throw new ServiceException("表格中不存在待导入数据!"); throw new ServiceException("表格中不存在待导入数据!");
} }
for (SysUserImportVo userImportVo : userImportList) {
System.out.println("👉🏻:"+userImportVo);
}
//开始导入业务 //开始导入业务
List<SysUserImportVo> failImportUsers = userService.batchImportUser(userImportList, updateSupport); List<SysUserImportVo> failImportUsers = userService.batchImportUser(userImportList, updateSupport);
...@@ -216,6 +227,7 @@ public class SysUserController extends BaseController { ...@@ -216,6 +227,7 @@ public class SysUserController extends BaseController {
@Log(title = "用户管理", businessType = BusinessType.DELETE) @Log(title = "用户管理", businessType = BusinessType.DELETE)
@DeleteMapping("/{userIds}") @DeleteMapping("/{userIds}")
public R<Void> remove(@PathVariable Long[] userIds) { public R<Void> remove(@PathVariable Long[] userIds) {
//不能删除当前登录账号
if (ArrayUtil.contains(userIds, getUserId())) { if (ArrayUtil.contains(userIds, getUserId())) {
return R.fail("当前用户不能删除"); return R.fail("当前用户不能删除");
} }
......
...@@ -140,7 +140,7 @@ security: ...@@ -140,7 +140,7 @@ security:
- /*/api-docs - /*/api-docs
- /*/api-docs/** - /*/api-docs/**
# actuator 监控配置 # actuator 监控配置
- /actuator - /api/**
- /actuator/** - /actuator/**
...@@ -300,3 +300,25 @@ management: ...@@ -300,3 +300,25 @@ management:
show-details: ALWAYS show-details: ALWAYS
logfile: logfile:
external-file: ./logs/sys-console.log external-file: ./logs/sys-console.log
gv:
img-path: D:\dsk\dsk-operate-sys\
#spring:
# datasource:
# type: com.alibaba.druid.pool.DruidDataSource
# druid:
# driver-class-name: com.mysql.cj.jdbc.Driver
# username: ${MYSQL_USER:root}
# password: ${MYSQL_PWD:root}
# url: jdbc:mysql://${MYSQL_HOST:pigx-mysql}:${MYSQL_PORT:3306}/${MYSQL_DB:pigxx_report}?characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=false&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=GMT%2B8&allowMultiQueries=true&allowPublicKeyRetrieval=true
# jpa:
# database-platform:
# org.hibernate.dialect.MySQL8Dialectsecurity:
# oauth2:
# client:
# ignore-urls:
# - /
# - /api/project/getData
# - /static/**
# - /api/project/get-file/*
# # 文件上传路径
...@@ -187,6 +187,12 @@ ...@@ -187,6 +187,12 @@
<scope>compile</scope> <scope>compile</scope>
</dependency> </dependency>
<!--中文转拼音-->
<dependency>
<groupId>com.belerweb</groupId>
<artifactId>pinyin4j</artifactId>
</dependency>
</dependencies> </dependencies>
</project> </project>
...@@ -18,34 +18,44 @@ public interface TenantConstants { ...@@ -18,34 +18,44 @@ public interface TenantConstants {
String DISABLE = "1"; String DISABLE = "1";
/** /**
* 超级管理员ID * 大司空超级管理员ID
*/ */
Long SUPER_ADMIN_ID = 1L; Long SUPER_ADMIN_ID = 1L;
/** /**
* 超级管理员角色 roleKey * 大司空超级管理员角色 roleKey
*/ */
String SUPER_ADMIN_ROLE_KEY = "superadmin"; String SUPER_ADMIN_ROLE_KEY = "superadmin";
/** /**
* 租户管理员角色 roleKey * 大司空租户管理员角色
*/ */
String TENANT_ADMIN_ROLE_KEY = "admin"; String DSK_TENANT_ADMIN_ROLE_KEY = "accountAdmin";
/** /**
* 租户管理员角色名称 * 大司空租户管理员角色名称
*/ */
String TENANT_ADMIN_ROLE_NAME = "管理员"; String DSK_TENANT_ADMIN_ROLE_NAME = "企业账号管理员";
/** /**
* 大司空租户管理员角色 * 企业超级管理员角色 roleKey
*/ */
String DSK_TENANT_ADMIN_ROLE_KEY = "accountAdmin"; String TENANT_SUPER_ADMIN_ROLE_KEY = "tenantSuperAdmin";
/** /**
* 大司空租户管理员角色名称 * 企业超级管理员角色名称
*/ */
String DSK_TENANT_ADMIN_ROLE_NAME = "企业账号管理员"; String TENANT_SUPER_ADMIN_ROLE_NAME = "企业管理员";
/**
* 企业普通管理员角色 roleKey
*/
String TENANT_ADMIN_ROLE_KEY = "tenantAdmin";
/**
* 企业普通管理员角色名称
*/
String TENANT_ADMIN_ROLE_NAME = "管理员";
/** /**
* 默认租户ID * 默认租户ID
......
...@@ -169,7 +169,7 @@ public class LoginHelper { ...@@ -169,7 +169,7 @@ public class LoginHelper {
* @return 结果 * @return 结果
*/ */
public static boolean isTenantAdmin(Set<String> rolePermission) { public static boolean isTenantAdmin(Set<String> rolePermission) {
return rolePermission.contains(TenantConstants.TENANT_ADMIN_ROLE_KEY); return rolePermission.contains(TenantConstants.TENANT_SUPER_ADMIN_ROLE_KEY);
} }
public static boolean isTenantAdmin() { public static boolean isTenantAdmin() {
......
package com.dsk.common.utils;
import net.sourceforge.pinyin4j.PinyinHelper;
import net.sourceforge.pinyin4j.format.HanyuPinyinCaseType;
import net.sourceforge.pinyin4j.format.HanyuPinyinOutputFormat;
import net.sourceforge.pinyin4j.format.HanyuPinyinToneType;
import net.sourceforge.pinyin4j.format.exception.BadHanyuPinyinOutputFormatCombination;
/**
* 中文转拼音工具类
*
* @author sxk
* @date 2023.11.13
*/
public class Chinese2PinyinUtils {
/**
* 中文转小写拼音
* @param chinese 待转义中文
* @return 转义后的拼音
*/
public static String toLowerPinyin(String chinese) {
StringBuilder pinyin = new StringBuilder();
HanyuPinyinOutputFormat format = new HanyuPinyinOutputFormat();
format.setCaseType(HanyuPinyinCaseType.LOWERCASE);
format.setToneType(HanyuPinyinToneType.WITHOUT_TONE);
char[] chars = chinese.toCharArray();
for (char c : chars) {
try {
String[] arr = PinyinHelper.toHanyuPinyinStringArray(c, format);
if (arr == null || arr.length == 0) {
pinyin.append(c);
} else {
pinyin.append(arr[0]);
}
} catch (BadHanyuPinyinOutputFormatCombination e) {
e.printStackTrace();
}
}
return pinyin.toString();
}
/**
* 中文转大写拼音
* @param chinese 待转义中文
* @return 转义后的拼音
*/
public static String toUpperPinyin(String chinese) {
StringBuilder pinyin = new StringBuilder();
HanyuPinyinOutputFormat format = new HanyuPinyinOutputFormat();
format.setCaseType(HanyuPinyinCaseType.UPPERCASE);
format.setToneType(HanyuPinyinToneType.WITHOUT_TONE);
char[] chars = chinese.toCharArray();
for (char c : chars) {
try {
String[] arr = PinyinHelper.toHanyuPinyinStringArray(c, format);
if (arr == null || arr.length == 0) {
pinyin.append(c);
} else {
pinyin.append(arr[0]);
}
} catch (BadHanyuPinyinOutputFormatCombination e) {
e.printStackTrace();
}
}
return pinyin.toString();
}
}
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<artifactId>dsk-module</artifactId>
<groupId>com.dsk</groupId>
<version>4.8.0</version>
</parent>
<groupId>com.dsk</groupId>
<artifactId>dsk-biz-bi</artifactId>
<name>dsk-biz-bi</name>
<description>BI数字大屏</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.dsk</groupId>
<artifactId>dsk-common</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
<!-- ORM -->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>${mybatis-plus.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<!-- hutool-core -->
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-core</artifactId>
</dependency>
<!-- hutool-core -->
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-json</artifactId>
</dependency>
<!-- hutool-http -->
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-http</artifactId>
</dependency>
<!-- hutool-extra -->
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-extra</artifactId>
</dependency>
<!--数据库-->
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
</dependencies>
<!-- <build>-->
<!-- <plugins>-->
<!-- <plugin>-->
<!-- <groupId>org.springframework.boot</groupId>-->
<!-- <artifactId>spring-boot-maven-plugin</artifactId>-->
<!-- <configuration>-->
<!-- <image>-->
<!-- <builder>paketobuildpacks/builder-jammy-base:latest</builder>-->
<!-- </image>-->
<!-- </configuration>-->
<!-- </plugin>-->
<!-- </plugins>-->
<!-- </build>-->
</project>
package com.dsk.biz.goview.common.base;
import cn.hutool.core.util.StrUtil;
import com.dsk.biz.goview.common.bean.AjaxResult;
import com.dsk.biz.goview.common.domain.ResultTable;
import org.springframework.beans.propertyeditors.CustomDateEditor;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.InitBinder;
import java.text.SimpleDateFormat;
import java.util.Date;
/**
* web层通用数据处理
*
* @author fuce
* @ClassName: BaseController
* @date 2018年8月18日
*/
public class BaseController {
/**
* 将前台传递过来的日期格式的字符串,自动转化为Date类型
*/
@InitBinder
public void initBinder(WebDataBinder binder) {
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
dateFormat.setLenient(false);
binder.registerCustomEditor(Date.class, new CustomDateEditor(dateFormat, true));
}
/**
* 响应返回结果
* @param rows 影响行数
* @return 操作结果
*/
protected AjaxResult toAjax(int rows) {
return rows > 0 ? success() : error();
}
/**
* 返回成功
*/
public AjaxResult success() {
return AjaxResult.success();
}
/**
* 返回失败消息
*/
public AjaxResult error() {
return AjaxResult.error();
}
/**
* 返回成功消息
*/
public AjaxResult success(String message) {
return AjaxResult.success(message);
}
/**
* 返回失败消息
*/
public AjaxResult error(String message) {
return AjaxResult.error(message);
}
/**
* 返回错误码消息
*/
public AjaxResult error(int code, String message) {
return AjaxResult.error(code, message);
}
/**
* 返回object数据
*/
public AjaxResult retobject(int code, Object data) {
return AjaxResult.successData(code, data);
}
/**
* 页面跳转
*/
public String redirect(String url) {
return StrUtil.format("redirect:{}", url);
}
/**
* Describe: 返回数据表格数据 分页 Param data Return 表格分页数据
*/
protected static ResultTable pageTable(Object data, long count) {
return ResultTable.pageTable(count, data);
}
/**
* Describe: 返回数据表格数据 Param data Return 表格分页数据
*/
protected static ResultTable dataTable(Object data) {
return ResultTable.dataTable(data);
}
/**
* Describe: 返回树状表格数据 分页 Param data Return 表格分页数据
*/
protected static ResultTable treeTable(Object data) {
return ResultTable.dataTable(data);
}
}
package com.dsk.biz.goview.common.base;
import org.apache.ibatis.annotations.Param;
import java.util.List;
/**
* 抽象类BaseService
*
* @ClassName: BaseService
* @Description: Service实现这个
* @author fuce
* @date 2018年6月3日
*
*/
public interface BaseService<T, T2> {
int deleteByPrimaryKey(String id);
int insertSelective(T record);
T selectByPrimaryKey(String id);
int updateByPrimaryKeySelective(T record);
int updateByExampleSelective(@Param("record") T record, @Param("example") T2 example);
int updateByExample(@Param("record") T record, @Param("example") T2 example);
List<T> selectByExample(T2 example);
long countByExample(T2 example);
int deleteByExample(T2 example);
}
package com.dsk.biz.goview.common.bean;
import java.util.HashMap;
/**
* @ClassName: AjaxResult
* @Description: ajax操作消息提醒
* @author fuce
* @date 2018年8月18日
*
*/
public class AjaxResult extends HashMap<String, Object> {
private static final long serialVersionUID = 1L;
/**
* 初始化一个新创建的 Message 对象
*/
public AjaxResult() {
}
/**
* 返回错误消息
* @return 错误消息
*/
public static AjaxResult error() {
return error(500, "操作失败");
}
/**
* 返回错误消息
* @param msg 内容
* @return 错误消息
*/
public static AjaxResult error(String msg) {
return error(500, msg);
}
/**
* 返回错误消息
* @param code 错误码
* @param msg 内容
* @return 错误消息
*/
public static AjaxResult error(int code, String msg) {
AjaxResult json = new AjaxResult();
json.put("code", code);
json.put("msg", msg);
return json;
}
/**
* 返回成功消息
* @param msg 内容
* @return 成功消息
*/
public static AjaxResult success(String msg) {
AjaxResult json = new AjaxResult();
json.put("msg", msg);
json.put("code", 200);
return json;
}
/**
* 返回成功消息
* @param msg 内容
* @return 成功消息
*/
public static AjaxResult successNullData(String msg) {
AjaxResult json = new AjaxResult();
json.put("msg", msg);
json.put("data", null);
json.put("code", 200);
return json;
}
/**
* 返回成功消息
* @return 成功消息
*/
public static AjaxResult success() {
return AjaxResult.success("操作成功");
}
public static AjaxResult successData(int code, Object value) {
AjaxResult json = new AjaxResult();
json.put("code", code);
json.put("data", value);
return json;
}
/**
* 返回成功消息
* @param key 键值
* @param value 内容
* @return 成功消息
*/
@Override
public AjaxResult put(String key, Object value) {
super.put(key, value);
return this;
}
}
package com.dsk.biz.goview.common.domain;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import lombok.Data;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Transient;
import java.io.Serializable;
import java.time.LocalDateTime;
@Data
@Entity
public class GoviewProject implements Serializable {
private static final long serialVersionUID = 1L;
@Id
@TableId(type = IdType.ASSIGN_UUID)
private String id;
private String projectName;
private Integer state;
private LocalDateTime createTime;
private String createUserId;
private Integer isDelete;
private String indexImage;
private String remarks;
private Long tenantId;
@Transient
@TableField(exist = false)
private String content;
}
package com.dsk.biz.goview.common.domain;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import lombok.Data;
import javax.persistence.*;
import java.io.Serializable;
import java.time.LocalDateTime;
@Data
@Entity
public class GoviewProjectData implements Serializable {
private static final long serialVersionUID = 1L;
@Id
@TableId(type = IdType.ASSIGN_UUID)
private String id;
private String projectId;
private LocalDateTime createTime;
private String createUserId;
private Long tenantId;
@Lob
@Basic(fetch = FetchType.LAZY)
@Column(columnDefinition = "TEXT")
private String content;
}
package com.dsk.biz.goview.common.domain;
import java.util.Map;
public class MagicHttp {
/**
* 请求url
*/
private String url;
/**
* 请求类型 get post
*/
private String requestType;
private Map<String, String> head;
private String body;
private Integer timeout;
private Map<String, Object> form;
private String cookie;
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
public String getRequestType() {
return requestType;
}
public void setRequestType(String requestType) {
this.requestType = requestType;
}
public Map<String, String> getHead() {
return head;
}
public void setHead(Map<String, String> head) {
this.head = head;
}
public String getBody() {
return body;
}
public void setBody(String body) {
this.body = body;
}
public String getCookie() {
return cookie;
}
public void setCookie(String cookie) {
this.cookie = cookie;
}
public Integer getTimeout() {
return timeout;
}
public void setTimeout(Integer timeout) {
this.timeout = timeout;
}
public Map<String, Object> getForm() {
return form;
}
public void setForm(Map<String, Object> form) {
this.form = form;
}
}
package com.dsk.biz.goview.common.domain;
public class ResultTable {
/**
* 状态码
*/
private Integer code;
/**
* 提示消息
*/
private String msg;
/**
* 消息总量
*/
private Long count;
/**
* 数据对象
*/
private Object data;
public Integer getCode() {
return code;
}
public void setCode(Integer code) {
this.code = code;
}
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
public Long getCount() {
return count;
}
public void setCount(Long count) {
this.count = count;
}
public Object getData() {
return data;
}
public void setData(Object data) {
this.data = data;
}
/**
* 构 建
*/
public static ResultTable pageTable(long count, Object data) {
ResultTable resultTable = new ResultTable();
resultTable.setData(data);
resultTable.setCode(0);
resultTable.setCount(count);
if (data != null) {
resultTable.setMsg("获取成功");
}
else {
resultTable.setMsg("获取失败");
}
return resultTable;
}
public static ResultTable dataTable(Object data) {
ResultTable resultTable = new ResultTable();
resultTable.setData(data);
resultTable.setCode(0);
if (data != null) {
resultTable.setMsg("获取成功");
}
else {
resultTable.setMsg("获取失败");
}
return resultTable;
}
}
package com.dsk.biz.goview.common.domain;
/**
* boostrap table post 参数
*
* @author fc
*
*/
public class Tablepar {
private int page;// 页码
private int limit;// 数量
private String orderByColumn;// 排序字段
private String isAsc;// 排序字符 asc desc
private String searchText;// 列表table里面的搜索
public int getPage() {
return page;
}
public void setPage(int page) {
this.page = page;
}
public int getLimit() {
return limit;
}
public void setLimit(int limit) {
this.limit = limit;
}
public String getOrderByColumn() {
return orderByColumn;
}
public void setOrderByColumn(String orderByColumn) {
this.orderByColumn = orderByColumn;
}
public String getIsAsc() {
return isAsc;
}
public void setIsAsc(String isAsc) {
this.isAsc = isAsc;
}
public String getSearchText() {
return searchText;
}
public void setSearchText(String searchText) {
this.searchText = searchText;
}
}
///*
// * Copyright (c) 2018-2025, lengleng All rights reserved.
// *
// * Redistribution and use in source and binary forms, with or without
// * modification, are permitted provided that the following conditions are met:
// *
// * Redistributions of source code must retain the above copyright notice,
// * this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright
// * notice, this list of conditions and the following disclaimer in the
// * documentation and/or other materials provided with the distribution.
// * Neither the name of the pig4cloud.com developer nor the names of its
// * contributors may be used to endorse or promote products derived from
// * this software without specific prior written permission.
// * Author: lengleng (wangiegie@gmail.com)
// */
//
//package com.dsk.biz.goview.config;
//
//import com.baomidou.mybatisplus.extension.plugins.handler.TenantLineHandler;
//import lombok.RequiredArgsConstructor;
//import lombok.extern.slf4j.Slf4j;
//import net.sf.jsqlparser.expression.Expression;
//import net.sf.jsqlparser.expression.LongValue;
//import net.sf.jsqlparser.expression.NullValue;
//
///**
// * @author lengleng
// * @date 2018-12-26
// * <p>
// * 租户维护处理器
// */
//@Slf4j
//@RequiredArgsConstructor
//public class DataVTenantHandler implements TenantLineHandler {
//
// /**
// * 获取租户 ID 值表达式,只支持单个 ID 值
// * <p>
// * @return 租户 ID 值表达式
// */
// @Override
// public Expression getTenantId() {
// Long tenantId = TenantContextHolder.getTenantId();
// log.debug("当前租户为 >> {}", tenantId);
//
// if (tenantId == null) {
// return new NullValue();
// }
// return new LongValue(tenantId);
// }
//
//}
package com.dsk.biz.goview.config;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
/**
* @author lengleng
* @date 2022/5/2
* <p>
* 数据大屏配置
*/
@Data
//@ConfigurationProperties("gv")
@Component
@ConfigurationProperties(prefix = "gv")
public class GoviewProperties {
/**
* 服务 http://IP:port
*/
private String host = "";
/**
* 路由前缀
*/
private String gatewayPrefix = "/api/gv";
/**
* 图片存放路径
*/
private String imgPath;
/**
* 项目 license
*/
private String license;
/**
* 是否开启检查更新
*/
private boolean checkUpdate = true;
}
///*
// * Copyright (c) 2020 pig4cloud Authors. All Rights Reserved.
// *
// * Licensed under the Apache License, Version 2.0 (the "License");
// * you may not use this file except in compliance with the License.
// * You may obtain a copy of the License at
// *
// * http://www.apache.org/licenses/LICENSE-2.0
// *
// * Unless required by applicable law or agreed to in writing, software
// * distributed under the License is distributed on an "AS IS" BASIS,
// * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// * See the License for the specific language governing permissions and
// * limitations under the License.
// */
//
//package com.dsk.biz.goview.config;
//
//import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
//import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
//import com.baomidou.mybatisplus.extension.plugins.inner.TenantLineInnerInterceptor;
//import org.mybatis.spring.annotation.MapperScan;
//import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
//import org.springframework.boot.autoconfigure.domain.EntityScan;
//import org.springframework.context.annotation.Bean;
//import org.springframework.context.annotation.Configuration;
//
///**
// * @author lengleng
// * @date 2020-03-14
// * <p>
// * mybatis plus 统一配置
// */
//@Configuration(proxyBeanMethods = false)
//@MapperScan(basePackages = "io.springboot.plugin.goview.mapper")
//@EntityScan(basePackages = "io.springboot.plugin.goview.common.domain")
//public class MybatisAutoConfiguration {
//
// @Bean
// public TenantContextHolderFilter tenantContextHolderFilter() {
// return new TenantContextHolderFilter();
// }
//
// /**
// * 分页插件, 对于单一数据库类型来说,都建议配置该值,避免每次分页都去抓取数据库类型
// */
// @Bean
// @ConditionalOnMissingBean
// public MybatisPlusInterceptor mybatisPlusInterceptor() {
// MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
// interceptor.addInnerInterceptor(new TenantLineInnerInterceptor(new DataVTenantHandler()));
// interceptor.addInnerInterceptor(new PaginationInnerInterceptor());
// return interceptor;
// }
//
//}
package com.dsk.biz.goview.config;
import org.springframework.beans.factory.config.YamlPropertiesFactoryBean;
import org.springframework.core.env.PropertiesPropertySource;
import org.springframework.core.env.PropertySource;
import org.springframework.core.io.support.EncodedResource;
import org.springframework.core.io.support.PropertySourceFactory;
import org.springframework.lang.Nullable;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.Properties;
/**
* @author lengleng
* @date 2023/4/5
*/
public class YamlPropertySourceFactory implements PropertySourceFactory {
@Override
public PropertySource<?> createPropertySource(@Nullable String name, EncodedResource resource) throws IOException {
Properties propertiesFromYaml = loadYamlIntoProperties(resource);
String sourceName = name != null ? name : resource.getResource().getFilename();
return new PropertiesPropertySource(sourceName, propertiesFromYaml);
}
private Properties loadYamlIntoProperties(EncodedResource resource) throws FileNotFoundException {
try {
YamlPropertiesFactoryBean factory = new YamlPropertiesFactoryBean();
factory.setResources(resource.getResource());
factory.afterPropertiesSet();
return factory.getObject();
}
catch (IllegalStateException e) {
Throwable cause = e.getCause();
if (cause instanceof FileNotFoundException)
throw (FileNotFoundException) e.getCause();
throw e;
}
}
}
package com.dsk.biz.goview.controller;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.plugins.IgnoreStrategy;
import com.baomidou.mybatisplus.core.plugins.InterceptorIgnoreHelper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.dsk.biz.goview.common.base.BaseController;
import com.dsk.biz.goview.common.bean.AjaxResult;
import com.dsk.biz.goview.common.domain.*;
import com.dsk.biz.goview.config.GoviewProperties;
import com.dsk.biz.goview.mapper.GoviewProjectDataMapper;
import com.dsk.biz.goview.mapper.GoviewProjectMapper;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.ContentDisposition;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.ui.ModelMap;
import org.springframework.util.FileCopyUtils;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import java.io.File;
import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* 项目表Controller
*
* @author fuce
* @ClassName: GoviewProjectController
* @date 2022-05-18 21:43:25
*/
@Slf4j
@RestController
@RequiredArgsConstructor
@RequestMapping("/api/goview/project")
public class GoViewProjectAPIController extends BaseController {
private final GoviewProjectDataMapper projectDataMapper;
private final GoviewProjectMapper projectMapper;
private final GoviewProperties goviewProperties;
@GetMapping("/list")
public ResultTable list(Tablepar tablepar, GoviewProject goviewProject) {
Page page = new Page(tablepar.getPage(), tablepar.getLimit());
Page result = projectMapper.selectPage(page, Wrappers.query(goviewProject));
ResultTable resultTable = pageTable(result.getRecords(), result.getTotal());
resultTable.setCode(200);
return resultTable;
}
/**
* 新增保存
* @param
* @return
*/
@PostMapping("/create")
public AjaxResult add(@RequestBody GoviewProject goviewProject) {
projectMapper.insert(goviewProject);
return AjaxResult.successData(200, goviewProject).put("msg", "创建成功");
}
/**
* 项目表删除
* @param ids
* @return
*/
@DeleteMapping("/delete")
public AjaxResult delete(String ids) {
projectMapper.deleteById(ids);
return success();
}
@PostMapping("/edit")
public AjaxResult editSave(@RequestBody GoviewProject goviewProject) {
projectMapper.updateById(goviewProject);
return success();
}
@PostMapping("/rename")
public AjaxResult rename(@RequestBody GoviewProject goviewProject) {
projectMapper.updateById(goviewProject);
return success();
}
// 发布/取消项目状态
@PutMapping("/publish")
@ResponseBody
public AjaxResult updateVisible(@RequestBody GoviewProject goviewProject) {
projectMapper.updateById(goviewProject);
return success();
}
/**
* 获取项目存储数据
* @param id 项目id
* @param mmap
* @return
*/
@GetMapping("/getData")
public AjaxResult getData(String projectId, ModelMap map) {
InterceptorIgnoreHelper.handle(IgnoreStrategy.builder().tenantLine(true).build());
GoviewProject goviewProject = projectMapper.selectById(projectId);
if (goviewProject == null) {
return AjaxResult.successData(200, null).put("msg", "无数据");
}
List<GoviewProjectData> goviewProjectDataList = projectDataMapper
.selectList(Wrappers.<GoviewProjectData>lambdaQuery().eq(GoviewProjectData::getProjectId, projectId));
if (CollUtil.isNotEmpty(goviewProjectDataList)) {
goviewProject.setContent(goviewProjectDataList.get(0).getContent());
return AjaxResult.successData(200, goviewProject).put("msg", "获取成功");
}
return AjaxResult.successData(200, null).put("msg", "无数据");
}
@PostMapping("/save/data")
public AjaxResult saveData(GoviewProjectData data) {
boolean exists = projectDataMapper
.exists(Wrappers.<GoviewProjectData>lambdaQuery().eq(GoviewProjectData::getProjectId, data.getProjectId()));
if (exists) {
projectDataMapper.update(data,
Wrappers.<GoviewProjectData>lambdaQuery().eq(GoviewProjectData::getProjectId, data.getProjectId()));
}
else {
projectDataMapper.insert(data);
}
return AjaxResult.success("操作成功");
}
/**
* 模拟请求
* @return
*/
@PostMapping("/magicHttp")
public AjaxResult magicHttp(@RequestBody MagicHttp magicHttp) {
return AjaxResult.successNullData("参数异常为null");
}
/**
* 上传文件
* @param file 文件流对象
* @return
* @throws Exception
*/
@PostMapping("/upload")
@ResponseBody
public AjaxResult upload(@RequestBody MultipartFile object) throws IOException {
File dest = new File(goviewProperties.getImgPath() + object.getOriginalFilename());
object.transferTo(dest);
Map<String, String> map = new HashMap(4);
String url;
if (StrUtil.isNotBlank(goviewProperties.getHost())) {
url = goviewProperties.getHost() + goviewProperties.getGatewayPrefix() + "/api/project/get-file/"
+ object.getOriginalFilename();
}
else {
url = goviewProperties.getGatewayPrefix() + "/api/project/get-file/" + object.getOriginalFilename();
}
map.put("link", url);
return AjaxResult.successData(200, map);
}
/**
* 文件获取
* @param fileName 文件名
*/
@GetMapping("/get-file/{fileName}")
public ResponseEntity<byte[]> getFile(@PathVariable String fileName) {
HttpHeaders headers = new HttpHeaders();
// 通知浏览器以下载文件方式打开
ContentDisposition contentDisposition = ContentDisposition.builder("attachment").filename(fileName).build();
headers.setContentDisposition(contentDisposition);
try {
return new ResponseEntity<>(
FileCopyUtils.copyToByteArray(new File(goviewProperties.getImgPath() + fileName)), headers,
HttpStatus.OK);
}
catch (IOException e) {
log.warn(e.getLocalizedMessage());
}
return null;
}
}
package com.dsk.biz.goview.controller;
import cn.dev33.satoken.annotation.SaIgnore;
import com.dsk.biz.goview.common.bean.AjaxResult;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import static com.dsk.biz.goview.common.bean.AjaxResult.success;
/**
* @author lengleng
* @date 2022/5/21
*/
@Slf4j
@Controller
@RequestMapping
@RequiredArgsConstructor
public class GoviewPageController {
@SaIgnore
@GetMapping({ "/", "/chart/**", "/project/**" })
public String index() {
return "index";
}
@GetMapping("/api/goview/sys/getOssInfo")
@ResponseBody
public AjaxResult getOssInfo() {
return success();
}
}
package com.dsk.biz.goview.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.dsk.biz.goview.common.domain.GoviewProjectData;
import org.apache.ibatis.annotations.Mapper;
/**
* @author lengleng
* @date 2023/4/4
*/
@Mapper
public interface GoviewProjectDataMapper extends BaseMapper<GoviewProjectData> {
}
package com.dsk.biz.goview.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.dsk.biz.goview.common.domain.GoviewProject;
import org.apache.ibatis.annotations.Mapper;
/**
* @author lengleng
* @date 2023/4/4
*/
@Mapper
public interface GoviewProjectMapper extends BaseMapper<GoviewProject> {
}
<!DOCTYPE html>
<html lang="zh-cmn-Hans">
<head>
<script>self["MonacoEnvironment"] = (function (paths) {
return {
globalAPI: false,
getWorkerUrl : function (moduleId, label) {
var result = paths[label];
if (/^((http:)|(https:)|(file:)|(\/\/))/.test(result)) {
var currentUrl = String(window.location);
var currentOrigin = currentUrl.substr(0, currentUrl.length - window.location.hash.length - window.location.search.length - window.location.pathname.length);
if (result.substring(0, currentOrigin.length) !== currentOrigin) {
var js = '/*' + label + '*/importScripts("' + result + '");';
var blob = new Blob([js], { type: 'application/javascript' });
return URL.createObjectURL(blob);
}
}
return result;
}
};
})({
"editorWorkerService": "/api/gv/monacoeditorwork/editor.worker.bundle.js",
"typescript": "/api/gv/monacoeditorwork/ts.worker.bundle.js",
"json": "/api/gv/monacoeditorwork/json.worker.bundle.js",
"html": "/api/gv/monacoeditorwork/html.worker.bundle.js",
"javascript": "/api/gv/monacoeditorwork/ts.worker.bundle.js",
"handlebars": "/api/gv/monacoeditorwork/html.worker.bundle.js",
"razor": "/api/gv/monacoeditorwork/html.worker.bundle.js"
});</script>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
<meta name="renderer" content="webkit" />
<meta name="description" content="GoView 是高效、高性能的拖拽式低代码数据可视化开发平台,将页面元素封装为基础组件,无需编写代码即可完成业务需求。">
<meta name="keywords" content="GoView,goview,低代码,可视化">
<meta name="author" content="奔跑的面条,面条">
<meta
name="viewport"
content="width=device-width,initial-scale=1.0,minimum-scale=1.0,maximum-scale=1.0,user-scalable=0"
/>
<link rel="icon" href="./favicon.ico" />
<title>GoView</title>
<script type="module" crossorigin src="/api/gv/static/js/index-ebdecea3.js"></script>
<link rel="stylesheet" href="/api/gv/static/css/index-9c2eb289.css">
</head>
<body>
<div id="appProvider" style="display: none;"></div>
<div id="app">
<div class="first-loading-wrp">
<div class="loading-wrp">
<span class="dot dot-spin"><i></i><i></i><i></i><i></i></span>
</div>
</div>
</div>
</body>
</html>
...@@ -22,6 +22,7 @@ ...@@ -22,6 +22,7 @@
<modules> <modules>
<module>dsk-biz-api</module> <module>dsk-biz-api</module>
<module>dsk-biz-bi</module>
</modules> </modules>
<build> <build>
......
...@@ -8,4 +8,4 @@ ENV = 'production' ...@@ -8,4 +8,4 @@ ENV = 'production'
VUE_APP_BASE_API = 'https://szhapi.jiansheku.com' VUE_APP_BASE_API = 'https://szhapi.jiansheku.com'
# 子系统地址 # 子系统地址
VUE_APP_SUB_SYSTEM_ADDRESS = "https://plug.jiansheku.com" VUE_APP_SUB_SYSTEM_ADDRESS = "https://plug.jiansheku.com"
\ No newline at end of file
...@@ -39,6 +39,7 @@ ...@@ -39,6 +39,7 @@
"dependencies": { "dependencies": {
"@cell-x/el-table-sticky": "^1.0.2", "@cell-x/el-table-sticky": "^1.0.2",
"@riophae/vue-treeselect": "0.4.0", "@riophae/vue-treeselect": "0.4.0",
"@vue/composition-api": "^1.7.2",
"axios": "0.24.0", "axios": "0.24.0",
"clipboard": "2.0.8", "clipboard": "2.0.8",
"core-js": "^3.32.2", "core-js": "^3.32.2",
...@@ -56,6 +57,7 @@ ...@@ -56,6 +57,7 @@
"js-cookie": "3.0.1", "js-cookie": "3.0.1",
"js-md5": "^0.7.3", "js-md5": "^0.7.3",
"jsencrypt": "3.0.0-rc.1", "jsencrypt": "3.0.0-rc.1",
"json-editor-vue": "^0.11.0",
"nprogress": "0.2.0", "nprogress": "0.2.0",
"quill": "1.3.7", "quill": "1.3.7",
"screenfull": "5.0.2", "screenfull": "5.0.2",
......
import request from '@/utils/request' import request from '@/utils/request';
//新增租户套餐 //新增租户套餐
export function addTenantPackage(param) { export function addTenantPackage(param) {
return request({ return request({
url: '/system/tenant/package', url: '/system/tenant/package',
method: 'POST', method: 'POST',
data: param data: param
}) });
} }
//修改租户套餐 //修改租户套餐
export function saveTenantPackage(param) { export function saveTenantPackage(param) {
...@@ -13,21 +13,21 @@ export function saveTenantPackage(param) { ...@@ -13,21 +13,21 @@ export function saveTenantPackage(param) {
url: '/system/tenant/package/', url: '/system/tenant/package/',
method: 'PUT', method: 'PUT',
data: param data: param
}) });
} }
//获取租户套餐 //获取租户套餐
export function detailTenantPackage(packageId) { export function detailTenantPackage(packageId) {
return request({ return request({
url: '/system/tenant/package/'+packageId, url: '/system/tenant/package/' + packageId,
method: 'get', method: 'get',
}) });
} }
//删除租户套餐 //删除租户套餐
export function deleteTenantPackage(packageId) { export function deleteTenantPackage(packageId) {
return request({ return request({
url: '/system/tenant/package/'+packageId, url: '/system/tenant/package/' + packageId,
method: 'DELETE', method: 'DELETE',
}) });
} }
//租户套餐列表 //租户套餐列表
export function getTenantPackage(param) { export function getTenantPackage(param) {
...@@ -35,7 +35,7 @@ export function getTenantPackage(param) { ...@@ -35,7 +35,7 @@ export function getTenantPackage(param) {
url: '/system/tenant/package/list', url: '/system/tenant/package/list',
method: 'get', method: 'get',
params: param params: param
}) });
} }
//同步企业方案 //同步企业方案
export function syncTenantPackage(param) { export function syncTenantPackage(param) {
...@@ -43,7 +43,7 @@ export function syncTenantPackage(param) { ...@@ -43,7 +43,7 @@ export function syncTenantPackage(param) {
url: '/system/tenant/syncTenantPackage', url: '/system/tenant/syncTenantPackage',
method: 'get', method: 'get',
params: param params: param
}) });
} }
//租户列表 //租户列表
...@@ -52,15 +52,15 @@ export function getTenantList(param) { ...@@ -52,15 +52,15 @@ export function getTenantList(param) {
url: '/system/tenant/list', url: '/system/tenant/list',
method: 'get', method: 'get',
params: param params: param
}) });
} }
//获取租户详情 //获取租户详情
export function getTenant(id) { export function getTenant(id) {
return request({ return request({
url: '/system/tenant/'+id, url: '/system/tenant/' + id,
method: 'get', method: 'get',
}) });
} }
//修改租户 //修改租户
...@@ -68,31 +68,52 @@ export function editTenant(data) { ...@@ -68,31 +68,52 @@ export function editTenant(data) {
return request({ return request({
url: '/system/tenant/', url: '/system/tenant/',
method: 'PUT', method: 'PUT',
data:data, data: data,
}) });
} }
//新增租户 //新增租户
export function saveTenant(data) { export function saveTenant(data) {
return request({ return request({
url: '/system/tenant/', url: '/system/tenant/',
method: 'POST', method: 'POST',
data:data, data: data,
}) });
} }
//删除租户 //删除租户
export function deleteTenant(ids) { export function deleteTenant(ids) {
return request({ return request({
url: '/system/tenant/'+ids, url: '/system/tenant/' + ids,
method: 'Delete', method: 'Delete',
}) });
} }
//租户请求企业套餐下拉 //租户请求企业套餐下拉
export function selectTenant(ids) { export function selectTenant(ids) {
return request({ return request({
url: '/system/tenant/package/selectList', url: '/system/tenant/package/selectList',
method: 'Get', method: 'Get',
}) });
} }
/**
* 企业管理新增账号
* @param {object} data
* @returns
*/
export const enterpriseAddAccountApi = (data) => request({
url: "/system/tenant/addTenantAdmin",
method: "post",
data
});
/**
* 租户ID查询大司空超管or租户管理员为其创建的企业管理员和管理员账号数量
* @param {*} tenantId
* @returns
*/
export const getEnterpriseAddAccountCountApi = (tenantId) => request({
url: `/system/user/queryTenantAdminNumCreatedByDSK/${tenantId}`,
method: "get"
})
...@@ -26,6 +26,16 @@ ...@@ -26,6 +26,16 @@
opacity: 0; opacity: 0;
} }
.list-enter-active,
.list-leave-active {
transition: all 0.5s ease;
}
.list-enter,
.list-leave-to {
opacity: 0;
transform: translateX(50px);
}
.el-message { .el-message {
z-index: 3000 !important; z-index: 3000 !important;
} }
...@@ -145,7 +145,8 @@ ...@@ -145,7 +145,8 @@
} }
.el-table .el-dropdown, .el-icon-arrow-down { .el-table .el-dropdown, .el-icon-arrow-down {
font-size: 12px; color: #232323;
font-size: 14px;
} }
.el-tree-node__content > .el-checkbox { .el-tree-node__content > .el-checkbox {
......
<template>
<div class="dsk-json-editor">
<json-editor-vue class="dsk-json-editor-ins" v-model="modelValue" ref="dskJsonEditor" :mode.sync="mode" :readOnly="readOnly"
@input="jsonChange"></json-editor-vue>
</div>
</template>
<script>
import JsonEditorVue from 'json-editor-vue';
import { jsonEscape, jsonTraversal } from "@/utils";
export default {
name: "dskJsonEditor",
components: {
JsonEditorVue
},
props: {
jsonValue: {
required: true,
type: [Object, String],
default: ""
},
defaultMode: {
required: true,
type: [String],
default: "text"
},
jsonReadOnly: {
required: true,
type: [Boolean],
default: false
}
},
watch: {
jsonValue: {
handler(newValue) {
this.modelValue = newValue;
},
deep: true
}
},
data() {
return {
modelValue: this.jsonValue,
mode: this.defaultMode,
readOnly: this.jsonReadOnly
};
},
//可访问data属性
created() {
},
//计算集
computed: {
},
//方法集
methods: {
validateJson() {
return new Promise((resolve, reject) => {
try {
let isPass = false;
// 验证通过
if (!this.$refs["dskJsonEditor"].jsonEditor.validate()) {
isPass = true;
let jsonText = this.modelValue;
// 初始默认对象
if (Object.prototype.toString.call(jsonText) == "[object Object]") {
// 对象转为json字符串
jsonText = JSON.stringify(jsonText);
}
// 转换字符串 去除空格 换行符
jsonText = jsonEscape(jsonText);
// 特殊字符识别编码
jsonText = JSON.stringify(jsonTraversal(JSON.parse(jsonText)));
console.log(jsonText);
return resolve({ isPass, value: jsonText });
}
resolve({ isPass });
} catch (error) {
console.log(error);
reject(error);
}
});
},
jsonChange(e) {
try {
this.$emit("jsonChange", e);
} catch (error) {
console.log(error);
}
}
},
}
</script>
<style lang="scss" scoped>
.dsk-json-editor {
width: 100%;
height: 100%;
box-sizing: border-box;
::v-deep .dsk-json-editor-ins {
width: 100%;
height: 100%;
.jsoneditor-vue {
width: 100%;
height: 100%;
}
.jsoneditor-poweredBy {
display: none;
}
}
}
</style>
...@@ -73,11 +73,8 @@ export default { ...@@ -73,11 +73,8 @@ export default {
}; };
}, },
computed: { computed: {
visitedViews: { visitedViews() {
get() { return this.$store.state.tagsView.visitedViews;
return this.$store.state.tagsView.visitedViews;
},
set() { }
}, },
iconName() { iconName() {
return function (val) { return function (val) {
...@@ -105,7 +102,6 @@ export default { ...@@ -105,7 +102,6 @@ export default {
}, },
watch: { watch: {
$route() { $route() {
// console.log(this.$route);
this.addTags(); this.addTags();
this.moveToCurrentTag(); this.moveToCurrentTag();
this.getviews(); this.getviews();
...@@ -118,10 +114,11 @@ export default { ...@@ -118,10 +114,11 @@ export default {
} }
}, },
}, },
mounted() { created() {
this.initTags(); this.$nextTick(() => {
this.addTags(); this.initTags();
// this.getviews() this.addTags();
});
}, },
methods: { methods: {
getviews() { getviews() {
......
import Vue from 'vue'; import Vue from 'vue';
import VCA from '@vue/composition-api' //composition APi
import Cookies from 'js-cookie'; import Cookies from 'js-cookie';
...@@ -8,6 +9,7 @@ import './assets/styles/element-variables.scss'; ...@@ -8,6 +9,7 @@ import './assets/styles/element-variables.scss';
import "@/assets/styles/common.css"; import "@/assets/styles/common.css";
import '@/assets/styles/index.scss'; // global css import '@/assets/styles/index.scss'; // global css
import '@/assets/styles/ruoyi.scss'; // ruoyi css import '@/assets/styles/ruoyi.scss'; // ruoyi css
import App from './App'; import App from './App';
import store from './store'; import store from './store';
import router from './router'; import router from './router';
...@@ -22,6 +24,7 @@ import './permission'; // permission control ...@@ -22,6 +24,7 @@ import './permission'; // permission control
import { getDicts } from "@/api/system/dict/data"; import { getDicts } from "@/api/system/dict/data";
import { getConfigKey } from "@/api/system/config"; import { getConfigKey } from "@/api/system/config";
import { parseTime, resetForm, addDateRange, selectDictLabel, selectDictLabels, handleTree } from "@/utils/ruoyi"; import { parseTime, resetForm, addDateRange, selectDictLabel, selectDictLabels, handleTree } from "@/utils/ruoyi";
// 分页组件 // 分页组件
import Pagination from "@/components/Pagination"; import Pagination from "@/components/Pagination";
// 自定义表格工具组件 // 自定义表格工具组件
...@@ -61,6 +64,7 @@ Vue.component('FileUpload', FileUpload); ...@@ -61,6 +64,7 @@ Vue.component('FileUpload', FileUpload);
Vue.component('ImageUpload', ImageUpload); Vue.component('ImageUpload', ImageUpload);
Vue.component('ImagePreview', ImagePreview); Vue.component('ImagePreview', ImagePreview);
Vue.use(VCA);
Vue.use(horizontalScroll); Vue.use(horizontalScroll);
Vue.use(elTableSticky); Vue.use(elTableSticky);
Vue.use(directive); Vue.use(directive);
......
import router from './router' import router from './router';
import store from './store' import store from './store';
import { Message } from 'element-ui' import { Message } from 'element-ui';
import NProgress from 'nprogress' import NProgress from 'nprogress';
import 'nprogress/nprogress.css' import 'nprogress/nprogress.css';
import { getToken } from '@/utils/auth' import { getToken } from '@/utils/auth';
import { isRelogin } from '@/utils/request' import { isRelogin } from '@/utils/request';
NProgress.configure({ showSpinner: false }) NProgress.configure({ showSpinner: false });
const whiteList = ['/login', '/register'] const whiteList = ['/login', '/register'];
router.beforeEach((to, from, next) => { router.beforeEach((to, from, next) => {
NProgress.start() NProgress.start();
if (getToken()) { if (getToken()) {
to.meta.title && store.dispatch('settings/setTitle', to.meta.title) // tab页签title
const { tabTitle, url } = to.query;
if (tabTitle) to.meta.title = decodeURIComponent(tabTitle);
if (!tabTitle && to.meta.isSubSystem && url) to.meta.title = decodeURIComponent(url);
to.meta.title && store.dispatch('settings/setTitle', to.meta.title);
/* has token*/ /* has token*/
if (to.path === '/login') { if (to.path === '/login') {
next({ path: '/' }) next({ path: '/' });
NProgress.done() NProgress.done();
} else { } else {
if (store.getters.roles.length === 0) { if (store.getters.roles.length === 0) {
isRelogin.show = true isRelogin.show = true;
// 判断当前用户是否已拉取完user_info信息 // 判断当前用户是否已拉取完user_info信息
store.dispatch('GetInfo').then(() => { store.dispatch('GetInfo').then(() => {
isRelogin.show = false isRelogin.show = false;
store.dispatch('GenerateRoutes').then(accessRoutes => { store.dispatch('GenerateRoutes').then(accessRoutes => {
// 根据roles权限生成可访问的路由表 // 根据roles权限生成可访问的路由表
router.addRoutes(accessRoutes) // 动态添加可访问路由表 router.addRoutes(accessRoutes); // 动态添加可访问路由表
next({ ...to, replace: true }) // hack方法 确保addRoutes已完成 next({ ...to, replace: true }); // hack方法 确保addRoutes已完成
}) });
}).catch(err => { }).catch(err => {
store.dispatch('LogOut').then(() => { store.dispatch('LogOut').then(() => {
Message.error(err) Message.error(err);
sessionStorage.removeItem('views') sessionStorage.removeItem('views');
next({ path: '/' }) next({ path: '/' });
}) });
}) });
} else { } else {
next() next();
} }
} }
} else { } else {
// 没有token // 没有token
if (whiteList.indexOf(to.path) !== -1) { if (whiteList.indexOf(to.path) !== -1) {
// 在免登录白名单,直接进入 // 在免登录白名单,直接进入
next() next();
} else { } else {
next(`/login?redirect=${to.fullPath}`) // 否则全部重定向到登录页 next(`/login?redirect=${to.fullPath}`); // 否则全部重定向到登录页
NProgress.done() NProgress.done();
} }
} }
}) });
router.afterEach(() => { router.afterEach(() => {
NProgress.done() NProgress.done();
}) });
import store from '@/store' import store from '@/store';
import router from '@/router'; import router from '@/router';
import { paramsToQuery } from "@/utils/";
export default { export default {
// 刷新当前tab页签 // 刷新当前tab页签
...@@ -15,12 +16,12 @@ export default { ...@@ -15,12 +16,12 @@ export default {
}); });
} }
return store.dispatch('tagsView/delCachedView', obj).then(() => { return store.dispatch('tagsView/delCachedView', obj).then(() => {
const { path, query } = obj const { path, query } = obj;
router.replace({ router.replace({
path: '/redirect' + path, path: '/redirect' + path,
query: query query: query
}) });
}) });
}, },
// 关闭当前tab页签,打开新页签 // 关闭当前tab页签,打开新页签
closeOpenPage(obj) { closeOpenPage(obj) {
...@@ -33,9 +34,9 @@ export default { ...@@ -33,9 +34,9 @@ export default {
closePage(obj) { closePage(obj) {
if (obj === undefined) { if (obj === undefined) {
return store.dispatch('tagsView/delView', router.currentRoute).then(({ visitedViews }) => { return store.dispatch('tagsView/delView', router.currentRoute).then(({ visitedViews }) => {
const latestView = visitedViews.slice(-1)[0] const latestView = visitedViews.slice(-1)[0];
if (latestView) { if (latestView) {
return router.push(latestView.fullPath) return router.push(latestView.fullPath);
} }
return router.push('/'); return router.push('/');
}); });
...@@ -59,13 +60,16 @@ export default { ...@@ -59,13 +60,16 @@ export default {
return store.dispatch('tagsView/delOthersViews', obj || router.currentRoute); return store.dispatch('tagsView/delOthersViews', obj || router.currentRoute);
}, },
// 添加tab页签 // 添加tab页签
openPage(title, url, params) { async openPage(title, url, params) {
var obj = { path: url, meta: { title: title } } const obj = { path: url, fullPath: url, query: params, meta: { title: title } };
store.dispatch('tagsView/addView', obj); if (params && Object.keys(params).length) {
obj.fullPath = `${obj.path}${paramsToQuery(params) ? "?" + paramsToQuery(params) : ""}`;
}
await store.dispatch('tagsView/addView', obj);
return router.push({ path: url, query: params }); return router.push({ path: url, query: params });
}, },
// 修改tab页签 // 修改tab页签
updatePage(obj) { updatePage(obj) {
return store.dispatch('tagsView/updateVisitedView', obj); return store.dispatch('tagsView/updateVisitedView', obj);
} }
} };
This diff is collapsed.
import auth from '@/plugins/auth' import auth from '@/plugins/auth';
import router, { constantRoutes, dynamicRoutes } from '@/router' import router, { constantRoutes, dynamicRoutes } from '@/router';
import { getRouters } from '@/api/menu' import { getRouters } from '@/api/menu';
import Layout from '@/layout/index' import Layout from '@/layout/index';
import ParentView from '@/components/ParentView' import ParentView from '@/components/ParentView';
import InnerLink from '@/layout/components/InnerLink' import InnerLink from '@/layout/components/InnerLink';
const permission = { const permission = {
state: { state: {
...@@ -15,17 +15,17 @@ const permission = { ...@@ -15,17 +15,17 @@ const permission = {
}, },
mutations: { mutations: {
SET_ROUTES: (state, routes) => { SET_ROUTES: (state, routes) => {
state.addRoutes = routes state.addRoutes = routes;
state.routes = constantRoutes.concat(routes) state.routes = constantRoutes.concat(routes);
}, },
SET_DEFAULT_ROUTES: (state, routes) => { SET_DEFAULT_ROUTES: (state, routes) => {
state.defaultRoutes = constantRoutes.concat(routes) state.defaultRoutes = constantRoutes.concat(routes);
}, },
SET_TOPBAR_ROUTES: (state, routes) => { SET_TOPBAR_ROUTES: (state, routes) => {
state.topbarRouters = routes state.topbarRouters = routes;
}, },
SET_SIDEBAR_ROUTERS: (state, routes) => { SET_SIDEBAR_ROUTERS: (state, routes) => {
state.sidebarRouters = routes state.sidebarRouters = routes;
}, },
}, },
actions: { actions: {
...@@ -34,100 +34,108 @@ const permission = { ...@@ -34,100 +34,108 @@ const permission = {
return new Promise(resolve => { return new Promise(resolve => {
// 向后端请求路由数据 // 向后端请求路由数据
getRouters().then(res => { getRouters().then(res => {
const sdata = JSON.parse(JSON.stringify(res.data)) const sdata = JSON.parse(JSON.stringify(res.data));
const rdata = JSON.parse(JSON.stringify(res.data)) const rdata = JSON.parse(JSON.stringify(res.data));
const sidebarRoutes = filterAsyncRouter(sdata) const sidebarRoutes = filterAsyncRouter(sdata);
const rewriteRoutes = filterAsyncRouter(rdata, false, true) const rewriteRoutes = filterAsyncRouter(rdata, false, true);
const asyncRoutes = filterDynamicRoutes(dynamicRoutes); const asyncRoutes = filterDynamicRoutes(dynamicRoutes);
rewriteRoutes.push({ path: '*', redirect: '/404', hidden: true }) rewriteRoutes.push({ path: '*', redirect: '/404', hidden: true });
router.addRoutes(asyncRoutes); router.addRoutes(asyncRoutes);
commit('SET_ROUTES', rewriteRoutes) commit('SET_ROUTES', rewriteRoutes);
commit('SET_SIDEBAR_ROUTERS', constantRoutes.concat(sidebarRoutes)) commit('SET_SIDEBAR_ROUTERS', constantRoutes.concat(sidebarRoutes));
commit('SET_DEFAULT_ROUTES', sidebarRoutes) commit('SET_DEFAULT_ROUTES', sidebarRoutes);
commit('SET_TOPBAR_ROUTES', sidebarRoutes) commit('SET_TOPBAR_ROUTES', sidebarRoutes);
resolve(rewriteRoutes) resolve(rewriteRoutes);
}) });
}) });
} }
} }
} };
// 遍历后台传来的路由字符串,转换为组件对象 // 遍历后台传来的路由字符串,转换为组件对象
function filterAsyncRouter(asyncRouterMap, lastRouter = false, type = false) { function filterAsyncRouter(asyncRouterMap, lastRouter = false, type = false) {
return asyncRouterMap.filter(route => { return asyncRouterMap.filter(route => {
if (type && route.children) { if (type && route.children) {
route.children = filterChildren(route.children) route.children = filterChildren(route.children);
}
// query默认参数转换
if (route.query) {
try {
route.query = JSON.parse(route.query);
} catch (error) {
}
} }
if (route.component) { if (route.component) {
// Layout ParentView 组件特殊处理 // Layout ParentView 组件特殊处理
if (route.component === 'Layout') { if (route.component === 'Layout') {
route.component = Layout route.component = Layout;
} else if (route.component === 'ParentView') { } else if (route.component === 'ParentView') {
route.component = ParentView route.component = ParentView;
} else if (route.component === 'InnerLink') { } else if (route.component === 'InnerLink') {
route.component = InnerLink route.component = InnerLink;
} else { } else {
route.component = loadView(route.component) route.component = loadView(route.component);
} }
} }
if (route.children != null && route.children && route.children.length) { if (route.children != null && route.children && route.children.length) {
route.children = filterAsyncRouter(route.children, route, type) route.children = filterAsyncRouter(route.children, route, type);
} else { } else {
delete route['children'] delete route['children'];
delete route['redirect'] delete route['redirect'];
} }
return true return true;
}) });
} }
function filterChildren(childrenMap, lastRouter = false) { function filterChildren(childrenMap, lastRouter = false) {
var children = [] var children = [];
childrenMap.forEach((el, index) => { childrenMap.forEach((el, index) => {
if (el.children && el.children.length) { if (el.children && el.children.length) {
if (el.component === 'ParentView' && !lastRouter) { if (el.component === 'ParentView' && !lastRouter) {
el.children.forEach(c => { el.children.forEach(c => {
c.path = el.path + '/' + c.path c.path = el.path + '/' + c.path;
if (c.children && c.children.length) { if (c.children && c.children.length) {
children = children.concat(filterChildren(c.children, c)) children = children.concat(filterChildren(c.children, c));
return return;
} }
children.push(c) children.push(c);
}) });
return return;
} }
} }
if (lastRouter) { if (lastRouter) {
el.path = lastRouter.path + '/' + el.path el.path = lastRouter.path + '/' + el.path;
} }
children = children.concat(el) children = children.concat(el);
}) });
return children return children;
} }
// 动态路由遍历,验证是否具备权限 // 动态路由遍历,验证是否具备权限
export function filterDynamicRoutes(routes) { export function filterDynamicRoutes(routes) {
const res = [] const res = [];
routes.forEach(route => { routes.forEach(route => {
if (route.permissions) { if (route.permissions) {
if (auth.hasPermiOr(route.permissions)) { if (auth.hasPermiOr(route.permissions)) {
res.push(route) res.push(route);
} }
} else if (route.roles) { } else if (route.roles) {
if (auth.hasRoleOr(route.roles)) { if (auth.hasRoleOr(route.roles)) {
res.push(route) res.push(route);
} }
} }
}) });
return res return res;
} }
export const loadView = (view) => { export const loadView = (view) => {
if (process.env.NODE_ENV === 'development') { if (process.env.NODE_ENV === 'development') {
return (resolve) => require([`@/views/${view}`], resolve) return (resolve) => require([`@/views/${view}`], resolve);
} else { } else {
// 使用 import 实现生产环境的路由懒加载 // 使用 import 实现生产环境的路由懒加载
return () => import(`@/views/${view}`) return () => import(`@/views/${view}`);
} }
} };
export default permission export default permission;
...@@ -3,227 +3,227 @@ const state = { ...@@ -3,227 +3,227 @@ const state = {
visitedViews: [], visitedViews: [],
cachedViews: [], cachedViews: [],
iframeViews: [] iframeViews: []
} };
const mutations = { const mutations = {
ADD_IFRAME_VIEW: (state, view) => { ADD_IFRAME_VIEW: (state, view) => {
if (state.iframeViews.some(v => v.fullPath === view.fullPath)) return if (state.iframeViews.some(v => v.fullPath === view.fullPath)) return;
state.iframeViews.push( state.iframeViews.push(
Object.assign({}, view, { Object.assign({}, view, {
title: view.meta.title || 'no-name' title: view.meta.title || 'no-name'
}) })
) );
}, },
ADD_VISITED_VIEW: (state, view) => { ADD_VISITED_VIEW: (state, view) => {
if (state.visitedViews.some(v => v.fullPath === view.fullPath)) return if (state.visitedViews.some(v => v.fullPath === view.fullPath)) return;
state.visitedViews.push( state.visitedViews.push(
Object.assign({}, view, { Object.assign({}, view, {
title: view.meta.title || 'no-name' title: view.meta.title || 'no-name'
}) })
) );
}, },
ADD_CACHED_VIEW: (state, view) => { ADD_CACHED_VIEW: (state, view) => {
if (state.cachedViews.includes(view.name)) return if (state.cachedViews.includes(view.name)) return;
if (view.meta && !view.meta.noCache) { if (view.meta && !view.meta.noCache) {
state.cachedViews.push(view.name) state.cachedViews.push(view.name);
} }
}, },
DEL_VISITED_VIEW: (state, view) => { DEL_VISITED_VIEW: (state, view) => {
for (const [i, v] of state.visitedViews.entries()) { for (const [i, v] of state.visitedViews.entries()) {
if (v.fullPath === view.fullPath) { if (v.fullPath === view.fullPath) {
state.visitedViews.splice(i, 1) state.visitedViews.splice(i, 1);
break break;
} }
} }
state.iframeViews = state.iframeViews.filter(item => item.fullPath !== view.fullPath) state.iframeViews = state.iframeViews.filter(item => item.fullPath !== view.fullPath);
}, },
DEL_IFRAME_VIEW: (state, view) => { DEL_IFRAME_VIEW: (state, view) => {
state.iframeViews = state.iframeViews.filter(item => item.fullPath !== view.fullPath) state.iframeViews = state.iframeViews.filter(item => item.fullPath !== view.fullPath);
}, },
DEL_CACHED_VIEW: (state, view) => { DEL_CACHED_VIEW: (state, view) => {
const index = state.cachedViews.indexOf(view.name) const index = state.cachedViews.indexOf(view.name);
index > -1 && state.cachedViews.splice(index, 1) index > -1 && state.cachedViews.splice(index, 1);
}, },
DEL_OTHERS_VISITED_VIEWS: (state, view) => { DEL_OTHERS_VISITED_VIEWS: (state, view) => {
state.visitedViews = state.visitedViews.filter(v => { state.visitedViews = state.visitedViews.filter(v => {
return v.meta.affix || v.fullPath === view.fullPath return v.meta.affix || v.fullPath === view.fullPath;
}) });
state.iframeViews = state.iframeViews.filter(item => item.fullPath === view.fullPath) state.iframeViews = state.iframeViews.filter(item => item.fullPath === view.fullPath);
}, },
DEL_OTHERS_CACHED_VIEWS: (state, view) => { DEL_OTHERS_CACHED_VIEWS: (state, view) => {
const index = state.cachedViews.indexOf(view.name) const index = state.cachedViews.indexOf(view.name);
if (index > -1) { if (index > -1) {
state.cachedViews = state.cachedViews.slice(index, index + 1) state.cachedViews = state.cachedViews.slice(index, index + 1);
} else { } else {
state.cachedViews = [] state.cachedViews = [];
} }
}, },
DEL_ALL_VISITED_VIEWS: state => { DEL_ALL_VISITED_VIEWS: state => {
// keep affix tags // keep affix tags
const affixTags = state.visitedViews.filter(tag => tag.meta.affix) const affixTags = state.visitedViews.filter(tag => tag.meta.affix);
state.visitedViews = affixTags state.visitedViews = affixTags;
state.iframeViews = [] state.iframeViews = [];
}, },
DEL_ALL_CACHED_VIEWS: state => { DEL_ALL_CACHED_VIEWS: state => {
state.cachedViews = [] state.cachedViews = [];
}, },
UPDATE_VISITED_VIEW: (state, view) => { UPDATE_VISITED_VIEW: (state, view) => {
for (let v of state.visitedViews) { for (let v of state.visitedViews) {
if (v.fullPath === view.fullPath) { if (v.fullPath === view.fullPath) {
v = Object.assign(v, view) v = Object.assign(v, view);
break break;
} }
} }
}, },
DEL_RIGHT_VIEWS: (state, view) => { DEL_RIGHT_VIEWS: (state, view) => {
const index = state.visitedViews.findIndex(v => v.fullPath === view.fullPath) const index = state.visitedViews.findIndex(v => v.fullPath === view.fullPath);
if (index === -1) { if (index === -1) {
return return;
} }
state.visitedViews = state.visitedViews.filter((item, idx) => { state.visitedViews = state.visitedViews.filter((item, idx) => {
if (idx <= index || (item.meta && item.meta.affix)) { if (idx <= index || (item.meta && item.meta.affix)) {
return true return true;
} }
const i = state.cachedViews.indexOf(item.name) const i = state.cachedViews.indexOf(item.name);
if (i > -1) { if (i > -1) {
state.cachedViews.splice(i, 1) state.cachedViews.splice(i, 1);
} }
if(item.meta.link) { if (item.meta.link) {
const fi = state.iframeViews.findIndex(v => v.fullPath === item.fullPath) const fi = state.iframeViews.findIndex(v => v.fullPath === item.fullPath);
state.iframeViews.splice(fi, 1) state.iframeViews.splice(fi, 1);
} }
return false return false;
}) });
}, },
DEL_LEFT_VIEWS: (state, view) => { DEL_LEFT_VIEWS: (state, view) => {
const index = state.visitedViews.findIndex(v => v.fullPath === view.fullPath) const index = state.visitedViews.findIndex(v => v.fullPath === view.fullPath);
if (index === -1) { if (index === -1) {
return return;
} }
state.visitedViews = state.visitedViews.filter((item, idx) => { state.visitedViews = state.visitedViews.filter((item, idx) => {
if (idx >= index || (item.meta && item.meta.affix)) { if (idx >= index || (item.meta && item.meta.affix)) {
return true return true;
} }
const i = state.cachedViews.indexOf(item.name) const i = state.cachedViews.indexOf(item.name);
if (i > -1) { if (i > -1) {
state.cachedViews.splice(i, 1) state.cachedViews.splice(i, 1);
} }
if(item.meta.link) { if (item.meta.link) {
const fi = state.iframeViews.findIndex(v => v.fullPath === item.fullPath) const fi = state.iframeViews.findIndex(v => v.fullPath === item.fullPath);
state.iframeViews.splice(fi, 1) state.iframeViews.splice(fi, 1);
} }
return false return false;
}) });
} }
} };
const actions = { const actions = {
addView({ dispatch }, view) { addView({ dispatch }, view) {
dispatch('addVisitedView', view) dispatch('addVisitedView', view);
dispatch('addCachedView', view) dispatch('addCachedView', view);
}, },
addIframeView({ commit }, view) { addIframeView({ commit }, view) {
commit('ADD_IFRAME_VIEW', view) commit('ADD_IFRAME_VIEW', view);
}, },
addVisitedView({ commit }, view) { addVisitedView({ commit }, view) {
commit('ADD_VISITED_VIEW', view) commit('ADD_VISITED_VIEW', view);
}, },
addCachedView({ commit }, view) { addCachedView({ commit }, view) {
commit('ADD_CACHED_VIEW', view) commit('ADD_CACHED_VIEW', view);
}, },
delView({ dispatch, state }, view) { delView({ dispatch, state }, view) {
return new Promise(resolve => { return new Promise(resolve => {
dispatch('delVisitedView', view) dispatch('delVisitedView', view);
dispatch('delCachedView', view) dispatch('delCachedView', view);
resolve({ resolve({
visitedViews: [...state.visitedViews], visitedViews: [...state.visitedViews],
cachedViews: [...state.cachedViews] cachedViews: [...state.cachedViews]
}) });
}) });
}, },
delVisitedView({ commit, state }, view) { delVisitedView({ commit, state }, view) {
return new Promise(resolve => { return new Promise(resolve => {
commit('DEL_VISITED_VIEW', view) commit('DEL_VISITED_VIEW', view);
resolve([...state.visitedViews]) resolve([...state.visitedViews]);
}) });
}, },
delIframeView({ commit, state }, view) { delIframeView({ commit, state }, view) {
return new Promise(resolve => { return new Promise(resolve => {
commit('DEL_IFRAME_VIEW', view) commit('DEL_IFRAME_VIEW', view);
resolve([...state.iframeViews]) resolve([...state.iframeViews]);
}) });
}, },
delCachedView({ commit, state }, view) { delCachedView({ commit, state }, view) {
return new Promise(resolve => { return new Promise(resolve => {
commit('DEL_CACHED_VIEW', view) commit('DEL_CACHED_VIEW', view);
resolve([...state.cachedViews]) resolve([...state.cachedViews]);
}) });
}, },
delOthersViews({ dispatch, state }, view) { delOthersViews({ dispatch, state }, view) {
return new Promise(resolve => { return new Promise(resolve => {
dispatch('delOthersVisitedViews', view) dispatch('delOthersVisitedViews', view);
dispatch('delOthersCachedViews', view) dispatch('delOthersCachedViews', view);
resolve({ resolve({
visitedViews: [...state.visitedViews], visitedViews: [...state.visitedViews],
cachedViews: [...state.cachedViews] cachedViews: [...state.cachedViews]
}) });
}) });
}, },
delOthersVisitedViews({ commit, state }, view) { delOthersVisitedViews({ commit, state }, view) {
return new Promise(resolve => { return new Promise(resolve => {
commit('DEL_OTHERS_VISITED_VIEWS', view) commit('DEL_OTHERS_VISITED_VIEWS', view);
resolve([...state.visitedViews]) resolve([...state.visitedViews]);
}) });
}, },
delOthersCachedViews({ commit, state }, view) { delOthersCachedViews({ commit, state }, view) {
return new Promise(resolve => { return new Promise(resolve => {
commit('DEL_OTHERS_CACHED_VIEWS', view) commit('DEL_OTHERS_CACHED_VIEWS', view);
resolve([...state.cachedViews]) resolve([...state.cachedViews]);
}) });
}, },
delAllViews({ dispatch, state }, view) { delAllViews({ dispatch, state }, view) {
return new Promise(resolve => { return new Promise(resolve => {
dispatch('delAllVisitedViews', view) dispatch('delAllVisitedViews', view);
dispatch('delAllCachedViews', view) dispatch('delAllCachedViews', view);
resolve({ resolve({
visitedViews: [...state.visitedViews], visitedViews: [...state.visitedViews],
cachedViews: [...state.cachedViews] cachedViews: [...state.cachedViews]
}) });
}) });
}, },
delAllVisitedViews({ commit, state }) { delAllVisitedViews({ commit, state }) {
return new Promise(resolve => { return new Promise(resolve => {
commit('DEL_ALL_VISITED_VIEWS') commit('DEL_ALL_VISITED_VIEWS');
resolve([...state.visitedViews]) resolve([...state.visitedViews]);
}) });
}, },
delAllCachedViews({ commit, state }) { delAllCachedViews({ commit, state }) {
return new Promise(resolve => { return new Promise(resolve => {
commit('DEL_ALL_CACHED_VIEWS') commit('DEL_ALL_CACHED_VIEWS');
resolve([...state.cachedViews]) resolve([...state.cachedViews]);
}) });
}, },
updateVisitedView({ commit }, view) { updateVisitedView({ commit }, view) {
commit('UPDATE_VISITED_VIEW', view) commit('UPDATE_VISITED_VIEW', view);
}, },
delRightTags({ commit }, view) { delRightTags({ commit }, view) {
return new Promise(resolve => { return new Promise(resolve => {
commit('DEL_RIGHT_VIEWS', view) commit('DEL_RIGHT_VIEWS', view);
resolve([...state.visitedViews]) resolve([...state.visitedViews]);
}) });
}, },
delLeftTags({ commit }, view) { delLeftTags({ commit }, view) {
return new Promise(resolve => { return new Promise(resolve => {
commit('DEL_LEFT_VIEWS', view) commit('DEL_LEFT_VIEWS', view);
resolve([...state.visitedViews]) resolve([...state.visitedViews]);
}) });
}, },
} };
export default { export default {
namespaced: true, namespaced: true,
state, state,
mutations, mutations,
actions actions
} };
/*
* @Author: thy
* @Date: 2023-11-08 09:28:17
* @LastEditors: thy
* @LastEditTime: 2023-11-17 09:36:01
* @Description: file content
* @FilePath: \dsk-operate-ui\src\utils\iframeTools.js
*/
import { dskAccessToken } from '@/api/common';
import { getUrlSearchQuery, isUrl, paramsToQuery } from "@/utils/";
import { Message } from "element-ui";
/**
* iframe嵌入参数处理
*/
class IframeTools {
queryParams = {};
pluginDomain = "";
subSystemIframe = null;
refreshTimer = null;
count = 0;
authToken = "";
origin = location.origin;
isOuter = false;
/**
* 插件域名地址
* @param {string} pluginDomain 默认当前环境变量VUE_APP_SUB_SYSTEM_ADDRESS
* @param {HTMLIFrameElement} subSystemIframe 子系统iframe dom节点
* @returns
*/
constructor(subSystemIframe, pluginDomain = process.env.VUE_APP_SUB_SYSTEM_ADDRESS) {
try {
const query = getUrlSearchQuery();
if (!query.url) return Message.warning("缺少子系统目标地址");
// 传入的iframeUrl不是一个合法地址
if (!isUrl(pluginDomain)) return Message.warning("子系统源地址不合法");
// 未获取到子系统节点
if (!subSystemIframe) return Message.warning("未获取到子系统节点");
this.queryParams = query;
this.pluginDomain = pluginDomain;
this.subSystemIframe = subSystemIframe;
this.isOuter = query.isOuter && typeof JSON.parse(query.isOuter) == "boolean" ? JSON.parse(query.isOuter) : false;
// 是一个合法地址 初始化 先替换域名地址 再获取令牌并 拼接
this.init();
} catch (error) {
throw new Error(error);
}
}
/**
* 初始化类
*/
async init() {
try {
// 不是合法url的情况下需要拼接完整路径 例如path /xxxx/xxx
!isUrl(this.queryParams.url) ? this.queryParams.url = `${this.pluginDomain}${this.queryParams.url}` : null;
// 获取到子系统加载地址query参数
const subSystemParams = getUrlSearchQuery(this.queryParams.url);
// 获取子系统path
const subSystemUrl = new URL(this.queryParams.url);
// 以环境文件地址为准 拼接子系统查询参数
let url = this.isOuter ? this.queryParams.url : `${this.pluginDomain}${subSystemUrl.pathname == "/" ? "" : subSystemUrl.pathname}`;
// 子系统地址带有查询参数 处理
Object.keys(subSystemParams).length ? url = `${url}?${paramsToQuery(subSystemParams)}` : null;
// 获取授权 token
const { accessToken, expire } = await this.getSubSystemToken();
// 拼接授权地址
if (accessToken) {
this.authToken = accessToken;
const query = {
initTime: new Date().valueOf(),
ak: accessToken,
uid: accessToken,
origin: this.origin
};
url = `${url}${paramsToQuery(query) ? "?" + paramsToQuery(query) : ""}`;
this.queryParams.url = url;
console.log(this.queryParams.url);
// 倒计时刷新token 正常误差10s 提前获取
this.setTokenRefresh(expire * 1000 - 1000 * 10);
}
} catch (error) {
console.log(error);
Message.warning(error.message ? error.message : (typeof error == "string") ? error : "子系统初始化错误");
}
}
/**
* 获取子系统token
*/
async getSubSystemToken() {
try {
const result = await dskAccessToken();
if (result.code == 200) {
return result.data;
}
throw new Error("子系统获取授权失败");
} catch (error) {
throw error;
}
}
/**
* 根据服务端返回过期时间刷新token有效期
*/
setTokenRefresh(expire) {
if (!expire) throw new Error("令牌无有效的刷新时间");
return new Promise((resolve, reject) => {
// 只允许出现一个定时器实例状态
this.clearRefreshTimer();
this.refreshTimer = setTimeout(async () => {
const result = await this.getSubSystemToken();
if (result.accessToken) {
this.count = 0;
this.authToken = result.accessToken;
this.setTokenRefresh(result.expire);
resolve(result);
} else {
// 请求失败进行重试 清理定时器
this.clearRefreshTimer();
// 尝试最多3次刷新 重新调取接口
while (this.count < 3) {
// 重试次数大于等于三次 停止刷新
if (this.count >= 3) {
return reject("子系统令牌刷新失败,请稍后重试");
}
this.count++;
Message.warning(`授权失败,正在尝试第 ${this.count} 次刷新令牌,请勿进行操作`);
const refreshAuth = await this.getSubSystemToken();
if (refreshAuth.accessToken) {
this.count = 0;
this.authToken = refreshAuth.accessToken;
this.setTokenRefresh(refreshAuth.expire);
resolve(refreshAuth);
}
}
}
}, expire);
});
}
clearRefreshTimer() {
clearTimeout(this.refreshTimer);
this.refreshTimer = null;
}
}
export default IframeTools;
\ No newline at end of file
import { Message } from "element-ui";
import { parseTime } from './ruoyi'; import { parseTime } from './ruoyi';
/** /**
...@@ -431,8 +432,7 @@ export const paramsToQuery = (query) => { ...@@ -431,8 +432,7 @@ export const paramsToQuery = (query) => {
searchStrArray.push(`${key}=${decodeURIComponent(value)}`); searchStrArray.push(`${key}=${decodeURIComponent(value)}`);
} }
}); });
searchStrArray = searchStrArray.join("&"); return searchStrArray.join("&");
return searchStr;
} catch (error) { } catch (error) {
console.log(error); console.log(error);
} }
...@@ -457,6 +457,136 @@ export const searchTextToQuery = (text) => { ...@@ -457,6 +457,136 @@ export const searchTextToQuery = (text) => {
} }
}; };
/**
* 验证链接是否是url
* @param {string} url
* @returns
*/
export function isUrl(url) {
return /https?:\/\/(www\.)?[-a-zA-Z0-9@:%._\+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b([-a-zA-Z0-9()@:%_\+.~#?&//=]*[\u4e00-\u9fa5\w]*)$/.test(url);
}
// 对查询关键字中的特殊字符进行编码
export function encodeSearchKey(key) {
const encodeArr = [{
code: '%',
encode: '%25'
}, {
code: '?',
encode: '%3F'
}, {
code: '#',
encode: '%23'
}, {
code: '&',
encode: '%26'
}, {
code: '=',
encode: '%3D'
}];
return key.replace(/[%?#&=]/g, ($, index, str) => {
for (const k of encodeArr) {
if (k.code === $) {
return k.encode;
}
}
});
}
/**
* 去除json 换行空格符号
* @param {string} str
* @returns
*/
export function jsonEscape(str) {
return str.replace(/(\r\n|\n|\r)/gm, "");
}
/**
* json递归特殊参数处理
* @param {object} target
*/
export function jsonTraversal(target, decode = false) {
try {
if (Object.prototype.toString.call(target) != "[object Object]") throw new Error("传入参数不是一个对象");
for (const key in target) {
// 传入指定key 或者 key数组长度未0 默认全编码
if (Object.prototype.toString.call(target[key]) == "[object Object]") {
target[key] = jsonTraversal(target[key], decode);
} else {
if (decode) {
isencodingStr(target[key]) ? target[key] = decodeURIComponent(target[key]) : null;
} else {
needEncodeComponent(target[key]) ? target[key] = encodeURIComponent(target[key]) : null;
}
}
}
return target;
} catch (error) {
console.log(error);
}
}
/**
* url查询参数中需要编码的特殊字符
* @param {string} componentStr
* @returns
*/
export function needEncodeComponent(componentStr) {
const reg = /[^a-zA-Z0-9\-_.!~*'()]/gim;
return reg.test(componentStr);
}
/**
* 字符串是否被编码过
* @param {string} checkStr
* @returns
*/
export function isencodingStr(checkStr) {
const reg = /%[0-9A-Fa-f]{2}/gim;
return reg.test(checkStr);
}
let messageSingleton = null;
/**
* element message 弹窗单例模式
* @param {string} type
* @param {string} messgage
*/
export async function elementMessageSingleton(type = "success", messgage = "") {
try {
if (messageSingleton) {
messageSingleton.close();
}
} catch (error) {
console.log(error);
} finally {
messageSingleton = Message[type](messgage);
}
}
/**
* 检测数组对象中是否有重复数据
* @param {Array} arr
* @param {string | null} mapKey
* @returns
*/
export function hasDuplicates(arr, mapKey = null) {
try {
const map = new Map();
for (const item of arr) {
const key = mapKey ? item[mapKey] : JSON.stringify(item);
if (map.has(key)) {
return { hasRepeat: true, repeatKey: key };
}
map.set(key, true);
}
return { hasRepeat: false };
} catch (error) {
console.log(error);
}
}
// 甲方详情左侧菜单映射 // 甲方详情左侧菜单映射
export const detailSideBar = new Map([ export const detailSideBar = new Map([
// 企业速览 // 企业速览
......
...@@ -37,33 +37,33 @@ service.interceptors.request.use(config => { ...@@ -37,33 +37,33 @@ service.interceptors.request.use(config => {
config.params = {}; config.params = {};
config.url = url; config.url = url;
} }
cancelPending(config) // cancelPending(config)
config.cancelToken = new CancelToken(res => { // config.cancelToken = new CancelToken(res => {
pending.push({'UrlPath': config.url, 'Cancel': res}) // pending.push({'UrlPath': config.url, 'Cancel': res})
}) // })
if (!isRepeatSubmit && (config.method === 'post' || config.method === 'put')) { // if (!isRepeatSubmit && (config.method === 'post' || config.method === 'put')) {
const requestObj = { // const requestObj = {
url: config.url, // url: config.url,
data: typeof config.data === 'object' ? JSON.stringify(config.data) : config.data, // data: typeof config.data === 'object' ? JSON.stringify(config.data) : config.data,
time: new Date().getTime() // time: new Date().getTime()
} // }
const sessionObj = cache.session.getJSON('sessionObj') // const sessionObj = cache.session.getJSON('sessionObj')
if (sessionObj === undefined || sessionObj === null || sessionObj === '') { // if (sessionObj === undefined || sessionObj === null || sessionObj === '') {
cache.session.setJSON('sessionObj', requestObj) // cache.session.setJSON('sessionObj', requestObj)
} else { // } else {
const s_url = sessionObj.url; // 请求地址 // const s_url = sessionObj.url; // 请求地址
const s_data = sessionObj.data; // 请求数据 // const s_data = sessionObj.data; // 请求数据
const s_time = sessionObj.time; // 请求时间 // const s_time = sessionObj.time; // 请求时间
const interval = 200; // 间隔时间(ms),小于此时间视为重复提交 // const interval = 200; // 间隔时间(ms),小于此时间视为重复提交
if (s_data === requestObj.data && requestObj.time - s_time < interval && s_url === requestObj.url) { // if (s_data === requestObj.data && requestObj.time - s_time < interval && s_url === requestObj.url) {
const message = '数据正在处理,请勿重复提交'; // const message = '数据正在处理,请勿重复提交';
console.warn(`[${s_url}]: ` + message) // console.warn(`[${s_url}]: ` + message)
return Promise.reject(new Error(message)) // return Promise.reject(new Error(message))
} else { // } else {
cache.session.setJSON('sessionObj', requestObj) // cache.session.setJSON('sessionObj', requestObj)
} // }
} // }
} // }
return config return config
}, error => { }, error => {
console.log(error) console.log(error)
...@@ -125,10 +125,11 @@ service.interceptors.response.use(res => { ...@@ -125,10 +125,11 @@ service.interceptors.response.use(res => {
Notification.error({ title: msg }) Notification.error({ title: msg })
return Promise.reject('error') return Promise.reject('error')
} else { } else {
cancelPending(res.config) // cancelPending(res.config)
return res.data return res.data
} }
},error => { },error => {
console.log(error);
console.log('err' + error) console.log('err' + error)
let { message } = error; let { message } = error;
/*if (message == "Network Error") { /*if (message == "Network Error") {
......
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
* @returns {Boolean} * @returns {Boolean}
*/ */
export function isExternal(path) { export function isExternal(path) {
return /^(https?:|mailto:|tel:)/.test(path) return /^(https?:|mailto:|tel:)/.test(path);
} }
/** /**
...@@ -11,8 +11,8 @@ export function isExternal(path) { ...@@ -11,8 +11,8 @@ export function isExternal(path) {
* @returns {Boolean} * @returns {Boolean}
*/ */
export function validUsername(str) { export function validUsername(str) {
const valid_map = ['admin', 'editor'] const valid_map = ['admin', 'editor'];
return valid_map.indexOf(str.trim()) >= 0 return valid_map.indexOf(str.trim()) >= 0;
} }
/** /**
...@@ -20,8 +20,8 @@ export function validUsername(str) { ...@@ -20,8 +20,8 @@ export function validUsername(str) {
* @returns {Boolean} * @returns {Boolean}
*/ */
export function validURL(url) { export function validURL(url) {
const reg = /^(https?|ftp):\/\/([a-zA-Z0-9.-]+(:[a-zA-Z0-9.&%$-]+)*@)*((25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9][0-9]?)(\.(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])){3}|([a-zA-Z0-9-]+\.)*[a-zA-Z0-9-]+\.(com|edu|gov|int|mil|net|org|biz|arpa|info|name|pro|aero|coop|museum|[a-zA-Z]{2}))(:[0-9]+)*(\/($|[a-zA-Z0-9.,?'\\+&%$#=~_-]+))*$/ const reg = /^(https?|ftp):\/\/([a-zA-Z0-9.-]+(:[a-zA-Z0-9.&%$-]+)*@)*((25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9][0-9]?)(\.(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])){3}|([a-zA-Z0-9-]+\.)*[a-zA-Z0-9-]+\.(com|edu|gov|int|mil|net|org|biz|arpa|info|name|pro|aero|coop|museum|[a-zA-Z]{2}))(:[0-9]+)*(\/($|[a-zA-Z0-9.,?'\\+&%$#=~_-]+))*$/;
return reg.test(url) return reg.test(url);
} }
/** /**
...@@ -29,8 +29,8 @@ export function validURL(url) { ...@@ -29,8 +29,8 @@ export function validURL(url) {
* @returns {Boolean} * @returns {Boolean}
*/ */
export function validLowerCase(str) { export function validLowerCase(str) {
const reg = /^[a-z]+$/ const reg = /^[a-z]+$/;
return reg.test(str) return reg.test(str);
} }
/** /**
...@@ -38,8 +38,8 @@ export function validLowerCase(str) { ...@@ -38,8 +38,8 @@ export function validLowerCase(str) {
* @returns {Boolean} * @returns {Boolean}
*/ */
export function validUpperCase(str) { export function validUpperCase(str) {
const reg = /^[A-Z]+$/ const reg = /^[A-Z]+$/;
return reg.test(str) return reg.test(str);
} }
/** /**
...@@ -47,8 +47,8 @@ export function validUpperCase(str) { ...@@ -47,8 +47,8 @@ export function validUpperCase(str) {
* @returns {Boolean} * @returns {Boolean}
*/ */
export function validAlphabets(str) { export function validAlphabets(str) {
const reg = /^[A-Za-z]+$/ const reg = /^[A-Za-z]+$/;
return reg.test(str) return reg.test(str);
} }
/** /**
...@@ -56,8 +56,8 @@ export function validAlphabets(str) { ...@@ -56,8 +56,8 @@ export function validAlphabets(str) {
* @returns {Boolean} * @returns {Boolean}
*/ */
export function validEmail(email) { export function validEmail(email) {
const reg = /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/ const reg = /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
return reg.test(email) return reg.test(email);
} }
/** /**
...@@ -66,9 +66,9 @@ export function validEmail(email) { ...@@ -66,9 +66,9 @@ export function validEmail(email) {
*/ */
export function isString(str) { export function isString(str) {
if (typeof str === 'string' || str instanceof String) { if (typeof str === 'string' || str instanceof String) {
return true return true;
} }
return false return false;
} }
/** /**
...@@ -77,7 +77,34 @@ export function isString(str) { ...@@ -77,7 +77,34 @@ export function isString(str) {
*/ */
export function isArray(arg) { export function isArray(arg) {
if (typeof Array.isArray === 'undefined') { if (typeof Array.isArray === 'undefined') {
return Object.prototype.toString.call(arg) === '[object Array]' return Object.prototype.toString.call(arg) === '[object Array]';
} }
return Array.isArray(arg) return Array.isArray(arg);
} }
/**
* 电话号码验证
* @param {object} rule
* @param {string} value
* @param {Function} callback
* @returns
*/
export function phoneNumberValidator(rule, value, callback) {
const phoneReg = /^1[3-9]\d{9}$/;
if (!value && !value?.toString()?.trim()) {
return callback(new Error(`请输入手机号码`));
}
if (value && !phoneReg.test(value)) {
return callback(new Error(`请输入正确的手机号码`));
}
return callback();
}
export function requiredStrLengthValidator(target) {
return function (rule, value, callback) {
if (!value && !value?.toString()?.trim()) {
return callback(new Error(`请输入${target}`));
}
return callback();
};
};
...@@ -278,13 +278,13 @@ export default { ...@@ -278,13 +278,13 @@ export default {
this.sideRoute[2].children[7].disabled = true; this.sideRoute[2].children[7].disabled = true;
} }
break; break;
case 'customer': case 'customerV1':
if (arr[i][j] < 1) { if (arr[i][j] < 1) {
this.sideRoute[3].children[0].disabled = true; this.sideRoute[3].children[0].disabled = true;
} }
break; break;
case 'supplier': case 'supplierV1':
if (arr[i][j] < 1) { if (arr[i][j] < 1) {
this.sideRoute[3].children[1].disabled = true; this.sideRoute[3].children[1].disabled = true;
} }
......
...@@ -377,6 +377,7 @@ export default { ...@@ -377,6 +377,7 @@ export default {
<style lang="scss" scoped> <style lang="scss" scoped>
.part-container { .part-container {
padding: 0; padding: 0;
margin: 0 24px;
} }
.part-main { .part-main {
margin-top: 12px; margin-top: 12px;
......
...@@ -184,7 +184,7 @@ export default { ...@@ -184,7 +184,7 @@ export default {
showMore: false, showMore: false,
showState: false, showState: false,
graphList: [ graphList: [
{ id: 1, name: '业务往来', isShow: true, intro: [{ id: 101, name: '客户', val: 0, category: 'global', field: 'customer' }, { id: 102, name: '供应商', val: 0, category: 'global', field: 'supplier' }], ico: require('@/assets/images/detail/overview/company_ywwl.png') }, { id: 1, name: '业务往来', isShow: true, intro: [{ id: 101, name: '客户', val: 0, category: 'global', field: 'customerV1' }, { id: 102, name: '供应商', val: 0, category: 'global', field: 'supplierV1' }], ico: require('@/assets/images/detail/overview/company_ywwl.png') },
{ id: 2, name: '商机线索', isShow: true, intro: [{ id: 201, name: '专项债项目', val: 0, category: 'performance', field: 'specialDebt' }, { id: 202, name: '招标计划', val: 0, category: 'performance', field: 'bidPlan' }], ico: require('@/assets/images/detail/overview/company_sjxs.png') }, { id: 2, name: '商机线索', isShow: true, intro: [{ id: 201, name: '专项债项目', val: 0, category: 'performance', field: 'specialDebt' }, { id: 202, name: '招标计划', val: 0, category: 'performance', field: 'bidPlan' }], ico: require('@/assets/images/detail/overview/company_sjxs.png') },
{ id: 3, name: '城投拿地', isShow: true, intro: [{ id: 301, name: '土地交易', val: 0, category: 'global', field: 'landInfo' }, { id: 302, name: '行政许可', val: 0, category: 'business', field: 'adminLicensing' }], ico: require('@/assets/images/detail/overview/company_ctnd.png') }, { id: 3, name: '城投拿地', isShow: true, intro: [{ id: 301, name: '土地交易', val: 0, category: 'global', field: 'landInfo' }, { id: 302, name: '行政许可', val: 0, category: 'business', field: 'adminLicensing' }], ico: require('@/assets/images/detail/overview/company_ctnd.png') },
{ id: 4, name: '对外投资', isShow: true, intro: [{ id: 401, name: '企业经营实力展现' }], ico: require('@/assets/images/detail/overview/company_dwtz.png') }, { id: 4, name: '对外投资', isShow: true, intro: [{ id: 401, name: '企业经营实力展现' }], ico: require('@/assets/images/detail/overview/company_dwtz.png') },
......
...@@ -842,7 +842,7 @@ export default { ...@@ -842,7 +842,7 @@ export default {
.el-checkbox-group { .el-checkbox-group {
.el-checkbox { .el-checkbox {
.el-checkbox__label { .el-checkbox__label {
color: #333333; color: #606266;
} }
&.is-checked { &.is-checked {
.el-checkbox__label { .el-checkbox__label {
......
<template>
<el-dialog title="添加账号" :visible.sync="dialogStatus" width="800px" @close="dialogClose" @open="dialogOpen" class="enterprise-add-account"
custom-class="enterprise-add-account-dialog" :close-on-click-modal="false">
<div class="enterprise-add-account-inner">
<el-form :model="accountForm" ref="accountForm" :rules="rules">
<transition-group tag="div" class="enterprise-add-account-list" name="list" appear>
<div class="enterprise-add-account-item" v-for="(item,index) of accountForm.accountList" :key="item.uid">
<div class="account-nickname">
<el-form-item label="用户名称" :prop="`accountList[${index}].nickName`" :rules="rules.nickName">
<el-input v-model="accountForm.accountList[index].nickName" placeholder="请输入用户名称" size="normal" clearable></el-input>
</el-form-item>
</div>
<div class="account-phone">
<el-form-item label="手机号码" :prop="`accountList[${index}].phonenumber`" :rules="rules.phonenumber">
<el-input v-model="accountForm.accountList[index].phonenumber" placeholder="请输入手机号码" size="normal" clearable></el-input>
</el-form-item>
</div>
<div class="remove-account-item" @click="removeAccount(item.uid)" v-if="accountForm.accountList.length > 1"><i class="el-icon-delete"></i>
</div>
</div>
</transition-group>
<!-- 添加按钮 -->
<div class="add-account-btn" @click="addAccount">
<i class="el-icon-plus"></i>
<span>增加账号</span>
</div>
</el-form>
</div>
<template slot="footer">
<!-- 底部提交 取消按钮 -->
<div class="add-account-footer">
<el-button type="primary" size="medium" @click="submitAdd">确定</el-button>
<el-button size="medium" @click="dialogStatus = false">取消</el-button>
</div>
</template>
</el-dialog>
</template>
<script>
import { Loading } from 'element-ui';
import { enterpriseAddAccountApi } from "@/api/enterpriseManagement/enterpriseManagement";
import { phoneNumberValidator, requiredStrLengthValidator } from "@/utils/validate";
import { elementMessageSingleton, hasDuplicates } from "@/utils/";
import { v4 } from 'uuid';
export default {
name: "enterpriseAddAccount",
props: {
openStatus: {
type: Boolean,
default: false
},
enterpriseInfo: {
type: Object,
default: () => ({})
},
addAccountCount: {
type: [String, Number],
default: 1
}
},
watch: {
openStatus(newValue) {
this.dialogStatus = newValue;
},
addAccountCount(newValue) {
this.comAddAccountCount = newValue;
},
enterpriseInfo: {
handler(newValue) {
this.comEnterpriseInfo = newValue;
},
deep: true
}
},
data() {
return {
dialogStatus: this.openStatus,
comEnterpriseInfo: this.enterpriseInfo,
comAddAccountCount: this.addAccountCount,
accountForm: {
accountList: []
},
rules: {
nickName: [{ required: true, trigger: ["blur"], validator: requiredStrLengthValidator("用户名称") }],
phonenumber: [{ required: true, trigger: ["blur", "change"], validator: phoneNumberValidator }]
}
};
},
//可访问data属性
created() {
},
//计算集
computed: {
},
//方法集
methods: {
dialogOpen() {
this.addAccount();
},
dialogClose() {
this.accountForm = this.$options.data.call(this).accountForm;
this.$emit("dialogClose");
},
removeAccount(uid) {
const index = this.accountForm.accountList.findIndex(item => item.uid == uid);
if (index > -1) {
this.accountForm.accountList.splice(index, 1);
}
},
addAccount() {
if (this.comAddAccountCount >= 6) return elementMessageSingleton("warning", "该租户下已经添加了五个账号");
if (this.accountForm.accountList?.length >= 5) return elementMessageSingleton("warning", "最多添加五个账号");
const remaining = 6 - this.comAddAccountCount;
const len = this.accountForm?.accountList?.length;
if (len >= remaining) return elementMessageSingleton("warning", `该租户下剩余可添加账号个数为 ${remaining} 个,现已添加 ${len} 个`);
this.accountForm.accountList.push({
nickName: "",
phonenumber: "",
uid: v4()
});
},
submitAdd() {
this.$refs["accountForm"].validate(async flag => {
if (!flag) return;
const { hasRepeat, repeatKey } = hasDuplicates(JSON.parse(JSON.stringify(this.accountForm.accountList)), "phonenumber");
if (hasRepeat) return elementMessageSingleton("warning", `电话号码 ${repeatKey} 不允许重复创建`);
const loadingService = Loading.service({
target: ".enterprise-add-account-dialog",
lock: true,
text: "正在添加账号,请勿关闭窗口"
});
let successCount = 0;
try {
// 验证通过提交信息
const array = (JSON.parse(JSON.stringify(this.accountForm.accountList))).map(({ nickName, phonenumber }) => ({ nickName, phonenumber }));
let len = array.length;
let count = 0;
while (count < len) {
try {
const result = await enterpriseAddAccountApi({
tenantId: this.comEnterpriseInfo.tenantId,
packageId: this.comEnterpriseInfo.packageId,
nickName: array[count].nickName,
phonenumber: array[count].phonenumber,
});
if (result.code == 200) {
successCount++;
// 进度加载
} else {
elementMessageSingleton("error", result.msg);
}
} catch (error) {
console.log(error);
} finally {
count++;
}
}
this.dialogStatus = false;
} catch (error) {
console.log(error);
} finally {
loadingService.close();
successCount > 0 ? elementMessageSingleton("success", "添加账号成功") : null;
}
});
}
},
}
</script>
<style lang="scss" scoped>
.enterprise-add-account {
::v-deep .enterprise-add-account-dialog {
.el-dialog__header {
display: flex;
align-items: center;
justify-content: space-between;
padding: 10px 20px;
border-bottom: 1px solid #eee;
box-sizing: border-box;
.el-dialog__title {
font-size: 16px;
}
.el-dialog__headerbtn {
position: static;
display: flex;
align-items: center;
}
}
.el-dialog__body {
padding: 20px;
box-sizing: border-box;
.enterprise-add-account-inner {
.el-form {
display: flex;
justify-content: space-between;
.enterprise-add-account-list {
display: flex;
flex-direction: column;
position: relative;
& > .enterprise-add-account-item:first-of-type {
margin-top: 0px;
}
.enterprise-add-account-item {
display: flex;
align-items: center;
margin-top: 15px;
&:hover {
.remove-account-item {
opacity: 1;
& > i {
cursor: pointer;
}
}
}
.account-phone {
margin-left: 30px;
}
.el-form-item {
display: flex;
margin-bottom: 0px;
.el-form-item__content,
.el-form-item__label {
line-height: 32px;
}
.el-input {
.el-input__inner {
line-height: 32px;
height: 32px;
&::placeholder {
color: #c0c4cc !important;
font-weight: 400 !important;
font-size: 12px;
}
}
.el-input__suffix {
display: flex;
align-items: center;
.el-input__icon {
line-height: 32px;
}
}
}
.el-form-item__error {
padding-top: 2px;
}
}
.remove-account-item {
display: flex;
align-items: center;
margin-left: 15px;
opacity: 0;
transition: opacity 0.3s;
& > i {
font-size: 16px;
&:hover {
color: #f56c6c;
}
}
}
}
}
.add-account-btn {
line-height: 32px;
align-self: flex-start;
cursor: pointer;
color: #1890ff;
font-size: 14px;
span {
margin-left: 5px;
}
}
}
}
}
.el-dialog__footer {
padding: 0px;
.add-account-footer {
display: flex;
align-items: center;
justify-content: flex-end;
padding: 20px;
border-top: 1px solid #eee;
box-sizing: border-box;
.el-button {
height: 32px;
line-height: 32px;
padding: 0px 20px;
box-sizing: border-box;
}
}
}
}
}
</style>
...@@ -24,7 +24,6 @@ ...@@ -24,7 +24,6 @@
<el-form-item prop="captchaCode" v-if="captchaEnabled"> <el-form-item prop="captchaCode" v-if="captchaEnabled">
<el-input <el-input
v-model="dxform.captchaCode" v-model="dxform.captchaCode"
@focus="getCode"
auto-complete="off" auto-complete="off"
placeholder="请输入图形验证码" placeholder="请输入图形验证码"
style="width: 196px;float: left;" style="width: 196px;float: left;"
...@@ -93,7 +92,6 @@ ...@@ -93,7 +92,6 @@
v-model="loginForm.code" v-model="loginForm.code"
auto-complete="off" auto-complete="off"
placeholder="请输入图形验证码" placeholder="请输入图形验证码"
@focus="getCode"
style="width: 196px;float: left;" style="width: 196px;float: left;"
@keyup.enter.native="handleLogin" @keyup.enter.native="handleLogin"
> >
......
...@@ -290,6 +290,8 @@ ...@@ -290,6 +290,8 @@
import skeleton from '../component/skeleton' import skeleton from '../component/skeleton'
import dataRegion from '@/assets/json/dataRegion' import dataRegion from '@/assets/json/dataRegion'
import { uipGroupData,urbanInvestmentPage,urbanInvestmentStatistics,claim,location,customerStatus,historyClaim,urbanInvestmentExport } from '@/api/macro/macro' import { uipGroupData,urbanInvestmentPage,urbanInvestmentStatistics,claim,location,customerStatus,historyClaim,urbanInvestmentExport } from '@/api/macro/macro'
import api from '@/api/enterpriseData/enterpriseData.js';
import { uipGroupData,urbanInvestmentPage,urbanInvestmentStatistics,claim,location,customerStatus,historyClaim } from '@/api/macro/macro'
import { infoHeader } from '@/api/detail/party-a/index' import { infoHeader } from '@/api/detail/party-a/index'
import Region from '../component/region' import Region from '../component/region'
import ExportDialog from "../../component/export-dialog" import ExportDialog from "../../component/export-dialog"
......
...@@ -57,7 +57,8 @@ export default { ...@@ -57,7 +57,8 @@ export default {
}, },
methods: { methods: {
linkListener(event) { linkListener(event) {
let { data } = event; let { data, origin } = event;
if (origin != this.domain) return;
if (data.id) { if (data.id) {
getUipIdByCid([data.id]).then(res => { getUipIdByCid([data.id]).then(res => {
if (res.code == 200) { if (res.code == 200) {
...@@ -73,9 +74,7 @@ export default { ...@@ -73,9 +74,7 @@ export default {
}); });
} else { } else {
if (data.url) { if (data.url) {
this.$tab.openPage(data.title, data.url).then(() => { this.$tab.openPage(data.title, data.url);
// 执行结束的逻辑
});
} }
} }
}, },
......
...@@ -93,8 +93,8 @@ ...@@ -93,8 +93,8 @@
<el-checkbox v-if="index<showNum" :label="item" :key="index">{{item}}</el-checkbox> <el-checkbox v-if="index<showNum" :label="item" :key="index">{{item}}</el-checkbox>
</template> </template>
</el-checkbox-group> </el-checkbox-group>
<span class="more" v-if="showNum==10" @click="showNum=99">更多<img src="@/assets/images/more.png" alt=""></span> <!--<span class="more" v-if="showNum==10" @click="showNum=99">更多<img src="@/assets/images/more.png" alt=""></span>-->
<span class="more more1" v-if="showNum==99" @click="showNum=10">收起<img src="@/assets/images/more.png" alt=""></span> <!--<span class="more more1" v-if="showNum==99" @click="showNum=10">收起<img src="@/assets/images/more.png" alt=""></span>-->
</div> </div>
</div> </div>
<div class="content_item content_item_padding0"> <div class="content_item content_item_padding0">
...@@ -729,6 +729,9 @@ export default { ...@@ -729,6 +729,9 @@ export default {
.ename_input { .ename_input {
width: 240px; width: 240px;
margin-right: 20px; margin-right: 20px;
::v-deep .el-input__inner::placeholder {
color: rgba(35, 35, 35, 0.2) !important;
}
} }
.keyword_checkbox { .keyword_checkbox {
margin-top: 6px; margin-top: 6px;
...@@ -737,7 +740,7 @@ export default { ...@@ -737,7 +740,7 @@ export default {
display: inline-block; display: inline-block;
} }
.checkbox_1122 { .checkbox_1122 {
width: 1122px; /*width: 1122px;*/
margin-right: 6px; margin-right: 6px;
} }
.el-checkbox { .el-checkbox {
......
<template>
<div class="iframe-com-ins" :style="stylesTransform(containerStyles)">
<iframe class="iframe-subsystem-ins" :src="url" marginwidth="0" marginheight="0" scrolling="no" frameborder="0" width="100%"
:style="stylesTransform(iframeInsStyles)"></iframe>
</div>
</template>
<script>
export default {
name: "iframeComIns",
props: {
// 容器样式
styles: {
type: [Object, String],
default: () => ("")
},
// iframe样式
iframeStyles: {
type: [Object, String],
default: () => ("")
},
// 子系统链接地址
url: {
type: String,
default: ""
}
},
watch: {
"styles": {
handler(newValue) {
this.containerStyles = newValue;
},
deep: true
},
"iframeStyles": {
handler(newValue) {
console.log(newValue);
this.iframeInsStyles = newValue;
},
deep: true
},
},
data() {
return {
containerStyles: this.styles,
iframeInsStyles: this.iframeStyles
};
},
//可访问data属性
created() {
},
//计算集
computed: {
},
//方法集
methods: {
stylesTransform(stylesStr) {
try {
const styles = typeof stylesStr == "string" ? JSON.parse(stylesStr) : stylesStr;
return styles ? styles : {};
} catch (error) {
return {};
}
}
},
}
</script>
<style lang="scss" scoped>
.iframe-com-ins {
width: 100%;
height: 100%;
box-sizing: border-box;
.iframe-subsystem-ins {
width: 100%;
height: 100%;
}
}
</style>
<template> <template>
<div class="subsystem-iframe-container"> <div class="subsystem-iframe-container">
<div @click="$router.push({path : '/subsystem',query : ({id:1})})">11</div> <iframe-com-ins ref="subsystemIframeContainer" :iframeStyles="urlQueryParams.iframeStyles" :styles="urlQueryParams.styles"
:url="urlQueryParams.url"></iframe-com-ins>
</div> </div>
</template> </template>
<script> <script>
import { getUrlSearchQuery } from "@/utils/"; import IframeComIns from "./components/IframeComIns";
import IframeTools from "@/utils/iframeTools";
export default { export default {
name: "subsystemIframeContainer", name: "subsystemIframeContainer",
components: {
IframeComIns
},
data() { data() {
return { return {
urlQueryParams: {},
iframeToolsIns: {}
}; };
}, },
//可访问data属性 //可访问data属性
created() { created() {
console.log(this.$route); this.Init();
console.log(getUrlSearchQuery()); },
beforeDestroy() {
if (this.iframeToolsIns) {
this.iframeToolsIns.clearRefreshTimer ? this.iframeToolsIns.clearRefreshTimer() : null;
}
}, },
//计算集 //计算集
computed: { computed: {
...@@ -23,12 +33,15 @@ export default { ...@@ -23,12 +33,15 @@ export default {
}, },
//方法集 //方法集
methods: { methods: {
async Init() {
await this.$nextTick();
const dom = this.$refs["subsystemIframeContainer"].$el.querySelector("iframe");
const iframeTools = new IframeTools(dom);
this.iframeToolsIns = iframeTools;
this.urlQueryParams = iframeTools.queryParams;
console.log(this.urlQueryParams);
}
}, },
// 渲染方法
render(createElement) {
}
} }
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
...@@ -38,7 +51,6 @@ export default { ...@@ -38,7 +51,6 @@ export default {
left: 0; left: 0;
width: 100%; width: 100%;
height: 100%; height: 100%;
padding: 16px 24px;
box-sizing: border-box; box-sizing: border-box;
} }
</style> </style>
<template> <template>
<div class="app-container"> <div class="app-container">
<el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch"> <el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch">
<el-form-item label="用户名称" prop="userName"> <el-form-item label="用户名称" prop="userName">
<el-input <el-input v-model="queryParams.userName" placeholder="请输入用户名称" clearable style="width: 240px" @keyup.enter.native="handleQuery" />
v-model="queryParams.userName"
placeholder="请输入用户名称"
clearable
style="width: 240px"
@keyup.enter.native="handleQuery"
/>
</el-form-item> </el-form-item>
<el-form-item label="手机号码" prop="phonenumber"> <el-form-item label="手机号码" prop="phonenumber">
<el-input <el-input v-model="queryParams.phonenumber" placeholder="请输入手机号码" clearable style="width: 240px" @keyup.enter.native="handleQuery" />
v-model="queryParams.phonenumber"
placeholder="请输入手机号码"
clearable
style="width: 240px"
@keyup.enter.native="handleQuery"
/>
</el-form-item> </el-form-item>
<el-form-item> <el-form-item>
<el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button> <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
...@@ -27,47 +15,29 @@ ...@@ -27,47 +15,29 @@
<el-row :gutter="10" class="mb8"> <el-row :gutter="10" class="mb8">
<el-col :span="1.5"> <el-col :span="1.5">
<el-button <el-button type="primary" plain icon="el-icon-plus" size="mini" @click="openSelectUser" v-hasPermi="['system:role:add']">添加用户</el-button>
type="primary"
plain
icon="el-icon-plus"
size="mini"
@click="openSelectUser"
v-hasPermi="['system:role:add']"
>添加用户</el-button>
</el-col> </el-col>
<el-col :span="1.5"> <el-col :span="1.5">
<el-button <el-button type="danger" plain icon="el-icon-circle-close" size="mini" :disabled="multiple" @click="cancelAuthUserAll"
type="danger" v-hasPermi="['system:role:remove']">批量取消授权</el-button>
plain
icon="el-icon-circle-close"
size="mini"
:disabled="multiple"
@click="cancelAuthUserAll"
v-hasPermi="['system:role:remove']"
>批量取消授权</el-button>
</el-col> </el-col>
<el-col :span="1.5"> <el-col :span="1.5">
<el-button <el-button type="warning" plain icon="el-icon-close" size="mini" @click="handleClose">关闭</el-button>
type="warning"
plain
icon="el-icon-close"
size="mini"
@click="handleClose"
>关闭</el-button>
</el-col> </el-col>
<right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar> <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
</el-row> </el-row>
<el-table v-loading="loading" :data="userList" @selection-change="handleSelectionChange"> <el-table v-loading="loading" :data="userList" @selection-change="handleSelectionChange">
<el-table-column type="selection" width="55" align="center" /> <el-table-column type="selection" width="55" align="center" />
<el-table-column label="用户名称" prop="userName" :show-overflow-tooltip="true" /> <el-table-column label="用户编号" align="center" prop="userId" />
<el-table-column label="用户昵称" prop="nickName" :show-overflow-tooltip="true" /> <!-- <el-table-column label="用户名称" prop="userName" :show-overflow-tooltip="true" /> -->
<el-table-column label="邮箱" prop="email" :show-overflow-tooltip="true" /> <el-table-column label="用户名称" prop="nickName" align="center" :show-overflow-tooltip="true" />
<el-table-column label="手机" prop="phonenumber" :show-overflow-tooltip="true" /> <el-table-column label="组织" align="center" prop="dept.deptName" :show-overflow-tooltip="true" />
<!-- <el-table-column label="邮箱" prop="email" :show-overflow-tooltip="true" /> -->
<el-table-column label="手机" prop="phonenumber" align="center" :show-overflow-tooltip="true" />
<el-table-column label="状态" align="center" prop="status"> <el-table-column label="状态" align="center" prop="status">
<template slot-scope="scope"> <template slot-scope="scope">
<dict-tag :options="dict.type.sys_normal_disable" :value="scope.row.status"/> <dict-tag :options="dict.type.sys_normal_disable" :value="scope.row.status" />
</template> </template>
</el-table-column> </el-table-column>
<el-table-column label="创建时间" align="center" prop="createTime" width="180"> <el-table-column label="创建时间" align="center" prop="createTime" width="180">
...@@ -77,24 +47,13 @@ ...@@ -77,24 +47,13 @@
</el-table-column> </el-table-column>
<el-table-column label="操作" align="center" class-name="small-padding fixed-width"> <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
<template slot-scope="scope"> <template slot-scope="scope">
<el-button <el-button size="mini" type="text" icon="el-icon-circle-close" @click="cancelAuthUser(scope.row)"
size="mini" v-hasPermi="['system:role:remove']">取消授权</el-button>
type="text"
icon="el-icon-circle-close"
@click="cancelAuthUser(scope.row)"
v-hasPermi="['system:role:remove']"
>取消授权</el-button>
</template> </template>
</el-table-column> </el-table-column>
</el-table> </el-table>
<pagination <pagination v-show="total>0" :total="total" :page.sync="queryParams.pageNum" :limit.sync="queryParams.pageSize" @pagination="getList" />
v-show="total>0"
:total="total"
:page.sync="queryParams.pageNum"
:limit.sync="queryParams.pageSize"
@pagination="getList"
/>
<select-user ref="select" :roleId="queryParams.roleId" @ok="handleQuery" /> <select-user ref="select" :roleId="queryParams.roleId" @ok="handleQuery" />
</div> </div>
</template> </template>
...@@ -143,10 +102,10 @@ export default { ...@@ -143,10 +102,10 @@ export default {
getList() { getList() {
this.loading = true; this.loading = true;
allocatedUserList(this.queryParams).then(response => { allocatedUserList(this.queryParams).then(response => {
this.userList = response.rows; this.userList = response.rows;
this.total = response.total; this.total = response.total;
this.loading = false; this.loading = false;
} }
); );
}, },
// 返回按钮 // 返回按钮
...@@ -166,8 +125,8 @@ export default { ...@@ -166,8 +125,8 @@ export default {
}, },
// 多选框选中数据 // 多选框选中数据
handleSelectionChange(selection) { handleSelectionChange(selection) {
this.userIds = selection.map(item => item.userId) this.userIds = selection.map(item => item.userId);
this.multiple = !selection.length this.multiple = !selection.length;
}, },
/** 打开授权用户表弹窗 */ /** 打开授权用户表弹窗 */
openSelectUser() { openSelectUser() {
...@@ -176,23 +135,37 @@ export default { ...@@ -176,23 +135,37 @@ export default {
/** 取消授权按钮操作 */ /** 取消授权按钮操作 */
cancelAuthUser(row) { cancelAuthUser(row) {
const roleId = this.queryParams.roleId; const roleId = this.queryParams.roleId;
this.$modal.confirm('确认要取消该用户"' + row.userName + '"角色吗?').then(function() { this.$modal.confirm('确认要取消该用户"' + row.userName + '"角色吗?').then(async () => {
return authUserCancel({ userId: row.userId, roleId: roleId }); try {
}).then(() => { const result = await authUserCancel({ userId: row.userId, roleId: roleId });
this.getList(); if (result.code == 200) {
this.$modal.msgSuccess("取消授权成功"); this.getList();
}).catch(() => {}); this.$modal.msgSuccess("取消授权成功");
} else {
this.$message.error(result.msg);
}
} catch (error) {
}
}).catch(() => { });
}, },
/** 批量取消授权按钮操作 */ /** 批量取消授权按钮操作 */
cancelAuthUserAll(row) { cancelAuthUserAll(row) {
const roleId = this.queryParams.roleId; const roleId = this.queryParams.roleId;
const userIds = this.userIds.join(","); const userIds = this.userIds.join(",");
this.$modal.confirm('是否取消选中用户授权数据项?').then(function() { this.$modal.confirm('是否取消选中用户授权数据项?').then(async () => {
return authUserCancelAll({ roleId: roleId, userIds: userIds }); try {
}).then(() => { const result = await authUserCancelAll({ roleId: roleId, userIds: userIds });
this.getList(); if (result.code == 200) {
this.$modal.msgSuccess("取消授权成功"); this.getList();
}).catch(() => {}); this.$modal.msgSuccess("取消授权成功");
} else {
this.$message.error(`${result.msg}账号下仅有一个角色,取消授权失败`);
}
} catch (error) {
}
}).catch(() => { });
} }
} }
}; };
......
...@@ -26,9 +26,11 @@ ...@@ -26,9 +26,11 @@
<el-row> <el-row>
<el-table @row-click="clickRow" ref="table" :data="userList" @selection-change="handleSelectionChange" height="260px"> <el-table @row-click="clickRow" ref="table" :data="userList" @selection-change="handleSelectionChange" height="260px">
<el-table-column type="selection" width="55"></el-table-column> <el-table-column type="selection" width="55"></el-table-column>
<el-table-column label="用户名称" prop="userName" :show-overflow-tooltip="true" /> <!-- <el-table-column label="用户名称" prop="userName" :show-overflow-tooltip="true" /> -->
<el-table-column label="用户昵称" prop="nickName" :show-overflow-tooltip="true" /> <el-table-column label="用户编号" align="center" prop="userId" />
<el-table-column label="邮箱" prop="email" :show-overflow-tooltip="true" /> <el-table-column label="用户名称" prop="nickName" align="center" :show-overflow-tooltip="true" />
<el-table-column label="组织" align="center" prop="dept.deptName" :show-overflow-tooltip="true" />
<!-- <el-table-column label="邮箱" prop="email" :show-overflow-tooltip="true" /> -->
<el-table-column label="手机" prop="phonenumber" :show-overflow-tooltip="true" /> <el-table-column label="手机" prop="phonenumber" :show-overflow-tooltip="true" />
<el-table-column label="状态" align="center" prop="status"> <el-table-column label="状态" align="center" prop="status">
<template slot-scope="scope"> <template slot-scope="scope">
......
'use strict' 'use strict';
const path = require('path') const path = require('path');
function resolve(dir) { function resolve(dir) {
return path.join(__dirname, dir) return path.join(__dirname, dir);
} }
const CompressionPlugin = require('compression-webpack-plugin') const CompressionPlugin = require('compression-webpack-plugin');
const name = process.env.VUE_APP_TITLE || '数字化经营履约全生命链路管理系统' // 网页标题 const name = process.env.VUE_APP_TITLE || '数字化经营履约全生命链路管理系统'; // 网页标题
const port = process.env.port || process.env.npm_config_port || 80 // 端口 const port = process.env.port || process.env.npm_config_port || 80; // 端口
// vue.config.js 配置说明 // vue.config.js 配置说明
//官方vue.config.js 参考文档 https://cli.vuejs.org/zh/config/#css-loaderoptions //官方vue.config.js 参考文档 https://cli.vuejs.org/zh/config/#css-loaderoptions
// 这里只列一部分,具体配置参考文档 // 这里只列一部分,具体配置参考文档
module.exports = { module.exports = {
transpileDependencies: ['json-editor-vue'],
// 部署生产环境和开发环境下的URL。 // 部署生产环境和开发环境下的URL。
// 默认情况下,Vue CLI 会假设你的应用是被部署在一个域名的根路径上 // 默认情况下,Vue CLI 会假设你的应用是被部署在一个域名的根路径上
// 例如 https://www.ruoyi.vip/。如果应用被部署在一个子路径上,你就需要用这个选项指定这个子路径。例如,如果你的应用被部署在 https://www.ruoyi.vip/admin/,则设置 baseUrl 为 /admin/。 // 例如 https://www.ruoyi.vip/。如果应用被部署在一个子路径上,你就需要用这个选项指定这个子路径。例如,如果你的应用被部署在 https://www.ruoyi.vip/admin/,则设置 baseUrl 为 /admin/。
...@@ -37,7 +38,8 @@ module.exports = { ...@@ -37,7 +38,8 @@ module.exports = {
target: `http://47.104.91.229:9099/prod-api`,//测试 target: `http://47.104.91.229:9099/prod-api`,//测试
// target: `https://szhapi.jiansheku.com`,//线上 // target: `https://szhapi.jiansheku.com`,//线上
// target: `http://122.9.160.122:9011`, //线上 // target: `http://122.9.160.122:9011`, //线上
// target: `http://192.168.0.165:9098`,//施 // target: `http://192.168.0.165:9098`,//施-无线
// target: `http://192.168.60.46:9098`,//施-有线
// target: `http://192.168.60.6:9098`,//谭 // target: `http://192.168.60.6:9098`,//谭
changeOrigin: true, changeOrigin: true,
pathRewrite: { pathRewrite: {
...@@ -73,14 +75,14 @@ module.exports = { ...@@ -73,14 +75,14 @@ module.exports = {
], ],
}, },
chainWebpack(config) { chainWebpack(config) {
config.plugins.delete('preload') // TODO: need test config.plugins.delete('preload'); // TODO: need test
config.plugins.delete('prefetch') // TODO: need test config.plugins.delete('prefetch'); // TODO: need test
// set svg-sprite-loader // set svg-sprite-loader
config.module config.module
.rule('svg') .rule('svg')
.exclude.add(resolve('src/assets/icons')) .exclude.add(resolve('src/assets/icons'))
.end() .end();
config.module config.module
.rule('icons') .rule('icons')
.test(/\.svg$/) .test(/\.svg$/)
...@@ -91,7 +93,15 @@ module.exports = { ...@@ -91,7 +93,15 @@ module.exports = {
.options({ .options({
symbolId: 'icon-[name]' symbolId: 'icon-[name]'
}) })
.end();
config.module
.rule("mjs")
.test(/\.mjs$/)
.include.add(/node_modules/)
.end() .end()
.type("javascript/auto");
config config
.when(process.env.NODE_ENV !== 'development', .when(process.env.NODE_ENV !== 'development',
...@@ -100,10 +110,10 @@ module.exports = { ...@@ -100,10 +110,10 @@ module.exports = {
.plugin('ScriptExtHtmlWebpackPlugin') .plugin('ScriptExtHtmlWebpackPlugin')
.after('html') .after('html')
.use('script-ext-html-webpack-plugin', [{ .use('script-ext-html-webpack-plugin', [{
// `runtime` must same as runtimeChunk name. default is `runtime` // `runtime` must same as runtimeChunk name. default is `runtime`
inline: /runtime\..*\.js$/ inline: /runtime\..*\.js$/
}]) }])
.end() .end();
config config
.optimization.splitChunks({ .optimization.splitChunks({
chunks: 'all', chunks: 'all',
...@@ -127,13 +137,13 @@ module.exports = { ...@@ -127,13 +137,13 @@ module.exports = {
reuseExistingChunk: true reuseExistingChunk: true
} }
} }
}) });
config.optimization.runtimeChunk('single'), config.optimization.runtimeChunk('single'),
{ {
from: path.resolve(__dirname, './public/robots.txt'), //防爬虫文件 from: path.resolve(__dirname, './public/robots.txt'), //防爬虫文件
to: './' //到根目录下 to: './' //到根目录下
} };
} }
) );
} }
} };
\ No newline at end of file
...@@ -51,7 +51,7 @@ public class SysRole extends TenantEntity { ...@@ -51,7 +51,7 @@ public class SysRole extends TenantEntity {
* 角色权限 * 角色权限
*/ */
@ExcelProperty(value = "角色权限") @ExcelProperty(value = "角色权限")
@NotBlank(message = "权限字符不能为空") //@NotBlank(message = "权限字符不能为空")
@Size(min = 0, max = 100, message = "权限字符长度不能超过{max}个字符") @Size(min = 0, max = 100, message = "权限字符长度不能超过{max}个字符")
private String roleKey; private String roleKey;
......
...@@ -2,6 +2,7 @@ package com.dsk.system.service; ...@@ -2,6 +2,7 @@ package com.dsk.system.service;
import com.dsk.common.core.domain.PageQuery; import com.dsk.common.core.domain.PageQuery;
import com.dsk.common.core.page.TableDataInfo; import com.dsk.common.core.page.TableDataInfo;
import com.dsk.system.domain.bo.SysTenantAdminBo;
import com.dsk.system.domain.bo.SysTenantBo; import com.dsk.system.domain.bo.SysTenantBo;
import com.dsk.system.domain.vo.SysTenantVo; import com.dsk.system.domain.vo.SysTenantVo;
...@@ -44,6 +45,14 @@ public interface ISysTenantService { ...@@ -44,6 +45,14 @@ public interface ISysTenantService {
*/ */
Boolean insertByBo(SysTenantBo bo); Boolean insertByBo(SysTenantBo bo);
/**
* 新增企业普通管理员账号
*
* @param tenantAdminBo 用户信息
* @return 结果
*/
Boolean addTenantAdmin(SysTenantAdminBo tenantAdminBo);
/** /**
* 校验租户是否允许操作 * 校验租户是否允许操作
*/ */
......
This diff is collapsed.
Markdown is supported
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