实现会议管理功能

目录

生成原始会议数据

一、数据结构

二、添加测试数据

查询会议列表分页数据(后端) 

一、业务分析

二、编写持久层代码

三、编辑业务层代码

四、编写Web层代码

查询成员列表(后端)

一、编写持久层代码

二、编写业务层代码

三、编写Web层代码

实现会议成员的增删

一、查询会议成员信息

部署工作流项目

一、为什么要把工作流独立成项目?

二、部署工作流项目

三、工作流BPMN

开启会议审批工作流(持久层&业务层) 

开启会议审批工作流(Web层)

保存会议记录(移动端)

加载现有会议详情

编辑会议重新发起工作流(持久层&业务层) 

编辑会议重新发起工作流(Web层&移动端)

删除会议和工作流(后端)

删除会议和工作流(移动端)


生成原始会议数据

一、数据结构

        前一个小节,我们把静态的会议列表页面做出来了,很多同学都想把其中的静态数据换成动态数据,所以咱们把后端的Java代码写一下。想要在页面上展示会议记录,那就需要读取tb_meeting 数据表,但是这个表里面并没有初始数据,所以我们来写程序生成原始会议数据。 

        首先咱们来认识一下会议表(tb_meeting),这个数据表包含了14个字段。其中的 members 字段是JSON格式,记录所有参会人员的ID。 instance_id 字段是工作流实例ID,因为会议创建出来之后,必须经过审批才能正式执行。

注意:数据表中date time类型 映射到 Java pojo包中String类型。 

二、添加测试数据

在 TbMeetingDao.xml 文件中添加INSERT语句

    <insert id="insertMeeting" parameterType="com.example.emos.wx.db.pojo.TbMeeting">INSERT INTO tb_meetingSET uuid = #{uuid},title = #{title},date = #{date},creator_id = #{creatorId},<if test="place!=null">place = #{place},</if>start = #{start},end = #{end},type = #{type},members = #{members},`desc` = #{desc},instance_id = #{instanceId},status = #{status},create_time = NOW()</insert>

编写 TbMeetingDao.java 接口,添加DAO方法 

@Mapper
public interface TbMeetingDao {public int insertMeeting(TbMeeting entity);
}

创建 MeetingService.java 接口,添加抽象方法 

public interface MeetingService { public void insertMeeting(TbMeeting entity);
} 

创建 MettingServiceImpl.java 类,添加实现方法 

@Service
@Slf4j
public class MeetingServiceImpl implements MeetingService {@Autowiredprivate TbMeetingDao meetingDao;@Overridepublic void insertMeeting(TbMeeting entity) {int row = meetingDao.insertMeeting(entity);if (row != 1) {throw new EmosException("会议添加失败");}//开启审批工作流//startMeetingWorkflow(entity.getUuid(), entity.getCreatorId().intValue(), entity.getDate(), entity.getStart());}
}

在 EmosWxApiApplicationTests.java 类中,编写生成原始会议记录的代码

@SpringBootTest
class EmosWxApiApplicationTests {@Autowiredprivate MeetingService meetingService;@Testvoid createMeetingData(){for (int i=1;i<=100;i++){TbMeeting meeting=new TbMeeting();meeting.setId((long)i);meeting.setUuid(IdUtil.simpleUUID());meeting.setTitle("测试会议"+i);meeting.setCreatorId(15L); //ROOT用户IDmeeting.setDate(DateUtil.today());meeting.setPlace("线上会议室");meeting.setStart("08:30");meeting.setEnd("10:30");meeting.setType((short) 1);meeting.setMembers("[15,16]");meeting.setDesc("会议研讨Emos项目上线测试");meeting.setInstanceId(IdUtil.simpleUUID());meeting.setStatus((short)3);meetingService.insertMeeting(meeting);}}
}

查询会议列表分页数据(后端) 

一、业务分析

