Compare commits

...

15 Commits

Author SHA1 Message Date
kkunkka
40c2da044a add: 获取未来的重要日子,获取过去的重要日子 2025-10-14 22:45:42 +08:00
kkunkka
8439653082 add: 跨域 2025-10-14 22:00:52 +08:00
jsh
1a71904608 add: 登录 2025-10-12 16:13:35 +08:00
jsh
68474c0c80 add: 登录 2025-10-12 16:13:04 +08:00
jsh
23ff4c814d style: 修改注释 2025-10-12 14:49:01 +08:00
jsh
363bcb83c6 fix: 修复还有多少天变成负数的问题 2025-10-12 14:27:19 +08:00
jsh
0200382ddf style: 清理引入 2025-10-12 14:11:01 +08:00
jsh
fa278dec01 add: 周年纪念日 2025-10-12 14:08:16 +08:00
jsh
ef224aa546 add: 周年纪念日 2025-10-11 16:18:18 +08:00
kkunkka
8a120a7223 add: 习惯curd 2025-10-10 15:58:20 +08:00
kkunkka
82e1f2deb4 add: 目标表增加根节点id和父节点id 2025-10-10 14:53:19 +08:00
kkunkka
affb754ae4 add: 习惯curd 2025-10-10 14:49:34 +08:00
kkunkka
79c0e37b87 refactor: 目标,任务,习惯都放一张表中 2025-10-10 12:40:31 +08:00
kkunkka
b9cb079139 sql 2025-10-10 11:41:50 +08:00
kkunkka
f86462bb24 add: 目标crud 2025-10-10 11:40:34 +08:00
33 changed files with 692 additions and 17 deletions

View File

@@ -1,16 +1,58 @@
drop table if exists `goals`; drop table if exists `user`
CREATE TABLE if not exists `goals` create table user
( (
id INT auto_increment NOT NULL PRIMARY KEY, id int unsigned auto_increment
status tinyint default 0 COMMENT '0进行中1已完成2已取消', primary key,
create_time datetime null,
update_time datetime null,
username varchar(100) not null,
password varchar(255) not null,
nickname varchar(100) null
)
comment '用户表';
drop table if exists `goal`;
CREATE TABLE if not exists `goal`
(
id INT unsigned auto_increment PRIMARY KEY,
status enum ('DOING', 'DONE', 'CANCEL') default 'DOING' not null,
create_time DATETIME NULL, create_time DATETIME NULL,
update_time DATETIME NULL, update_time DATETIME NULL,
type enum ('GOAL', 'TASK', 'HABIT') default 'TASK' NOT NULL,
name varchar(100) NOT NULL, name varchar(100) NOT NULL,
tag varchar(100) NULL, tag varchar(100) NULL,
detail varchar(100) NULL detail varchar(100) NULL,
root_id int unsigned null,
parent_id int unsigned null
) )
ENGINE = InnoDB
DEFAULT CHARSET = utf8mb4
COLLATE = utf8mb4_0900_ai_ci
COMMENT ='目标管理表'; COMMENT ='目标管理表';
drop table if exists `habit_record`;
create table habit_record
(
id int unsigned auto_increment
primary key,
create_time datetime null,
update_time datetime null,
goal_id int unsigned not null
)
comment '习惯记录表';
drop table if exists `anniversary`
create table `anniversary`
(
id int unsigned auto_increment,
create_time datetime null,
update_time datetime null,
name varchar(100) not null,
date date not null comment '重要的日期',
type enum ('ANNIVERSARY', 'COMMEMORATION') default 'ANNIVERSARY' not null
)
comment '周年纪念日';

View File

@@ -53,6 +53,7 @@
<groupId>org.projectlombok</groupId> <groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId> <artifactId>lombok</artifactId>
<optional>true</optional> <optional>true</optional>
<scope>compile</scope>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.springframework.boot</groupId> <groupId>org.springframework.boot</groupId>

View File

@@ -0,0 +1,19 @@
package com.dota.nexus.config;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
public class CorsConfig implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedOriginPatterns("*")
.allowedHeaders("*")
.allowCredentials(true)
.allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS")
.maxAge(3600);
}
}

View File

