subscribed;
93 |
94 | @Data
95 | public static class GraphSubConfig {
96 |
97 | /**
98 | * skuName
99 | */
100 | private String skuName;
101 |
102 | /**
103 | * 显示名称
104 | */
105 | private String displayName;
106 |
107 | /**
108 | * skuId
109 | */
110 | private String skuId;
111 |
112 | }
113 |
114 | /**
115 | * 获取对应订阅的配置
116 | *
117 | * @param skuName 订阅名称
118 | * @return 配置
119 | */
120 | public GraphProperties.GraphSubConfig getSubConfig(String skuName) {
121 | for (GraphProperties.GraphSubConfig maConfig : subscribed) {
122 | if (maConfig.getSkuName().equals(skuName)) {
123 | return maConfig;
124 | }
125 | }
126 | return subscribed.get(0);
127 | }
128 |
129 | public String getSubConfigName(String skuId) {
130 | for (GraphProperties.GraphSubConfig maConfig : subscribed) {
131 | if (maConfig.getSkuId().equals(skuId)) {
132 | return maConfig.getSkuName();
133 | }
134 | }
135 | return skuId;
136 | }
137 |
138 | public String getSubConfigDisplayName(String skuId) {
139 | for (GraphProperties.GraphSubConfig maConfig : subscribed) {
140 | if (maConfig.getSkuId().equals(skuId)) {
141 | return maConfig.getDisplayName();
142 | }
143 | }
144 | return null;
145 | }
146 |
147 | public String[] listUsageLocation(String appName) {
148 | String usageLocations = getConfig(appName).getUsageLocation();
149 | if (StringUtils.isEmpty(usageLocations)) {
150 | usageLocations = getUsageLocation();
151 | if (StringUtils.isEmpty(usageLocations)) {
152 | return new String[]{"HK"};
153 | }
154 | }
155 | return usageLocations.split(",");
156 | }
157 | }
158 |
--------------------------------------------------------------------------------
/src/main/java/cn/itbat/microsoft/config/ThreadPoolConfig.java:
--------------------------------------------------------------------------------
1 | package cn.itbat.microsoft.config;
2 |
3 | import org.springframework.context.annotation.Bean;
4 | import org.springframework.context.annotation.Configuration;
5 | import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
6 |
7 | import java.util.concurrent.ThreadPoolExecutor;
8 |
9 | /**
10 | * 线程池
11 | *
12 | * 使用方法 @Async("asyncPoolTaskExecutor")
13 | *
14 | * @author mjj (;¬_¬)
15 | * @version 1.0
16 | * @date 2019/6/11 19:27
17 | */
18 | @Configuration
19 | public class ThreadPoolConfig {
20 |
21 | /**
22 | * 配置线程池
23 | *
24 | * @return 线程池
25 | */
26 | @Bean(name = "asyncPoolTaskExecutor")
27 | public ThreadPoolTaskExecutor getAsyncThreadPoolTaskExecutor() {
28 | ThreadPoolTaskExecutor taskExecutor = new ThreadPoolTaskExecutor();
29 | taskExecutor.setCorePoolSize(20);
30 | taskExecutor.setMaxPoolSize(200);
31 | taskExecutor.setQueueCapacity(25);
32 | taskExecutor.setKeepAliveSeconds(200);
33 | taskExecutor.setThreadNamePrefix("microsoft-async-");
34 | // 设置线程池关闭的时候等待所有任务都完成再继续销毁其他的Bean
35 | taskExecutor.setWaitForTasksToCompleteOnShutdown(true);
36 | // 设置线程池中任务的等待时间,如果超过这个时候还没有销毁就强制销毁,以确保应⽤最后能够被关闭,⽽不是阻塞住。
37 | taskExecutor.setAwaitTerminationSeconds(60);
38 | // 线程池对拒绝任务(无线程可用)的处理策略,目前只支持AbortPolicy、CallerRunsPolicy;默认为后者
39 | taskExecutor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
40 | taskExecutor.initialize();
41 | return taskExecutor;
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/src/main/java/cn/itbat/microsoft/controller/FrontDeskController.java:
--------------------------------------------------------------------------------
1 | package cn.itbat.microsoft.controller;
2 |
3 | import cn.itbat.microsoft.config.GraphProperties;
4 | import cn.itbat.microsoft.service.FrontDeskService;
5 | import cn.itbat.microsoft.vo.BaseResultVo;
6 | import cn.itbat.microsoft.vo.GraphUserVo;
7 | import org.springframework.util.StringUtils;
8 | import org.springframework.web.bind.annotation.GetMapping;
9 | import org.springframework.web.bind.annotation.PostMapping;
10 | import org.springframework.web.bind.annotation.RequestMapping;
11 | import org.springframework.web.bind.annotation.RestController;
12 |
13 | import javax.annotation.Resource;
14 |
15 | /**
16 | * 前台
17 | *
18 | * @author huahui.wu
19 | * @date 2020年11月24日 16:32:52
20 | */
21 | @RestController
22 | @RequestMapping("/front")
23 | public class FrontDeskController {
24 |
25 | @Resource
26 | private FrontDeskService frontDeskService;
27 |
28 | @Resource
29 | private GraphProperties graphProperties;
30 |
31 | @GetMapping("/listLicense")
32 | public BaseResultVo listLicense() {
33 | return BaseResultVo.success(frontDeskService.listLicense());
34 | }
35 |
36 | @PostMapping("/create")
37 | public BaseResultVo createUser(GraphUserVo graphUserVo) {
38 |
39 | // 参数判断
40 | if (graphUserVo == null) {
41 | return BaseResultVo.error("参数为空!");
42 | }
43 | if (StringUtils.isEmpty(graphUserVo.getAppName())) {
44 | return BaseResultVo.error("参数为空!");
45 | }
46 | if (StringUtils.isEmpty(graphUserVo.getCode())) {
47 | return BaseResultVo.error("邀请码为空!");
48 | }
49 | if (StringUtils.isEmpty(graphUserVo.getSkuId())) {
50 | return BaseResultVo.error("订阅为空!");
51 | }
52 | if (StringUtils.isEmpty(graphUserVo.getPassword())) {
53 | return BaseResultVo.error("密码为空!");
54 | }
55 | if (StringUtils.isEmpty(graphUserVo.getMailNickname())) {
56 | return BaseResultVo.error("邮箱前缀为空!");
57 | }
58 | if (StringUtils.isEmpty(graphUserVo.getDisplayName())) {
59 | return BaseResultVo.error("用户名为空!");
60 | }
61 | return BaseResultVo.success(frontDeskService.create(graphUserVo));
62 | }
63 |
64 | /**
65 | * 查询可注册地区
66 | *
67 | * @param appName 组织类型
68 | * @return 地区
69 | */
70 | @GetMapping("/listUsageLocation")
71 | public BaseResultVo listUsageLocation(String appName) {
72 | return BaseResultVo.success(graphProperties.listUsageLocation(appName));
73 | }
74 | }
75 |
--------------------------------------------------------------------------------
/src/main/java/cn/itbat/microsoft/controller/InvitationCodeController.java:
--------------------------------------------------------------------------------
1 | package cn.itbat.microsoft.controller;
2 |
3 | import cn.itbat.microsoft.model.Pager;
4 | import cn.itbat.microsoft.model.entity.InvitationCode;
5 | import cn.itbat.microsoft.service.InvitationCodeService;
6 | import cn.itbat.microsoft.vo.BaseResultVo;
7 | import lombok.extern.slf4j.Slf4j;
8 | import org.springframework.web.bind.annotation.GetMapping;
9 | import org.springframework.web.bind.annotation.PostMapping;
10 | import org.springframework.web.bind.annotation.RequestMapping;
11 | import org.springframework.web.bind.annotation.RestController;
12 |
13 | import javax.annotation.Resource;
14 |
15 | /**
16 | * @author huahui.wu
17 | * @date 2020年11月24日 16:15:19
18 | */
19 | @Slf4j
20 | @RestController
21 | @RequestMapping("/microsoft/code")
22 | public class InvitationCodeController {
23 |
24 | @Resource
25 | private InvitationCodeService invitationCodeService;
26 |
27 | @GetMapping("/getCodeStatistics")
28 | public BaseResultVo getCodeStatistics() {
29 | return BaseResultVo.success(invitationCodeService.getStatistics());
30 | }
31 |
32 | @GetMapping("/list")
33 | public BaseResultVo list(InvitationCode invitationCode, Pager pager) {
34 | return BaseResultVo.success(invitationCodeService.list(invitationCode, pager));
35 | }
36 |
37 | @PostMapping("/generate")
38 | public BaseResultVo generate(Integer num) {
39 | invitationCodeService.generateInvitationCode(num);
40 | return BaseResultVo.success();
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/src/main/java/cn/itbat/microsoft/controller/SystemController.java:
--------------------------------------------------------------------------------
1 | package cn.itbat.microsoft.controller;
2 |
3 |
4 | import cn.itbat.microsoft.model.support.SystemMonitorInfo;
5 | import cn.itbat.microsoft.vo.BaseResultVo;
6 | import org.springframework.web.bind.annotation.GetMapping;
7 | import org.springframework.web.bind.annotation.RequestMapping;
8 | import org.springframework.web.bind.annotation.RestController;
9 |
10 |
11 | /**
12 | * 系统 Controller
13 | *
14 | * @author mjj
15 | * @date 2020年08月11日 09:50:37
16 | */
17 | @RestController
18 | @RequestMapping("/system")
19 | public class SystemController {
20 |
21 | /**
22 | * 获取系统监控信息
23 | */
24 | @GetMapping("/monitor")
25 | public BaseResultVo monitor() {
26 | return BaseResultVo.success(new SystemMonitorInfo());
27 | }
28 |
29 | }
--------------------------------------------------------------------------------
/src/main/java/cn/itbat/microsoft/enums/AccountStatusEnum.java:
--------------------------------------------------------------------------------
1 | package cn.itbat.microsoft.enums;
2 |
3 | import lombok.Getter;
4 |
5 | /**
6 | * sku订阅状态
7 | *
8 | * @author mjj
9 | * @date 2019年09月24日 15:41:15
10 | */
11 | @Getter
12 | public enum AccountStatusEnum {
13 |
14 | /**
15 | * 禁用
16 | */
17 | DISABLE(Boolean.FALSE, "禁用"),
18 |
19 | /**
20 | * 启用
21 | */
22 | ENABLE(Boolean.TRUE, "启用"),
23 |
24 | ;
25 |
26 |
27 | private Boolean type;
28 |
29 | private String name;
30 |
31 |
32 | AccountStatusEnum(Boolean type, String name) {
33 | this.name = name;
34 | this.type = type;
35 | }
36 |
37 | public static AccountStatusEnum parse(Boolean type) {
38 | for (AccountStatusEnum item : values()) {
39 | if (item.getType().equals(type)) {
40 | return item;
41 | }
42 | }
43 | return null;
44 | }
45 |
46 | public static String getName(Boolean type) {
47 | for (AccountStatusEnum item : values()) {
48 | if (item.getType().equals(type)) {
49 | return item.getName();
50 | }
51 | }
52 | return null;
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/src/main/java/cn/itbat/microsoft/enums/CapabilityStatusEnum.java:
--------------------------------------------------------------------------------
1 | package cn.itbat.microsoft.enums;
2 |
3 | import lombok.Getter;
4 |
5 | /**
6 | * sku订阅状态
7 | *
8 | * @author mjj
9 | * @date 2019年09月24日 15:41:15
10 | */
11 | @Getter
12 | public enum CapabilityStatusEnum {
13 |
14 | /**
15 | * 禁用
16 | */
17 | ENABLE("Enabled", "启用"),
18 |
19 | /**
20 | * 启用
21 | */
22 | WARNING("Warning", "警告"),
23 |
24 | /**
25 | * 启用
26 | */
27 | SUSPENDED("Suspended", "暂停"),
28 |
29 | /**
30 | * 启用
31 | */
32 | DELETED("Deleted", "删除"),
33 |
34 | /**
35 | * 启用
36 | */
37 | LOCKED_OUT("锁定", "锁定"),
38 |
39 |
40 | ;
41 |
42 |
43 | private String type;
44 |
45 | private String name;
46 |
47 |
48 | CapabilityStatusEnum(String type, String name) {
49 | this.name = name;
50 | this.type = type;
51 | }
52 |
53 | public static CapabilityStatusEnum parse(String type) {
54 | for (CapabilityStatusEnum item : values()) {
55 | if (item.getType().equals(type)) {
56 | return item;
57 | }
58 | }
59 | return null;
60 | }
61 |
62 | public static String getName(String type) {
63 | for (CapabilityStatusEnum item : values()) {
64 | if (item.getType().equals(type)) {
65 | return item.getName();
66 | }
67 | }
68 | return null;
69 | }
70 | }
71 |
--------------------------------------------------------------------------------
/src/main/java/cn/itbat/microsoft/enums/RefreshTypeEnum.java:
--------------------------------------------------------------------------------
1 | package cn.itbat.microsoft.enums;
2 |
3 | import lombok.Getter;
4 |
5 | /**
6 | * 刷新缓存类型
7 | *
8 | * @author mjj
9 | * @date 2019年09月24日 15:41:15
10 | */
11 | @Getter
12 | public enum RefreshTypeEnum {
13 |
14 | /**
15 | * 禁用
16 | */
17 | USER(1, "用户"),
18 |
19 | /**
20 | * 启用
21 | */
22 | SUB(2, "订阅"),
23 |
24 | /**
25 | * 启用
26 | */
27 | DOMAIN(3, "域名"),
28 | ;
29 |
30 |
31 | private Integer type;
32 |
33 | private String name;
34 |
35 |
36 | RefreshTypeEnum(Integer type, String name) {
37 | this.name = name;
38 | this.type = type;
39 | }
40 |
41 | public static RefreshTypeEnum parse(Integer type) {
42 | for (RefreshTypeEnum item : values()) {
43 | if (item.getType().equals(type)) {
44 | return item;
45 | }
46 | }
47 | return null;
48 | }
49 |
50 | public static String getName(Integer type) {
51 | for (RefreshTypeEnum item : values()) {
52 | if (item.getType().equals(type)) {
53 | return item.getName();
54 | }
55 | }
56 | return null;
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/src/main/java/cn/itbat/microsoft/model/GraphUser.java:
--------------------------------------------------------------------------------
1 | package cn.itbat.microsoft.model;
2 |
3 | import com.fasterxml.jackson.annotation.JsonFormat;
4 | import lombok.AllArgsConstructor;
5 | import lombok.Builder;
6 | import lombok.Data;
7 | import lombok.NoArgsConstructor;
8 | import org.springframework.format.annotation.DateTimeFormat;
9 |
10 | /**
11 | * office 365 用户
12 | *
13 | * @author mjj
14 | * @date 2020年05月12日 15:59:03
15 | */
16 | @Data
17 | @Builder
18 | @NoArgsConstructor
19 | @AllArgsConstructor
20 | public class GraphUser {
21 |
22 | /**
23 | * 用户id
24 | */
25 | private String userId;
26 |
27 | /**
28 | * 订阅
29 | */
30 | private String skuId;
31 |
32 | /**
33 | * 订阅类型
34 | */
35 | private String skuType;
36 |
37 |
38 | /**
39 | * 域名
40 | */
41 | private String domain;
42 |
43 | /**
44 | * 姓
45 | */
46 | private String surname;
47 |
48 | /**
49 | * 姓
50 | */
51 | private String givenName;
52 |
53 | /**
54 | * 显示名称
55 | */
56 | private String displayName;
57 |
58 | /**
59 | * 邮箱前缀
60 | */
61 | private String mailNickname;
62 |
63 | /**
64 | * 用户名
65 | */
66 | private String userPrincipalName;
67 |
68 | /**
69 | * 密码
70 | */
71 | private String password;
72 |
73 | /**
74 | * 密码类型
75 | */
76 | @Builder.Default
77 | private String passwordPolicies = "DisablePasswordExpiration, DisableStrongPassword";
78 |
79 | /**
80 | * 手机号码
81 | */
82 | private String mobilePhone;
83 |
84 | /**
85 | * 邮箱
86 | */
87 | private String mail;
88 |
89 | /**
90 | * 公司名
91 | */
92 | private String companyName;
93 |
94 | /**
95 | * 位置
96 | */
97 | @Builder.Default
98 | private String usageLocation = "CN";
99 |
100 | /**
101 | * 街道地址
102 | */
103 | private String streetAddress;
104 |
105 | /**
106 | * 城市
107 | */
108 | private String city;
109 |
110 | /**
111 | * 省
112 | */
113 | private String state;
114 |
115 | /**
116 | * 国家
117 | */
118 | private String country;
119 |
120 | /**
121 | * 是否启用
122 | */
123 | @Builder.Default
124 | private Boolean accountEnabled = true;
125 |
126 | /**
127 | * 用户创建时间
128 | */
129 | @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
130 | @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
131 | private String createdDateTime;
132 |
133 |
134 | }
135 |
--------------------------------------------------------------------------------
/src/main/java/cn/itbat/microsoft/model/Pager.java:
--------------------------------------------------------------------------------
1 | package cn.itbat.microsoft.model;
2 |
3 | import lombok.Data;
4 |
5 | /**
6 | * 分页参数
7 | *
8 | * @author mjj
9 | * @date 2020年05月12日 16:30:29
10 | */
11 | @Data
12 | public class Pager {
13 |
14 |
15 | /**
16 | * 当前页码
17 | */
18 | private Integer pageIndex;
19 |
20 | /**
21 | * 每页数量
22 | */
23 | private Integer pageSize;
24 |
25 | /**
26 | * 排序 公共枚举 SqlOrderByEnum
27 | */
28 | private Integer orderByClause;
29 |
30 |
31 | public Pager() {
32 |
33 | }
34 |
35 | public Pager(Integer orderByClause) {
36 | this.orderByClause = orderByClause;
37 | }
38 |
39 | public Pager(Integer pageIndex, Integer pageSize, Integer orderByClause) {
40 | this.pageIndex = pageIndex;
41 | this.pageSize = pageSize;
42 | this.orderByClause = orderByClause;
43 | }
44 |
45 | public Pager(Integer pageIndex, Integer pageSize) {
46 | this.pageIndex = pageIndex;
47 | this.pageSize = pageSize;
48 | }
49 | }
--------------------------------------------------------------------------------
/src/main/java/cn/itbat/microsoft/model/entity/InvitationCode.java:
--------------------------------------------------------------------------------
1 | package cn.itbat.microsoft.model.entity;
2 |
3 | import com.fasterxml.jackson.annotation.JsonFormat;
4 | import lombok.AllArgsConstructor;
5 | import lombok.Builder;
6 | import lombok.Data;
7 | import lombok.NoArgsConstructor;
8 | import org.springframework.format.annotation.DateTimeFormat;
9 |
10 | import javax.persistence.Entity;
11 | import javax.persistence.GeneratedValue;
12 | import javax.persistence.GenerationType;
13 | import javax.persistence.Id;
14 | import java.util.Date;
15 |
16 | /**
17 | * @author huahui.wu
18 | * @date 2020年11月24日 14:53:11
19 | */
20 | @Entity(name = "INVITATION_CODE")
21 | @Data
22 | @Builder
23 | @NoArgsConstructor
24 | @AllArgsConstructor
25 | public class InvitationCode {
26 |
27 | @Id
28 | @GeneratedValue(strategy = GenerationType.IDENTITY)
29 | private Integer id;
30 |
31 | /**
32 | * 邀请码
33 | */
34 | private String code;
35 |
36 | /**
37 | * 是否有效
38 | */
39 | private Boolean valid;
40 |
41 | /**
42 | * 失效时间
43 | */
44 | @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
45 | @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
46 | private Date expirationTime;
47 |
48 | /**
49 | * 被邀请用户
50 | */
51 | private String invitedUser;
52 |
53 | /**
54 | * 订阅
55 | */
56 | private String subscribe;
57 |
58 | @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
59 | @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
60 | private Date createTime;
61 |
62 | }
63 |
--------------------------------------------------------------------------------
/src/main/java/cn/itbat/microsoft/model/support/Jvm.java:
--------------------------------------------------------------------------------
1 | package cn.itbat.microsoft.model.support;
2 |
3 | import lombok.Data;
4 |
5 | /**
6 | * JVM
7 | *
8 | * @author mjj
9 | * @date 2020年05月13日 10:17:33
10 | */
11 | @Data
12 | public class Jvm {
13 |
14 | /**
15 | * 当前 JVM 占用的内存总数 (M)
16 | */
17 | private double total;
18 |
19 | /**
20 | * JVM 最大可用内存总数 (M)
21 | */
22 | private double max;
23 |
24 | /**
25 | * JVM 空闲内存 (M)
26 | */
27 | private double free;
28 |
29 | /**
30 | * JDK 版本
31 | */
32 | private String version;
33 |
34 | public Jvm() {
35 | double mb = 1024 * 1024;
36 | Runtime runtime = Runtime.getRuntime();
37 | this.total = runtime.totalMemory() / mb;
38 | this.free = runtime.freeMemory() / mb;
39 | this.max = runtime.maxMemory() / mb;
40 | this.version = System.getProperty("java.version");
41 |
42 | }
43 |
44 | }
45 |
--------------------------------------------------------------------------------
/src/main/java/cn/itbat/microsoft/model/support/Mem.java:
--------------------------------------------------------------------------------
1 | package cn.itbat.microsoft.model.support;
2 |
3 | import com.sun.management.OperatingSystemMXBean;
4 | import lombok.Data;
5 |
6 | import java.lang.management.ManagementFactory;
7 |
8 | /**
9 | * @author mjj
10 | * @date 2020年05月13日 10:17:33
11 | */
12 | @Data
13 | public class Mem {
14 |
15 | /**
16 | * 内存总量
17 | */
18 | private double total;
19 |
20 | /**
21 | * 已用内存
22 | */
23 | private double used;
24 |
25 | /**
26 | * 剩余内存
27 | */
28 | private double free;
29 |
30 | public Mem() {
31 | double mb = 1024 * 1024;
32 | OperatingSystemMXBean osb = (OperatingSystemMXBean) ManagementFactory.getOperatingSystemMXBean();
33 | // 总的物理内存+虚拟内存
34 | long totalVirtualMemory = osb.getTotalSwapSpaceSize();
35 | // 剩余的物理内存
36 | long freePhysicalMemorySize = osb.getFreePhysicalMemorySize();
37 | this.total = totalVirtualMemory / mb;
38 | this.free = freePhysicalMemorySize / mb;
39 | this.used = (totalVirtualMemory - freePhysicalMemorySize) / mb;
40 | }
41 |
42 |
43 | }
44 |
--------------------------------------------------------------------------------
/src/main/java/cn/itbat/microsoft/model/support/Sys.java:
--------------------------------------------------------------------------------
1 | package cn.itbat.microsoft.model.support;
2 |
3 | import cn.hutool.core.date.BetweenFormater;
4 | import cn.hutool.core.date.DateUtil;
5 | import lombok.Builder;
6 | import lombok.Data;
7 |
8 | import java.lang.management.ManagementFactory;
9 | import java.util.Date;
10 |
11 | /**
12 | * @author mjj
13 | * @date 2020年05月13日 10:17:33
14 | */
15 | @Data
16 | public class Sys {
17 |
18 | /**
19 | * 项目路径
20 | */
21 | @Builder.Default
22 | private String projectDir = "";
23 |
24 | /**
25 | * 操作系统
26 | */
27 | private String osName;
28 |
29 | /**
30 | * 系统架构
31 | */
32 | private String osArch;
33 |
34 | /**
35 | * 系统版本
36 | */
37 | private String osVersion;
38 |
39 | /**
40 | * 启动时间
41 | */
42 | private String upTime;
43 |
44 | public Sys() {
45 | this.osName = System.getProperty("os.name");
46 | this.osArch = System.getProperty("os.arch");
47 | this.osVersion = System.getProperty("os.version");
48 | long uptime = ManagementFactory.getRuntimeMXBean().getUptime();
49 | this.upTime = DateUtil.formatBetween(uptime, BetweenFormater.Level.SECOND);
50 | }
51 |
52 | }
53 |
--------------------------------------------------------------------------------
/src/main/java/cn/itbat/microsoft/model/support/SystemMonitorInfo.java:
--------------------------------------------------------------------------------
1 | package cn.itbat.microsoft.model.support;
2 |
3 | import lombok.Data;
4 |
5 | import java.io.Serializable;
6 |
7 | /**
8 | * 系统信息
9 | *
10 | * @author mjj
11 | * @date 2020年05月13日 10:17:33
12 | */
13 | @Data
14 | public class SystemMonitorInfo implements Serializable {
15 |
16 | /**
17 | * 服务器基本信息
18 | */
19 | private Sys sys;
20 |
21 | /**
22 | * JVM 信息
23 | */
24 | private Jvm jvm;
25 |
26 | /**
27 | * 系统内存
28 | */
29 | private Mem mem;
30 |
31 | public SystemMonitorInfo() {
32 | this.jvm = new Jvm();
33 | this.sys = new Sys();
34 | this.mem = new Mem();
35 | }
36 |
37 | }
38 |
--------------------------------------------------------------------------------
/src/main/java/cn/itbat/microsoft/repository/InvitationCodeRepository.java:
--------------------------------------------------------------------------------
1 | package cn.itbat.microsoft.repository;
2 |
3 | import cn.itbat.microsoft.model.entity.InvitationCode;
4 | import org.springframework.data.jpa.repository.JpaRepository;
5 | import org.springframework.stereotype.Repository;
6 |
7 | import java.util.List;
8 |
9 | /**
10 | * @author huahui.wu
11 | * @date 2020年11月24日 14:57:25
12 | */
13 | @Repository
14 | public interface InvitationCodeRepository extends JpaRepository {
15 |
16 | /**
17 | * 根据code查询
18 | *
19 | * @param code 邀请码
20 | * @param valid 是否有效
21 | * @return InvitationCode
22 | */
23 | InvitationCode findFirstByCodeAndValid(String code, Boolean valid);
24 |
25 | /**
26 | * 批量查询code
27 | *
28 | * @param codes 邀请码集合
29 | * @return List
30 | */
31 | List findAllByCodeIn(List codes);
32 | }
33 |
--------------------------------------------------------------------------------
/src/main/java/cn/itbat/microsoft/security/Md5PasswordEncoder.java:
--------------------------------------------------------------------------------
1 | package cn.itbat.microsoft.security;
2 |
3 | import cn.hutool.crypto.SecureUtil;
4 | import org.springframework.security.crypto.password.PasswordEncoder;
5 |
6 | /**
7 | * @author mjj
8 | * @date 2020年05月11日 16:23:11
9 | */
10 | public class Md5PasswordEncoder implements PasswordEncoder {
11 |
12 | @Override
13 | public String encode(CharSequence rawPassword) {
14 | return SecureUtil.md5(rawPassword.toString());
15 | }
16 |
17 | @Override
18 | public boolean matches(CharSequence rawPassword, String encodedPassword) {
19 | return rawPassword.toString().equals(SecureUtil.md5(encodedPassword));
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/src/main/java/cn/itbat/microsoft/security/MySecurityConfig.java:
--------------------------------------------------------------------------------
1 | package cn.itbat.microsoft.security;
2 |
3 | import cn.itbat.microsoft.vo.BaseResultVo;
4 | import com.fasterxml.jackson.databind.ObjectMapper;
5 | import org.springframework.context.annotation.Bean;
6 | import org.springframework.http.HttpMethod;
7 | import org.springframework.security.authentication.BadCredentialsException;
8 | import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
9 | import org.springframework.security.config.annotation.web.builders.HttpSecurity;
10 | import org.springframework.security.config.annotation.web.builders.WebSecurity;
11 | import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
12 | import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
13 | import org.springframework.security.core.userdetails.UsernameNotFoundException;
14 | import org.springframework.security.crypto.password.PasswordEncoder;
15 | import org.springframework.security.web.firewall.HttpFirewall;
16 | import org.springframework.security.web.firewall.StrictHttpFirewall;
17 |
18 | import javax.annotation.Resource;
19 | import javax.servlet.http.HttpServletResponse;
20 | import java.io.PrintWriter;
21 |
22 | /**
23 | * 自定义 Security 配置类
24 | *
25 | * @author mjj
26 | * @date 2020年08月11日 09:50:37
27 | */
28 | @EnableWebSecurity
29 | public class MySecurityConfig extends WebSecurityConfigurerAdapter {
30 |
31 | @Resource
32 | private ObjectMapper objectMapper;
33 |
34 | @Override
35 | protected void configure(HttpSecurity http) throws Exception {
36 | http
37 | // .authenticationProvider(authenticationProvider())
38 | .exceptionHandling()
39 | // 未登录时,进行 json 格式的提示.
40 | .authenticationEntryPoint((request, response, authException) -> {
41 | response.setContentType("application/json;charset=utf-8");
42 | response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
43 | PrintWriter out = response.getWriter();
44 | out.write(objectMapper.writeValueAsString(BaseResultVo.error(1001, "未登录")));
45 | out.flush();
46 | out.close();
47 | })
48 | .and()
49 | .authorizeRequests()
50 | .antMatchers("/").permitAll()
51 | .antMatchers("/microsoft/**").authenticated()
52 | .and()
53 | // 使用自带的登录
54 | .formLogin().loginPage("/login").usernameParameter("userName").passwordParameter("password")
55 | // 登录失败,返回json
56 | .failureHandler((request, response, ex) -> {
57 | response.setContentType("application/json;charset=utf-8");
58 | response.setStatus(HttpServletResponse.SC_FORBIDDEN);
59 | PrintWriter out = response.getWriter();
60 | String msg;
61 | if (ex instanceof UsernameNotFoundException || ex instanceof BadCredentialsException) {
62 | msg = "用户名或密码错误";
63 | } else {
64 | msg = "登录失败";
65 | }
66 | out.write(objectMapper.writeValueAsString(BaseResultVo.error(msg)));
67 | out.flush();
68 | out.close();
69 | })
70 | // 登录成功,返回json
71 | .successHandler((request, response, authentication) -> {
72 | response.setContentType("application/json;charset=utf-8");
73 | PrintWriter out = response.getWriter();
74 | out.write(objectMapper.writeValueAsString(BaseResultVo.success(authentication)));
75 | out.flush();
76 | out.close();
77 | })
78 | .and()
79 | .exceptionHandling()
80 | // 没有权限,返回json
81 | .accessDeniedHandler((request, response, ex) -> {
82 | response.setContentType("application/json;charset=utf-8");
83 | response.setStatus(HttpServletResponse.SC_FORBIDDEN);
84 | PrintWriter out = response.getWriter();
85 | out.write(objectMapper.writeValueAsString(BaseResultVo.error("权限不足")));
86 | out.flush();
87 | out.close();
88 | })
89 | .and()
90 | .logout()
91 | // 退出成功,返回 json
92 | .logoutSuccessHandler((request, response, authentication) -> {
93 | response.setContentType("application/json;charset=utf-8");
94 | PrintWriter out = response.getWriter();
95 | out.write(objectMapper.writeValueAsString(BaseResultVo.error("注销成功")));
96 | out.flush();
97 | out.close();
98 | })
99 | .and()
100 | .logout().permitAll();
101 |
102 | http.cors();
103 | http.csrf().disable();
104 | http.headers().frameOptions().sameOrigin();
105 | }
106 |
107 | @Bean
108 | public HttpFirewall allowUrlEncodedSlashHttpFirewall() {
109 | StrictHttpFirewall firewall = new StrictHttpFirewall();
110 | firewall.setAllowUrlEncodedPercent(true);
111 | return firewall;
112 | }
113 |
114 | @Override
115 | public void configure(AuthenticationManagerBuilder web) throws Exception {
116 | web.userDetailsService(myUserDetailsServiceImpl()).passwordEncoder(passwordEncoder());
117 | }
118 |
119 | @Bean
120 | public MyUserDetailsServiceImpl myUserDetailsServiceImpl() {
121 | return new MyUserDetailsServiceImpl();
122 | }
123 |
124 | @Override
125 | public void configure(WebSecurity web) {
126 | // 对于在 header 里面增加 token 等类似情况,放行所有 OPTIONS 请求。
127 | web.ignoring().antMatchers(HttpMethod.OPTIONS, "/**");
128 | web.httpFirewall(allowUrlEncodedSlashHttpFirewall());
129 | }
130 |
131 | @Bean
132 | public static PasswordEncoder passwordEncoder() {
133 | return new Md5PasswordEncoder();
134 | }
135 |
136 | }
--------------------------------------------------------------------------------
/src/main/java/cn/itbat/microsoft/security/MyUserDetailsServiceImpl.java:
--------------------------------------------------------------------------------
1 | package cn.itbat.microsoft.security;
2 |
3 | import cn.itbat.microsoft.config.GraphProperties;
4 | import org.springframework.security.core.GrantedAuthority;
5 | import org.springframework.security.core.authority.SimpleGrantedAuthority;
6 | import org.springframework.security.core.userdetails.User;
7 | import org.springframework.security.core.userdetails.UserDetails;
8 | import org.springframework.security.core.userdetails.UserDetailsService;
9 | import org.springframework.security.core.userdetails.UsernameNotFoundException;
10 |
11 | import javax.annotation.Resource;
12 | import java.util.ArrayList;
13 | import java.util.Collections;
14 | import java.util.List;
15 |
16 | /**
17 | * @author mjj
18 | * @date 2020年05月11日 16:23:11
19 | */
20 | public class MyUserDetailsServiceImpl implements UserDetailsService {
21 |
22 | @Resource
23 | private GraphProperties graphProperties;
24 |
25 | /**
26 | * 授权的时候是对角色授权,认证的时候应该基于资源,而不是角色,因为资源是不变的,而用户的角色是会变的
27 | */
28 | @Override
29 | public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
30 | if (!username.equals(graphProperties.getUserName())){
31 | throw new UsernameNotFoundException("用户名或密码错误!");
32 | }
33 | return new User(graphProperties.getUserName(), graphProperties.getPassword(), Collections.emptyList());
34 | }
35 |
36 | }
--------------------------------------------------------------------------------
/src/main/java/cn/itbat/microsoft/service/FrontDeskService.java:
--------------------------------------------------------------------------------
1 | package cn.itbat.microsoft.service;
2 |
3 | import cn.itbat.microsoft.vo.FontSkuSku;
4 | import cn.itbat.microsoft.vo.FontUser;
5 | import cn.itbat.microsoft.vo.GraphUserVo;
6 |
7 | import java.util.List;
8 |
9 | /**
10 | * @author huahui.wu
11 | * @date 2020年11月24日 16:34:06
12 | */
13 | public interface FrontDeskService {
14 |
15 | /**
16 | * 创建用户
17 | *
18 | * @param graphUserVo 用户信息
19 | * @return FontUser
20 | */
21 | FontUser create(GraphUserVo graphUserVo);
22 |
23 | /**
24 | * 查询用户的订阅
25 | *
26 | * @return 成功
27 | */
28 | List listLicense();
29 | }
30 |
--------------------------------------------------------------------------------
/src/main/java/cn/itbat/microsoft/service/GraphService.java:
--------------------------------------------------------------------------------
1 | package cn.itbat.microsoft.service;
2 |
3 | import cn.itbat.microsoft.model.GraphUser;
4 | import cn.itbat.microsoft.vo.DirectoryRoleVo;
5 | import cn.itbat.microsoft.vo.GraphUserVo;
6 | import com.microsoft.graph.models.*;
7 |
8 | import java.util.List;
9 | import java.util.Map;
10 | import java.util.Set;
11 |
12 | /**
13 | * graph 的具体操作方法
14 | *
15 | * @author mjj
16 | * @date 2020年05月12日 16:30:29
17 | */
18 | public interface GraphService {
19 |
20 | /**
21 | * 获取所有的订阅
22 | *
23 | * @param appName appName
24 | * @return List
25 | */
26 | List getSubscribedSkus(String appName);
27 |
28 | /**
29 | * 获取绑定的域名
30 | *
31 | * @param appName appName
32 | * @return 域名
33 | */
34 | List getDomains(String appName);
35 |
36 | /**
37 | * 获取当前用户信息
38 | *
39 | * @param appName appName
40 | * @return User
41 | */
42 | User getUser(String appName);
43 |
44 | /**
45 | * 根据用户id获取用户
46 | *
47 | * @param appName appName
48 | * @param userId 用户id
49 | * @return User
50 | */
51 | User getUser(String appName, String userId);
52 |
53 | /**
54 | * 获取所有的用户
55 | *
56 | * @param appName appName
57 | * @return IUserCollectionPage
58 | */
59 | List getUsers(String appName);
60 |
61 |
62 | /**
63 | * 根据用户id获取用户
64 | *
65 | * @param graphUserVo 查询条件
66 | * @return List
67 | */
68 | List getUsers(GraphUserVo graphUserVo);
69 |
70 |
71 | /**
72 | * 创建用户
73 | *
74 | * @param appName appName
75 | * @param graphUser 用户信息
76 | * @return User
77 | */
78 | User createUser(String appName, GraphUser graphUser);
79 |
80 | /**
81 | * 添加许可证
82 | *
83 | * @param appName appName
84 | * @param skuId 订阅
85 | * @param userId 用户
86 | * @return User
87 | */
88 | User addLicense(String appName, String userId, String skuId);
89 |
90 |
91 | /**
92 | * 取消许可证
93 | *
94 | * @param appName 组织类型
95 | * @param skuId 许可证
96 | * @param userId 用户
97 | * @return 用户信息
98 | */
99 | User cancelLicense(String appName, String skuId, String userId);
100 |
101 | /**
102 | * 启用禁用账户
103 | *
104 | * @param appName 组织类型
105 | * @param userId 用户
106 | * @param accountEnabled 启用禁用
107 | */
108 | void enableDisableUser(String appName, String userId, Boolean accountEnabled);
109 |
110 | /**
111 | * 重置密码
112 | *
113 | * @param appName 组织类型
114 | * @param userId 用户
115 | * @param password 密码
116 | */
117 | void resetPassword(String appName, String userId, String password);
118 |
119 |
120 | /**
121 | * 更新用户信息
122 | *
123 | * @param appName 组织类型
124 | * @param graphUser 用户
125 | */
126 | void updateUser(String appName, GraphUser graphUser);
127 |
128 | /**
129 | * 删除用户
130 | *
131 | * @param appName appName
132 | * @param userName 用户信息
133 | */
134 | void deletedUser(String appName, String userName);
135 |
136 | /**
137 | * 列出当前激活的用户角色
138 | *
139 | * @param appName appName
140 | */
141 | List listDirectoryRoles(String appName);
142 |
143 | /**
144 | * 列出用户角色下的用户
145 | *
146 | * @param appName appName
147 | * @param objectId --both the object ID and template ID are OK.-- Now only object ID is effective.
148 | */
149 | List listMembersOfADirectoryRole(String appName, String objectId);
150 |
151 | /**
152 | * 查询当前有哪些角色,并查询其角色下有哪些用户
153 | *
154 | * @param appName appName
155 | */
156 | Map> directoryRoleToUserNameMap(String appName);
157 |
158 | /**
159 | * 增加用户角色
160 | *
161 | * @param appName 组织类型
162 | * @param userId 用户id
163 | * @param roleId 角色id
164 | * @return 结果
165 | */
166 | Boolean addDirectoryRoleMember(String appName, String userId, String roleId);
167 |
168 | }
169 |
--------------------------------------------------------------------------------
/src/main/java/cn/itbat/microsoft/service/InvitationCodeService.java:
--------------------------------------------------------------------------------
1 | package cn.itbat.microsoft.service;
2 |
3 | import cn.itbat.microsoft.model.Pager;
4 | import cn.itbat.microsoft.model.entity.InvitationCode;
5 | import org.springframework.data.domain.Page;
6 |
7 | import java.util.List;
8 | import java.util.Map;
9 |
10 | /**
11 | * 邀请码
12 | *
13 | * @author huahui.wu
14 | * @date 2020年11月24日 15:17:45
15 | */
16 | public interface InvitationCodeService {
17 | /**
18 | * 根据code查询(有效的邀请码)
19 | *
20 | * @param code 邀请码
21 | * @return InvitationCode
22 | */
23 | InvitationCode selectByCode(String code);
24 |
25 | /**
26 | * 更新邀请码
27 | *
28 | * @param invitationCode 邀请码信息
29 | */
30 | void update(InvitationCode invitationCode);
31 |
32 | /**
33 | * 生成邀请码
34 | *
35 | * @param num 数量
36 | */
37 | void generateInvitationCode(Integer num);
38 |
39 | /**
40 | * 查询
41 | *
42 | * @param invitationCode 查询参数
43 | * @return List
44 | */
45 | List list(InvitationCode invitationCode);
46 |
47 | /**
48 | * 分页查询
49 | *
50 | * @param invitationCode 查询参数
51 | * @param pager 分页参数
52 | * @return Page
53 | */
54 | Page list(InvitationCode invitationCode, Pager pager);
55 |
56 | /**
57 | * 统计信息
58 | *
59 | * @return 结果
60 | */
61 | Map getStatistics();
62 | }
63 |
--------------------------------------------------------------------------------
/src/main/java/cn/itbat/microsoft/service/MailService.java:
--------------------------------------------------------------------------------
1 | package cn.itbat.microsoft.service;
2 |
3 | /**
4 | * @author huahui.wu
5 | * @date 2020年11月23日 17:28:09
6 | */
7 | public interface MailService {
8 |
9 | /**
10 | * 发送邮件
11 | *
12 | * @param to 接收人
13 | * @param userName office用户名
14 | * @param password office密码
15 | */
16 | void sendMail(String to, String userName, String password);
17 | }
18 |
--------------------------------------------------------------------------------
/src/main/java/cn/itbat/microsoft/service/Microsoft365Service.java:
--------------------------------------------------------------------------------
1 | package cn.itbat.microsoft.service;
2 |
3 |
4 | import cn.itbat.microsoft.model.GraphUser;
5 | import cn.itbat.microsoft.model.Pager;
6 | import cn.itbat.microsoft.utils.PageInfo;
7 | import cn.itbat.microsoft.vo.*;
8 |
9 | import java.util.List;
10 |
11 | /**
12 | * @author mjj (;¬_¬)
13 | * @version 1.0
14 | * @date 2019-07-16 19:06
15 | **/
16 | public interface Microsoft365Service {
17 |
18 | /**
19 | * 刷新
20 | *
21 | * @param appName 组织类型
22 | * @param type 刷新类型
23 | */
24 | void refresh(String appName, Integer type);
25 |
26 | /**
27 | * 查询订阅
28 | *
29 | * @param appName 组织类型
30 | * @return List
31 | */
32 | List getSubscribed(String appName);
33 |
34 |
35 | /**
36 | * 查询域名
37 | *
38 | * @param appName 组织类型
39 | * @return List
40 | */
41 | List getDomainVo(String appName);
42 |
43 | /**
44 | * 创建用户
45 | *
46 | * @param graphUserVo 用户信息
47 | * @return GraphUser
48 | */
49 | GraphUserVo create(GraphUserVo graphUserVo);
50 |
51 | /**
52 | * 更新用户信息
53 | *
54 | * @param appName 组织类型
55 | * @param graphUser 用户
56 | */
57 |
58 | void updateUser(String appName, GraphUser graphUser);
59 |
60 | /**
61 | * 启用禁用账户
62 | *
63 | * @param appName 组织类型
64 | * @param userId 用户
65 | * @param accountEnabled 启用禁用
66 | */
67 | void enableDisableUser(String appName, String userId, Boolean accountEnabled);
68 |
69 | /**
70 | * 添加订阅
71 | *
72 | * @param appName 组织类型
73 | * @param userId 用户
74 | * @param skuId 订阅
75 | * @return 用户信息
76 | */
77 | GraphUserVo addLicense(String appName, String userId, String skuId);
78 |
79 |
80 | /**
81 | * 取消订阅
82 | *
83 | * @param appName 组织类型
84 | * @param skuId 订阅
85 | * @param userId 用户
86 | * @return 用户信息
87 | */
88 | GraphUserVo cancelLicense(String appName, String userId, String skuId);
89 |
90 | /**
91 | * 重置密码
92 | *
93 | * @param appName 组织类型
94 | * @param userName 用户
95 | * @param password 密码
96 | */
97 | void resetPassword(String appName, String userName, String password);
98 |
99 |
100 | /**
101 | * 根据用户Id获取
102 | *
103 | * @param appName 组织类型
104 | * @param userId 用户
105 | * @return user
106 | */
107 | GraphUserVo getGraphUserVo(String appName, String userId);
108 |
109 |
110 | /**
111 | * 获取所有的用户
112 | *
113 | * @param appName 组织类型
114 | * @param pager 分页参数
115 | * @return List
116 | */
117 | PageInfo getGraphUserVos(String appName, Pager pager);
118 |
119 | /**
120 | * 根据用户id获取用户
121 | *
122 | * @param graphUserVo 查询条件
123 | * @param pager 分页参数
124 | * @param sorter 排序参数
125 | * @return List
126 | */
127 | PageInfo getGraphUserVos(GraphUserVo graphUserVo, Pager pager, GraphUserSorterVo sorter);
128 |
129 |
130 | /**
131 | * 删除指定用户
132 | *
133 | * @param type 组织类型
134 | * @param userName 用户名
135 | */
136 | void deletedUser(String type, String userName);
137 |
138 | /**
139 | * 删除用户
140 | *
141 | * @param appName 组织类型
142 | */
143 | void deletedUsers(String appName);
144 |
145 | /**
146 | * 批量创建创建Office用户
147 | *
148 | * @param num num
149 | * @param appName 组织类型
150 | * @param skuId 订阅
151 | * @param domain 域名后缀
152 | */
153 | void createBatch(Integer num, String appName, String skuId, String domain, String password, String usageLocation);
154 |
155 | /**
156 | * 首页
157 | *
158 | * @param appName 组织类型
159 | * @return 首页数据
160 | */
161 | HomePageVo homePage(String appName);
162 |
163 | /**
164 | * 统计许可证信息
165 | *
166 | * @param appName 组织类型
167 | * @return 结果
168 | */
169 | StatisticsVo getLicenseStatistics(String appName);
170 |
171 | /**
172 | * 统计用户信息
173 | *
174 | * @param appName 组织类型
175 | * @return 结果
176 | */
177 | StatisticsVo getUsersStatistics(String appName);
178 |
179 | /**
180 | * 获取用户角色列表
181 | *
182 | * @param appName 组织类型
183 | * @return 结果
184 | */
185 | List listRoles(String appName);
186 |
187 | /**
188 | * 增加用户角色
189 | *
190 | * @param appName 组织类型
191 | * @param userId 用户id
192 | * @param roleId 角色id
193 | * @return 结果
194 | */
195 | Boolean addDirectoryRoleMember(String appName, String userId, String roleId);
196 | }
197 |
198 |
--------------------------------------------------------------------------------
/src/main/java/cn/itbat/microsoft/service/impl/FrontDeskServiceImpl.java:
--------------------------------------------------------------------------------
1 | package cn.itbat.microsoft.service.impl;
2 |
3 | import cn.itbat.microsoft.cache.GraphCache;
4 | import cn.itbat.microsoft.config.GraphProperties;
5 | import cn.itbat.microsoft.model.entity.InvitationCode;
6 | import cn.itbat.microsoft.service.FrontDeskService;
7 | import cn.itbat.microsoft.service.InvitationCodeService;
8 | import cn.itbat.microsoft.service.Microsoft365Service;
9 | import cn.itbat.microsoft.vo.*;
10 | import org.springframework.beans.BeanUtils;
11 | import org.springframework.beans.factory.annotation.Value;
12 | import org.springframework.stereotype.Service;
13 | import org.springframework.transaction.annotation.Transactional;
14 | import org.springframework.util.CollectionUtils;
15 | import org.springframework.util.StringUtils;
16 |
17 | import javax.annotation.Resource;
18 | import java.util.ArrayList;
19 | import java.util.Date;
20 | import java.util.List;
21 | import java.util.stream.Collectors;
22 |
23 | /**
24 | * @author huahui.wu
25 | * @date 2020年11月24日 16:34:12
26 | */
27 | @Service
28 | public class FrontDeskServiceImpl implements FrontDeskService {
29 |
30 | @Resource
31 | private Microsoft365Service microsoft365Service;
32 |
33 | @Resource
34 | private InvitationCodeService invitationCodeService;
35 |
36 | @Resource
37 | private GraphCache graphCache;
38 |
39 | @Resource
40 | private GraphProperties graphProperties;
41 |
42 | @Value("${graph.invite}")
43 | private String invite;
44 | @Value("${graph.inviteDomain}")
45 | private String inviteDomain;
46 |
47 | @Transactional(rollbackFor = Exception.class)
48 | @Override
49 | public FontUser create(GraphUserVo graphUserVo) {
50 | // 判断邀请码是否有效
51 | InvitationCode invitationCode = invitationCodeService.selectByCode(graphUserVo.getCode());
52 | if (invitationCode == null || !invitationCode.getValid()) {
53 | throw new RuntimeException("邀请码已失效!");
54 | }
55 | if (!StringUtils.isEmpty(inviteDomain)) {
56 | List domainVo = microsoft365Service.getDomainVo(graphUserVo.getAppName());
57 | if (!CollectionUtils.isEmpty(domainVo)) {
58 | if (domainVo.stream().map(DomainVo::getId).collect(Collectors.toList()).contains(inviteDomain)) {
59 | graphUserVo.setDomain(inviteDomain);
60 | }
61 | }
62 | }
63 | GraphUserVo userVo = microsoft365Service.create(graphUserVo);
64 | invitationCode.setValid(Boolean.FALSE);
65 | invitationCode.setExpirationTime(new Date());
66 | invitationCode.setInvitedUser(userVo.getUserPrincipalName());
67 | invitationCode.setSubscribe(StringUtils.isEmpty(userVo.getSkuType()) ? graphProperties.getSubConfigName(graphUserVo.getSkuId()) : graphProperties.getSubConfig(graphUserVo.getSkuType()).getDisplayName());
68 | invitationCodeService.update(invitationCode);
69 | return FontUser.builder().displayName(userVo.getDisplayName()).userPrincipalName(userVo.getUserPrincipalName()).password(userVo.getPassword()).build();
70 | }
71 |
72 | @Override
73 | public List listLicense() {
74 | List appNames = graphProperties.getConfigs().stream().map(GraphProperties.GraphConfig::getAppName).collect(Collectors.toList());
75 | String[] split = invite.split(",");
76 |
77 | List fontSkuSkus = new ArrayList<>();
78 | for (String appName : split) {
79 | if (!appNames.contains(appName)) {
80 | continue;
81 | }
82 | List subscribed = microsoft365Service.getSubscribed(appName);
83 | if (!CollectionUtils.isEmpty(subscribed)) {
84 | for (SubscribedSkuVo subscribedSkuVo : subscribed) {
85 | FontSkuSku fontSkuSku = new FontSkuSku();
86 | BeanUtils.copyProperties(subscribedSkuVo, fontSkuSku);
87 | fontSkuSkus.add(fontSkuSku);
88 | }
89 | }
90 | }
91 | return fontSkuSkus;
92 | }
93 | }
94 |
--------------------------------------------------------------------------------
/src/main/java/cn/itbat/microsoft/service/impl/InvitationCodeServiceImpl.java:
--------------------------------------------------------------------------------
1 | package cn.itbat.microsoft.service.impl;
2 |
3 | import cn.hutool.core.date.DateUtil;
4 | import cn.hutool.core.util.RandomUtil;
5 | import cn.itbat.microsoft.model.Pager;
6 | import cn.itbat.microsoft.model.entity.InvitationCode;
7 | import cn.itbat.microsoft.repository.InvitationCodeRepository;
8 | import cn.itbat.microsoft.service.InvitationCodeService;
9 | import org.springframework.data.domain.*;
10 | import org.springframework.stereotype.Service;
11 | import org.springframework.transaction.annotation.Transactional;
12 | import org.springframework.util.CollectionUtils;
13 | import org.springframework.util.StringUtils;
14 |
15 | import javax.annotation.Resource;
16 | import java.util.*;
17 | import java.util.stream.Collectors;
18 |
19 | /**
20 | * 邀请码
21 | *
22 | * @author huahui.wu
23 | * @date 2020年11月24日 15:18:03
24 | */
25 | @Service
26 | public class InvitationCodeServiceImpl implements InvitationCodeService {
27 |
28 | @Resource
29 | private InvitationCodeRepository invitationCodeRepository;
30 |
31 | @Override
32 | public InvitationCode selectByCode(String code) {
33 | return invitationCodeRepository.findFirstByCodeAndValid(code, Boolean.TRUE);
34 | }
35 |
36 | @Transactional(rollbackFor = Exception.class)
37 | @Override
38 | public void update(InvitationCode invitationCode) {
39 | invitationCodeRepository.save(invitationCode);
40 | }
41 |
42 | @Transactional(rollbackFor = Exception.class)
43 | @Override
44 | public void generateInvitationCode(Integer num) {
45 | List invitationCodes = new ArrayList<>();
46 | for (int i = 0; i < num; i++) {
47 | String randomString = "G-" + DateUtil.thisDayOfMonth() + "-" + RandomUtil.randomStringUpper(6);
48 | invitationCodes.add(InvitationCode.builder().code(randomString).createTime(new Date()).valid(Boolean.TRUE).build());
49 | }
50 | List codes = invitationCodeRepository.findAllByCodeIn(invitationCodes.stream().map(InvitationCode::getCode).collect(Collectors.toList()));
51 | if (!CollectionUtils.isEmpty(codes)) {
52 | List userDelete = invitationCodes.stream().filter(l -> codes.stream().map(InvitationCode::getCode).collect(Collectors.toList()).contains(l.getCode())).collect(Collectors.toList());
53 | invitationCodeRepository.saveAll(userDelete);
54 | } else {
55 | invitationCodeRepository.saveAll(invitationCodes);
56 | }
57 | }
58 |
59 | @Override
60 | public List list(InvitationCode invitationCode) {
61 | return invitationCodeRepository.findAll(Example.of(invitationCode));
62 | }
63 |
64 | @Override
65 | public Page list(InvitationCode invitationCode, Pager pager) {
66 | // Sort sort = new Sort(Sort.Direction.DESC, Collections.singletonList("id"));
67 | if (StringUtils.isEmpty(invitationCode.getCode())) {
68 | invitationCode.setCode(null);
69 | }
70 | return invitationCodeRepository.findAll(Example.of(invitationCode, ExampleMatcher.matching()
71 | .withIgnoreNullValues()), PageRequest.of(pager.getPageIndex() - 1, pager.getPageSize()));
72 | }
73 |
74 | @Override
75 | public Map getStatistics() {
76 | List all = invitationCodeRepository.findAll();
77 | if (CollectionUtils.isEmpty(all)) {
78 | return new HashMap<>(0);
79 | }
80 | Map result = new HashMap<>(3);
81 | result.put("codes", all.size());
82 | result.put("valid", all.stream().filter(InvitationCode::getValid).count());
83 | result.put("invalid", all.stream().filter(l -> !l.getValid()).count());
84 | result.put("users", all.stream().filter(l -> l.getInvitedUser() != null).count());
85 | return result;
86 | }
87 |
88 |
89 | }
90 |
--------------------------------------------------------------------------------
/src/main/java/cn/itbat/microsoft/service/impl/MailServiceImpl.java:
--------------------------------------------------------------------------------
1 | package cn.itbat.microsoft.service.impl;
2 |
3 | import cn.itbat.microsoft.service.MailService;
4 | import org.springframework.beans.factory.annotation.Value;
5 | import org.springframework.mail.SimpleMailMessage;
6 | import org.springframework.mail.javamail.JavaMailSender;
7 | import org.springframework.scheduling.annotation.Async;
8 | import org.springframework.stereotype.Service;
9 |
10 | import javax.annotation.Resource;
11 |
12 | /**
13 | * @author huahui.wu
14 | * @date 2020年11月23日 17:28:17
15 | */
16 | @Service
17 | public class MailServiceImpl implements MailService {
18 |
19 | @Resource
20 | private JavaMailSender mailSender;
21 |
22 | @Value("${spring.mail.username}")
23 | private String from;
24 |
25 | @Async("asyncPoolTaskExecutor")
26 | @Override
27 | public void sendMail(String to, String userName, String password) {
28 | //简单邮件
29 | SimpleMailMessage simpleMailMessage = new SimpleMailMessage();
30 | simpleMailMessage.setFrom(from);
31 | simpleMailMessage.setTo(to);
32 | simpleMailMessage.setSubject("Office 365帐户信息");
33 | simpleMailMessage.setText("已创建或修改用户帐户\n" +
34 | " \n" +
35 | "用户名: " + userName + "\n" +
36 | "临时密码: " + password + "\n" +
37 | " \n" +
38 | " \n" +
39 | "要执行的后续步骤如下: \n" +
40 | "登陆地址:https://www.office.com/\n");
41 | mailSender.send(simpleMailMessage);
42 | }
43 |
44 | }
45 |
--------------------------------------------------------------------------------
/src/main/java/cn/itbat/microsoft/utils/HttpClientUtils.java:
--------------------------------------------------------------------------------
1 | package cn.itbat.microsoft.utils;
2 |
3 | import java.io.BufferedReader;
4 | import java.io.IOException;
5 | import java.io.InputStreamReader;
6 | import java.io.PrintWriter;
7 | import java.net.URL;
8 | import java.net.URLConnection;
9 | import java.util.List;
10 | import java.util.Map;
11 |
12 | /**
13 | * http 请求工具
14 | *
15 | * @author mjj
16 | */
17 | public class HttpClientUtils {
18 | /**
19 | * 向指定URL发送GET方法的请求
20 | *
21 | * @param url 发送请求的URL
22 | * @param param 请求参数,请求参数应该是 name1=value1&name2=value2 的形式。
23 | * @return URL 所代表远程资源的响应结果
24 | */
25 | public static String sendGet(String url, String param) {
26 | StringBuilder result = new StringBuilder();
27 | BufferedReader in = null;
28 | try {
29 | String urlNameString = url + "?" + param;
30 | URL realUrl = new URL(urlNameString);
31 | // 打开和URL之间的连接
32 | URLConnection connection = realUrl.openConnection();
33 | // 设置通用的请求属性
34 | connection.setRequestProperty("accept", "*/*");
35 | connection.setRequestProperty("connection", "Keep-Alive");
36 | connection.setRequestProperty("user-agent",
37 | "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)");
38 | // 建立实际的连接
39 | connection.connect();
40 | // 获取所有响应头字段
41 | Map> map = connection.getHeaderFields();
42 | // 遍历所有的响应头字段
43 | for (String key : map.keySet()) {
44 | System.out.println(key + "--->" + map.get(key));
45 | }
46 | // 定义 BufferedReader输入流来读取URL的响应
47 | in = new BufferedReader(new InputStreamReader(
48 | connection.getInputStream()));
49 | String line;
50 | while ((line = in.readLine()) != null) {
51 | result.append(line);
52 | }
53 | } catch (Exception e) {
54 | System.out.println("发送GET请求出现异常!" + e);
55 | e.printStackTrace();
56 | }
57 | // 使用finally块来关闭输入流
58 | finally {
59 | try {
60 | if (in != null) {
61 | in.close();
62 | }
63 | } catch (Exception e2) {
64 | e2.printStackTrace();
65 | }
66 | }
67 | return result.toString();
68 | }
69 |
70 | /**
71 | * 向指定 URL 发送POST方法的请求
72 | *
73 | * @param url 发送请求的 URL
74 | * @param param 请求参数,请求参数应该是 name1=value1&name2=value2 的形式。
75 | * @return 所代表远程资源的响应结果
76 | */
77 | public static String sendPost(String url, String param) {
78 | PrintWriter out = null;
79 | BufferedReader in = null;
80 | StringBuilder result = new StringBuilder();
81 | try {
82 | URL realUrl = new URL(url);
83 | // 打开和URL之间的连接
84 | URLConnection conn = realUrl.openConnection();
85 | // 设置通用的请求属性
86 | conn.setRequestProperty("accept", "*/*");
87 | conn.setRequestProperty("connection", "Keep-Alive");
88 | conn.setRequestProperty("user-agent",
89 | "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)");
90 | // 发送POST请求必须设置如下两行
91 | conn.setDoOutput(true);
92 | conn.setDoInput(true);
93 | // 获取URLConnection对象对应的输出流
94 | out = new PrintWriter(conn.getOutputStream());
95 | // 发送请求参数
96 | out.print(param);
97 | // flush输出流的缓冲
98 | out.flush();
99 | // 定义BufferedReader输入流来读取URL的响应
100 | in = new BufferedReader(
101 | new InputStreamReader(conn.getInputStream()));
102 | String line;
103 | while ((line = in.readLine()) != null) {
104 | result.append(line);
105 | }
106 | } catch (Exception e) {
107 | System.out.println("发送 POST 请求出现异常!" + e);
108 | e.printStackTrace();
109 | }
110 | //使用finally块来关闭输出流、输入流
111 | finally {
112 | try {
113 | if (out != null) {
114 | out.close();
115 | }
116 | if (in != null) {
117 | in.close();
118 | }
119 | } catch (IOException ex) {
120 | ex.printStackTrace();
121 | }
122 | }
123 | return result.toString();
124 | }
125 | }
--------------------------------------------------------------------------------
/src/main/java/cn/itbat/microsoft/utils/IpUtils.java:
--------------------------------------------------------------------------------
1 | package cn.itbat.microsoft.utils;
2 |
3 | import java.net.Inet4Address;
4 | import java.net.InetAddress;
5 | import java.net.NetworkInterface;
6 | import java.net.SocketException;
7 | import java.util.ArrayList;
8 | import java.util.Collections;
9 | import java.util.Enumeration;
10 |
11 | /**
12 | * @author huahui.wu
13 | * @date 2020年10月28日 17:12:27
14 | */
15 | public class IpUtils {
16 | public static void main(String[] args) {
17 | System.out.println( getLocalIpAddr());
18 | }
19 |
20 | public static ArrayList getLocalIpAddr() {
21 | ArrayList ipList = new ArrayList();
22 | InetAddress[] addrList;
23 | try {
24 | Enumeration interfaces = NetworkInterface.getNetworkInterfaces();
25 | while (interfaces.hasMoreElements()) {
26 | NetworkInterface ni = (NetworkInterface) interfaces.nextElement();
27 | Enumeration ipAddrEnum = ni.getInetAddresses();
28 | while (ipAddrEnum.hasMoreElements()) {
29 | InetAddress addr = (InetAddress) ipAddrEnum.nextElement();
30 | if (addr.isLoopbackAddress() == true) {
31 | continue;
32 | }
33 |
34 | String ip = addr.getHostAddress();
35 | if (ip.indexOf(":") != -1) {
36 | //skip the IPv6 addr
37 | continue;
38 | }
39 | ipList.add(ip);
40 | }
41 | }
42 |
43 | Collections.sort(ipList);
44 | } catch (Exception e) {
45 | e.printStackTrace();
46 | }
47 |
48 | return ipList;
49 | }
50 | /**
51 | * 获取本地真正的IP地址,即获得有线或者 无线WiFi 地址。
52 | * 过滤虚拟机、蓝牙等地址
53 | *
54 | * @return IPv4
55 | */
56 | public static String getRealIP() {
57 | try {
58 | Enumeration allNetInterfaces = NetworkInterface.getNetworkInterfaces();
59 | while (allNetInterfaces.hasMoreElements()) {
60 | NetworkInterface netInterface = allNetInterfaces.nextElement();
61 | // 去除回环接口,子接口,未运行和接口
62 | if (netInterface.isLoopback() || netInterface.isVirtual() || !netInterface.isUp()) {
63 | continue;
64 | }
65 |
66 | if (!netInterface.getDisplayName().contains("Intel")
67 | && !netInterface.getDisplayName().contains("Realtek")
68 | && !netInterface.getDisplayName().contains("Ethernet")) {
69 | continue;
70 | }
71 |
72 | Enumeration addresses = netInterface.getInetAddresses();
73 | while (addresses.hasMoreElements()) {
74 | InetAddress ip = addresses.nextElement();
75 | if (ip != null) {
76 | // ipv4
77 | if (ip instanceof Inet4Address) {
78 | return ip.getHostAddress();
79 | }
80 | }
81 | }
82 | break;
83 | }
84 | } catch (SocketException e) {
85 | //捕获异常
86 | }
87 | return null;
88 | }
89 |
90 | }
--------------------------------------------------------------------------------
/src/main/java/cn/itbat/microsoft/utils/PageInfo.java:
--------------------------------------------------------------------------------
1 | package cn.itbat.microsoft.utils;
2 |
3 |
4 | import cn.itbat.microsoft.model.Pager;
5 |
6 | import java.util.Collections;
7 | import java.util.List;
8 |
9 | /**
10 | * 自定义内存分页
11 | *
12 | * @author mjj
13 | * @date 2020年08月06日 19:23:16
14 | */
15 | public class PageInfo {
16 |
17 | private long total;
18 |
19 | private Integer pageNum;
20 |
21 | private Integer pageSize;
22 |
23 | private List list;
24 |
25 | public PageInfo() {
26 |
27 | }
28 |
29 | public PageInfo(List list, Pager pager) {
30 | if (list.isEmpty()) {
31 | this.total = 0L;
32 | this.pageNum = 1;
33 | this.pageSize = 10;
34 | this.list = Collections.emptyList();
35 | } else {
36 | this.total = list.size();
37 | this.list = list;
38 | this.pageNum = (pager.getPageSize() == null || 0 == pager.getPageIndex()) ? 1 : pager.getPageIndex();
39 | this.pageSize = (pager.getPageIndex() == null || 0 == pager.getPageSize()) ? 10 : pager.getPageSize();
40 | this.paging();
41 | }
42 | }
43 |
44 | private void paging() {
45 | Integer totalNum = list.size();
46 | Integer totalPage = 0;
47 | if (totalNum > 0) {
48 | totalPage = totalNum % pageSize == 0 ? totalNum / pageSize : totalNum / pageSize + 1;
49 | }
50 | if (pageNum > totalPage) {
51 | pageNum = totalPage;
52 | }
53 | int startPoint = (pageNum - 1) * pageSize;
54 | int endPoint = startPoint + pageSize;
55 | if (totalNum <= endPoint) {
56 | endPoint = totalNum;
57 | }
58 | //分页处理
59 | this.list = list.subList(startPoint, endPoint);
60 | }
61 |
62 | public List getList() {
63 | return this.list;
64 | }
65 |
66 | public long getTotal() {
67 | return this.total;
68 | }
69 | }
70 |
--------------------------------------------------------------------------------
/src/main/java/cn/itbat/microsoft/utils/PasswordGenerator.java:
--------------------------------------------------------------------------------
1 | package cn.itbat.microsoft.utils;
2 |
3 | import java.util.ArrayList;
4 | import java.util.Arrays;
5 | import java.util.List;
6 | import java.util.Random;
7 |
8 | /**
9 | * @author mjj
10 | * @date 2020年05月28日 16:37:46
11 | */
12 |
13 | public class PasswordGenerator {
14 | /**
15 | * 密码能包含的特殊字符
16 | */
17 | public static final char[] ALLOWED_SPECIAL_CHARACTORS = {
18 | '`', '~', '@', '#', '$', '%', '^', '&',
19 | '*', '(', ')', '-', '_', '=', '+', '[',
20 | '{', '}', ']', '\\', '|', ';', ':', '"',
21 | '\'', ',', '<', '.', '>', '/', '?'};
22 | private static final int LETTER_RANGE = 26;
23 | private static final int NUMBER_RANGE = 10;
24 | private static final Random RANDOM = new Random();
25 | /**
26 | * 密码的长度
27 | */
28 | private int passwordLength;
29 | /**
30 | * 密码包含字符的最少种类
31 | */
32 | private int minVariousType;
33 |
34 | public PasswordGenerator(int passwordLength, int minVariousType) {
35 | if (minVariousType > CharacterType.values().length) {
36 | minVariousType = CharacterType.values().length;
37 | }
38 | if (minVariousType > passwordLength) {
39 | minVariousType = passwordLength;
40 | }
41 | this.passwordLength = passwordLength;
42 | this.minVariousType = minVariousType;
43 | }
44 |
45 | public String generateRandomPassword() {
46 | char[] password = new char[passwordLength];
47 | List pwCharsIndex = new ArrayList();
48 | for (int i = 0; i < password.length; i++) {
49 | pwCharsIndex.add(i);
50 | }
51 | List takeTypes = new ArrayList(Arrays.asList(CharacterType.values()));
52 | List fixedTypes = Arrays.asList(CharacterType.values());
53 | int typeCount = 0;
54 | while (pwCharsIndex.size() > 0) {
55 | //随机填充一位密码
56 | int pwIndex = pwCharsIndex.remove(RANDOM.nextInt(pwCharsIndex.size()));
57 | Character c;
58 | //生成不同种类字符
59 | if (typeCount < minVariousType) {
60 | c = generateCharacter(takeTypes.remove(RANDOM.nextInt(takeTypes.size())));
61 | typeCount++;
62 | } else {
63 | //随机生成所有种类密码
64 | c = generateCharacter(fixedTypes.get(RANDOM.nextInt(fixedTypes.size())));
65 | }
66 | password[pwIndex] = c;
67 | }
68 | return String.valueOf(password);
69 | }
70 |
71 | private Character generateCharacter(CharacterType type) {
72 | Character c = null;
73 | int rand;
74 | switch (type) {
75 | //随机小写字母
76 | case LOWERCASE:
77 | rand = RANDOM.nextInt(LETTER_RANGE);
78 | rand += 97;
79 | c = (char) rand;
80 | break;
81 | //随机大写字母
82 | case UPPERCASE:
83 | rand = RANDOM.nextInt(LETTER_RANGE);
84 | rand += 65;
85 | c = (char) rand;
86 | break;
87 | //随机数字
88 | case NUMBER:
89 | rand = RANDOM.nextInt(NUMBER_RANGE);
90 | rand += 48;
91 | c = (char) rand;
92 | break;
93 | default:
94 | }
95 | return c;
96 | }
97 | }
98 |
99 | enum CharacterType {
100 | /**
101 | * LOWERCASE
102 | */
103 | LOWERCASE,
104 | /**
105 | * UPPERCASE
106 | */
107 | UPPERCASE,
108 | /**
109 | * NUMBER
110 | */
111 | NUMBER
112 | }
113 |
--------------------------------------------------------------------------------
/src/main/java/cn/itbat/microsoft/vo/BaseResultVo.java:
--------------------------------------------------------------------------------
1 | package cn.itbat.microsoft.vo;
2 |
3 | import lombok.Data;
4 |
5 | import java.io.Serializable;
6 |
7 | /**
8 | * 接口返回封装对象
9 | *
10 | * @author mjj (;¬_¬)
11 | * @version 1.0
12 | * @date 2019-07-10 11:34
13 | **/
14 | @Data
15 | public class BaseResultVo implements Serializable {
16 | /**
17 | * 状态
18 | */
19 | private int status = SUCCESS_CODE;
20 |
21 | /**
22 | * 消息
23 | */
24 | private String message = SUCCESS_MSG;
25 |
26 | /**
27 | * 数据
28 | */
29 | private Object data;
30 |
31 | public static final Integer SUCCESS_CODE = 200;
32 | public static final Integer ERROR_CODE = 500;
33 | public static final Integer NOT_LOGIN = 300;
34 | public static final Integer PAYMENT_FAILURE = 301;
35 |
36 | public static final String SUCCESS_MSG = "操作成功";
37 | public static final String ERROR_MSG = "操作失败";
38 | public static final String NOT_LOGIN_MSG = "未登录";
39 |
40 |
41 | public BaseResultVo(Object data, int status, String message) {
42 | this.status = status;
43 | this.message = message;
44 | this.data = data;
45 | }
46 |
47 | public BaseResultVo(Object data) {
48 | this.data = data;
49 | }
50 |
51 | public BaseResultVo(int status, String message) {
52 | this.status = status;
53 | this.message = message;
54 | }
55 |
56 | public BaseResultVo() {
57 | }
58 |
59 |
60 | public static BaseResultVo success() {
61 | return new BaseResultVo(SUCCESS_CODE, SUCCESS_MSG);
62 | }
63 |
64 | public static BaseResultVo success(Object data) {
65 | return new BaseResultVo(data, SUCCESS_CODE, SUCCESS_MSG);
66 | }
67 |
68 | public static BaseResultVo error(String message) {
69 | return new BaseResultVo(ERROR_CODE, message);
70 | }
71 |
72 | public static BaseResultVo error() {
73 | BaseResultVo baseResultVo = new BaseResultVo();
74 | baseResultVo.setStatus(BaseResultVo.ERROR_CODE);
75 | baseResultVo.setMessage(BaseResultVo.ERROR_MSG);
76 | return baseResultVo;
77 | }
78 |
79 | public static BaseResultVo notLogin() {
80 | return new BaseResultVo(NOT_LOGIN, NOT_LOGIN_MSG);
81 | }
82 |
83 | public static BaseResultVo error(Integer code, String message) {
84 | return new BaseResultVo(code, message);
85 | }
86 | }
87 |
--------------------------------------------------------------------------------
/src/main/java/cn/itbat/microsoft/vo/DirectoryRoleVo.java:
--------------------------------------------------------------------------------
1 | package cn.itbat.microsoft.vo;
2 |
3 | import com.microsoft.graph.models.DirectoryRole;
4 | import lombok.Data;
5 |
6 | @Data
7 | public class DirectoryRoleVo {
8 |
9 | /**
10 | * 角色描述
11 | */
12 | public String description;
13 |
14 | /**
15 | * 角色名称
16 | */
17 | public String displayName;
18 |
19 | /**
20 | * 角色模板ID
21 | */
22 | public String roleTemplateId;
23 |
24 | public DirectoryRoleVo(DirectoryRole role) {
25 | description = role.description;
26 | displayName = role.displayName;
27 | roleTemplateId = role.roleTemplateId;
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/src/main/java/cn/itbat/microsoft/vo/DomainVo.java:
--------------------------------------------------------------------------------
1 | package cn.itbat.microsoft.vo;
2 |
3 | import lombok.AllArgsConstructor;
4 | import lombok.Builder;
5 | import lombok.Data;
6 | import lombok.NoArgsConstructor;
7 |
8 | import java.io.Serializable;
9 |
10 | /**
11 | * 绑定域名
12 | *
13 | * @author mjj
14 | * @date 2020年08月11日 14:57:32
15 | */
16 | @Data
17 | @Builder
18 | @NoArgsConstructor
19 | @AllArgsConstructor
20 | public class DomainVo implements Serializable {
21 |
22 | /**
23 | * 域名
24 | */
25 | private String id;
26 |
27 | private Boolean isDefault;
28 |
29 | /**
30 | * 是否是默认域名
31 | */
32 | private String displayIsDefault;
33 |
34 | private Boolean isRoot;
35 |
36 | /**
37 | * 是否是根域名
38 | */
39 | private String displayIsRoot;
40 | }
41 |
--------------------------------------------------------------------------------
/src/main/java/cn/itbat/microsoft/vo/FontSkuSku.java:
--------------------------------------------------------------------------------
1 | package cn.itbat.microsoft.vo;
2 |
3 | import lombok.AllArgsConstructor;
4 | import lombok.Builder;
5 | import lombok.Data;
6 | import lombok.NoArgsConstructor;
7 |
8 | /**
9 | * @author huahui.wu
10 | * @date 2020年11月25日 11:57:22
11 | */
12 | @Data
13 | @Builder
14 | @NoArgsConstructor
15 | @AllArgsConstructor
16 | public class FontSkuSku {
17 | /**
18 | * 组织名称
19 | */
20 | private String appName;
21 |
22 | /**
23 | * 订阅id
24 | */
25 | private String id;
26 |
27 | /**
28 | * 许可证id
29 | */
30 | private String skuId;
31 |
32 | /**
33 | * 许可证名称
34 | */
35 | private String skuName;
36 |
37 | }
38 |
39 |
--------------------------------------------------------------------------------
/src/main/java/cn/itbat/microsoft/vo/FontUser.java:
--------------------------------------------------------------------------------
1 | package cn.itbat.microsoft.vo;
2 |
3 | import lombok.AllArgsConstructor;
4 | import lombok.Builder;
5 | import lombok.Data;
6 | import lombok.NoArgsConstructor;
7 |
8 | /**
9 | * @author huahui.wu
10 | * @date 2020年11月25日 13:13:25
11 | */
12 | @Data
13 | @Builder
14 | @NoArgsConstructor
15 | @AllArgsConstructor
16 | public class FontUser {
17 |
18 | /**
19 | * 显示名称
20 | */
21 | private String displayName;
22 |
23 | /**
24 | * 用户名
25 | */
26 | private String userPrincipalName;
27 |
28 | /**
29 | * 密码
30 | */
31 | private String password;
32 | }
33 |
--------------------------------------------------------------------------------
/src/main/java/cn/itbat/microsoft/vo/GraphUserSorterVo.java:
--------------------------------------------------------------------------------
1 | package cn.itbat.microsoft.vo;
2 |
3 | import lombok.Data;
4 |
5 | @Data
6 | public class GraphUserSorterVo {
7 | /**
8 | * 两个字母的国家/地区代码(ISO 标准 3166)。检查服务在国家/地区的可用性
9 | */
10 | private String sortusageLocation;
11 |
12 | /**
13 | * 用户创建时间
14 | */
15 | private String sortcreatedDateTime;
16 |
17 | /**
18 | * 用户名
19 | */
20 | private String sortuserPrincipalName;
21 |
22 | /**
23 | * 角色
24 | */
25 | private String sortroles;
26 |
27 | }
28 |
--------------------------------------------------------------------------------
/src/main/java/cn/itbat/microsoft/vo/GraphUserVo.java:
--------------------------------------------------------------------------------
1 | package cn.itbat.microsoft.vo;
2 |
3 | import cn.itbat.microsoft.model.GraphUser;
4 | import lombok.Builder;
5 | import lombok.Data;
6 | import lombok.EqualsAndHashCode;
7 | import org.springframework.beans.BeanUtils;
8 |
9 | import java.util.ArrayList;
10 | import java.util.List;
11 |
12 | /**
13 | * @author mjj
14 | * @date 2020年06月12日 18:29:58
15 | */
16 | @EqualsAndHashCode(callSuper = true)
17 | @Data
18 | public class GraphUserVo extends GraphUser {
19 |
20 | /**
21 | * 组织类型
22 | */
23 | private String appName;
24 |
25 |
26 | /**
27 | * 是否需要删除一个许可证
28 | */
29 | private Boolean needDeleted;
30 |
31 | /**
32 | * 用户状态
33 | */
34 | private String displayAccountEnable;
35 |
36 | /**
37 | * 订阅名称
38 | */
39 | private String skuName;
40 |
41 | /**
42 | * 是否分配许可证
43 | */
44 | private Boolean assignLicense;
45 |
46 | /**
47 | * 是否发送邮件
48 | */
49 | private Boolean sendMail;
50 |
51 | /**
52 | * 邮箱
53 | */
54 | private String mailbox;
55 |
56 | /**
57 | * 邀请码
58 | */
59 | private String code;
60 |
61 | /**
62 | * 查询大小,默认999
63 | */
64 | @Builder.Default
65 | private Integer top = 999;
66 |
67 | /**
68 | * 订阅信息
69 | */
70 | private List skuVos;
71 |
72 | /**
73 | * 两个字母的国家/地区代码(ISO 标准 3166)。检查服务在国家/地区的可用性
74 | */
75 | private String usageLocation;
76 |
77 | /**
78 | * 用户角色
79 | */
80 | private List directoryRoles;
81 |
82 | public GraphUserVo() {
83 | directoryRoles = new ArrayList<>();
84 | }
85 |
86 | public GraphUserVo(GraphUser graphUser) {
87 | if (null != graphUser) {
88 | BeanUtils.copyProperties(graphUser, this);
89 | }
90 | }
91 | }
92 |
--------------------------------------------------------------------------------
/src/main/java/cn/itbat/microsoft/vo/HomePageVo.java:
--------------------------------------------------------------------------------
1 | package cn.itbat.microsoft.vo;
2 |
3 | import lombok.AllArgsConstructor;
4 | import lombok.Builder;
5 | import lombok.Data;
6 | import lombok.NoArgsConstructor;
7 |
8 | import java.io.Serializable;
9 | import java.util.List;
10 |
11 | /**
12 | * 首页展示信息
13 | *
14 | * @author mjj
15 | * @date 2020年08月11日 10:38:56
16 | */
17 | @Data
18 | @Builder
19 | @NoArgsConstructor
20 | @AllArgsConstructor
21 | public class HomePageVo implements Serializable {
22 |
23 | /**
24 | * 统计信息
25 | */
26 | private StatisticsVo statisticsVo;
27 |
28 | /**
29 | * 禁止登陆用户
30 | */
31 | private List noLandingUsers;
32 |
33 | /**
34 | * 未授权用户
35 | */
36 | private List unauthorizedUsers;
37 |
38 | }
39 |
--------------------------------------------------------------------------------
/src/main/java/cn/itbat/microsoft/vo/SkuVo.java:
--------------------------------------------------------------------------------
1 | package cn.itbat.microsoft.vo;
2 |
3 | import lombok.AllArgsConstructor;
4 | import lombok.Builder;
5 | import lombok.Data;
6 | import lombok.NoArgsConstructor;
7 |
8 | /**
9 | * 订阅信息
10 | *
11 | * @author mjj
12 | * @date 2020年08月06日 12:52:08
13 | */
14 | @Data
15 | @Builder
16 | @NoArgsConstructor
17 | @AllArgsConstructor
18 | public class SkuVo {
19 |
20 |
21 | private String skuId;
22 |
23 | /**
24 | * 订阅类型
25 | */
26 | private String skuType;
27 |
28 | /**
29 | * 订阅名称
30 | */
31 | private String skuName;
32 | }
33 |
--------------------------------------------------------------------------------
/src/main/java/cn/itbat/microsoft/vo/StatisticsVo.java:
--------------------------------------------------------------------------------
1 | package cn.itbat.microsoft.vo;
2 |
3 | import lombok.AllArgsConstructor;
4 | import lombok.Builder;
5 | import lombok.Data;
6 | import lombok.NoArgsConstructor;
7 |
8 | import java.io.Serializable;
9 |
10 | /**
11 | * 统计信息
12 | *
13 | * @author mjj
14 | * @date 2020年08月11日 10:40:09
15 | */
16 | @Data
17 | @Builder
18 | @NoArgsConstructor
19 | @AllArgsConstructor
20 | public class StatisticsVo implements Serializable {
21 |
22 | /**
23 | * 产品订阅
24 | */
25 | @Builder.Default
26 | private Integer productSubs = 0;
27 |
28 | /**
29 | * 许可证数
30 | */
31 | @Builder.Default
32 | private Integer licenses = 0;
33 |
34 | /**
35 | * 已分配许可证数
36 | */
37 | @Builder.Default
38 | private Integer allocatedLicenses = 0;
39 |
40 | /**
41 | * 可用许可证数
42 | */
43 | @Builder.Default
44 | private Integer availableLicenses = 0;
45 |
46 | /**
47 | * 用户数
48 | */
49 | @Builder.Default
50 | private Integer users = 0;
51 |
52 | /**
53 | * 允许登陆用户数
54 | */
55 | @Builder.Default
56 | private Integer allowedUsers = 0;
57 |
58 | /**
59 | * 禁止登陆用户数
60 | */
61 | @Builder.Default
62 | private Integer biddenUsers = 0;
63 |
64 | /**
65 | * 未授权用户数
66 | */
67 | @Builder.Default
68 | private Integer unauthorizedUsers = 0;
69 | }
70 |
--------------------------------------------------------------------------------
/src/main/java/cn/itbat/microsoft/vo/SubscribedSkuVo.java:
--------------------------------------------------------------------------------
1 | package cn.itbat.microsoft.vo;
2 |
3 | import cn.itbat.microsoft.enums.CapabilityStatusEnum;
4 | import com.microsoft.graph.models.SubscribedSku;
5 | import lombok.AllArgsConstructor;
6 | import lombok.Builder;
7 | import lombok.Data;
8 | import lombok.NoArgsConstructor;
9 |
10 | import java.io.Serializable;
11 |
12 | /**
13 | * @author mjj
14 | * @date 2020年06月13日 15:56:26
15 | */
16 | @Data
17 | @Builder
18 | @NoArgsConstructor
19 | @AllArgsConstructor
20 | public class SubscribedSkuVo implements Serializable {
21 |
22 | /**
23 | * 组织名称
24 | */
25 | private String appName;
26 |
27 | /**
28 | * 订阅id
29 | */
30 | private String id;
31 |
32 | /**
33 | * 许可证id
34 | */
35 | private String skuId;
36 | /**
37 | * 可取值为:Enabled、Warning、Suspended、Deleted、LockedOut。
38 | *
39 | * @see cn.itbat.microsoft.enums.CapabilityStatusEnum
40 | */
41 | private String capabilityStatus;
42 |
43 | /**
44 | * 状态
45 | */
46 | private String displayStatus;
47 |
48 | /**
49 | * 已分配的许可证数量。
50 | */
51 | private Integer consumedUnits;
52 |
53 | /**
54 | * 唯一 SKU 显示名称
55 | */
56 | private String skuPartNumber;
57 |
58 | /**
59 | * 许可证名称
60 | */
61 | private String skuName;
62 |
63 | /**
64 | * 已启用
65 | */
66 | private Integer enabled;
67 |
68 | /**
69 | * 已挂起
70 | */
71 | private Integer suspended;
72 |
73 | /**
74 | * 警告
75 | */
76 | private Integer warning;
77 |
78 | public SubscribedSkuVo(SubscribedSku subscribedSku) {
79 | id = subscribedSku.id;
80 | skuId = subscribedSku.skuId.toString();
81 | enabled = subscribedSku.prepaidUnits.enabled;
82 | suspended = subscribedSku.prepaidUnits.suspended;
83 | warning = subscribedSku.prepaidUnits.warning;
84 | capabilityStatus = subscribedSku.capabilityStatus;
85 | consumedUnits = subscribedSku.consumedUnits;
86 | displayStatus = CapabilityStatusEnum.getName(subscribedSku.capabilityStatus);
87 | skuPartNumber = subscribedSku.skuPartNumber;
88 | }
89 |
90 | }
91 |
--------------------------------------------------------------------------------
/src/main/java/cn/itbat/microsoft/vo/UserVo.java:
--------------------------------------------------------------------------------
1 | package cn.itbat.microsoft.vo;
2 |
3 | import lombok.Data;
4 |
5 | /**
6 | * @author mjj
7 | * @date 2020年05月28日 16:46:28
8 | */
9 | @Data
10 | public class UserVo {
11 | private String id;
12 | private Boolean accountEnabled;
13 | private String name;
14 | private String surname;
15 | private String gender;
16 | private String region;
17 | private int age;
18 | private String title;
19 | private String phone;
20 | private String email;
21 | private String password;
22 | private String photo;
23 |
24 | }
--------------------------------------------------------------------------------
/src/main/resources/application.yml:
--------------------------------------------------------------------------------
1 | server:
2 | port: 8099
3 |
4 | spring:
5 | application:
6 | name: Microsoft 365 Admin
7 | profiles: # 默认的profile为dev
8 | active: dev
9 |
10 | logging:
11 | level:
12 | global: debug
13 |
--------------------------------------------------------------------------------
/src/main/resources/config/application-dev.yml:
--------------------------------------------------------------------------------
1 | spring:
2 | mail: # 邮件配置,自行修改
3 | host: smtp.qq.com # smtp.qq.com
4 | username: 123@qq.com # 发送邮箱地址
5 | password: 123 # 发送邮箱密码
6 | output:
7 | ansi:
8 | enabled: always
9 | h2:
10 | console:
11 | settings:
12 | web-allow-others: true
13 | path: /h2-console
14 | enabled: false
15 | datasource:
16 | # 初始化数据导入
17 | # data: classpath*:db/data.sql
18 | # sql-script-encoding: utf-8
19 |
20 | initialization-mode: always
21 | continue-on-error: true
22 |
23 | # h2 内存数据库 配置
24 | driver-class-name: org.h2.Driver
25 | url: jdbc:h2:${graph.db.path}
26 | username: graph
27 | password: 123456
28 | jackson:
29 | date-format: yyyy-MM-dd HH:mm
30 | time-zone: GMT+8
31 | jpa:
32 | hibernate:
33 | ddl-auto: update
34 | properties:
35 | hibernate:
36 | format_sql: false
37 | show-sql: false
38 | # redis: # redis 配置
39 | # database: 0
40 | # host: 127.0.0.1
41 | # port: 6379
42 |
43 | # 程序自定义配置
44 | graph:
45 | cache:
46 | token: default # token 缓存方式默认内存,redis 方式 需要配置 redis
47 | timeout: # 缓存超时时间 单位分钟
48 | user: 60 # 默认一小时
49 | license: 1440 # 默认一天
50 | domain: 1440 # 默认一天
51 | db:
52 | path: ${user.home}/.graph/db/graph
53 |
54 | # 后台登陆配置
55 | userName: root # 登陆账户,自行修改
56 | password: 123456 # 登陆密码,自行修改
57 |
58 | # 邀请注册配置
59 | invite: mjj,mjj2 # 可以被注册的账号类型,为下面 configs.appName 的配置(必填,','分隔)
60 | inviteSub: # 为空表示全部
61 | inviteDomain: # 为空表示使用默认域名,格式:xxx.onmicrosoft.com
62 | usageLocation: HK,US #(此处会针对上面的配置覆盖)可选择的地区,用','分隔,首个将成为默认值,为空表示只使用HK(可以为空)
63 |
64 | # api配置
65 | configs:
66 | - appName: mjj # 自定义该账号的类型(建议使用英文:默认域名前缀,必填)
67 | appId: mjj # 应用程序(客户端) ID client(必填)
68 | appTenant: mjj # 目录(租户) tenant(必填)
69 | appSecret: mjj # secrets(必填)
70 | admin: mjj # 全局管理员账号(可以为空)
71 | usageLocation: HK,US #(此处会针对上面的配置覆盖)可选择的地区,用','分隔,首个将成为默认值,为空表示只使用HK(可以为空)
72 | - appName: mjj2 # 账号2配置,如果不需要请删除
73 | appId: mjj2
74 | appTenant: mjj2
75 | appSecret: mjj2
76 | domain: mjj2
77 | admin: mjj2
78 | usageLocation: US #(此处会针对上面的配置覆盖)可选择的地区,用','分隔,首个将成为默认值,为空表示只使用HK(可以为空)
79 | subscribed: # 订阅类型,自行添加其他
80 | - skuName: STANDARDWOFFPACK_STUDENT
81 | displayName: A1 学生版
82 | skuId: 314c4481-f395-4525-be8b-2ec4bb1e9d91
83 | - skuName: STANDARDWOFFPACK_FACULTY
84 | displayName: A1 教师版
85 | skuId: 94763226-9b3c-4e75-a931-5c89701abe66
86 | - skuName: OFFICE_365_A1_PLUS_FOR_STUDENT
87 | displayName: A1P 学生版
88 | skuId: e82ae690-a2d5-4d76-8d30-7c6e01e6022e
89 | - skuName: OFFICE_365_A1_PLUS_FOR_FACULTY
90 | displayName: A1P 教师版
91 | skuId: 78e66a63-337a-4a9a-8959-41c6654dfb56
92 | - skuName: M365EDU_A3_STUUSEBNFT_RPA1
93 | displayName: A3 无人值守版
94 | skuId: 1aa94593-ca12-4254-a738-81a5972958e8
95 | - skuName: Office_365_E3Y
96 | displayName: E3Y
97 | skuId: 6fd2c87f-b296-42f0-b197-1e91e994b900
98 | - skuName: DEVELOPERPACK_E5
99 | displayName: E5 开发者订阅
100 | skuId: c42b9cae-ea4f-4ab7-9717-81576235ccac
101 |
102 |
103 |
--------------------------------------------------------------------------------
/src/main/resources/db/data.sql:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/6mb/Microsoft-365-Admin/89ca444776dae12d49047e55ac0bbbd3daabc9cf/src/main/resources/db/data.sql
--------------------------------------------------------------------------------
/src/main/resources/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/6mb/Microsoft-365-Admin/89ca444776dae12d49047e55ac0bbbd3daabc9cf/src/main/resources/favicon.ico
--------------------------------------------------------------------------------
/src/main/resources/static/css/gm-diy.css:
--------------------------------------------------------------------------------
1 | .gm-microsoft-365-skin .table-header{
2 | background: white;
3 | }
4 | .gm-microsoft-365-skin .gm-toolbar{
5 | background-color: white;
6 | }
7 | .gm-microsoft-365-skin .gm-toolbar .pagination {
8 | height: 10px;
9 | }
--------------------------------------------------------------------------------
/src/main/resources/static/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/6mb/Microsoft-365-Admin/89ca444776dae12d49047e55ac0bbbd3daabc9cf/src/main/resources/static/favicon.ico
--------------------------------------------------------------------------------
/src/main/resources/static/fonts/materialdesignicons.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/6mb/Microsoft-365-Admin/89ca444776dae12d49047e55ac0bbbd3daabc9cf/src/main/resources/static/fonts/materialdesignicons.eot
--------------------------------------------------------------------------------
/src/main/resources/static/fonts/materialdesignicons.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/6mb/Microsoft-365-Admin/89ca444776dae12d49047e55ac0bbbd3daabc9cf/src/main/resources/static/fonts/materialdesignicons.ttf
--------------------------------------------------------------------------------
/src/main/resources/static/fonts/materialdesignicons.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/6mb/Microsoft-365-Admin/89ca444776dae12d49047e55ac0bbbd3daabc9cf/src/main/resources/static/fonts/materialdesignicons.woff
--------------------------------------------------------------------------------
/src/main/resources/static/fonts/materialdesignicons.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/6mb/Microsoft-365-Admin/89ca444776dae12d49047e55ac0bbbd3daabc9cf/src/main/resources/static/fonts/materialdesignicons.woff2
--------------------------------------------------------------------------------
/src/main/resources/static/images/captcha.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/6mb/Microsoft-365-Admin/89ca444776dae12d49047e55ac0bbbd3daabc9cf/src/main/resources/static/images/captcha.png
--------------------------------------------------------------------------------
/src/main/resources/static/images/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/6mb/Microsoft-365-Admin/89ca444776dae12d49047e55ac0bbbd3daabc9cf/src/main/resources/static/images/favicon.ico
--------------------------------------------------------------------------------
/src/main/resources/static/images/gallery/1.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/6mb/Microsoft-365-Admin/89ca444776dae12d49047e55ac0bbbd3daabc9cf/src/main/resources/static/images/gallery/1.jpg
--------------------------------------------------------------------------------
/src/main/resources/static/images/gallery/10.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/6mb/Microsoft-365-Admin/89ca444776dae12d49047e55ac0bbbd3daabc9cf/src/main/resources/static/images/gallery/10.jpg
--------------------------------------------------------------------------------
/src/main/resources/static/images/gallery/11.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/6mb/Microsoft-365-Admin/89ca444776dae12d49047e55ac0bbbd3daabc9cf/src/main/resources/static/images/gallery/11.jpg
--------------------------------------------------------------------------------
/src/main/resources/static/images/gallery/13.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/6mb/Microsoft-365-Admin/89ca444776dae12d49047e55ac0bbbd3daabc9cf/src/main/resources/static/images/gallery/13.jpg
--------------------------------------------------------------------------------
/src/main/resources/static/images/gallery/14.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/6mb/Microsoft-365-Admin/89ca444776dae12d49047e55ac0bbbd3daabc9cf/src/main/resources/static/images/gallery/14.jpg
--------------------------------------------------------------------------------
/src/main/resources/static/images/gallery/15.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/6mb/Microsoft-365-Admin/89ca444776dae12d49047e55ac0bbbd3daabc9cf/src/main/resources/static/images/gallery/15.jpg
--------------------------------------------------------------------------------
/src/main/resources/static/images/gallery/16.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/6mb/Microsoft-365-Admin/89ca444776dae12d49047e55ac0bbbd3daabc9cf/src/main/resources/static/images/gallery/16.jpg
--------------------------------------------------------------------------------
/src/main/resources/static/images/gallery/17.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/6mb/Microsoft-365-Admin/89ca444776dae12d49047e55ac0bbbd3daabc9cf/src/main/resources/static/images/gallery/17.jpg
--------------------------------------------------------------------------------
/src/main/resources/static/images/gallery/2.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/6mb/Microsoft-365-Admin/89ca444776dae12d49047e55ac0bbbd3daabc9cf/src/main/resources/static/images/gallery/2.jpg
--------------------------------------------------------------------------------
/src/main/resources/static/images/gallery/3.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/6mb/Microsoft-365-Admin/89ca444776dae12d49047e55ac0bbbd3daabc9cf/src/main/resources/static/images/gallery/3.jpg
--------------------------------------------------------------------------------
/src/main/resources/static/images/gallery/4.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/6mb/Microsoft-365-Admin/89ca444776dae12d49047e55ac0bbbd3daabc9cf/src/main/resources/static/images/gallery/4.jpg
--------------------------------------------------------------------------------
/src/main/resources/static/images/gallery/5.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/6mb/Microsoft-365-Admin/89ca444776dae12d49047e55ac0bbbd3daabc9cf/src/main/resources/static/images/gallery/5.jpg
--------------------------------------------------------------------------------
/src/main/resources/static/images/gallery/6.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/6mb/Microsoft-365-Admin/89ca444776dae12d49047e55ac0bbbd3daabc9cf/src/main/resources/static/images/gallery/6.jpg
--------------------------------------------------------------------------------
/src/main/resources/static/images/gallery/7.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/6mb/Microsoft-365-Admin/89ca444776dae12d49047e55ac0bbbd3daabc9cf/src/main/resources/static/images/gallery/7.jpg
--------------------------------------------------------------------------------
/src/main/resources/static/images/gallery/8.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/6mb/Microsoft-365-Admin/89ca444776dae12d49047e55ac0bbbd3daabc9cf/src/main/resources/static/images/gallery/8.jpg
--------------------------------------------------------------------------------
/src/main/resources/static/images/gallery/9.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/6mb/Microsoft-365-Admin/89ca444776dae12d49047e55ac0bbbd3daabc9cf/src/main/resources/static/images/gallery/9.jpg
--------------------------------------------------------------------------------
/src/main/resources/static/images/img-slide-1.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/6mb/Microsoft-365-Admin/89ca444776dae12d49047e55ac0bbbd3daabc9cf/src/main/resources/static/images/img-slide-1.jpg
--------------------------------------------------------------------------------
/src/main/resources/static/images/img-slide-2.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/6mb/Microsoft-365-Admin/89ca444776dae12d49047e55ac0bbbd3daabc9cf/src/main/resources/static/images/img-slide-2.jpg
--------------------------------------------------------------------------------
/src/main/resources/static/images/img-slide-3.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/6mb/Microsoft-365-Admin/89ca444776dae12d49047e55ac0bbbd3daabc9cf/src/main/resources/static/images/img-slide-3.jpg
--------------------------------------------------------------------------------
/src/main/resources/static/images/img-slide-4.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/6mb/Microsoft-365-Admin/89ca444776dae12d49047e55ac0bbbd3daabc9cf/src/main/resources/static/images/img-slide-4.jpg
--------------------------------------------------------------------------------
/src/main/resources/static/images/img-slide-5.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/6mb/Microsoft-365-Admin/89ca444776dae12d49047e55ac0bbbd3daabc9cf/src/main/resources/static/images/img-slide-5.jpg
--------------------------------------------------------------------------------
/src/main/resources/static/images/login-bg-2.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/6mb/Microsoft-365-Admin/89ca444776dae12d49047e55ac0bbbd3daabc9cf/src/main/resources/static/images/login-bg-2.jpg
--------------------------------------------------------------------------------
/src/main/resources/static/images/login-bg-3.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/6mb/Microsoft-365-Admin/89ca444776dae12d49047e55ac0bbbd3daabc9cf/src/main/resources/static/images/login-bg-3.jpg
--------------------------------------------------------------------------------
/src/main/resources/static/images/login-bg-4.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/6mb/Microsoft-365-Admin/89ca444776dae12d49047e55ac0bbbd3daabc9cf/src/main/resources/static/images/login-bg-4.jpg
--------------------------------------------------------------------------------
/src/main/resources/static/images/login-bg.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/6mb/Microsoft-365-Admin/89ca444776dae12d49047e55ac0bbbd3daabc9cf/src/main/resources/static/images/login-bg.jpg
--------------------------------------------------------------------------------
/src/main/resources/static/images/logo-ico.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/6mb/Microsoft-365-Admin/89ca444776dae12d49047e55ac0bbbd3daabc9cf/src/main/resources/static/images/logo-ico.png
--------------------------------------------------------------------------------
/src/main/resources/static/images/logo-sidebar--2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/6mb/Microsoft-365-Admin/89ca444776dae12d49047e55ac0bbbd3daabc9cf/src/main/resources/static/images/logo-sidebar--2.png
--------------------------------------------------------------------------------
/src/main/resources/static/images/logo-sidebar-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/6mb/Microsoft-365-Admin/89ca444776dae12d49047e55ac0bbbd3daabc9cf/src/main/resources/static/images/logo-sidebar-1.png
--------------------------------------------------------------------------------
/src/main/resources/static/images/logo-sidebar.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/6mb/Microsoft-365-Admin/89ca444776dae12d49047e55ac0bbbd3daabc9cf/src/main/resources/static/images/logo-sidebar.png
--------------------------------------------------------------------------------
/src/main/resources/static/images/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/6mb/Microsoft-365-Admin/89ca444776dae12d49047e55ac0bbbd3daabc9cf/src/main/resources/static/images/logo.png
--------------------------------------------------------------------------------
/src/main/resources/static/images/users/avatar.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/6mb/Microsoft-365-Admin/89ca444776dae12d49047e55ac0bbbd3daabc9cf/src/main/resources/static/images/users/avatar.jpg
--------------------------------------------------------------------------------
/src/main/resources/static/js/about.js:
--------------------------------------------------------------------------------
1 | let path = url;
2 |
3 | $(window).on("load", function () {
4 | $('#titleName').html(" 关于平台 ");
5 | $("#appNameSelect").hide();
6 | $("#clearCache").hide();
7 | getSystemMonitor();
8 | });
9 |
10 | setInterval(function () {
11 | getSystemMonitor();
12 | }, 10000);
13 |
14 | function getSystemMonitor() {
15 | $.ajax({
16 | type: "get",
17 | url: path + "/system/monitor",
18 | data: {},
19 | dataType: "json",
20 | success: function (r) {
21 | if (r.status !== 200) {
22 | lightyear.notify(r.message, 'danger', 1000);
23 | } else {
24 | $("#systemTable").empty();
25 | $("#jvmTable").empty();
26 | sys = r.data.sys;
27 | jvm = r.data.jvm;
28 | $("#systemTable").append('\n' +
29 | '\n' +
30 | '系统属性 | \n' +
31 | ' | \n' +
32 | '
'
33 | );
34 | $("#systemTable").append('' + ' 操作系统 | ' + '' + sys.osName + ' | ' + '
');
35 | $("#systemTable").append('' + ' 系统版本 | ' + '' + sys.osVersion + ' | ' + '
');
36 | $("#systemTable").append('' + ' 系统架构 | ' + '' + sys.osArch + ' | ' + '
');
37 | $("#systemTable").append('' + ' 系统启动时间 | ' + '' + sys.upTime + ' | ' + '
');
38 | $("#jvmTable").append('\n' +
39 | '\n' +
40 | 'JVM属性 | \n' +
41 | ' | \n' +
42 | '
\n' +
43 | ''
44 | );
45 | $("#jvmTable").append('' + ' JVM 版本' + ' | ' + '' + jvm.version + ' | ' + '
');
46 | $("#jvmTable").append('' + ' JVM 可占用内存' + ' | ' + '' + jvm.max.toFixed(2) + ' MB | ' + '
');
47 | $("#jvmTable").append('' + ' JVM 已占用内存' + ' | ' + '' + jvm.free.toFixed(2) + ' MB | ' + '
');
48 | $("#jvmTable").append('' + ' JVM 空闲内存' + ' | ' + '' + jvm.total.toFixed(2) + ' MB | ' + '
');
49 | }
50 | },
51 | error: function () {
52 | /*错误信息处理*/
53 | lightyear.notify("服务器错误,请稍后再试~", 'danger', 100);
54 | }
55 | });
56 | }
57 |
--------------------------------------------------------------------------------
/src/main/resources/static/js/bootstrap-colorpicker/css/bootstrap-colorpicker.css:
--------------------------------------------------------------------------------
1 | /*!
2 | * Bootstrap Colorpicker v2.3.3
3 | * http://mjolnic.github.io/bootstrap-colorpicker/
4 | *
5 | * Originally written by (c) 2012 Stefan Petre
6 | * Licensed under the Apache License v2.0
7 | * http://www.apache.org/licenses/LICENSE-2.0.txt
8 | *
9 | */
10 | .colorpicker-saturation {
11 | width: 100px;
12 | height: 100px;
13 | background-image: url("../img/bootstrap-colorpicker/saturation.png");
14 | cursor: crosshair;
15 | float: left;
16 | }
17 | .colorpicker-saturation i {
18 | display: block;
19 | height: 5px;
20 | width: 5px;
21 | border: 1px solid #000;
22 | -webkit-border-radius: 5px;
23 | -moz-border-radius: 5px;
24 | border-radius: 5px;
25 | position: absolute;
26 | top: 0;
27 | left: 0;
28 | margin: -4px 0 0 -4px;
29 | }
30 | .colorpicker-saturation i b {
31 | display: block;
32 | height: 5px;
33 | width: 5px;
34 | border: 1px solid #fff;
35 | -webkit-border-radius: 5px;
36 | -moz-border-radius: 5px;
37 | border-radius: 5px;
38 | }
39 | .colorpicker-hue,
40 | .colorpicker-alpha {
41 | width: 15px;
42 | height: 100px;
43 | float: left;
44 | cursor: row-resize;
45 | margin-left: 4px;
46 | margin-bottom: 4px;
47 | }
48 | .colorpicker-hue i,
49 | .colorpicker-alpha i {
50 | display: block;
51 | height: 1px;
52 | background: #000;
53 | border-top: 1px solid #fff;
54 | position: absolute;
55 | top: 0;
56 | left: 0;
57 | width: 100%;
58 | margin-top: -1px;
59 | }
60 | .colorpicker-hue {
61 | background-image: url("../img/bootstrap-colorpicker/hue.png");
62 | }
63 | .colorpicker-alpha {
64 | background-image: url("../img/bootstrap-colorpicker/alpha.png");
65 | display: none;
66 | }
67 | .colorpicker-saturation,
68 | .colorpicker-hue,
69 | .colorpicker-alpha {
70 | background-size: contain;
71 | }
72 | .colorpicker {
73 | padding: 4px;
74 | min-width: 130px;
75 | margin-top: 1px;
76 | -webkit-border-radius: 4px;
77 | -moz-border-radius: 4px;
78 | border-radius: 4px;
79 | z-index: 2500;
80 | }
81 | .colorpicker:before,
82 | .colorpicker:after {
83 | display: table;
84 | content: "";
85 | line-height: 0;
86 | }
87 | .colorpicker:after {
88 | clear: both;
89 | }
90 | .colorpicker:before {
91 | content: '';
92 | display: inline-block;
93 | border-left: 7px solid transparent;
94 | border-right: 7px solid transparent;
95 | border-bottom: 7px solid #ccc;
96 | border-bottom-color: rgba(0, 0, 0, 0.2);
97 | position: absolute;
98 | top: -7px;
99 | left: 6px;
100 | }
101 | .colorpicker:after {
102 | content: '';
103 | display: inline-block;
104 | border-left: 6px solid transparent;
105 | border-right: 6px solid transparent;
106 | border-bottom: 6px solid #ffffff;
107 | position: absolute;
108 | top: -6px;
109 | left: 7px;
110 | }
111 | .colorpicker div {
112 | position: relative;
113 | }
114 | .colorpicker.colorpicker-with-alpha {
115 | min-width: 140px;
116 | }
117 | .colorpicker.colorpicker-with-alpha .colorpicker-alpha {
118 | display: block;
119 | }
120 | .colorpicker-color {
121 | height: 10px;
122 | margin-top: 5px;
123 | clear: both;
124 | background-image: url("../img/bootstrap-colorpicker/alpha.png");
125 | background-position: 0 100%;
126 | }
127 | .colorpicker-color div {
128 | height: 10px;
129 | }
130 | .colorpicker-selectors {
131 | display: none;
132 | height: 10px;
133 | margin-top: 5px;
134 | clear: both;
135 | }
136 | .colorpicker-selectors i {
137 | cursor: pointer;
138 | float: left;
139 | height: 10px;
140 | width: 10px;
141 | }
142 | .colorpicker-selectors i + i {
143 | margin-left: 3px;
144 | }
145 | .colorpicker-element .input-group-addon i,
146 | .colorpicker-element .add-on i {
147 | display: inline-block;
148 | cursor: pointer;
149 | height: 16px;
150 | vertical-align: text-top;
151 | width: 16px;
152 | }
153 | .colorpicker.colorpicker-inline {
154 | position: relative;
155 | display: inline-block;
156 | float: none;
157 | z-index: auto;
158 | }
159 | .colorpicker.colorpicker-horizontal {
160 | width: 110px;
161 | min-width: 110px;
162 | height: auto;
163 | }
164 | .colorpicker.colorpicker-horizontal .colorpicker-saturation {
165 | margin-bottom: 4px;
166 | }
167 | .colorpicker.colorpicker-horizontal .colorpicker-color {
168 | width: 100px;
169 | }
170 | .colorpicker.colorpicker-horizontal .colorpicker-hue,
171 | .colorpicker.colorpicker-horizontal .colorpicker-alpha {
172 | width: 100px;
173 | height: 15px;
174 | float: left;
175 | cursor: col-resize;
176 | margin-left: 0px;
177 | margin-bottom: 4px;
178 | }
179 | .colorpicker.colorpicker-horizontal .colorpicker-hue i,
180 | .colorpicker.colorpicker-horizontal .colorpicker-alpha i {
181 | display: block;
182 | height: 15px;
183 | background: #ffffff;
184 | position: absolute;
185 | top: 0;
186 | left: 0;
187 | width: 1px;
188 | border: none;
189 | margin-top: 0px;
190 | }
191 | .colorpicker.colorpicker-horizontal .colorpicker-hue {
192 | background-image: url("../img/bootstrap-colorpicker/hue-horizontal.png");
193 | }
194 | .colorpicker.colorpicker-horizontal .colorpicker-alpha {
195 | background-image: url("../img/bootstrap-colorpicker/alpha-horizontal.png");
196 | }
197 | .colorpicker.colorpicker-hidden {
198 | display: none;
199 | }
200 | .colorpicker.colorpicker-visible {
201 | display: block;
202 | }
203 | .colorpicker-inline.colorpicker-visible {
204 | display: inline-block;
205 | }
206 | .colorpicker-right:before {
207 | left: auto;
208 | right: 6px;
209 | }
210 | .colorpicker-right:after {
211 | left: auto;
212 | right: 7px;
213 | }
214 | .colorpicker-no-arrow:before {
215 | border-right: 0;
216 | border-left: 0;
217 | }
218 | .colorpicker-no-arrow:after {
219 | border-right: 0;
220 | border-left: 0;
221 | }
222 | /*# sourceMappingURL=bootstrap-colorpicker.css.map */
--------------------------------------------------------------------------------
/src/main/resources/static/js/bootstrap-colorpicker/css/bootstrap-colorpicker.css.map:
--------------------------------------------------------------------------------
1 | {"version":3,"sources":["src/less/colorpicker.less"],"names":[],"mappings":";;;;;;;;;AAqBA;EACE,YAAA;EACA,aAAA;EAXA,sBAAsB,8CAAtB;EAaA,iBAAA;EACA,WAAA;;AALF,uBAME;EACE,cAAA;EACA,WAAA;EACA,UAAA;EACA,sBAAA;EAfF,0BAAA;EACA,uBAAA;EACA,kBAAA;EAeE,kBAAA;EACA,MAAA;EACA,OAAA;EACA,qBAAA;;AAfJ,uBAME,EAUE;EACE,cAAA;EACA,WAAA;EACA,UAAA;EACA,sBAAA;EAzBJ,0BAAA;EACA,uBAAA;EACA,kBAAA;;AA6BF;AACA;EACE,WAAA;EACA,aAAA;EACA,WAAA;EACA,kBAAA;EACA,gBAAA;EACA,kBAAA;;AAGF,gBAAiB;AACjB,kBAAmB;EACjB,cAAA;EACA,WAAA;EACA,gBAAA;EACA,0BAAA;EACA,kBAAA;EACA,MAAA;EACA,OAAA;EACA,WAAA;EACA,gBAAA;;AAGF;EA1DE,sBAAsB,uCAAtB;;AA8DF;EA9DE,sBAAsB,yCAAtB;EAgEA,aAAA;;AAGF;AACA;AACA;EACE,wBAAA;;AAGF;EACE,YAAA;EACA,gBAAA;EACA,eAAA;EAxEA,0BAAA;EACA,uBAAA;EACA,kBAAA;EAwEA,aAAA;;AAGF,YAAY;AACZ,YAAY;EACV,cAAA;EACA,SAAS,EAAT;EACA,cAAA;;AAGF,YAAY;EACV,WAAA;;AAGF,YAAY;EACV,SAAS,EAAT;EACA,qBAAA;EACA,kCAAA;EACA,mCAAA;EACA,6BAAA;EACA,uCAAA;EACA,kBAAA;EACA,SAAA;EACA,SAAA;;AAGF,YAAY;EACV,SAAS,EAAT;EACA,qBAAA;EACA,kCAAA;EACA,mCAAA;EACA,gCAAA;EACA,kBAAA;EACA,SAAA;EACA,SAAA;;AAGF,YAAa;EACX,kBAAA;;AAGF,YAAY;EACV,gBAAA;;AAGF,YAAY,uBAAwB;EAClC,cAAA;;AAGF;EACE,YAAA;EACA,eAAA;EACA,WAAA;EAlIA,sBAAsB,yCAAtB;EAoIA,2BAAA;;AAGF,kBAAmB;EACjB,YAAA;;AAGF;EACE,aAAA;EACA,YAAA;EACA,eAAA;EACA,WAAA;;AAGF,sBAAuB;EACrB,eAAA;EACA,WAAA;EACA,YAAA;EACA,WAAA;;AAGF,sBAAuB,EAAE;EACvB,gBAAA;;AAGF,oBAAqB,mBAAmB;AACxC,oBAAqB,QAAQ;EAC3B,qBAAA;EACA,eAAA;EACA,YAAA;EACA,wBAAA;EACA,WAAA;;AAGF,YAAY;EACV,kBAAA;EACA,qBAAA;EACA,WAAA;EACA,aAAA;;AAGF,YAAY;EACV,YAAA;EACA,gBAAA;EACA,YAAA;;AAGF,YAAY,uBAAwB;EAClC,kBAAA;;AAGF,YAAY,uBAAwB;EAClC,YAAA;;AAGF,YAAY,uBAAwB;AACpC,YAAY,uBAAwB;EAClC,YAAA;EACA,YAAA;EACA,WAAA;EACA,kBAAA;EACA,gBAAA;EACA,kBAAA;;AAGF,YAAY,uBAAwB,iBAAiB;AACrD,YAAY,uBAAwB,mBAAmB;EACrD,cAAA;EACA,YAAA;EACA,mBAAA;EACA,kBAAA;EACA,MAAA;EACA,OAAA;EACA,UAAA;EACA,YAAA;EACA,eAAA;;AAGF,YAAY,uBAAwB;EAlNlC,sBAAsB,kDAAtB;;AAsNF,YAAY,uBAAwB;EAtNlC,sBAAsB,oDAAtB;;AA0NF,YAAY;EACV,aAAA;;AAGF,YAAY;EACV,cAAA;;AAGF,mBAAmB;EACjB,qBAAA;;AAGF,kBAAkB;EAChB,UAAA;EACA,UAAA;;AAGF,kBAAkB;EAChB,UAAA;EACA,UAAA;;AAGF,qBAAqB;EACnB,eAAA;EACA,cAAA;;AAGF,qBAAqB;EACnB,eAAA;EACA,cAAA","sourcesContent":["/*!\n * Bootstrap Colorpicker v2.3.3\n * http://mjolnic.github.io/bootstrap-colorpicker/\n *\n * Originally written by (c) 2012 Stefan Petre\n * Licensed under the Apache License v2.0\n * http://www.apache.org/licenses/LICENSE-2.0.txt\n *\n */\n@imgPath: \"../img/bootstrap-colorpicker/\";\n\n.bgImg(@imgFilename) {\n background-image: url(\"@{imgPath}@{imgFilename}\");\n}\n\n.borderRadius(@size) {\n -webkit-border-radius: @size;\n -moz-border-radius: @size;\n border-radius: @size;\n}\n\n.colorpicker-saturation {\n width: 100px;\n height: 100px;\n .bgImg('saturation.png');\n cursor: crosshair;\n float: left;\n i {\n display: block;\n height: 5px;\n width: 5px;\n border: 1px solid #000;\n .borderRadius(5px);\n position: absolute;\n top: 0;\n left: 0;\n margin: -4px 0 0 -4px;\n b {\n display: block;\n height: 5px;\n width: 5px;\n border: 1px solid #fff;\n .borderRadius(5px);\n }\n }\n}\n\n.colorpicker-hue,\n.colorpicker-alpha {\n width: 15px;\n height: 100px;\n float: left;\n cursor: row-resize;\n margin-left: 4px;\n margin-bottom: 4px;\n}\n\n.colorpicker-hue i,\n.colorpicker-alpha i {\n display: block;\n height: 1px;\n background: #000;\n border-top: 1px solid #fff;\n position: absolute;\n top: 0;\n left: 0;\n width: 100%;\n margin-top: -1px;\n}\n\n.colorpicker-hue {\n .bgImg('hue.png');\n}\n\n.colorpicker-alpha {\n .bgImg('alpha.png');\n display: none;\n}\n\n.colorpicker-saturation,\n.colorpicker-hue,\n.colorpicker-alpha {\n background-size: contain;\n}\n\n.colorpicker {\n padding: 4px;\n min-width: 130px;\n margin-top: 1px;\n .borderRadius(4px);\n z-index: 2500;\n}\n\n.colorpicker:before,\n.colorpicker:after {\n display: table;\n content: \"\";\n line-height: 0;\n}\n\n.colorpicker:after {\n clear: both;\n}\n\n.colorpicker:before {\n content: '';\n display: inline-block;\n border-left: 7px solid transparent;\n border-right: 7px solid transparent;\n border-bottom: 7px solid #ccc;\n border-bottom-color: rgba(0, 0, 0, 0.2);\n position: absolute;\n top: -7px;\n left: 6px;\n}\n\n.colorpicker:after {\n content: '';\n display: inline-block;\n border-left: 6px solid transparent;\n border-right: 6px solid transparent;\n border-bottom: 6px solid #ffffff;\n position: absolute;\n top: -6px;\n left: 7px;\n}\n\n.colorpicker div {\n position: relative;\n}\n\n.colorpicker.colorpicker-with-alpha {\n min-width: 140px;\n}\n\n.colorpicker.colorpicker-with-alpha .colorpicker-alpha {\n display: block;\n}\n\n.colorpicker-color {\n height: 10px;\n margin-top: 5px;\n clear: both;\n .bgImg('alpha.png');\n background-position: 0 100%;\n}\n\n.colorpicker-color div {\n height: 10px;\n}\n\n.colorpicker-selectors {\n display: none;\n height: 10px;\n margin-top: 5px;\n clear: both;\n}\n\n.colorpicker-selectors i {\n cursor: pointer;\n float: left;\n height: 10px;\n width: 10px;\n}\n\n.colorpicker-selectors i + i {\n margin-left: 3px;\n}\n\n.colorpicker-element .input-group-addon i,\n.colorpicker-element .add-on i {\n display: inline-block;\n cursor: pointer;\n height: 16px;\n vertical-align: text-top;\n width: 16px;\n}\n\n.colorpicker.colorpicker-inline {\n position: relative;\n display: inline-block;\n float: none;\n z-index: auto;\n}\n\n.colorpicker.colorpicker-horizontal {\n width: 110px;\n min-width: 110px;\n height: auto;\n}\n\n.colorpicker.colorpicker-horizontal .colorpicker-saturation {\n margin-bottom: 4px;\n}\n\n.colorpicker.colorpicker-horizontal .colorpicker-color {\n width: 100px;\n}\n\n.colorpicker.colorpicker-horizontal .colorpicker-hue,\n.colorpicker.colorpicker-horizontal .colorpicker-alpha {\n width: 100px;\n height: 15px;\n float: left;\n cursor: col-resize;\n margin-left: 0px;\n margin-bottom: 4px;\n}\n\n.colorpicker.colorpicker-horizontal .colorpicker-hue i,\n.colorpicker.colorpicker-horizontal .colorpicker-alpha i {\n display: block;\n height: 15px;\n background: #ffffff;\n position: absolute;\n top: 0;\n left: 0;\n width: 1px;\n border: none;\n margin-top: 0px;\n}\n\n.colorpicker.colorpicker-horizontal .colorpicker-hue {\n .bgImg('hue-horizontal.png');\n}\n\n.colorpicker.colorpicker-horizontal .colorpicker-alpha {\n .bgImg('alpha-horizontal.png');\n}\n\n.colorpicker.colorpicker-hidden {\n display: none;\n}\n\n.colorpicker.colorpicker-visible {\n display: block;\n}\n\n.colorpicker-inline.colorpicker-visible {\n display: inline-block;\n}\n\n.colorpicker-right:before {\n left: auto;\n right: 6px;\n}\n\n.colorpicker-right:after {\n left: auto;\n right: 7px;\n}\n\n.colorpicker-no-arrow:before {\n border-right: 0;\n border-left: 0;\n}\n\n.colorpicker-no-arrow:after {\n border-right: 0;\n border-left: 0;\n}\n"]}
--------------------------------------------------------------------------------
/src/main/resources/static/js/bootstrap-colorpicker/css/bootstrap-colorpicker.min.css:
--------------------------------------------------------------------------------
1 | /*!
2 | * Bootstrap Colorpicker v2.3.3
3 | * http://mjolnic.github.io/bootstrap-colorpicker/
4 | *
5 | * Originally written by (c) 2012 Stefan Petre
6 | * Licensed under the Apache License v2.0
7 | * http://www.apache.org/licenses/LICENSE-2.0.txt
8 | *
9 | */.colorpicker-saturation{width:100px;height:100px;background-image:url(../img/bootstrap-colorpicker/saturation.png);cursor:crosshair;float:left}.colorpicker-saturation i{display:block;height:5px;width:5px;border:1px solid #000;-webkit-border-radius:5px;-moz-border-radius:5px;border-radius:5px;position:absolute;top:0;left:0;margin:-4px 0 0 -4px}.colorpicker-saturation i b{display:block;height:5px;width:5px;border:1px solid #fff;-webkit-border-radius:5px;-moz-border-radius:5px;border-radius:5px}.colorpicker-alpha,.colorpicker-hue{width:15px;height:100px;float:left;cursor:row-resize;margin-left:4px;margin-bottom:4px}.colorpicker-alpha i,.colorpicker-hue i{display:block;height:1px;background:#000;border-top:1px solid #fff;position:absolute;top:0;left:0;width:100%;margin-top:-1px}.colorpicker-hue{background-image:url(../img/bootstrap-colorpicker/hue.png)}.colorpicker-alpha{background-image:url(../img/bootstrap-colorpicker/alpha.png);display:none}.colorpicker-alpha,.colorpicker-hue,.colorpicker-saturation{background-size:contain}.colorpicker{padding:4px;min-width:130px;margin-top:1px;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;z-index:2500}.colorpicker:after,.colorpicker:before{display:table;content:"";line-height:0}.colorpicker:after{clear:both}.colorpicker:before{content:'';display:inline-block;border-left:7px solid transparent;border-right:7px solid transparent;border-bottom:7px solid #ccc;border-bottom-color:rgba(0,0,0,.2);position:absolute;top:-7px;left:6px}.colorpicker:after{content:'';display:inline-block;border-left:6px solid transparent;border-right:6px solid transparent;border-bottom:6px solid #fff;position:absolute;top:-6px;left:7px}.colorpicker div{position:relative}.colorpicker.colorpicker-with-alpha{min-width:140px}.colorpicker.colorpicker-with-alpha .colorpicker-alpha{display:block}.colorpicker-color{height:10px;margin-top:5px;clear:both;background-image:url(../img/bootstrap-colorpicker/alpha.png);background-position:0 100%}.colorpicker-color div{height:10px}.colorpicker-selectors{display:none;height:10px;margin-top:5px;clear:both}.colorpicker-selectors i{cursor:pointer;float:left;height:10px;width:10px}.colorpicker-selectors i+i{margin-left:3px}.colorpicker-element .add-on i,.colorpicker-element .input-group-addon i{display:inline-block;cursor:pointer;height:16px;vertical-align:text-top;width:16px}.colorpicker.colorpicker-inline{position:relative;display:inline-block;float:none;z-index:auto}.colorpicker.colorpicker-horizontal{width:110px;min-width:110px;height:auto}.colorpicker.colorpicker-horizontal .colorpicker-saturation{margin-bottom:4px}.colorpicker.colorpicker-horizontal .colorpicker-color{width:100px}.colorpicker.colorpicker-horizontal .colorpicker-alpha,.colorpicker.colorpicker-horizontal .colorpicker-hue{width:100px;height:15px;float:left;cursor:col-resize;margin-left:0;margin-bottom:4px}.colorpicker.colorpicker-horizontal .colorpicker-alpha i,.colorpicker.colorpicker-horizontal .colorpicker-hue i{display:block;height:15px;background:#fff;position:absolute;top:0;left:0;width:1px;border:none;margin-top:0}.colorpicker.colorpicker-horizontal .colorpicker-hue{background-image:url(../img/bootstrap-colorpicker/hue-horizontal.png)}.colorpicker.colorpicker-horizontal .colorpicker-alpha{background-image:url(../img/bootstrap-colorpicker/alpha-horizontal.png)}.colorpicker.colorpicker-hidden{display:none}.colorpicker.colorpicker-visible{display:block}.colorpicker-inline.colorpicker-visible{display:inline-block}.colorpicker-right:before{left:auto;right:6px}.colorpicker-right:after{left:auto;right:7px}.colorpicker-no-arrow:before{border-right:0;border-left:0}.colorpicker-no-arrow:after{border-right:0;border-left:0}
10 | /*# sourceMappingURL=bootstrap-colorpicker.min.css.map */
--------------------------------------------------------------------------------
/src/main/resources/static/js/bootstrap-colorpicker/css/bootstrap-colorpicker.min.css.map:
--------------------------------------------------------------------------------
1 | {"version":3,"sources":["src/less/colorpicker.less"],"names":[],"mappings":";;;;;;;;AAqBA,wBACE,MAAA,MACA,OAAA,MAXA,iBAAsB,iDAatB,OAAA,UACA,MAAA,KACA,0BACE,QAAA,MACA,OAAA,IACA,MAAA,IACA,OAAA,IAAA,MAAA,KAfF,sBAAA,IACA,mBAAA,IACA,cAAA,IAeE,SAAA,SACA,IAAA,EACA,KAAA,EACA,OAAA,KAAA,EAAA,EAAA,KACA,4BACE,QAAA,MACA,OAAA,IACA,MAAA,IACA,OAAA,IAAA,MAAA,KAzBJ,sBAAA,IACA,mBAAA,IACA,cAAA,IA8BF,mBADA,iBAEE,MAAA,KACA,OAAA,MACA,MAAA,KACA,OAAA,WACA,YAAA,IACA,cAAA,IAIiB,qBADF,mBAEf,QAAA,MACA,OAAA,IACA,WAAA,KACA,WAAA,IAAA,MAAA,KACA,SAAA,SACA,IAAA,EACA,KAAA,EACA,MAAA,KACA,WAAA,KAGF,iBA1DE,iBAAsB,0CA8DxB,mBA9DE,iBAAsB,4CAgEtB,QAAA,KAKF,mBADA,iBADA,wBAGE,gBAAA,QAGF,aACE,QAAA,IACA,UAAA,MACA,WAAA,IAxEA,sBAAA,IACA,mBAAA,IACA,cAAA,IAwEA,QAAA,KAIU,mBADA,oBAEV,QAAA,MACA,QAAA,GACA,YAAA,EAGU,mBACV,MAAA,KAGU,oBACV,QAAA,GACA,QAAA,aACA,YAAA,IAAA,MAAA,YACA,aAAA,IAAA,MAAA,YACA,cAAA,IAAA,MAAA,KACA,oBAAA,eACA,SAAA,SACA,IAAA,KACA,KAAA,IAGU,mBACV,QAAA,GACA,QAAA,aACA,YAAA,IAAA,MAAA,YACA,aAAA,IAAA,MAAA,YACA,cAAA,IAAA,MAAA,KACA,SAAA,SACA,IAAA,KACA,KAAA,IAGW,iBACX,SAAA,SAGU,oCACV,UAAA,MAGkC,uDAClC,QAAA,MAGF,mBACE,OAAA,KACA,WAAA,IACA,MAAA,KAlIA,iBAAsB,4CAoItB,oBAAA,EAAA,KAGiB,uBACjB,OAAA,KAGF,uBACE,QAAA,KACA,OAAA,KACA,WAAA,IACA,MAAA,KAGqB,yBACrB,OAAA,QACA,MAAA,KACA,OAAA,KACA,MAAA,KAGuB,2BACvB,YAAA,IAI2B,+BADW,0CAEtC,QAAA,aACA,OAAA,QACA,OAAA,KACA,eAAA,SACA,MAAA,KAGU,gCACV,SAAA,SACA,QAAA,aACA,MAAA,KACA,QAAA,KAGU,oCACV,MAAA,MACA,UAAA,MACA,OAAA,KAGkC,4DAClC,cAAA,IAGkC,uDAClC,MAAA,MAIkC,uDADA,qDAElC,MAAA,MACA,OAAA,KACA,MAAA,KACA,OAAA,WACA,YAAA,EACA,cAAA,IAIqD,yDADF,uDAEnD,QAAA,MACA,OAAA,KACA,WAAA,KACA,SAAA,SACA,IAAA,EACA,KAAA,EACA,MAAA,IACA,OAAA,KACA,WAAA,EAGkC,qDAlNlC,iBAAsB,qDAsNY,uDAtNlC,iBAAsB,uDA0NZ,gCACV,QAAA,KAGU,iCACV,QAAA,MAGiB,wCACjB,QAAA,aAGgB,0BAChB,KAAA,KACA,MAAA,IAGgB,yBAChB,KAAA,KACA,MAAA,IAGmB,6BACnB,aAAA,EACA,YAAA,EAGmB,4BACnB,aAAA,EACA,YAAA"}
--------------------------------------------------------------------------------
/src/main/resources/static/js/bootstrap-colorpicker/img/bootstrap-colorpicker/alpha-horizontal.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/6mb/Microsoft-365-Admin/89ca444776dae12d49047e55ac0bbbd3daabc9cf/src/main/resources/static/js/bootstrap-colorpicker/img/bootstrap-colorpicker/alpha-horizontal.png
--------------------------------------------------------------------------------
/src/main/resources/static/js/bootstrap-colorpicker/img/bootstrap-colorpicker/alpha.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/6mb/Microsoft-365-Admin/89ca444776dae12d49047e55ac0bbbd3daabc9cf/src/main/resources/static/js/bootstrap-colorpicker/img/bootstrap-colorpicker/alpha.png
--------------------------------------------------------------------------------
/src/main/resources/static/js/bootstrap-colorpicker/img/bootstrap-colorpicker/hue-horizontal.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/6mb/Microsoft-365-Admin/89ca444776dae12d49047e55ac0bbbd3daabc9cf/src/main/resources/static/js/bootstrap-colorpicker/img/bootstrap-colorpicker/hue-horizontal.png
--------------------------------------------------------------------------------
/src/main/resources/static/js/bootstrap-colorpicker/img/bootstrap-colorpicker/hue.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/6mb/Microsoft-365-Admin/89ca444776dae12d49047e55ac0bbbd3daabc9cf/src/main/resources/static/js/bootstrap-colorpicker/img/bootstrap-colorpicker/hue.png
--------------------------------------------------------------------------------
/src/main/resources/static/js/bootstrap-colorpicker/img/bootstrap-colorpicker/saturation.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/6mb/Microsoft-365-Admin/89ca444776dae12d49047e55ac0bbbd3daabc9cf/src/main/resources/static/js/bootstrap-colorpicker/img/bootstrap-colorpicker/saturation.png
--------------------------------------------------------------------------------
/src/main/resources/static/js/bootstrap-notify.min.js:
--------------------------------------------------------------------------------
1 | /* Project: Bootstrap Growl = v3.1.3 | Description: Turns standard Bootstrap alerts into "Growl-like" notifications. | Author: Mouse0270 aka Robert McIntosh | License: MIT License | Website: https://github.com/mouse0270/bootstrap-growl */
2 | !function(t){"function"==typeof define&&define.amd?define(["jquery"],t):t("object"==typeof exports?require("jquery"):jQuery)}(function(t){function e(e,i,n){var i={content:{message:"object"==typeof i?i.message:i,title:i.title?i.title:"",icon:i.icon?i.icon:"",url:i.url?i.url:"#",target:i.target?i.target:"-"}};n=t.extend(!0,{},i,n),this.settings=t.extend(!0,{},s,n),this._defaults=s,"-"==this.settings.content.target&&(this.settings.content.target=this.settings.url_target),this.animations={start:"webkitAnimationStart oanimationstart MSAnimationStart animationstart",end:"webkitAnimationEnd oanimationend MSAnimationEnd animationend"},"number"==typeof this.settings.offset&&(this.settings.offset={x:this.settings.offset,y:this.settings.offset}),this.init()}var s={element:"body",position:null,type:"info",allow_dismiss:!0,newest_on_top:!1,showProgressbar:!1,placement:{from:"top",align:"right"},offset:20,spacing:10,z_index:1031,delay:5e3,timer:1e3,url_target:"_blank",mouse_over:null,animate:{enter:"animated fadeInDown",exit:"animated fadeOutUp"},onShow:null,onShown:null,onClose:null,onClosed:null,icon_type:"class",template:''};String.format=function(){for(var t=arguments[0],e=1;e .progress-bar').removeClass("progress-bar-"+t.settings.type),t.settings.type=i[e],this.$ele.addClass("alert-"+i[e]).find('[data-notify="progressbar"] > .progress-bar').addClass("progress-bar-"+i[e]);break;case"icon":var n=this.$ele.find('[data-notify="icon"]');"class"==t.settings.icon_type.toLowerCase()?n.removeClass(t.settings.content.icon).addClass(i[e]):(n.is("img")||n.find("img"),n.attr("src",i[e]));break;case"progress":var a=t.settings.delay-t.settings.delay*(i[e]/100);this.$ele.data("notify-delay",a),this.$ele.find('[data-notify="progressbar"] > div').attr("aria-valuenow",i[e]).css("width",i[e]+"%");break;case"url":this.$ele.find('[data-notify="url"]').attr("href",i[e]);break;case"target":this.$ele.find('[data-notify="url"]').attr("target",i[e]);break;default:this.$ele.find('[data-notify="'+e+'"]').html(i[e])}var o=this.$ele.outerHeight()+parseInt(t.settings.spacing)+parseInt(t.settings.offset.y);t.reposition(o)},close:function(){t.close()}}},buildNotify:function(){var e=this.settings.content;this.$ele=t(String.format(this.settings.template,this.settings.type,e.title,e.message,e.url,e.target)),this.$ele.attr("data-notify-position",this.settings.placement.from+"-"+this.settings.placement.align),this.settings.allow_dismiss||this.$ele.find('[data-notify="dismiss"]').css("display","none"),(this.settings.delay<=0&&!this.settings.showProgressbar||!this.settings.showProgressbar)&&this.$ele.find('[data-notify="progressbar"]').remove()},setIcon:function(){"class"==this.settings.icon_type.toLowerCase()?this.$ele.find('[data-notify="icon"]').addClass(this.settings.content.icon):this.$ele.find('[data-notify="icon"]').is("img")?this.$ele.find('[data-notify="icon"]').attr("src",this.settings.content.icon):this.$ele.find('[data-notify="icon"]').append('
')},styleURL:function(){this.$ele.find('[data-notify="url"]').css({backgroundImage:"url(data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7)",height:"100%",left:"0px",position:"absolute",top:"0px",width:"100%",zIndex:this.settings.z_index+1}),this.$ele.find('[data-notify="dismiss"]').css({position:"absolute",right:"10px",top:"5px",zIndex:this.settings.z_index+2})},placement:function(){var e=this,s=this.settings.offset.y,i={display:"inline-block",margin:"0px auto",position:this.settings.position?this.settings.position:"body"===this.settings.element?"fixed":"absolute",transition:"all .5s ease-in-out",zIndex:this.settings.z_index},n=!1,a=this.settings;switch(t('[data-notify-position="'+this.settings.placement.from+"-"+this.settings.placement.align+'"]:not([data-closing="true"])').each(function(){return s=Math.max(s,parseInt(t(this).css(a.placement.from))+parseInt(t(this).outerHeight())+parseInt(a.spacing))}),1==this.settings.newest_on_top&&(s=this.settings.offset.y),i[this.settings.placement.from]=s+"px",this.settings.placement.align){case"left":case"right":i[this.settings.placement.align]=this.settings.offset.x+"px";break;case"center":i.left=0,i.right=0}this.$ele.css(i).addClass(this.settings.animate.enter),t.each(Array("webkit","moz","o","ms",""),function(t,s){e.$ele[0].style[s+"AnimationIterationCount"]=1}),t(this.settings.element).append(this.$ele),1==this.settings.newest_on_top&&(s=parseInt(s)+parseInt(this.settings.spacing)+this.$ele.outerHeight(),this.reposition(s)),t.isFunction(e.settings.onShow)&&e.settings.onShow.call(this.$ele),this.$ele.one(this.animations.start,function(){n=!0}).one(this.animations.end,function(){t.isFunction(e.settings.onShown)&&e.settings.onShown.call(this)}),setTimeout(function(){n||t.isFunction(e.settings.onShown)&&e.settings.onShown.call(this)},600)},bind:function(){var e=this;if(this.$ele.find('[data-notify="dismiss"]').on("click",function(){e.close()}),this.$ele.mouseover(function(){t(this).data("data-hover","true")}).mouseout(function(){t(this).data("data-hover","false")}),this.$ele.data("data-hover","false"),this.settings.delay>0){e.$ele.data("notify-delay",e.settings.delay);var s=setInterval(function(){var t=parseInt(e.$ele.data("notify-delay"))-e.settings.timer;if("false"===e.$ele.data("data-hover")&&"pause"==e.settings.mouse_over||"pause"!=e.settings.mouse_over){var i=(e.settings.delay-t)/e.settings.delay*100;e.$ele.data("notify-delay",t),e.$ele.find('[data-notify="progressbar"] > div').attr("aria-valuenow",i).css("width",i+"%")}t<=-e.settings.timer&&(clearInterval(s),e.close())},e.settings.timer)}},close:function(){var e=this,s=parseInt(this.$ele.css(this.settings.placement.from)),i=!1;this.$ele.data("closing","true").addClass(this.settings.animate.exit),e.reposition(s),t.isFunction(e.settings.onClose)&&e.settings.onClose.call(this.$ele),this.$ele.one(this.animations.start,function(){i=!0}).one(this.animations.end,function(){t(this).remove(),t.isFunction(e.settings.onClosed)&&e.settings.onClosed.call(this)}),setTimeout(function(){i||(e.$ele.remove(),e.settings.onClosed&&e.settings.onClosed(e.$ele))},600)},reposition:function(e){var s=this,i='[data-notify-position="'+this.settings.placement.from+"-"+this.settings.placement.align+'"]:not([data-closing="true"])',n=this.$ele.nextAll(i);1==this.settings.newest_on_top&&(n=this.$ele.prevAll(i)),n.each(function(){t(this).css(s.settings.placement.from,e),e=parseInt(e)+parseInt(s.settings.spacing)+t(this).outerHeight()})}}),t.notify=function(t,s){var i=new e(this,t,s);return i.notify},t.notifyDefaults=function(e){return s=t.extend(!0,{},s,e)},t.notifyClose=function(e){"undefined"==typeof e||"all"==e?t("[data-notify]").find('[data-notify="dismiss"]').trigger("click"):t('[data-notify-position="'+e+'"]').find('[data-notify="dismiss"]').trigger("click")}});
--------------------------------------------------------------------------------
/src/main/resources/static/js/code.js:
--------------------------------------------------------------------------------
1 | let codeList;
2 | let pageITotal;
3 | let pageIndex = 1;
4 |
5 | $(window).load(function () {
6 | $('#titleName').html(" 邀请管理 ");
7 | lightyear.loading('show');
8 | // 设置组织类型
9 | var success = setAppName();
10 | if (success) {
11 | getCodeStatistics();
12 | listCode();
13 | }
14 | lightyear.loading('hide');
15 | });
16 |
17 | function getCodeStatistics() {
18 | $.ajax({
19 | type: "get",
20 | async: false,
21 | url: path + "/code/getCodeStatistics",
22 | data: {},
23 | dataType: "json",
24 | success: function (r) {
25 | if (r.status !== 200) {
26 | lightyear.notify(r.message, 'danger', 1000);
27 | } else {
28 | $("#codes").text(r.data.codes);
29 | $("#codeValid").text(r.data.valid);
30 | $("#codeInvalid").text(r.data.invalid);
31 | $("#codeInvalidUser").text(r.data.users);
32 | }
33 | },
34 | error: function () {
35 | /*错误信息处理*/
36 | lightyear.notify("服务器错误,请稍后再试~", 'danger', 100);
37 | }
38 | });
39 | }
40 |
41 | function listCode() {
42 | $.ajax({
43 | type: "get",
44 | async: false,
45 | url: path + "/code/list",
46 | data: {
47 | "code": getInput("#codeInput"),
48 | "valid": getSelect("#codeValidSelect"),
49 | "pageIndex": pageIndex,
50 | "pageSize": 10
51 | },
52 | dataType: "json",
53 | success: function (r) {
54 | if (r.status !== 200) {
55 | lightyear.notify(r.message, 'danger', 1000);
56 | } else {
57 | // 表格
58 | let codeTable = r.data.content;
59 | let num = (pageIndex - 1) * 10;
60 | for (i in codeTable) {
61 | var tr = '' + (parseInt(num) + parseInt(i) + 1) + ' | '
62 | + '' + codeTable[i].code + ' | '
63 | + '' + (isNotNull(codeTable[i].createTime) ? codeTable[i].createTime : "-") + ' | '
64 | + '' + (Boolean(codeTable[i].valid) ? ('有效') : ('失效')) + ' | '
65 | + '' + (isNotNull(codeTable[i].expirationTime) ? codeTable[i].expirationTime : "-") + ' | '
66 | + '' + (isNotNull(codeTable[i].invitedUser) ? codeTable[i].invitedUser : '-') + ' | '
67 | + '' + (isNotNull(codeTable[i].subscribe) ? codeTable[i].subscribe : '-') + ' | ';
68 | $("#codeTable").append('' + tr + '
')
69 | }
70 | // 分页处理,计算总页数
71 | pageITotal = r.data.totalPages;
72 | $("#codeTotal").text("总页数:" + pageITotal);
73 | $("#codeIndex").text("当前页:" + pageIndex);
74 | lightyear.loading('hide');
75 | }
76 | },
77 | error: function () {
78 | /*错误信息处理*/
79 | lightyear.notify("服务器错误,请稍后再试~", 'danger', 100);
80 | }
81 | });
82 | }
83 |
84 | function pageOnclickCode(data) {
85 | $("#codeTable tr:not(:first)").empty();
86 | pageIndex = isNotNull(getCookie("pageIndexCode")) ? getCookie("pageIndexCode") : 1;
87 | if (data === 0 && pageIndex > 1) {
88 | pageIndex = parseInt(pageIndex) - 1;
89 | }
90 | if (data === 1 && pageIndex < pageITotal) {
91 | pageIndex = parseInt(pageIndex) + 1;
92 | }
93 | setCookie("pageIndexCode", pageIndex);
94 | listCode();
95 | }
96 |
97 | function searchCodes() {
98 | lightyear.loading('show');
99 | $("#codeTable tr:not(:first)").empty();
100 | listCode();
101 | }
102 |
103 | function addCodeClick() {
104 | lightyear.loading('show');
105 | let num = $("#numCode").val();
106 | // 提交请求
107 | $.ajax({
108 | type: "post",
109 | url: path + "/code/generate",
110 | data: {
111 | "num": num
112 | },
113 | dataType: "json",
114 | success: function (r) {
115 | if (r.status !== 200) {
116 | lightyear.loading('hide');
117 | lightyear.notify(r.message, 'danger', delay);
118 | } else {
119 | console.log(r);
120 | lightyear.loading('hide');
121 | lightyear.notify('创建邀请码成功数量:' + num, 'success', delay);
122 | }
123 | },
124 | error: function () {
125 | /*错误信息处理*/
126 | lightyear.notify("服务器错误,请稍后再试~", 'danger', delay);
127 | lightyear.loading('hide');
128 | }
129 | });
130 | }
131 |
--------------------------------------------------------------------------------
/src/main/resources/static/js/common.js:
--------------------------------------------------------------------------------
1 | var path = url + "/microsoft";
2 | var appNameList;
3 | $.ajax({
4 | type: "get",
5 | async: false,
6 | url: path + "/365/getAppName",
7 | data: {},
8 | dataType: "json",
9 | success: function (r) {
10 | if (r.status !== 200) {
11 | lightyear.notify(r.message, 'error', 1000);
12 | } else {
13 | appNameList = r.data;
14 | }
15 | },
16 | error: function (r) {
17 | console.log(r)
18 | if (r.status === 401) {
19 | lightyear.notify(r.message, 'error', 200);
20 | window.location.href = "login.html";
21 | } else {
22 | /*错误信息处理*/
23 | lightyear.notify("服务器错误,请稍后再试~", 'danger', 100);
24 | }
25 | }
26 | });
27 |
28 | function refreshCache(successFunc) {
29 | lightyear.loading('show');
30 | $.ajax({
31 | type: "get",
32 | url: path + "/365/refresh",
33 | data: {
34 | "appName": getAppName()
35 | },
36 | dataType: "json",
37 | success: function (r) {
38 | lightyear.loading('hide');
39 | if (r.status !== 200) {
40 | lightyear.notify(r.message, 'danger', 200);
41 | } else {
42 | lightyear.notify("刷新缓存成功!", 'success', 200);
43 | if (successFunc != null) {
44 | successFunc();
45 | } else {
46 | reloadPage();
47 | }
48 | }
49 | },
50 | error: function () {
51 | /*错误信息处理*/
52 | lightyear.notify("服务器错误,请稍后再试~", 'danger', 200);
53 | }
54 |
55 | });
56 | }
57 |
58 | function reloadPage() {
59 | lightyear.loading('show');
60 | setCookie("appName", getAppName());
61 | location.reload();
62 | lightyear.loading('hide');
63 | }
64 |
65 |
66 | function setCookie(name, value) {
67 | var exp = new Date();
68 | exp.setTime(exp.getTime() + 24 * 60 * 60 * 1000);
69 | document.cookie = name + "=" + escape(value) + ";expires=" + exp.toGMTString();
70 | }
71 |
72 | function getCookie(name) {
73 | var regExp = new RegExp("(^| )" + name + "=([^;]*)(;|$)");
74 | var arr = document.cookie.match(regExp);
75 | if (arr == null) {
76 | return null;
77 | }
78 | return unescape(arr[2]);
79 | }
80 |
81 | function setAppName() {
82 | if (!isNotNull(appNameList)) {
83 | return false;
84 | }
85 | var appName = getCookie("appName");
86 | for (i in appNameList) {
87 | if (appName !== null && appNameList[i] === appName) {
88 | var option = "";
89 | } else {
90 | var option = "";
91 | }
92 | $("#appNameSelect").append(option);
93 | }
94 | return true;
95 | }
96 |
97 | function getAppName() {
98 | var options = $("#appNameSelect option:selected");
99 | return options.val();
100 | }
101 |
102 | function getSelect(id) {
103 | var options = $(id + " option:selected");
104 | return options.val();
105 | }
106 |
107 | function getInput(id) {
108 | return $(id).val();
109 | }
110 |
111 | function isNotNull(ele) {
112 | if (typeof ele === 'undefined') {
113 | return false;
114 | } else if (ele == null) {
115 | return false;
116 | } else if (ele === '') {
117 | return false;
118 | }
119 | return true;
120 | }
121 |
122 |
--------------------------------------------------------------------------------
/src/main/resources/static/js/config.js:
--------------------------------------------------------------------------------
1 | // 如果前端文件单独部署,则需要将后端地址填写上,否则为空
2 | let url = "";
3 | // let url = "http://127.0.0.1:8099";
--------------------------------------------------------------------------------
/src/main/resources/static/js/index.js:
--------------------------------------------------------------------------------
1 | $(window).on("load", function () {
2 | $('#titleName').html(" 后台首页 ");
3 | lightyear.loading('show');
4 | // 设置组织类型
5 | var success = setAppName();
6 | if (success) {
7 | homePage();
8 | }
9 | });
10 |
11 | function homePage() {
12 | $.ajax({
13 | type: "get",
14 | url: path + "/365/homePage",
15 | data: {
16 | "appName": getAppName()
17 | },
18 | dataType: "json",
19 | success: function (r) {
20 | if (r.status !== 200) {
21 | lightyear.notify(r.message, 'danger', 100);
22 | } else {
23 | $("#productSubs").text(r.data.statisticsVo.productSubs);
24 | $("#licenses").text(r.data.statisticsVo.licenses);
25 | $("#allocatedLicenses").text(r.data.statisticsVo.allocatedLicenses);
26 | $("#availableLicenses").text(r.data.statisticsVo.availableLicenses);
27 | $("#users").text(r.data.statisticsVo.users);
28 | $("#allowedUsers").text(r.data.statisticsVo.allowedUsers);
29 | $("#biddenUsers").text(r.data.statisticsVo.biddenUsers);
30 | $("#unauthorizedUsers").text(r.data.statisticsVo.unauthorizedUsers);
31 |
32 | // 表格
33 | var noLandingUsers = r.data.noLandingUsers;
34 | for (i in noLandingUsers) {
35 | var skuName = "";
36 | if (noLandingUsers[i].skuVos !== null) {
37 | for (j in noLandingUsers[i].skuVos) {
38 | skuName = skuName + noLandingUsers[i].skuVos[j].skuName;
39 | }
40 | }
41 | var tr = '' + (parseInt(i) + 1) + ' | '
42 | + '' + noLandingUsers[i].userId + ' | '
43 | + '' + noLandingUsers[i].userPrincipalName + ' | '
44 | + '' + noLandingUsers[i].displayName + ' | '
45 | + '' + skuName + ' | '
46 | + '' + noLandingUsers[i].displayAccountEnable + ' | ';
47 | $("#noLandingUsersTable").append('' + tr + '
')
48 | }
49 |
50 | // 表格
51 | var unauthorizedUsers = r.data.unauthorizedUsers;
52 | for (i in unauthorizedUsers) {
53 | var skuName = "";
54 | if (unauthorizedUsers[i].skuVos !== null) {
55 | for (j in unauthorizedUsers[i].skuVos) {
56 | skuName = skuName + unauthorizedUsers[i].skuVos[j].skuName;
57 | }
58 | } else {
59 | skuName = "无";
60 | }
61 | var tr = '' + (parseInt(i) + 1) + ' | '
62 | + '' + unauthorizedUsers[i].userId + ' | '
63 | + '' + unauthorizedUsers[i].userPrincipalName + ' | '
64 | + '' + unauthorizedUsers[i].displayName + ' | '
65 | + '' + skuName + ' | '
66 | + '' + unauthorizedUsers[i].displayAccountEnable + ' | ';
67 | $("#unauthorizedUsersTable").append('' + tr + '
')
68 | }
69 | }
70 | lightyear.loading('hide');
71 | },
72 | error: function () {
73 | lightyear.loading('hide');
74 | /*错误信息处理*/
75 | lightyear.notify("服务器错误,请稍后再试~", 'danger', 100);
76 | }
77 | });
78 | }
--------------------------------------------------------------------------------
/src/main/resources/static/js/invite.js:
--------------------------------------------------------------------------------
1 | let delay = 2000;
2 | let usageLocationList;
3 | $(window).on("load", function () {
4 | $('#titleName').html(" 申请账号 ");
5 | lightyear.loading('show');
6 |
7 | listLicense();
8 | });
9 |
10 | function listLicense() {
11 | $.ajax({
12 | type: "get",
13 | url: "/front/listLicense",
14 | data: {},
15 | dataType: "json",
16 | success: function (r) {
17 | if (r.status !== 200) {
18 | lightyear.notify(r.message, 'danger', delay);
19 | } else {
20 | licenseList = r.data;
21 | setLicense("g-sub-select");
22 | }
23 | lightyear.loading('hide');
24 | },
25 | error: function () {
26 | lightyear.loading('hide');
27 | /*错误信息处理*/
28 | lightyear.notify("服务器错误,请稍后再试~", 'danger', delay);
29 | }
30 | });
31 | }
32 |
33 |
34 | function setLicense(id) {
35 | let licenseSelect = $("#" + id);
36 | // 先清空下数据
37 | licenseSelect.empty();
38 | licenseSelect.append("\n");
39 | for (i in licenseList) {
40 | let option = "";
41 | licenseSelect.append(option);
42 | }
43 | licenseSelect.change(function () {
44 | let appName = $('#' + id + ' option:selected').data('appname');
45 | listUsageLocation(appName);
46 | setUsageLocation('g-usageLocation-select');
47 | })
48 | }
49 |
50 | function listUsageLocation(appName) {
51 | $.ajax({
52 | type: "get",
53 | url: "/front/listUsageLocation",
54 | data: {
55 | appName: appName
56 | },
57 | success: function (r) {
58 | if (r.status !== 200) {
59 | lightyear.notify(r.message, 'danger', delay);
60 | } else {
61 | usageLocationList = r.data;
62 | setUsageLocation("g-usageLocation-select");
63 | }
64 | lightyear.loading('hide');
65 | },
66 | error: function () {
67 | lightyear.loading('hide');
68 | /*错误信息处理*/
69 | lightyear.notify("服务器错误,请稍后再试~", 'danger', delay);
70 | }
71 | });
72 | }
73 |
74 | function setUsageLocation(id) {
75 | let usageLocationSelect = $("#" + id);
76 | usageLocationSelect.empty();
77 | for (let i in usageLocationList) {
78 | let option = "";
79 | usageLocationSelect.append(option);
80 | }
81 | }
82 |
83 | function getSelect(id) {
84 | var options = $(id + " option:selected");
85 | return options.val();
86 | }
87 |
88 | function getInput(id) {
89 | return $(id).val();
90 | }
91 |
92 | function addUserClick() {
93 | lightyear.loading('show');
94 | // 参数获取
95 | let select = getSelect("#g-sub-select")
96 | let appName = select.split("_")[0];
97 | let skuId = select.split("_")[1];
98 | let displayName = getInput("#g_name");
99 | let mailNickname = getInput("#g_mail_sub");
100 | let password = getInput("#g-password");
101 | let mailbox = getInput("#g-send_mail");
102 | let code = getInput("#g-code");
103 | let usageLocation = getSelect("#g-usageLocation");
104 |
105 | // 参数校验
106 |
107 | // 提交请求
108 | $.ajax({
109 | type: "post",
110 | url: "/front/create",
111 | data: {
112 | "appName": appName,
113 | "displayName": displayName,
114 | "skuId": skuId,
115 | "mailNickname": mailNickname,
116 | "password": password,
117 | "mailbox": mailbox,
118 | "code": code,
119 | "usageLocation": usageLocation
120 | },
121 | dataType: "json",
122 | success: function (r) {
123 | if (r.status !== 200) {
124 | lightyear.loading('hide');
125 | let message = r.message;
126 | let password_error = "Error code: Request_BadRequestError message: The specified password does not comply with password complexity requirements. Please provide a different password.";
127 | let name_error = "Error code: Request_BadRequestError message: Another object with the same value for property userPrincipalName already exists.";
128 | if (password_error === message) {
129 | message = "密码太简单啦,";
130 | }
131 | if (name_error === message) {
132 | message = "该邮箱前缀已经被抢啦!";
133 | }
134 | lightyear.notify(message, 'danger', delay);
135 | } else {
136 | console.log(r);
137 | let userInfo = '名称:' + r.data.displayName + '
账号:' + r.data.userPrincipalName + '
密码:' + r.data.password;
138 | lightyear.loading('hide');
139 | $.alert({
140 | title: '新增账号成功!',
141 | content: '
' + userInfo + '
',
142 | buttons: {
143 | confirm: {
144 | text: '确认',
145 | btnClass: 'btn-primary',
146 | action: function () {
147 | window.location.reload();
148 | }
149 | }
150 | }
151 | });
152 | }
153 | },
154 | error: function () {
155 | lightyear.loading('hide');
156 | /*错误信息处理*/
157 | lightyear.notify("服务器错误,请稍后再试~", 'danger', delay);
158 | }
159 | });
160 |
161 | }
--------------------------------------------------------------------------------
/src/main/resources/static/js/jquery-tags-input/jquery.tagsinput.min.css:
--------------------------------------------------------------------------------
1 | div.tagsinput{border:1px solid #ebebeb;background:#FFF;padding:6px 12px 1px 6px;width:300px;height:100px;overflow-y:auto;}div.tagsinput span.tag{border:none;-moz-border-radius:2px;-webkit-border-radius:2px;display:block;float:left;padding:2px 5px;text-decoration:none;background:#33cabb;color:#fff;margin-right:5px;margin-bottom:5px;font-family:'Microsoft yahei',Roboto,sans-serif;font-size:13px;line-height:18px}div.tagsinput span.tag a{font-weight:bold;color:rgba(255,255,255,0.5);text-decoration:none;font-size:12px;}div.tagsinput input{width:80px;margin:0px;font-family:'Microsoft yahei',Roboto,sans-serif;font-size:13px;border:1px solid transparent;padding:0;background:transparent;color:#000;outline:0px;margin-right:5px;margin-bottom:5px;}div.tagsinput div{display:block;float:left;}.tags_clear{clear:both;width:100%;height:0px;}.not_valid{background:#FBD8DB !important;color:#90111A !important;}
--------------------------------------------------------------------------------
/src/main/resources/static/js/jquery-tags-input/jquery.tagsinput.min.js:
--------------------------------------------------------------------------------
1 | !function(a){var b=new Array,c=new Array;a.fn.doAutosize=function(b){var c=a(this).data("minwidth"),d=a(this).data("maxwidth"),e="",f=a(this),g=a("#"+a(this).data("tester_id"));if(e!==(e=f.val())){var h=e.replace(/&/g,"&").replace(/\s/g," ").replace(//g,">");g.html(h);var i=g.width(),j=i+b.comfortZone>=c?i+b.comfortZone:c,k=f.width(),l=k>j&&j>=c||j>c&&d>j;l&&f.width(j)}},a.fn.resetAutosize=function(b){var c=a(this).data("minwidth")||b.minInputWidth||a(this).width(),d=a(this).data("maxwidth")||b.maxInputWidth||a(this).closest(".tagsinput").width()-b.inputPadding,e=a(this),f=a("").css({position:"absolute",top:-9999,left:-9999,width:"auto",fontSize:e.css("fontSize"),fontFamily:e.css("fontFamily"),fontWeight:e.css("fontWeight"),letterSpacing:e.css("letterSpacing"),whiteSpace:"nowrap"}),g=a(this).attr("id")+"_autosize_tester";!a("#"+g).length>0&&(f.attr("id",g),f.appendTo("body")),e.data("minwidth",c),e.data("maxwidth",d),e.data("tester_id",g),e.css("width",c)},a.fn.addTag=function(d,e){return e=jQuery.extend({focus:!1,callback:!0},e),this.each(function(){var f=a(this).attr("id"),g=a(this).val().split(b[f]);if(""==g[0]&&(g=new Array),d=jQuery.trim(d),e.unique){var h=a(this).tagExist(d);1==h&&a("#"+f+"_tag").addClass("not_valid")}else var h=!1;if(""!=d&&1!=h){if(a("").addClass("tag").append(a("").text(d).append(" "),a("",{href:"#",title:"Removing tag",text:"x"}).click(function(){return a("#"+f).removeTag(escape(d))})).insertBefore("#"+f+"_addTag"),g.push(d),a("#"+f+"_tag").val(""),e.focus?a("#"+f+"_tag").focus():a("#"+f+"_tag").blur(),a.fn.tagsInput.updateTagsField(this,g),e.callback&&c[f]&&c[f].onAddTag){var i=c[f].onAddTag;i.call(this,d)}if(c[f]&&c[f].onChange){var j=g.length,i=c[f].onChange;i.call(this,a(this),g[j-1])}}}),!1},a.fn.removeTag=function(d){return d=unescape(d),this.each(function(){var e=a(this).attr("id"),f=a(this).val().split(b[e]);for(a("#"+e+"_tagsinput .tag").remove(),str="",i=0;i=0},a.fn.importTags=function(b){var c=a(this).attr("id");a("#"+c+"_tagsinput .tag").remove(),a.fn.tagsInput.importTags(this,b)},a.fn.tagsInput=function(e){var f=jQuery.extend({interactive:!0,defaultText:"添加标签",minChars:0,width:"300px",height:"100px",autocomplete:{selectFirst:!1},hide:!0,delimiter:",",unique:!0,removeWithBackspace:!0,placeholderColor:"#666666",autosize:!0,comfortZone:20,inputPadding:12},e),g=0;return this.each(function(){if("undefined"==typeof a(this).attr("data-tagsinput-init")){a(this).attr("data-tagsinput-init",!0),f.hide&&a(this).hide();var e=a(this).attr("id");(!e||b[a(this).attr("id")])&&(e=a(this).attr("id","tags"+(new Date).getTime()+g++).attr("id"));var h=jQuery.extend({pid:e,real_input:"#"+e,holder:"#"+e+"_tagsinput",input_wrapper:"#"+e+"_addTag",fake_input:"#"+e+"_tag"},f);b[e]=h.delimiter,(f.onAddTag||f.onRemoveTag||f.onChange)&&(c[e]=new Array,c[e].onAddTag=f.onAddTag,c[e].onRemoveTag=f.onRemoveTag,c[e].onChange=f.onChange);var i='',a(i).insertAfter(this),a(h.holder).css("width",f.width),a(h.holder).css("min-height",f.height),a(h.holder).css("height",f.height),""!=a(h.real_input).val()&&a.fn.tagsInput.importTags(a(h.real_input),a(h.real_input).val()),f.interactive){if(a(h.fake_input).val(a(h.fake_input).attr("data-default")),a(h.fake_input).css("color",f.placeholderColor),a(h.fake_input).resetAutosize(f),a(h.holder).bind("click",h,function(b){a(b.data.fake_input).focus()}),a(h.fake_input).bind("focus",h,function(b){a(b.data.fake_input).val()==a(b.data.fake_input).attr("data-default")&&a(b.data.fake_input).val(""),a(b.data.fake_input).css("color","#000000")}),void 0!=f.autocomplete_url){autocomplete_options={source:f.autocomplete_url};for(attrname in f.autocomplete)autocomplete_options[attrname]=f.autocomplete[attrname];void 0!==jQuery.Autocompleter?(a(h.fake_input).autocomplete(f.autocomplete_url,f.autocomplete),a(h.fake_input).bind("result",h,function(b,c,d){c&&a("#"+e).addTag(c[0]+"",{focus:!0,unique:f.unique})})):void 0!==jQuery.ui.autocomplete&&(a(h.fake_input).autocomplete(autocomplete_options),a(h.fake_input).bind("autocompleteselect",h,function(b,c){return a(b.data.real_input).addTag(c.item.value,{focus:!0,unique:f.unique}),!1}))}else a(h.fake_input).bind("blur",h,function(b){var c=a(this).attr("data-default");return""!=a(b.data.fake_input).val()&&a(b.data.fake_input).val()!=c?b.data.minChars<=a(b.data.fake_input).val().length&&(!b.data.maxChars||b.data.maxChars>=a(b.data.fake_input).val().length)&&a(b.data.real_input).addTag(a(b.data.fake_input).val(),{focus:!0,unique:f.unique}):(a(b.data.fake_input).val(a(b.data.fake_input).attr("data-default")),a(b.data.fake_input).css("color",f.placeholderColor)),!1});a(h.fake_input).bind("keypress",h,function(b){return d(b)?(b.preventDefault(),b.data.minChars<=a(b.data.fake_input).val().length&&(!b.data.maxChars||b.data.maxChars>=a(b.data.fake_input).val().length)&&a(b.data.real_input).addTag(a(b.data.fake_input).val(),{focus:!0,unique:f.unique}),a(b.data.fake_input).resetAutosize(f),!1):void(b.data.autosize&&a(b.data.fake_input).doAutosize(f))}),h.removeWithBackspace&&a(h.fake_input).bind("keydown",function(b){if(8==b.keyCode&&""==a(this).val()){b.preventDefault();var c=a(this).closest(".tagsinput").find(".tag:last").text(),d=a(this).attr("id").replace(/_tag$/,"");c=c.replace(/[\s]+x$/,""),a("#"+d).removeTag(escape(c)),a(this).trigger("focus")}}),a(h.fake_input).blur(),h.unique&&a(h.fake_input).keydown(function(b){(8==b.keyCode||String.fromCharCode(b.which).match(/\w+|[áéíóúÁÉÍÓÚñÑ,/]+/))&&a(this).removeClass("not_valid")})}}}),this},a.fn.tagsInput.updateTagsField=function(c,d){var e=a(c).attr("id");a(c).val(d.join(b[e]))},a.fn.tagsInput.importTags=function(d,e){a(d).val("");var f=a(d).attr("id"),g=e.split(b[f]);for(i=0;i=a.currentIndex());c(b.nextSelector,d).toggleClass("disabled",a.currentIndex()>=a.navigationLength());c(b.nextSelector,d).toggleClass("hidden",
13 | a.currentIndex()>=a.navigationLength()&&0=a.navigationLength()&&0=a.navigationLength()&&0a.navigationLength()||(h.push(g),e.find('li:has([data-toggle="tab"])'+
15 | (b.withVisible?":visible":"")+":eq("+c+") a").tab("show"))};this.previous=function(g){if(d.hasClass("first")||b.onPrevious&&"function"===typeof b.onPrevious&&!1===b.onPrevious(f,e,a.previousIndex()))return!1;g=a.currentIndex();var c=a.previousIndex();0>c||(h.push(g),e.find('li:has([data-toggle="tab"])'+(b.withVisible?":visible":"")+":eq("+c+") a").tab("show"))};this.first=function(g){if(b.onFirst&&"function"===typeof b.onFirst&&!1===b.onFirst(f,e,a.firstIndex())||d.hasClass("disabled"))return!1;h.push(a.currentIndex());
16 | e.find('li:has([data-toggle="tab"]):eq(0) a').tab("show")};this.last=function(g){if(b.onLast&&"function"===typeof b.onLast&&!1===b.onLast(f,e,a.lastIndex())||d.hasClass("disabled"))return!1;h.push(a.currentIndex());e.find('li:has([data-toggle="tab"]):eq('+a.navigationLength()+") a").tab("show")};this.finish=function(g){if(b.onFinish&&"function"===typeof b.onFinish)b.onFinish(f,e,a.lastIndex())};this.back=function(){if(0==h.length)return null;var a=h.pop();if(b.onBack&&"function"===typeof b.onBack&&
17 | !1===b.onBack(f,e,a))return h.push(a),!1;d.find('li:has([data-toggle="tab"]):eq('+a+") a").tab("show")};this.currentIndex=function(){return e.find('li:has([data-toggle="tab"])'+(b.withVisible?":visible":"")).index(f)};this.firstIndex=function(){return 0};this.lastIndex=function(){return a.navigationLength()};this.getIndex=function(a){return e.find('li:has([data-toggle="tab"])'+(b.withVisible?":visible":"")).index(a)};this.nextIndex=function(){var a=this.currentIndex(),c;do a++,c=e.find('li:has([data-toggle="tab"])'+
18 | (b.withVisible?":visible":"")+":eq("+a+")");while(c&&c.hasClass("disabled"));return a};this.previousIndex=function(){var a=this.currentIndex(),c;do a--,c=e.find('li:has([data-toggle="tab"])'+(b.withVisible?":visible":"")+":eq("+a+")");while(c&&c.hasClass("disabled"));return a};this.navigationLength=function(){return e.find('li:has([data-toggle="tab"])'+(b.withVisible?":visible":"")).length-1};this.activeTab=function(){return f};this.nextTab=function(){return e.find('li:has([data-toggle="tab"]):eq('+
19 | (a.currentIndex()+1)+")").length?e.find('li:has([data-toggle="tab"]):eq('+(a.currentIndex()+1)+")"):null};this.previousTab=function(){return 0>=a.currentIndex()?null:e.find('li:has([data-toggle="tab"]):eq('+parseInt(a.currentIndex()-1)+")")};this.show=function(b){b=isNaN(b)?d.find('li:has([data-toggle="tab"]) a[href="#'+b+'"]'):d.find('li:has([data-toggle="tab"]):eq('+b+") a");0'
56 | + '' + licenseTable[i].skuName + ' | '
57 | + '' + licenseTable[i].displayStatus + ' | '
58 | + '' + (licenseTable[i].enabled + licenseTable[i].suspended + licenseTable[i].warning) + ' | '
59 | + '' + licenseTable[i].consumedUnits + ' | '
60 | + '' + (licenseTable[i].enabled - licenseTable[i].consumedUnits) + ' | '
61 | + '' + licenseTable[i].enabled + ' | '
62 | + '' + licenseTable[i].suspended + ' | '
63 | + '' + licenseTable[i].warning + ' | ';
64 | $("#licenseTable").append('' + tr + '
')
65 | }
66 | }
67 | },
68 | error: function () {
69 | /*错误信息处理*/
70 | lightyear.notify("服务器错误,请稍后再试~", 'danger', 100);
71 | }
72 | });
73 | }
--------------------------------------------------------------------------------
/src/main/resources/static/js/lightyear.js:
--------------------------------------------------------------------------------
1 | var lightyear = function(){
2 |
3 | /**
4 | * 页面loading
5 | */
6 | var pageLoader = function($mode) {
7 | var $loadingEl = jQuery('#lyear-loading');
8 | $mode = $mode || 'show';
9 | if ($mode === 'show') {
10 | if ($loadingEl.length) {
11 | $loadingEl.fadeIn(250);
12 | } else {
13 | jQuery('body').prepend('');
14 | }
15 | } else if ($mode === 'hide') {
16 | if ($loadingEl.length) {
17 | $loadingEl.fadeOut(250);
18 | }
19 | }
20 | return false;
21 | };
22 |
23 | /**
24 | * 页面小提示
25 | * @param $msg 提示信息
26 | * @param $type 提示类型:'info', 'success', 'warning', 'danger'
27 | * @param $delay 毫秒数,例如:1000
28 | * @param $icon 图标,例如:'fa fa-user' 或 'glyphicon glyphicon-warning-sign'
29 | * @param $from 'top' 或 'bottom'
30 | * @param $align 'left', 'right', 'center'
31 | * @param $url 跳转链接 例如: https://www.xxxx.com
32 | * @author CaiWeiMing <314013107@qq.com>
33 | */
34 | var tips = function ($msg, $type, $delay, $icon, $from, $align, $url) {
35 | $type = $type || 'info';
36 | $delay = $delay || 1000;
37 | $from = $from || 'top';
38 | $align = $align || 'center';
39 | $enter = $type == 'danger' ? 'animated shake' : 'animated fadeInUp';
40 | $url = $url || url;
41 | jQuery.notify({
42 | icon: $icon,
43 | message: $msg
44 | },
45 | {
46 | element: 'body',
47 | type: $type,
48 | allow_dismiss: true,
49 | newest_on_top: true,
50 | showProgressbar: false,
51 | placement: {
52 | from: $from,
53 | align: $align
54 | },
55 | offset: 20,
56 | spacing: 10,
57 | z_index: 10800,
58 | delay: $delay,
59 | //timer: 1000,
60 | animate: {
61 | enter: $enter,
62 | exit: 'animated fadeOutDown'
63 | }
64 | });
65 | if($url!=''){
66 | setTimeout(function(){
67 | window.location.href=$url;
68 | },$delay);
69 | }
70 |
71 | };
72 |
73 | var url = '';
74 |
75 | return {
76 | // 页面小提示
77 | notify : function ($msg, $type, $delay, $icon, $from, $align, $url) {
78 | tips($msg, $type, $delay, $icon, $from, $align, $url);
79 | },
80 | url : function ($url){
81 | url=$url;
82 | },
83 | // 页面加载动画
84 | loading : function ($mode) {
85 | pageLoader($mode);
86 | }
87 | };
88 | }();
--------------------------------------------------------------------------------
/src/main/resources/static/js/login.js:
--------------------------------------------------------------------------------
1 | let delay = 2000;
2 | function loginClick() {
3 | // lightyear.loading('show');
4 | let username = $("#username").val();
5 | let password = $("#password").val();
6 | console.log(username + " "+password)
7 | // 对密码加密
8 |
9 | // 提交请求
10 | $.ajax({
11 | type: "post",
12 | url: url + "/login",
13 | data: {
14 | "userName": username,
15 | "password": md5(password)
16 | },
17 | dataType: "json",
18 | success: function (r) {
19 | if (r.status !== 200) {
20 | lightyear.loading('hide');
21 | lightyear.notify(r.message, 'danger', delay);
22 | } else {
23 | console.log(r);
24 | lightyear.loading('hide');
25 | lightyear.notify('登陆成功!', 'success', delay);
26 | window.location.href = "index.html";
27 | }
28 | },
29 | error: function (r) {
30 | /*错误信息处理*/
31 | lightyear.notify(r.responseJSON.message, 'danger', delay);
32 | lightyear.loading('hide');
33 | }
34 | });
35 |
36 | }
37 |
38 | $(document).on('keypress', function (e) {
39 | if (e.which === 13) {
40 | loginClick();
41 | }
42 | });
43 |
44 | $('#invitePage').click(
45 | function () {
46 | window.location.href = '/invite.html'
47 | }
48 | )
--------------------------------------------------------------------------------
/src/main/resources/static/js/main.min.js:
--------------------------------------------------------------------------------
1 | ;
2 |
3 | jQuery( function() {
4 | $("body").on('click','[data-stopPropagation]',function (e) {
5 | e.stopPropagation();
6 | });
7 |
8 | // 滚动条
9 | const ps = new PerfectScrollbar('.lyear-layout-sidebar-scroll', {
10 | swipeEasing: false,
11 | suppressScrollX: true
12 | });
13 |
14 | // 侧边栏
15 | $(document).on('click', '.lyear-aside-toggler', function() {
16 | $('.lyear-layout-sidebar').toggleClass('lyear-aside-open');
17 | $("body").toggleClass('lyear-layout-sidebar-close');
18 |
19 | if ($('.lyear-mask-modal').length == 0) {
20 | $('').prependTo('body');
21 | } else {
22 | $( '.lyear-mask-modal' ).remove();
23 | }
24 | });
25 |
26 | // 遮罩层
27 | $(document).on('click', '.lyear-mask-modal', function() {
28 | $( this ).remove();
29 | $('.lyear-layout-sidebar').toggleClass('lyear-aside-open');
30 | $('body').toggleClass('lyear-layout-sidebar-close');
31 | });
32 |
33 | // 侧边栏导航
34 | $(document).on('click', '.nav-item-has-subnav > a', function() {
35 | $subnavToggle = jQuery( this );
36 | $navHasSubnav = $subnavToggle.parent();
37 | $topHasSubNav = $subnavToggle.parents('.nav-item-has-subnav').last();
38 | $subnav = $navHasSubnav.find('.nav-subnav').first();
39 | $viSubHeight = $navHasSubnav.siblings().find('.nav-subnav:visible').outerHeight();
40 | $scrollBox = $('.lyear-layout-sidebar-scroll');
41 | $navHasSubnav.siblings().find('.nav-subnav:visible').slideUp(500).parent().removeClass('open');
42 | $subnav.slideToggle( 300, function() {
43 | $navHasSubnav.toggleClass( 'open' );
44 |
45 | // 新增滚动条处理
46 | var scrollHeight = 0;
47 | pervTotal = $topHasSubNav.prevAll().length,
48 | boxHeight = $scrollBox.outerHeight(),
49 | innerHeight = $('.sidebar-main').outerHeight(),
50 | thisScroll = $scrollBox.scrollTop(),
51 | thisSubHeight = $(this).outerHeight(),
52 | footHeight = 121;
53 |
54 | if (footHeight + innerHeight - boxHeight >= (pervTotal * 48)) {
55 | scrollHeight = pervTotal * 48;
56 | }
57 | if ($subnavToggle.parents('.nav-item-has-subnav').length == 1) {
58 | $scrollBox.animate({scrollTop: scrollHeight}, 300);
59 | } else {
60 | // 子菜单操作
61 | if (typeof($viSubHeight) != 'undefined' && $viSubHeight != null) {
62 | scrollHeight = thisScroll + thisSubHeight - $viSubHeight;
63 | $scrollBox.animate({scrollTop: scrollHeight}, 300);
64 | } else {
65 | if ((thisScroll + boxHeight - $scrollBox[0].scrollHeight) == 0) {
66 | scrollHeight = thisScroll - thisSubHeight;
67 | $scrollBox.animate({scrollTop: scrollHeight}, 300);
68 | }
69 | }
70 | }
71 | });
72 | });
73 |
74 | // 提示
75 | if($('[data-toggle="tooltip"]')[0]) {
76 | $('[data-toggle="tooltip"]').tooltip({
77 | "container" : 'body',
78 | });
79 | }
80 |
81 | // 弹出框
82 | if($('[data-toggle="popover"]')[0]) {
83 | $('[data-toggle="popover"]').popover();
84 | }
85 |
86 | // 标签
87 | $('.js-tags-input').each(function() {
88 | var $this = $(this);
89 | $this.tagsInput({
90 | height: $this.data('height') ? $this.data('height') : '38px',
91 | width: '100%',
92 | defaultText: $this.attr("placeholder"),
93 | removeWithBackspace: true,
94 | delimiter: [',']
95 | });
96 | });
97 |
98 | // 时间选择
99 | jQuery('.js-datetimepicker').each(function() {
100 | var $input = jQuery(this);
101 | $input.datetimepicker({
102 | format: $input.data('format') ? $input.data('format') : false,
103 | useCurrent: $input.data('use-current') ? $input.data('use-current') : false,
104 | locale: moment.locale('' + ($input.data('locale') ? $input.data('locale') : '') + ''),
105 | showTodayButton: $input.data('show-today-button') ? $input.data('show-today-button') : false,
106 | showClear: $input.data('show-clear') ? $input.data('show-clear') : false,
107 | showClose: $input.data('show-close') ? $input.data('show-close') : false,
108 | sideBySide: $input.data('side-by-side') ? $input.data('side-by-side') : false,
109 | inline: $input.data('inline') ? $input.data('inline') : false,
110 | });
111 | });
112 |
113 | // 日期选择
114 | jQuery('.js-datepicker').each(function() {
115 | var options = {
116 | weekStart: 1,
117 | autoclose: typeof($(this).data('auto-close')) != 'undefined' ? $(this).data('auto-close') : true,
118 | language: 'zh-CN', // 默认简体中文
119 | multidateSeparator: ', ', // 默认多个日期用,分隔
120 | format: $(this).data('date-format') ? $(this).data('date-format') : 'yyyy-mm-dd',
121 | };
122 |
123 | if ( $(this).prop("tagName") != 'INPUT' ) {
124 | options.inputs = [$(this).find('input:first'), $(this).find('input:last')];
125 | }
126 |
127 | $(this).datepicker(options);
128 | });
129 |
130 | // 颜色选取
131 | jQuery('.js-colorpicker').each(function() {
132 | var $colorpicker = jQuery(this);
133 | var $colorpickerMode = $colorpicker.data('colorpicker-mode') ? $colorpicker.data('colorpicker-mode') : 'hex';
134 | var $colorpickerinline = $colorpicker.data('colorpicker-inline') ? true: false;
135 | $colorpicker.colorpicker({
136 | 'format': $colorpickerMode,
137 | 'inline': $colorpickerinline
138 | });
139 | });
140 |
141 | // 复选框全选
142 | $("#check-all").change(function () {
143 | $("input[type='checkbox']").prop('checked', $(this).prop("checked"));
144 | });
145 |
146 | // 设置主题配色
147 | setTheme = function(input_name, data_name) {
148 | $("input[name='"+input_name+"']").click(function(){
149 | $('body').attr(data_name, $(this).val());
150 | });
151 | }
152 | setTheme('site_theme', 'data-theme');
153 | setTheme('logo_bg', 'data-logobg');
154 | setTheme('header_bg', 'data-headerbg');
155 | setTheme('sidebar_bg', 'data-sidebarbg');
156 |
157 | });
--------------------------------------------------------------------------------
/src/main/resources/static/js/md5.min.js:
--------------------------------------------------------------------------------
1 | !function(n){"use strict";function d(n,t){var r=(65535&n)+(65535&t);return(n>>16)+(t>>16)+(r>>16)<<16|65535&r}function f(n,t,r,e,o,u){return d((c=d(d(t,n),d(e,u)))<<(f=o)|c>>>32-f,r);var c,f}function l(n,t,r,e,o,u,c){return f(t&r|~t&e,n,t,o,u,c)}function v(n,t,r,e,o,u,c){return f(t&e|r&~e,n,t,o,u,c)}function g(n,t,r,e,o,u,c){return f(t^r^e,n,t,o,u,c)}function m(n,t,r,e,o,u,c){return f(r^(t|~e),n,t,o,u,c)}function i(n,t){var r,e,o,u;n[t>>5]|=128<>>9<<4)]=t;for(var c=1732584193,f=-271733879,i=-1732584194,a=271733878,h=0;h>5]>>>e%32&255);return t}function h(n){var t=[];for(t[(n.length>>2)-1]=void 0,e=0;e>5]|=(255&n.charCodeAt(e/8))<>>4&15)+r.charAt(15&t);return e}function r(n){return unescape(encodeURIComponent(n))}function o(n){return a(i(h(t=r(n)),8*t.length));var t}function u(n,t){return function(n,t){var r,e,o=h(n),u=[],c=[];for(u[15]=c[15]=void 0,16
2 |
3 |
4 |
5 | 登录 - Microsoft 365 管理系统
6 |
7 |
8 |
9 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
愿你有好运气,如果没有,愿你在不幸中学会慈悲;愿你被很多人爱,如果没有,愿你在寂寞中学会宽容。 - 刘瑜《愿你慢慢长大》
118 |
119 |
120 |
121 |
122 |
123 |

124 |
125 |
126 |
127 |
128 |
129 |
130 |
131 |
132 |
133 |
134 |
135 |
136 |
137 |
138 |
139 |
140 |
141 |
142 |
143 |
144 |
145 |
146 |
147 |
148 |
149 |
150 |
151 |
152 |
153 |
154 |
155 |