        每个员工只能看到自己参与的会议记录,自己不参与的会议是看不到的。而且会议必须是未开始状态,或者进行中状态才能被看到,已经结束的会议、审批中的会议、审批不通过的会议都是无法被看到的。

二、编写持久层代码

在 TbMeetingDao.xml 文件中编写分页查询的SQL语句

    <select id="searchMyMeetingListByPage" parameterType="HashMap" resultType="HashMap">SELECTm.id,m.uuid,m.title,u2.name,DATE_FORMAT(m.date,'%Y年%m月%d日') AS date,m.place,DATE_FORMAT(m.start,'%H:%i') AS start,DATE_FORMAT(m.end,'%H:%i') AS end,m.type,m.status,m.desc,u2.photo,TIMESTAMPDIFF(HOUR,CONCAT(m.date," ",m.start),CONCAT(m.date," ",m.end)) AS hourFROM tb_meeting mJOIN tb_user u1 ON JSON_CONTAINS(m.members,CAST(u1.id AS CHAR))JOIN tb_user u2 ON m.creator_id=u2.idWHERE u1.id = #{userId} AND u1.status = 1 AND u2.status = 1AND m.status IN(3,4)ORDER BY m.date,m.start,m.idLIMIT #{start}, #{length}</select>

在 TbMeetingDao.java 接口中定义Dao方法 

@Mapper
public interface TbMeetingDao {……public ArrayList<HashMap> searchMyMeetingListByPage(HashMap param);
}

三、编辑业务层代码

在 MeetingService.java 中添加抽象分页方法 

public interface MeetingService { ……public ArrayList<HashMap> searchMyMeetingListByPage(HashMap param);
} 

在 MeetingServiceImpl.java 中添加分页方法

@Service
@Slf4j
public class MeetingServiceImpl implements MeetingService {……@Overridepublic ArrayList<HashMap> searchMyMeetingListByPage(HashMap param) {ArrayList<HashMap> list = meetingDao.searchMyMeetingListByPage(param);String date = null;ArrayList resultList = new ArrayList();HashMap resultMap = null;JSONArray array = null;for (HashMap map : list) {String temp = map.get("date").toString();if (!temp.equals(date)) {date = temp;resultMap = new HashMap();resultMap.put("date", date);array = new JSONArray();resultMap.put("list", array);resultList.add(resultMap);}array.put(map);}return resultList;}
}

四、编写Web层代码

创建 SearchMyMeetingListByPageForm.java 封装分页请求数据 

@Data
@ApiModel
public class SearchMyMeetingListByPageForm {@NotNull@Min(1)private Integer page;@NotNull@Range(min = 1,max = 40)private Integer length;}

创建 MeetingController.java 类,添加分页查询Web方法

@RestController
@RequestMapping("/meeting")
@Slf4j
public class MeetingController {@Autowiredprivate JwtUtil jwtUtil;@Autowiredprivate MeetingService meetingService;@PostMapping("/searchMyMeetingListByPage")@ApiOperation("查询会议列表分页数据")public R searchMyMeetingListByPage(@Valid @RequestBody SearchMyMeetingListByPageForm form,@RequestHeader("token") String token){int userId=jwtUtil.getUserId(token);int page=form.getPage();int length=form.getLength();long start=(page-1)*length;HashMap map=new HashMap();map.put("userId",userId);map.put("start",start);map.put("length",length);ArrayList list=meetingService.searchMyMeetingListByPage(map);return R.ok().put("result",list);}
}

查询成员列表(后端)

一、编写持久层代码

在TbDeptDao.xml文件中编写SQL语句

  <select id="searchDeptMembers" parameterType="String" resultType="HashMap">SELECTd.id,d.dept_name AS deptName,COUNT(u.id) AS countFROM tb_dept d LEFT JOIN tb_user u ON u.dept_id=d.id AND u.status=1<if test="keyword!=null">WHERE u.name LIKE '%${keyword}%'</if>GROUP BY d.id</select>

在 TbDeptDao.java 接口中的DAO方法

@Mapper
public interface TbDeptDao {public ArrayList<HashMap> searchDeptMembers(String keyword);
}

在 TbUserDao.xml 文件中编写SQL语句