@@ -0,0 +1,50 @@
package com.dota.nexus.controller;
import com.dota.nexus.entity.Anniversary;
import com.dota.nexus.entity.R;
import com.dota.nexus.service.AnniversaryService;
import org.springframework.web.bind.annotation.*;
@RestController
@RequestMapping("anniversary")
public class AnniversaryController {
AnniversaryService anniversaryService;
public AnniversaryController(AnniversaryService anniversaryService) {
this.anniversaryService = anniversaryService;
}
/**
* 获取未来所有周年日和纪念日
*/
@GetMapping("future")
public R getFuture() {
return R.ok(anniversaryService.getFuture());
}
/**
* 获取过去的纪念日
*/
@GetMapping("past")
public R getPast() {
return R.ok(anniversaryService.getPast());
}
@PostMapping
public R add(Anniversary anniversary) {
anniversaryService.saveOrUpdate(anniversary);
return R.ok();
}
@DeleteMapping
public R del(Integer id) {
anniversaryService.removeById(id);
return R.ok();
}
@PutMapping
public R update(Anniversary anniversary) {
anniversaryService.saveOrUpdate(anniversary);
return R.ok();
}
}

View File

@@ -0,0 +1,62 @@
package com.dota.nexus.controller;
import com.dota.nexus.entity.Goal;
import com.dota.nexus.entity.R;
import com.dota.nexus.service.GoalService;
import org.springframework.web.bind.annotation.*;
@RestController
@RequestMapping("goal")
public class GoalController {
GoalService goalService;
public GoalController(GoalService goalService) {
this.goalService = goalService;
}
/**
* 新增目标
*/
@PostMapping
public R addGoal(Goal goal) {
goalService.save(goal);
return R.ok();
}
/**
* 删除目标
*/
@DeleteMapping
public R deleteGoal(Integer id) {
goalService.removeById(id);
return R.ok();
}
/**
* 完成目标
*/
@PostMapping("done")
public R doneGoal(Integer id) {
goalService.doneGoal(id);
return R.ok();
}
/**
* 目标进行中
*/
@PostMapping("doing")
public R doingGoal(Integer id) {
goalService.doingGoal(id);
return R.ok();
}
/**
* 取消目标
*/
@PostMapping("cancel")
public R cancelGoal(Integer id) {
goalService.cancelGoal(id);
return R.ok();
}
}

View File

@@ -0,0 +1,40 @@
package com.dota.nexus.controller;
import com.dota.nexus.entity.HabitRecord;
import com.dota.nexus.entity.R;
import com.dota.nexus.service.HabitRecordService;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.time.LocalDateTime;
@RestController
@RequestMapping("habit")
public class HabitRecordController {
HabitRecordService habitRecordService;
public HabitRecordController(HabitRecordService habitRecordService) {
this.habitRecordService = habitRecordService;
}
/**
* 根据目标id查询习惯记录
*/
@GetMapping
public R getHabitRecords(Integer id) {
return R.ok(habitRecordService.getHabitRecordsByGoalId(id));
}
@PostMapping
public R addHabitRecord(Integer id) {
var habit = new HabitRecord();
habit.setCreateTime(LocalDateTime.now());
habit.setUpdateTime(LocalDateTime.now());
habit.setGoalId(id);
habitRecordService.save(habit);
return R.ok();
}
}

View File

@@ -0,0 +1,28 @@
package com.dota.nexus.controller;
import com.dota.nexus.entity.LoginDTO;
import com.dota.nexus.entity.R;
import com.dota.nexus.service.UserService;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("user")
public class UserController {
UserService userService;
public UserController(UserService userService) {
this.userService = userService;
}
@PostMapping("login")
public R login(LoginDTO loginDTO) throws Exception {
var res = userService.login(loginDTO.username(), loginDTO.password());
if (res==null) {
return R.error("用户不存在或者密码错误");
}
return R.ok(res);
}
}

View File

@@ -0,0 +1,16 @@
package com.dota.nexus.entity;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.time.LocalDate;
@Data
@EqualsAndHashCode(callSuper = true)
public class Anniversary extends Entity{
private String name;
private LocalDate date;
private AnniversaryEnum type;
}

View File

@@ -0,0 +1,15 @@
package com.dota.nexus.entity;
import lombok.Getter;
@Getter
public enum AnniversaryEnum {
ANNIVERSARY("周年日"),
COMMEMORATION("纪念日");
private String value;
AnniversaryEnum(String value) {
this.value = value;
}
}

View File