    <select id="searchUserGroupByDept" parameterType="String" resultType="HashMap">SELECTd.id AS deptId,d.dept_name AS deptName,u.id AS userId,u.nameFROM tb_dept d JOIN tb_user u ON u.dept_id=d.idWHERE u.status=1<if test="keyword!=null">AND u.name LIKE '%${keyword}%'</if>ORDER BY d.id, u.id;</select>

编写 TbUserDao.java 接口中的DAO方法 

@Mapper
public interface TbUserDao {……public ArrayList<HashMap> searchUserGroupByDept(String keyword);
}

二、编写业务层代码

在 UserService.java 中创建编写抽象方法

public interface UserService {……public ArrayList<HashMap> searchUserGroupByDept(String keyword);
}

在 UserServiceImpl.java 中实现抽象方法

@Service
@Slf4j
@Scope("prototype")
public class UserServiceImpl implements UserService {……@Overridepublic ArrayList<HashMap> searchUserGroupByDept(String keyword) {ArrayList<HashMap> list_1=deptDao.searchDeptMembers(keyword);ArrayList<HashMap> list_2=userDao.searchUserGroupByDept(keyword);for(HashMap map_1:list_1){long deptId=(Long)map_1.get("id");ArrayList members=new ArrayList();for(HashMap map_2:list_2){long id=(Long) map_2.get("deptId");if(deptId==id){members.add(map_2);}}map_1.put("members",members);}return list_1;}
}// 数据表中 int 类型 可能映射为 Java中 Long 类型

三、编写Web层代码

创建 SearchUserGroupByDeptForm.java 类,接收移动端提交的数据

@Data
@ApiModel
public class SearchUserGroupByDeptForm {@Pattern(regexp = "^[\\u4e00-\\u9fa5]{1,15}$")private String keyword;
}

编写 UserController.java 的Web方法,接收移动端请求

@RestController
@RequestMapping("/user")
@Api("用户模块Web接口")
public class UserController {……@PostMapping("/searchUserGroupByDept")@ApiOperation("查询员工列表,按照部门分组排列")@RequiresPermissions(value = {"ROOT","EMPLOYEE:SELECT"},logical = Logical.OR)public R searchUserGroupByDept(@Valid @RequestBody SearchUserGroupByDeptForm form){ArrayList<HashMap> list=userService.searchUserGroupByDept(form.getKeyword());return R.ok().put("result",list);}
}

实现会议成员的增删

一、查询会议成员信息

编写 TBUserDao.xml 文件中的SQL语句

    <select id="searchMembers" parameterType="list" resultType="HashMap">SELECT id,name,photoFROM tb_userWHERE status = 1AND id IN<foreach collection="list" item="one" separator="," open="(" close=")">#{one}</foreach></select>

在 TbUserDao.java 中声明DAO方法

@Mapper
public interface TbUserDao {……public ArrayList<HashMap> searchMembers(List param);
}

在 UserService.java 接口中声明抽象方法

public interface UserService {……public ArrayList<HashMap> searchMembers(List param);
}

在 UserServiceImpl.java 类中实现抽象方法

@Service
@Slf4j
@Scope("prototype")
public class UserServiceImpl implements UserService {……@Overridepublic ArrayList<HashMap> searchMembers(List param) {ArrayList<HashMap> list=userDao.searchMembers(param);return list;}
}

创建 SearchMembersForm.java 类,接收移动端提交的数据

@Data
@ApiModel
public class SearchMembersForm {@NotBlankprivate String members;
}

编写 UserController.java 中的Web方法

@RestController
@RequestMapping("/user")
@Api("用户模块Web接口")
public class UserController {……@PostMapping("/searchMembers")@ApiOperation("查询成员")@RequiresPermissions(value = {"ROOT", "MEETING:INSERT", "MEETING:UPDATE"},logical = Logical.OR)public R searchMembers(@Valid @RequestBody SearchMembersForm form){if(!JSONUtil.isJsonArray(form.getMembers())){throw new EmosException("members不是JSON数组");}List param=JSONUtil.parseArray(form.getMembers()).toList(Integer.class);ArrayList list=userService.searchMembers(param);return R.ok().put("result",list);}
}// JSONUtil.isJsonArray()
// JSONUtil.parseArray().toList(Integer.class)
// 对应前端AJAX提交数据 {members: JSON.stringify(members)}

部署工作流项目

一、为什么要把工作流独立成项目?

        本课程的工作流部分已经剥离成独立的项目,跟emos-wx-api项目形成分布式调用关系。为什么要把工作流独立出来有三点考虑:

  1. 最新的Activiti7工作流引擎需要JDK1.8以上的环境,很多同学的JDK都还是1,8的,所以独立出来可以单独部署在高版本JDK的Docker容器里面,并不影响emos-wx-api项目。
  2. 因为工作流引擎搭建和BPMN绘制较为麻烦,所以方便大家使用,我就把该部分内容打成JAR文件了,直接部署就可以使用工作流引擎。
  3. 独立出来的工作流项目部署在其他的主机上面,容易获得更好的性能。如果所有的功能都整合到一个项目中,运行的时候主机压力较高,而且无法分拆。

二、部署工作流项目

大家在GIT 项目上面下载 jdk.tar.gz 镜像文件,把该镜像上传到centos系统,导入Docker环境

docker load < jdk.tar.gz

然后执行命令,创建JDK容器

docker run -it -d --name=workflow -p 9090:9090 -v /root/workflow:/root/workflow jdk

在Navicat上面上面执行 工作流.sql 文件,导入工作流依赖的各种数据表

        用好压软件(推荐此款压缩软件)打开 emos-workflow.jar文件。找到application.yml 文件,点击右键,选择用内部查看器打开。修改其中的MYSQL连接信息和Redis连接信息,并且保存该文件。好压软件会弹出对话框是否更新该压缩文件,选择确定。

        把 emos-workflow. jar 文件上传到Linux的 /root/workflow 文件夹,然后进入到Docker容器,运行工作流程序

// 注意先配置好 java 和 nohup 环境变量docker exec -it workflow bashcd /root/workflownohup java -jar emos-workflow.jar >> out.log 2>&1 &

三、工作流BPMN

        会议审批流程如上图,因为无论审批结果是什么,都要向emos-wx-api 项目发送HTTP请求,告知审批结果。

  1. 如果创建会议的是总经理,那么不需要审批,该会议直接通过;如果创建会议的不是总经理,那么必须要经过审批。
  2. 如果参会人都不是同一个部门的,需要先由发起人所在部门的经理审批,然后由总经理审批;如果参会人都是一个部门的,那就只需要该部门的经理审批即可。

开启会议审批工作流(持久层&业务层) 