@@ -1,15 +1,16 @@
package com.dota.nexus.entity; package com.dota.nexus.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import lombok.Data; import lombok.Data;
import java.time.LocalDateTime; import java.time.LocalDateTime;
@Data @Data
public class Entity { public class Entity {
@TableId(type = IdType.AUTO)
Integer id; Integer id;
Integer status;
LocalDateTime createTime; LocalDateTime createTime;
LocalDateTime updateTime; LocalDateTime updateTime;

View File

@@ -6,9 +6,17 @@ import lombok.EqualsAndHashCode;
@EqualsAndHashCode(callSuper = true) @EqualsAndHashCode(callSuper = true)
@Data @Data
public class Goal extends Entity { public class Goal extends Entity {
private GoalStatusEnum status;
private GoalTypeEnum type;
private String name; private String name;
private String tag; private String tag;
private String detail; private String detail;
private Integer rootId;
private Integer parentId;
} }

View File

@@ -0,0 +1,16 @@
package com.dota.nexus.entity;
import lombok.Getter;
@Getter
public enum GoalStatusEnum {
DOING("进行中"),
DONE("完成"),
CANCEL("已取消");
private final String value;
GoalStatusEnum(String value) {
this.value = value;
}
}

View File

@@ -0,0 +1,13 @@
package com.dota.nexus.entity;
public enum GoalTypeEnum {
GOAL("目标"),
TASK("任务"),
HABIT("习惯");
private String value;
GoalTypeEnum(String value) {
this.value = value;
}
}

View File

@@ -0,0 +1,10 @@
package com.dota.nexus.entity;
import lombok.Data;
import lombok.EqualsAndHashCode;
@EqualsAndHashCode(callSuper = true)
@Data
public class HabitRecord extends Entity {
private Integer goalId;
}

View File

@@ -0,0 +1,4 @@
package com.dota.nexus.entity;
public record LoginDTO(String username, String password) {
}

View File

@@ -0,0 +1,45 @@
package com.dota.nexus.entity;
import lombok.Data;
@Data
public class R {
private Integer code;
private String msg;
private Object data;
public R(Integer code, String msg){
this.code = code;
this.msg = msg;
}
public R (Integer code, String msg, Object data) {
this.code = code;
this.msg = msg;
this.data = data;
}
public static R ok() {
return ok(null);
}
public static R ok(Object data) {
return new R(200, "ok", data);
}
public static R error(String msg){
return new R(500, msg);
}
public static R error(){
return error("服务端发生未知错误");
}
public static R unauthorized() {
return new R(401, "未授权,客户端没有提供认证信息");
}
public static R forbidden(){
return new R(403, "没有权限");
}
}

View File

@@ -0,0 +1,14 @@
package com.dota.nexus.entity;
import lombok.Data;
import lombok.EqualsAndHashCode;
@EqualsAndHashCode(callSuper = true)
@Data
public class User extends Entity{
private String name;
private String password;
private String nickname;
}

View File

@@ -0,0 +1,4 @@
package com.dota.nexus.entity.vo;
public record AnniversaryVO(String name, String date, int distance) {
}

View File

@@ -0,0 +1,9 @@
package com.dota.nexus.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.dota.nexus.entity.Anniversary;
import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface AnniversaryMapper extends BaseMapper<Anniversary> {
}

View File

@@ -0,0 +1,9 @@
package com.dota.nexus.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.dota.nexus.entity.HabitRecord;
import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface HabitRecordMapper extends BaseMapper<HabitRecord> {
}

View File

@@ -0,0 +1,9 @@
package com.dota.nexus.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.dota.nexus.entity.User;
import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface UserMapper extends BaseMapper<User> {
}

View File

@@ -0,0 +1,13 @@
package com.dota.nexus.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.dota.nexus.entity.Anniversary;
import com.dota.nexus.entity.vo.AnniversaryVO;
import java.util.List;
public interface AnniversaryService extends IService<Anniversary> {
List<AnniversaryVO> getFuture();
List<AnniversaryVO> getPast();
}

View File

@@ -4,4 +4,11 @@ import com.baomidou.mybatisplus.extension.service.IService;
import com.dota.nexus.entity.Goal; import com.dota.nexus.entity.Goal;
public interface GoalService extends IService<Goal> { public interface GoalService extends IService<Goal> {
void delGoal(Integer id);
void doneGoal(Integer id);
void doingGoal(Integer id);
void cancelGoal(Integer id);
} }

View File

@@ -0,0 +1,10 @@
package com.dota.nexus.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.dota.nexus.entity.HabitRecord;
import java.util.List;
public interface HabitRecordService extends IService<HabitRecord> {
List<HabitRecord> getHabitRecordsByGoalId(Integer goalId);
}

View File

@@ -0,0 +1,9 @@
package com.dota.nexus.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.dota.nexus.entity.User;
public interface UserService extends IService<User> {
String login(String username, String password) throws Exception;
}

View File

@@ -0,0 +1,55 @@
package com.dota.nexus.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.dota.nexus.entity.Anniversary;
import com.dota.nexus.entity.AnniversaryEnum;
import com.dota.nexus.entity.vo.AnniversaryVO;
import com.dota.nexus.mapper.AnniversaryMapper;
import com.dota.nexus.service.AnniversaryService;
import org.springframework.stereotype.Service;
import java.time.LocalDate;
import java.time.temporal.ChronoUnit;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.stream.Collectors;
@Service
public class AnniversaryServiceImpl extends ServiceImpl<AnniversaryMapper, Anniversary> implements AnniversaryService {
@Override
public List<AnniversaryVO> getFuture() {
var anniversaries = this.baseMapper.selectList(null);
var list = new ArrayList<AnniversaryVO>();
var now = LocalDate.now();
for (Anniversary anniversary : anniversaries) {
// 周年,变成今年或者明年
if (anniversary.getType() == AnniversaryEnum.ANNIVERSARY) {
LocalDate date = anniversary.getDate();
date = date.withYear(now.getYear());
if (date.isBefore(now)) {
date = date.withYear(now.getYear() + 1);
}
list.add(new AnniversaryVO(anniversary.getName(), date.toString(), (int) ChronoUnit.DAYS.between(now, date)));
} else if (anniversary.getType() == AnniversaryEnum.COMMEMORATION && !anniversary.getDate().isBefore(now)) {
list.add(new AnniversaryVO(anniversary.getName(), anniversary.getDate().toString(), (int) ChronoUnit.DAYS.between(now, anniversary.getDate())));
}
}
list.sort(Comparator.comparingInt(AnniversaryVO::distance));
return list;
}
@Override
public List<AnniversaryVO> getPast() {
var q = new LambdaQueryWrapper<Anniversary>();
q.eq(Anniversary::getType, AnniversaryEnum.COMMEMORATION);
var anniversaries = this.baseMapper.selectList(q);
var now = LocalDate.now();
return anniversaries.stream().map(a -> new AnniversaryVO(a.getName(), a.getDate().toString(), (int) ChronoUnit.DAYS.between(now, a.getDate()))).sorted((a,b)->b.distance()-a.distance()).collect(Collectors.toList());
}
}

View File

@@ -1,10 +1,53 @@
package com.dota.nexus.service.impl; package com.dota.nexus.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.dota.nexus.entity.Goal; import com.dota.nexus.entity.Goal;
import com.dota.nexus.entity.GoalStatusEnum;
import com.dota.nexus.entity.HabitRecord;
import com.dota.nexus.mapper.GoalMapper; import com.dota.nexus.mapper.GoalMapper;
import com.dota.nexus.mapper.HabitRecordMapper;
import com.dota.nexus.service.GoalService; import com.dota.nexus.service.GoalService;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@Service
public class GoalServiceImpl extends ServiceImpl<GoalMapper, Goal> implements GoalService { public class GoalServiceImpl extends ServiceImpl<GoalMapper, Goal> implements GoalService {
HabitRecordMapper habitRecordMapper;
public GoalServiceImpl(HabitRecordMapper habitRecordMapper) {
this.habitRecordMapper = habitRecordMapper;
}
@Override
@Transactional
public void delGoal(Integer id) {
removeById(id);
var q = new LambdaQueryWrapper<HabitRecord>();
q.eq(HabitRecord::getGoalId, id);
habitRecordMapper.delete(q);
}
@Override
public void doneGoal(Integer id) {
updateStatus(id, GoalStatusEnum.DONE);
}
@Override
public void doingGoal(Integer id) {
updateStatus(id, GoalStatusEnum.DOING);
}
@Override
public void cancelGoal(Integer id) {
updateStatus(id, GoalStatusEnum.CANCEL);
}
private void updateStatus(Integer id, GoalStatusEnum status) {
var update = new LambdaUpdateWrapper<Goal>();
update.eq(Goal::getId, id);
update.set(Goal::getStatus, status);
this.baseMapper.update(update);
}
} }

View File

@@ -0,0 +1,21 @@
package com.dota.nexus.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.dota.nexus.entity.HabitRecord;
import com.dota.nexus.mapper.HabitRecordMapper;
import com.dota.nexus.service.HabitRecordService;
import org.springframework.stereotype.Service;
import java.util.List;
@Service
public class HabitRecordServiceImpl extends ServiceImpl<HabitRecordMapper, HabitRecord> implements HabitRecordService {
@Override
public List<HabitRecord> getHabitRecordsByGoalId(Integer goalId) {
var q = new LambdaQueryWrapper<HabitRecord>();
q.eq(HabitRecord::getGoalId, goalId);
return this.baseMapper.selectList(q);
}
}

View File

@@ -0,0 +1,27 @@
package com.dota.nexus.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.dota.nexus.entity.User;
import com.dota.nexus.mapper.UserMapper;
import com.dota.nexus.service.UserService;
import com.dota.nexus.util.GlobalMap;
import com.dota.nexus.util.PasswordUtil;
import org.springframework.stereotype.Service;
import java.util.UUID;
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {
public String login(String username, String password) throws Exception {
var q = new LambdaQueryWrapper<User>();
q.eq(User::getName, username);
var u = this.baseMapper.selectOne(q);
if (u!=null && PasswordUtil.verify(password, u.getPassword())) {
var uuid = UUID.randomUUID().toString();
GlobalMap.put(uuid, u.getId());
return uuid;
}
return null;
}
}

View File

@@ -0,0 +1,16 @@
package com.dota.nexus.util;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
public class GlobalMap {
private static final Map<String, Object> MAP = new ConcurrentHashMap<>();
public static void put(String k, Object v) {
MAP.put(k,v);
}
public static Object get(String k) {
return MAP.get(k);
}
}

View File

@@ -0,0 +1,47 @@
package com.dota.nexus.util;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.PBEKeySpec;
import java.security.SecureRandom;
import java.util.Base64;
public class PasswordUtil {
public static String encrypt(String password) throws Exception{
var random = new SecureRandom();
var salt = new byte[16];
random.nextBytes(salt);
var spec = new PBEKeySpec(
password.toCharArray(),
salt,
100000,
256
);
var factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256");
var hash = factory.generateSecret(spec).getEncoded();
return Base64.getEncoder().encodeToString(salt) + ":" + Base64.getEncoder().encodeToString(hash);
}
public static boolean verify(String password, String storedHash) throws Exception {
var parts = storedHash.split(":");
var salt = Base64.getDecoder().decode(parts[0]);
PBEKeySpec spec = new PBEKeySpec(
password.toCharArray(),
salt,
100000,
256
);
byte[] testHash = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256")
.generateSecret(spec).getEncoded();
return parts[1].equals(Base64.getEncoder().encodeToString(testHash));
}
public static void main(String[] args) throws Exception{
var s = "nexus2017";
var pass =encrypt(s);
System.out.println(pass);
System.out.println(pass.length());
System.out.println(verify(s, pass));
}
}

View File

@@ -0,0 +1,13 @@
package com.dota.nexus.util;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
public class TokenUtil {
public static Integer CurrentUserId() {
var req = ((ServletRequestAttributes)RequestContextHolder.currentRequestAttributes()).getRequest();
String authorization = req.getHeader("Authorization");
var token = authorization.replace("Bearer ", "");
return (Integer) GlobalMap.get(token);
}
}

View File

@@ -1,10 +1,9 @@
package com.dota.nexus.mapper; package com.dota.nexus.mapper;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers; import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.conditions.query.LambdaQueryChainWrapper;
import com.dota.nexus.entity.Goal; import com.dota.nexus.entity.Goal;
import com.dota.nexus.entity.GoalStatusEnum;
import jakarta.annotation.Resource; import jakarta.annotation.Resource;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.test.context.SpringBootTest;
@@ -21,7 +20,7 @@ public class GoalMapperTest {
@Test @Test
public void testInsert() { public void testInsert() {
var g = new Goal(); var g = new Goal();
g.setStatus(1); g.setStatus(GoalStatusEnum.DONE);
g.setCreateTime(LocalDateTime.now()); g.setCreateTime(LocalDateTime.now());
g.setTag("test"); g.setTag("test");
g.setName("测试"); g.setName("测试");