  <select id="searchUserInfo" parameterType="int" resultType="HashMap">SELECTu.open_id AS openId,u.nickname,u.name,u.photo,u.sex,u.tel,u.email,d.dept_name AS dept,u.hiredate,CASE u.statusWHEN 1 THEN "在职"WHEN 2 THEN "离职"END AS status,( SELECT GROUP_CONCAT( role_name separator "," ) FROM tb_role WHERE JSON_CONTAINS ( u.role, CONVERT ( id, CHAR ) ) ) AS rolesFROM tb_user uLEFT JOIN tb_dept d ON u.dept_id = d.idWHERE u.id = #{userId} AND u.status = 1</select>
  <select id="searchDeptManagerId" parameterType="int" resultType="int">SELECTu2.idFROM tb_user u1 JOIN tb_user u2 ON u1.dept_id=u2.dept_idJOIN tb_role r ON JSON_CONTAINS(u2.role, CAST(r.id AS CHAR))WHERE u1.id=#{id} AND r.id=2 AND u1.status = 1 AND u2.status = 1</select><select id="searchGmId" resultType="int">SELECTu.idFROM tb_user uJOIN tb_role r ON JSON_CONTAINS(u.role, CAST(r.id AS CHAR))WHERE r.id=1 AND u.status = 1</select>
  <select id="searchMeetingMembersInSameDept" parameterType="String" resultType="boolean">SELECTIF(COUNT(DISTINCT u.dept_id)=1,TRUE,FALSE ) AS boolFROM tb_meeting mJOIN tb_user u ON JSON_CONTAINS ( m.members, CAST( u.id AS CHAR ) )WHERE m.uuid=#{uuid} AND u.status = 1</select>
    private void startMeetingWorkflow(String uuid, int creatorId, String date, String start) {HashMap info = userDao.searchUserInfo(creatorId);JSONObject json = new JSONObject();json.set("url", recieveNotify);json.set("uuid", uuid);json.set("openId", info.get("openId"));json.set("code", code);json.set("date", date);json.set("start", start);String[] roles = info.get("roles").toString().split(",");if (!ArrayUtil.contains(roles, "总经理")) {Integer managerId = userDao.searchDeptManagerId(creatorId);json.set("managerId", managerId);Integer gmId = userDao.searchGmId();json.set("gmId", gmId);boolean bool = meetingDao.searchMeetingMembersInSameDept(uuid);json.set("sameDept", bool);}String url = workflow + "/workflow/startMeetingProcess";HttpResponse resp = HttpRequest.post(url).header("Content-Type", "application/json").body(json.toString()).execute();if (resp.getStatus() == 200) {json = JSONUtil.parseObj(resp.body());String instanceId = json.getStr("instanceId");HashMap param = new HashMap();param.put("uuid", uuid);param.put("instanceId", instanceId);int row = meetingDao.updateMeetingInstanceId(param);if (row != 1) {throw new EmosException("保存会议工作流实例ID失败");}}}

开启会议审批工作流(Web层)

@Data
@ApiModel
public class InsertMeetingForm {@NotBlankprivate String title;@NotNull@Pattern(regexp = "^((((1[6-9]|[2-9]\\d)\\d{2})-(0?[13578]|1[02])-(0?[1-9]|[12]\\d|3[01]))|(((1[6-9]|[2-9]\\d)\\d{2})-(0?[13456789]|1[012])-(0?[1-9]|[12]\\d|30))|(((1[6-9]|[2-9]\\d)\\d{2})-0?2-(0?[1-9]|1\\d|2[0-8]))|(((1[6-9]|[2-9]\\d)(0[48]|[2468][048]|[13579][26])|((16|[2468][048]|[3579][26])00))-0?2-29-))$")private String date;private String place;@NotNull@Pattern(regexp = "^([01]?[0-9]|2[0-3]):[0-5][0-9]$")private String start;@NotNull@Pattern(regexp = "^([01]?[0-9]|2[0-3]):[0-5][0-9]$")private String end;@Range(min = 1,max = 2)private Byte type;@NotBlankprivate String members;@NotBlankprivate String desc;}
    @PostMapping("/insertMeeting")@ApiOperation("添加会议")@RequiresPermissions(value = {"ROOT", "MEETING:INSERT"},logical = Logical.OR)public R insertMeeting(@Valid @RequestBody InsertMeetingForm form, @RequestHeader("token") String token){if(form.getType()==2&&(form.getPlace()==null||form.getPlace().length()==0)){throw new EmosException("线下会议地点不能为空");}DateTime d1= DateUtil.parse(form.getDate()+" "+form.getStart()+":00");DateTime d2= DateUtil.parse(form.getDate()+" "+form.getEnd()+":00");if(d2.isBeforeOrEquals(d1)){throw new EmosException("结束时间必须大于开始时间");}if(!JSONUtil.isJsonArray(form.getMembers())){throw new EmosException("members不是JSON数组");}TbMeeting entity=new TbMeeting();entity.setUuid(UUID.randomUUID().toString(true));entity.setTitle(form.getTitle());entity.setCreatorId((long)jwtUtil.getUserId(token));entity.setDate(form.getDate());entity.setPlace(form.getPlace());entity.setStart(form.getStart() + ":00");entity.setEnd(form.getEnd() + ":00");entity.setType((short)form.getType());entity.setMembers(form.getMembers());entity.setDesc(form.getDesc());entity.setStatus((short)1);meetingService.insertMeeting(entity);return R.ok().put("result","success");}

保存会议记录(移动端)

JwtUtil int > entity long > dao int > 数据表 int

前端JSON.stringify > entity Object > dao Object > 数据表 json

加载现有会议详情

  <select id="searchMeetingById" parameterType="int" resultType="HashMap">SELECTm.uuid,m.creator_id AS creatorId,m.title,u.name,DATE_FORMAT( m.date, '%Y-%m-%d' ) AS date,m.place,DATE_FORMAT( m.START, '%H:%i' ) AS start,DATE_FORMAT( m.END, '%H:%i' ) AS end,m.type,m.status,m.desc,m.instance_id AS instanceIdFROM tb_meeting mJOIN tb_user u ON m.creator_id = u.idWHERE m.id =#{id} AND u.status = 1</select>
  <select id="searchMeetingMembers" parameterType="int" resultType="HashMap">SELECTu.id,u.name,u.photoFROM tb_meeting mJOIN tb_user u ON JSON_CONTAINS ( m.members, CAST( u.id AS CHAR ) )WHERE m.id=#{id} AND u.status = 1</select>

编辑会议重新发起工作流(持久层&业务层) 

    @Overridepublic void updateMeetingInfo(HashMap param) {int id = (int) param.get("id");String date = param.get("date").toString();String start = param.get("start").toString();String instanceId = param.get("instanceId").toString();HashMap oldMeeting = meetingDao.searchMeetingById(id);String uuid = oldMeeting.get("uuid").toString();Integer creatorId = Integer.parseInt(oldMeeting.get("creatorId").toString());int row = meetingDao.updateMeetingInfo(param);if (row != 1) {throw new EmosException("会议更新失败");}JSONObject json = new JSONObject();json.set("instanceId", instanceId);json.set("reason", "会议被修改");json.set("uuid", uuid);json.set("code", code);String url = workflow + "/workflow/deleteProcessById";HttpResponse resp = HttpRequest.post(url).header("content-type", "application/json").body(json.toString()).execute();if (resp.getStatus() != 200) {log.error("删除工作流失败");throw new EmosException("删除工作流失败");}startMeetingWorkflow(uuid, creatorId, date, start);}

编辑会议重新发起工作流(Web层&移动端)

        ……

删除会议和工作流(后端)

DateTime date = DateUtil.parse(meeting.get("date") + " " + meeting.get("start"));
DateTime now = DateUtil.date();
if (now.isAfterOrEquals(date.offset(DateField.MINUTE, -20))) {throw new EmosException("距离会议开始不足20分钟,不能删除会议");
}
int row = meetingDao.deleteMeetingById(id);
if (row != 1) {throw new EmosException("会议删除失败");
}

  UUID 在线会议房间号。

删除会议和工作流(移动端)

        ……

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/63609.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

会议中的Meeting App

接着我们上两篇博客文章&#xff0c;我们说了如何开发会议前和会议后的 meeting app&#xff0c;那如何开发一个会议中的 app 呢&#xff0c;实际上比较简单&#xff0c;我们只需要在 tab 的配置项中勾选下面这两个选项即可。 勾选后&#xff0c;我们安装app到我们的一个会议中…

个人微信的腾讯会议(相关会议)同步至企业微信

打开个人微信账号的腾讯会议 点击头像 - 点击同步日历 获得个人腾讯会议的CalDAV账号密码 打开企业微信 - 日程 - 添加日历 - 其他日历账号 将微信个人腾讯会议的账号信息添加企业微信中 随后企业微信自动识别CalDAV账号需要将信息补全后 *默认类型是Exchange&#xff1b;需要…

开会没带纸和笔?按下手机这个按钮,一键完成会议纪要

在工作中&#xff0c;我们每次开会都要手写会议记录。 事实上&#xff0c;苹果手机自带一个会议录音神器。 只需按下此按钮&#xff0c;即可一键录制会议内容。 方法一&#xff1a;输入法 如果按住麦克风按钮&#xff0c;还可以在不同的识别语言之间切换&#xff0c;包括普通…

Urban Outdoor风格入门穿搭单品推荐

1.渔夫帽 2.马甲&#xff08;搭配T恤、卫衣、衬衫&#xff09; 多口袋的钓鱼马甲很容易营造一种户外的感觉。 3.双肩包&#xff08;尽量选择有立体感的双肩包&#xff0c;而不是书包&#xff09; 4.挎包 5.裤子 没有约束 6.鞋子 没有约束 具体单品可以去看看《GO out》杂志…

几个超赞的颜色搭配网站,非常实用!强烈推荐!!

1.Color Hunt 这是几个配色网站中我用到最多的一个网站。下图是它的内容&#xff0c;鼠标放在相应的颜色上点击一下就可以复制颜色&#xff01; 2.FLAT UI COLORS 漂亮的扁平化配色&#xff0c;这个网站提供了多种主流 UI 配色方案&#xff0c;点击色块就可以直接复制颜色&am…

设计师的色彩搭配指南

色彩搭配在室内设计中有着重要影响&#xff0c;如果能合理创新地运用好无疑会为我们设计增添亮点。 一、色彩关键字 原色&#xff0c;这里指美术三原色&#xff0c;红、黄、蓝。 间色&#xff0c;将原色两两混合后得到的三个二级色&#xff0c;绿、橙、紫。 复色&#xff0c…

8个值得模仿的明星穿搭,各个时尚有型

对于对于时尚有要求的男生们&#xff0c;怎么穿才够有型和王者荣耀多少级是一样重要的事情。 工作日要上班通勤&#xff0c;晚上还有女票的约会&#xff0c;周末还时不时的碰上点休闲娱乐活动。如何在正确的时间和场合挑选正确的OUTFIT&#xff0c;变得尤为重要&#xff1b;男…

时尚界新宠,高级穿搭1+1

在这寒冷的冬天&#xff0c;11的高级穿搭法则深得时尚圈的宠爱&#xff0c;保暖的同时还可时髦&#xff0c;时髦的同时还可拥有层次感。 而且“11”两件一起穿法则令各大国际品牌的设计师着迷不已&#xff0c;它兼具了温度的同时&#xff0c;时髦感更是爆棚&#xff01; 为什么…

[fashion]女性的穿衣技巧

丫头语:下午带两个弟弟去买衣服~我想妈妈是带错地方&#xff0c;他们说西安的衣服很难看-_-!!    对于西安这个地方&#xff0c;我想小寨那边的衣服会更适合他们的品位&#xff0c;西安好看的衣服是有~ 不过却是从广州那边进来的&#xff0c;想想还真贵~就当出…

皮肤黄的人穿什么颜色的衣服好看显白

皮肤黄的人穿什么颜色好看 黑色 黑色是百搭的颜色&#xff0c;任何肤色的人穿上黑色都会显得比较白皙&#xff0c;尤其是皮肤暗黄的mm&#xff0c;可以选择一天精致、优雅的黑色外套&#xff0c;会看上去非常的有复古气质。当然。黑色也是曼哈顿职业女性的首选颜色&#xff0c…

好看的颜色搭配

Python画图时&#xff0c;好的颜色搭配让人赏心悦目&#xff0c;如下记录一些好看的颜色搭配。 (1) Assign colors for each airline and the names colors [‘#E69F00’, ‘#56B4E9’, ‘#F0E442’, ‘#009E73’, ‘#D55E00’] (2) 圆形图 描述RGB十六进制蓝框R:154 G:197 …

超实用的中国风配色 这些颜色你熟悉吗

我们常常能看到通过RGB表达出来的一些颜色&#xff0c;但是在国内&#xff0c;也有一些中国风配色会让人眼前一亮。比如2022冬奥会色彩系统上的霞光红和迎春黄等颜色&#xff0c;在色系的搭配上更加具有国风韵味。那么问题来了&#xff0c;中国风配色哪里找&#xff1f;国风配色…

测试适合什么颜色衣服的软件,超准的颜色测试!一语道破你最适合穿什么颜色的衣服!...

原标题&#xff1a;超准的颜色测试&#xff01;一语道破你最适合穿什么颜色的衣服&#xff01; 测试最适合穿什么 颜色的衣服~ 想知道自己更适合穿什么颜色吗 快来做个测试吧 所谓适合自己的颜色&#xff0c;是指根据每个人的肤色、头发的颜色、瞳孔的颜色等条件综合决定出&…

基于体型的服饰穿搭

参考&#xff1a; https://zhuanlan.zhihu.com/p/55210242 基于体型的服饰穿搭 关于体型的分类方法有很多种&#xff0c;比如有字母型、几何图形、人体测量医学等方法&#xff0c;这里选用比较直观的字母分类法&#xff0c;也就是将体型分为X、O、Y、A、H五类。 各体型的特点…

一款三搭_巴黎造型师的气质穿搭,大众色系也能穿出高级感,简单又实用_

在日常穿搭中&#xff0c;大众色系常常被采纳。在搭配大众色系的时候&#xff0c;款式的选择格外重要&#xff0c;个性时尚的系列会增添时尚的气质。但有一些女生偏爱传统的版型&#xff0c;在搭配这类服装的时候会容易出现沉闷乏味的感觉。那么我们可以学习这位巴黎造型师的春…

都市美女们的日常穿搭,女孩子春天这样穿才最时髦

春天美女海多呀&#xff0c;话不多说&#xff0c;上图。 春天穿黑衣的美女尤其多&#xff0c;美女一身黑的的装扮&#xff0c;在视觉上显瘦又显高。黑色外套搭配紧身衣和紧身裤&#xff0c;完美勾勒出美女的好身材&#xff0c;非常有女人味。脚踩黑色短靴&#xff0c;一身黑色装…

IEEE 论文排版之LaTeX模板

说明 主要介绍IEEE LaTeX论文模板的使用。 获取模板 IEEE的所有期刊、会议、杂志的模板都可以从 IEEE Template Selector 页面获得&#xff0c;以期刊 IEEE Transactions on Geoscience and Remote Sensing 为例&#xff0c;在 “Select Publication Type” 界面选择“Trans…

下载IEEE期刊Latex模板步骤

Google或百度检索想要下载什么期刊的Latex模板&#xff0c;或直接在IEEE官网IEEE Xplore搜索期刊名称&#xff0c;下面以TASE&#xff0c;IEEE Transactions on Automation Science and Engineering期刊为例。 1.进入TASE期刊的主页 &#xff0c;这里可以看到期刊的主编信息&a…

自用-华东师范大学硕士学位论文LATEX模板

文章目录 前言部分页面效果预览使用说明&#xff1a;毕业论文LaTeX模板1. 安装LaTeX发行版和TeX Studio&#xff1a;2. 下载毕业论文模板&#xff1a;3. 编辑论文内容&#xff1a;**标题和作者信息&#xff1a;****摘要和关键词&#xff1a;****章节内容&#xff1a;****图片插…

学姐写毕业论文,图表在PDF上,复制下来格式全乱,头疼了一晚,幸亏有我

Author&#xff1a;Runsen 最近认识了一位漂亮同级的学姐&#xff0c;当学姐确定研究生录取的那一刻&#xff0c;以为即将走上人生巅峰 结果毕业论文还没写&#xff0c;从此开启了写论文之路。 于是高高兴兴地去知网下载论文和图表&#xff0c;结果知网不友好&#xff0c;提供…