java定时任务 设置开始时间、结束时间;每周一、四、六执行;并且隔n周执行。最后计算所有执行时间
java定时任务 设置开始时间、结束时间;每周一、四、六执行;并且隔n周执行。最后计算所有执行时间)
- 定时任务需求
- 程序设计
- 依赖引入
- 程序
- 一、计算开始时间那周的周一时间
- 二、根据executeTime和weekList.get(n),计算每个cron表达式。
- 三、根据一和二得出的cron表达式和开始时间的那周的周一时间,计算每次定时任务执行的第一次时间。
- 四、计算所有执行时间
- 五、测试
- 六、测试结果
- 最终代码:
定时任务需求
在一个特殊的项目需求中,我们设计一个定时任务,并算出它所有的执行时间点。
1.有开始时间和结束时间。
2.每周一、四、六执行(动态参数) 执行的时和分HH:mm(动态参数)
3.隔n周执行(动态参数)
4.算每次执行时间。
程序设计
| 参数 | 类型 | 说明 |
|---|---|---|
| 定时任务开始时间 | startTime | yyyy-MM-dd |
| 定时任务结束时间 | endTime | yyyy-MM-dd |
| 执行时间 | executeTime | HH:mm |
| 周几执行列表 | weekList: [0,1,2,3,4,5,6] 代表:[周日,周一,周二,周三,周四,周五,周六] | cron中 [1,2,3,4,5,6,7] 代表:[周日,周一,周二,周三,周四,周五,周六] |
| 隔几周执行一次 | interval | 数字n |
依赖引入
<dependency><groupId>org.quartz-scheduler</groupId><artifactId>quartz</artifactId><version>2.3.2</version></dependency>
程序
一、计算开始时间那周的周一时间
考虑隔周执行,一定要以开始时间那个周的周一为起点,否则时间会算错。
/*** 开始时间点的周一时间* @param startDate* @return*/public static Date getMonday(Date startDate){/*** 计算给出时间的周一时间*/Calendar calendar = Calendar.getInstance();calendar.setTime(startDate);// 将小时、分钟、秒和毫秒字段设置为0calendar.set(Calendar.HOUR_OF_DAY, 0);calendar.set(Calendar.MINUTE, 0);calendar.set(Calendar.SECOND, 0);calendar.set(Calendar.MILLISECOND, 0);// 将日期设置为本周第一天(默认为周日)的前一天(即周一)calendar.add(Calendar.DAY_OF_WEEK, Calendar.MONDAY - calendar.get(Calendar.DAY_OF_WEEK));// 输出周一0点的时间return calendar.getTime();}
二、根据executeTime和weekList.get(n),计算每个cron表达式。
/***计算cron表达式*@param executeTime 执行时间 HH:mm* @param week 周几* @return cron表达式* @throws ParseException*/public static String createCronStr(String executeTime, Integer week) {String weekStr = String.valueOf(week + 1);// 设置cron表达式,周三,下午3点30分执行String cronExpression = "0 %1$s %2$s ? * %3$s";String[] times = executeTime.split(":");String hour = times[0];String minute = times[1];return String.format(cronExpression, minute, hour, weekStr);}
三、根据一和二得出的cron表达式和开始时间的那周的周一时间,计算每次定时任务执行的第一次时间。
/*** 计算下次执行时间* @param cronExpression cron* @param startTime2 开始时间(开始时间的周一时间)* @return* @throws ParseException*/public static Date getNextExecutionTime(String cronExpression, Date startTime2) throws ParseException {CronExpression cron = new CronExpression(cronExpression);Date nextExecutionTime = cron.getNextValidTimeAfter(startTime2);System.out.println("下次执行时间: " + nextExecutionTime);return nextExecutionTime;}
四、计算所有执行时间
/**** @param startTime 定时任务开始时间 yyyy-MM-dd* @param endTime 定时任务结束时间 yyyy-MM-dd* @param executeTime 执行时间 HH:mm* @param weekList 周几执行列表 [0,1,2,3,4,5,6] 代表:[周日,周一,周二,周三,周四,周五,周六]* @param interval 隔几周执行一次* @return*/public static List<String> getExecuteTimeList(String startTime, String endTime, String executeTime, List<Integer> weekList, int interval) {List<String> list = new ArrayList<>();try {String startStr = startTime + executeTime;String endStr = endTime + executeTime;SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-ddHH:mm");Date endDate = dateFormat.parse(endStr);Date startDate = dateFormat.parse(startStr);Date now = new Date();//设置日期过期,返回空if (now.getTime() > endDate.getTime()) {return new ArrayList<>();}interval++;for (Integer week : weekList) {String cronExpression = createCronStr(executeTime, week);if (StringUtils.isBlank(cronExpression)) {continue;}Date startTime2 = getMonday(startDate);Date nextExecutionTime = getNextExecutionTime(cronExpression,startTime2);int add = 0;Date nownext = nextExecutionTime;while (nownext.getTime() <= endDate.getTime()) {nownext = new Date(nextExecutionTime.getTime() + add * interval * 7 * 24 * 60 * 60 * 1000L);SimpleDateFormat dateFormat2 = new SimpleDateFormat("yyyy-MM-dd HH:mm");String str = dateFormat2.format(nownext);if (nownext.getTime() <= endDate.getTime() && nownext.getTime()>=startDate.getTime()) {list.add(str);}add++;}}Collections.sort(list);} catch (ParseException e) {System.out.println("解析异常: " + e.getMessage());e.printStackTrace();}return list;}
五、测试
计算2024-06-15到2026-12-31,每周一、四、六的20:40,并隔一周执行一次的所有执行时间
public static void main(String[] args) {List<Integer> week = new ArrayList<>();week.add(1);week.add(4);week.add(6);long start = System.currentTimeMillis();List<String> list = getExecuteTimeList("2024-06-15", "2026-12-31", "20:40", week, 1);long end = System.currentTimeMillis();System.out.println(end - start + " ms");for(String element : list) {System.out.println(element);}}
六、测试结果
下次执行时间: Mon Jun 10 20:40:00 CST 2024
下次执行时间: Thu Jun 13 20:40:00 CST 2024
下次执行时间: Sat Jun 15 20:40:00 CST 2024
74 ms
2024-06-15 20:40
2024-06-24 20:40
2024-06-27 20:40
2024-06-29 20:40
2024-07-08 20:40
2024-07-11 20:40
2024-07-13 20:40
2024-07-22 20:40
2024-07-25 20:40
2024-07-27 20:40
2024-08-05 20:40
2024-08-08 20:40
2024-08-10 20:40
2024-08-19 20:40
2024-08-22 20:40
2024-08-24 20:40
2024-09-02 20:40
2024-09-05 20:40
2024-09-07 20:40
2024-09-16 20:40
2024-09-19 20:40
2024-09-21 20:40
2024-09-30 20:40
2024-10-03 20:40
2024-10-05 20:40
2024-10-14 20:40
2024-10-17 20:40
2024-10-19 20:40
2024-10-28 20:40
2024-10-31 20:40
2024-11-02 20:40
2024-11-11 20:40
2024-11-14 20:40
2024-11-16 20:40
2024-11-25 20:40
2024-11-28 20:40
2024-11-30 20:40
2024-12-09 20:40
2024-12-12 20:40
2024-12-14 20:40
2024-12-23 20:40
2024-12-26 20:40
2024-12-28 20:40
2025-01-06 20:40
2025-01-09 20:40
2025-01-11 20:40
2025-01-20 20:40
2025-01-23 20:40
2025-01-25 20:40
2025-02-03 20:40
2025-02-06 20:40
2025-02-08 20:40
2025-02-17 20:40
2025-02-20 20:40
2025-02-22 20:40
2025-03-03 20:40
2025-03-06 20:40
2025-03-08 20:40
2025-03-17 20:40
2025-03-20 20:40
2025-03-22 20:40
2025-03-31 20:40
2025-04-03 20:40
2025-04-05 20:40
2025-04-14 20:40
2025-04-17 20:40
2025-04-19 20:40
2025-04-28 20:40
2025-05-01 20:40
2025-05-03 20:40
2025-05-12 20:40
2025-05-15 20:40
2025-05-17 20:40
2025-05-26 20:40
2025-05-29 20:40
2025-05-31 20:40
2025-06-09 20:40
2025-06-12 20:40
2025-06-14 20:40
2025-06-23 20:40
2025-06-26 20:40
2025-06-28 20:40
2025-07-07 20:40
2025-07-10 20:40
2025-07-12 20:40
2025-07-21 20:40
2025-07-24 20:40
2025-07-26 20:40
2025-08-04 20:40
2025-08-07 20:40
2025-08-09 20:40
2025-08-18 20:40
2025-08-21 20:40
2025-08-23 20:40
2025-09-01 20:40
2025-09-04 20:40
2025-09-06 20:40
2025-09-15 20:40
2025-09-18 20:40
2025-09-20 20:40
2025-09-29 20:40
2025-10-02 20:40
2025-10-04 20:40
2025-10-13 20:40
2025-10-16 20:40
2025-10-18 20:40
2025-10-27 20:40
2025-10-30 20:40
2025-11-01 20:40
2025-11-10 20:40
2025-11-13 20:40
2025-11-15 20:40
2025-11-24 20:40
2025-11-27 20:40
2025-11-29 20:40
2025-12-08 20:40
2025-12-11 20:40
2025-12-13 20:40
2025-12-22 20:40
2025-12-25 20:40
2025-12-27 20:40
2026-01-05 20:40
2026-01-08 20:40
2026-01-10 20:40
2026-01-19 20:40
2026-01-22 20:40
2026-01-24 20:40
2026-02-02 20:40
2026-02-05 20:40
2026-02-07 20:40
2026-02-16 20:40
2026-02-19 20:40
2026-02-21 20:40
2026-03-02 20:40
2026-03-05 20:40
2026-03-07 20:40
2026-03-16 20:40
2026-03-19 20:40
2026-03-21 20:40
2026-03-30 20:40
2026-04-02 20:40
2026-04-04 20:40
2026-04-13 20:40
2026-04-16 20:40
2026-04-18 20:40
2026-04-27 20:40
2026-04-30 20:40
2026-05-02 20:40
2026-05-11 20:40
2026-05-14 20:40
2026-05-16 20:40
2026-05-25 20:40
2026-05-28 20:40
2026-05-30 20:40
2026-06-08 20:40
2026-06-11 20:40
2026-06-13 20:40
2026-06-22 20:40
2026-06-25 20:40
2026-06-27 20:40
2026-07-06 20:40
2026-07-09 20:40
2026-07-11 20:40
2026-07-20 20:40
2026-07-23 20:40
2026-07-25 20:40
2026-08-03 20:40
2026-08-06 20:40
2026-08-08 20:40
2026-08-17 20:40
2026-08-20 20:40
2026-08-22 20:40
2026-08-31 20:40
2026-09-03 20:40
2026-09-05 20:40
2026-09-14 20:40
2026-09-17 20:40
2026-09-19 20:40
2026-09-28 20:40
2026-10-01 20:40
2026-10-03 20:40
2026-10-12 20:40
2026-10-15 20:40
2026-10-17 20:40
2026-10-26 20:40
2026-10-29 20:40
2026-10-31 20:40
2026-11-09 20:40
2026-11-12 20:40
2026-11-14 20:40
2026-11-23 20:40
2026-11-26 20:40
2026-11-28 20:40
2026-12-07 20:40
2026-12-10 20:40
2026-12-12 20:40
2026-12-21 20:40
2026-12-24 20:40
2026-12-26 20:40Process finished with exit code 0
最终代码:
import org.apache.commons.lang.StringUtils;
import org.quartz.CronExpression;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;/*** @author dume* @ClassName CronUtils* @description: TODO* @date 2024年06月06日* @version: 1.0*/
public class CronUtils {/**** @param startTime 定时任务开始时间 yyyy-MM-dd* @param endTime 定时任务结束时间 yyyy-MM-dd* @param executeTime 执行时间 HH:mm* @param weekList 周几执行列表 [0,1,2,3,4,5,6] 代表:[周日,周一,周二,周三,周四,周五,周六]* @param interval 隔几周执行一次* @return*/public static List<String> getExecuteTimeList(String startTime, String endTime, String executeTime, List<Integer> weekList, int interval) {List<String> list = new ArrayList<>();try {String startStr = startTime + executeTime;String endStr = endTime + executeTime;SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-ddHH:mm");Date endDate = dateFormat.parse(endStr);Date startDate = dateFormat.parse(startStr);Date now = new Date();//设置日期过期,返回空if (now.getTime() > endDate.getTime()) {return new ArrayList<>();}interval++;for (Integer week : weekList) {String cronExpression = createCronStr(executeTime, week);if (StringUtils.isBlank(cronExpression)) {continue;}Date startTime2 = getMonday(startDate);Date nextExecutionTime = getNextExecutionTime(cronExpression,startTime2);int add = 0;Date nownext = nextExecutionTime;while (nownext.getTime() <= endDate.getTime()) {nownext = new Date(nextExecutionTime.getTime() + add * interval * 7 * 24 * 60 * 60 * 1000L);SimpleDateFormat dateFormat2 = new SimpleDateFormat("yyyy-MM-dd HH:mm");String str = dateFormat2.format(nownext);if (nownext.getTime() <= endDate.getTime() && nownext.getTime()>=startDate.getTime()) {list.add(str);}add++;}}Collections.sort(list);} catch (ParseException e) {System.out.println("解析异常: " + e.getMessage());e.printStackTrace();}return list;}/***计算cron表达式*@param executeTime 执行时间 HH:mm* @param week 周几* @return cron表达式* @throws ParseException*/public static String createCronStr(String executeTime, Integer week) {String weekStr = String.valueOf(week + 1);// 设置cron表达式,周三,下午3点30分执行String cronExpression = "0 %1$s %2$s ? * %3$s";String[] times = executeTime.split(":");String hour = times[0];String minute = times[1];return String.format(cronExpression, minute, hour, weekStr);}/*** 计算下次执行时间* @param cronExpression cron* @param startTime2 开始时间(开始时间的周一时间)* @return* @throws ParseException*/public static Date getNextExecutionTime(String cronExpression, Date startTime2) throws ParseException {CronExpression cron = new CronExpression(cronExpression);Date nextExecutionTime = cron.getNextValidTimeAfter(startTime2);System.out.println("下次执行时间: " + nextExecutionTime);return nextExecutionTime;}/*** 开始时间点的周一时间* @param startDate* @return*/public static Date getMonday(Date startDate){/*** 计算给出时间的周一时间*/Calendar calendar = Calendar.getInstance();calendar.setTime(startDate);// 将小时、分钟、秒和毫秒字段设置为0calendar.set(Calendar.HOUR_OF_DAY, 0);calendar.set(Calendar.MINUTE, 0);calendar.set(Calendar.SECOND, 0);calendar.set(Calendar.MILLISECOND, 0);// 将日期设置为本周第一天(默认为周日)的前一天(即周一)calendar.add(Calendar.DAY_OF_WEEK, Calendar.MONDAY - calendar.get(Calendar.DAY_OF_WEEK));// 输出周一0点的时间return calendar.getTime();}public static void main(String[] args) {List<Integer> week = new ArrayList<>();week.add(1);week.add(4);week.add(6);long start = System.currentTimeMillis();List<String> list = getExecuteTimeList("2024-06-15", "2026-12-31", "20:40", week, 1);long end = System.currentTimeMillis();System.out.println(end - start + " ms");for(String element : list) {System.out.println(element);}}}相关文章:
java定时任务 设置开始时间、结束时间;每周一、四、六执行;并且隔n周执行。最后计算所有执行时间
java定时任务 设置开始时间、结束时间;每周一、四、六执行;并且隔n周执行。最后计算所有执行时间) 定时任务需求程序设计依赖引入程序一、计算开始时间那周的周一时间二、根据executeTime和weekList.get(n),计算每个cron表达式。三、根据一和…...
linux的持续性学习
安装php 第一步:配置yum源 第二步:下载php。 yum install php php-gd php-fpm php-mysql -y 第三步:启动php。 systemctl start php-fpm 第四步:检查php是否启动 lsof -i :9000 计划任务 作用&am…...
MyBatis:概念简章
1. hello world 配置文件:mybatis-config.xml(核心配置文件,用于配置连接的数据库信息)(一般一个)XxxMapper.xml 该文件用于操作表(执行sql语句)(一张表一个)…...
有什么接码平台比较好用的
接码平台,也被称作短信接收平台或虚拟号码服务,主要是提供可以接收短信验证码的虚拟手机号码服务。这种服务通常被用于需要在网络平台上注册大量账号的情况,如营销推广、应用测试或是海淘购物时所需的手机号验证。下面将推荐几个较为好用的接…...
微服务之负载均衡器
1、负载均衡介绍 负载均衡就是将负载(工作任务,访问请求)进行分摊到多个操作单元(服务器,组件)上 进行执行。 根据负载均衡发生位置的不同, 一般分为服务端负载均衡和客户端负载均衡。 服务端负载均衡指的是发生在服务提供者一方ÿ…...
《时间管理九段》前四阶段学习笔记
文章目录 0.何谓时间管理九段0.1 第一段--把一件事做好0.2 第二段--把一天过好0.3 第三段--掌控两周内的固定日程0.4 第四段--掌控两周内的弹性时间0.5 第五段--科学管理3个月的项目事件0.6 第六段--实现一年的梦想0.7 第七段--明确一生的愿景0.8 第八段--正确补充和释放自身能…...
LLVM Cpu0 新后端5 静态重定位 动态重定位
想好好熟悉一下llvm开发一个新后端都要干什么,于是参考了老师的系列文章: LLVM 后端实践笔记 代码在这里(还没来得及准备,先用网盘暂存一下): 链接: https://pan.baidu.com/s/1yLAtXs9XwtyEzYSlDCSlqw?…...
旅游卡是项目还是骗局?还是实实在在的旅游项目?
旅游卡是一个实实在在的旅游项目,而非骗局。以下是我对旅游卡项目的几点分析: 项目实质: 旅游卡项目是由国内外多条旅游线路整合而成的卡片,为旅游者提供方便、实惠的旅游方式。持有旅游卡,可以完全抵销跟团游线路中的…...
大模型+RAG,全面介绍!
1 、介绍 大型语言模型(LLMs)在处理特定领域或高度专业化的查询时存在局限性,如生成不正确信息或“幻觉”。缓解这些限制的一种有前途的方法是检索增强生成(RAG),RAG就像是一个外挂,将外部数据…...
智能合约中存储和计算效率漏洞
存储和计算效率 不当的存储结构或计算密集型操作可能导致高Gas费用和性能瓶颈。示例场景:频繁读取和写入大数组 假设你正在构建一个投票系统,其中每个提案都有一个独立的计票器。为了实现这一点,你可能最初会考虑使用一个映射(m…...
软件测试基础知识总结
🍅 视频学习:文末有免费的配套视频可观看 🍅 点击文末小卡片,免费获取软件测试全套资料,资料在手,涨薪更快 一、软件测试概述 1、什么是软件 定义:计算机系统中与硬件相互依存的一部分&#x…...
C语言 | Leetcode C语言题解之第143题重排链表
题目: 题解: struct ListNode* middleNode(struct ListNode* head) {struct ListNode* slow head;struct ListNode* fast head;while (fast->next ! NULL && fast->next->next ! NULL) {slow slow->next;fast fast->next-&g…...
探寻性能优化:如何衡量?如何决策?
目录 一、衡量指标说明 (一)响应时间(Response Time) 平均响应时间(Average Response Time) 百分位数响应时间(Percentile Response Time) (二)吞吐量&a…...
Python Django 5 Web应用开发实战
Django 是一个高级 Python Web 框架,它鼓励快速开发和简洁、务实的设计。下面是一个关于如何使用 Django 开发一个包含五个基本页面的 Web 应用的实战指南。请注意,这里仅提供一个概述,实际开发中会有更多细节和步骤。 1. 安装 Django 首先,你需要安装 Django。你可以使用…...
H.264官方文档下载
H.264是ITU(International Telecommunication Union,国际通信联盟)和MPEG(Motion Picture Experts Group,运动图像专家组)联合制定的视频编码标准。其官方文档可以在ITU官网上下载:https://www.…...
minio多节点部署
MinIO 是一个高性能的分布式对象存储服务,它可以配置为多节点(或多服务器)模式以提供高可用性和数据冗余。以下是一个基本的多节点MinIO部署示例: 确保你有多个服务器或虚拟机。在每个节点上安装MinIO。使用minio server命令启动多…...
2024年工业设计与制造工程国际会议(ICIDME 2024)
2024年工业设计与制造工程国际会议 2024 International Conference on Industrial Design and Manufacturing Engineering 会议简介 2024年工业设计与制造工程国际会议是一个集结全球工业设计与制造工程领域精英的盛会。本次会议旨在为业界专家、学者、工程技术人员提供一个分享…...
一次曝 9 个大模型,「字节 AI」这一年都在做什么?
字节跳动的大模型家族,会长出下一个抖音吗? 整个 2023 年,字节并没有对外官宣其内部自研的大模型。外界一度认为,大模型这一技术变革,字节入场晚了。梁汝波在去年底的年会上也提到了这一点,他表示「字节对…...
PR基本概念数学知识
1、2基本概念 监督学习与非监督学习期望风险与经验风险结构风险最小化(SRM)与经验风险最小化(ERM)期望风险的上界过拟合数据预处理模型评价方法分类与聚类 数学知识 矩阵求逆、矩阵乘法协方差矩阵的计算特征值、特征向量的计算…...
信驰达蓝牙数字钥匙方案持续创新,助推智慧汽车生态发展
随着汽车智能化的加速发展,数字钥匙正成为全球化的新趋势,它通过数字化的手段连接人、车以及更广泛的生态,引领着出行方式的革命和用户体验的转变。数字钥匙不仅仅是一个简单的访问工具,它重新定义了人与车的互动方式,…...
调用支付宝接口响应40004 SYSTEM_ERROR问题排查
在对接支付宝API的时候,遇到了一些问题,记录一下排查过程。 Body:{"datadigital_fincloud_generalsaas_face_certify_initialize_response":{"msg":"Business Failed","code":"40004","sub_msg…...
k8s从入门到放弃之Ingress七层负载
k8s从入门到放弃之Ingress七层负载 在Kubernetes(简称K8s)中,Ingress是一个API对象,它允许你定义如何从集群外部访问集群内部的服务。Ingress可以提供负载均衡、SSL终结和基于名称的虚拟主机等功能。通过Ingress,你可…...
聊聊 Pulsar:Producer 源码解析
一、前言 Apache Pulsar 是一个企业级的开源分布式消息传递平台,以其高性能、可扩展性和存储计算分离架构在消息队列和流处理领域独树一帜。在 Pulsar 的核心架构中,Producer(生产者) 是连接客户端应用与消息队列的第一步。生产者…...
2.Vue编写一个app
1.src中重要的组成 1.1main.ts // 引入createApp用于创建应用 import { createApp } from "vue"; // 引用App根组件 import App from ./App.vue;createApp(App).mount(#app)1.2 App.vue 其中要写三种标签 <template> <!--html--> </template>…...
macOS多出来了:Google云端硬盘、YouTube、表格、幻灯片、Gmail、Google文档等应用
文章目录 问题现象问题原因解决办法 问题现象 macOS启动台(Launchpad)多出来了:Google云端硬盘、YouTube、表格、幻灯片、Gmail、Google文档等应用。 问题原因 很明显,都是Google家的办公全家桶。这些应用并不是通过独立安装的…...
第25节 Node.js 断言测试
Node.js的assert模块主要用于编写程序的单元测试时使用,通过断言可以提早发现和排查出错误。 稳定性: 5 - 锁定 这个模块可用于应用的单元测试,通过 require(assert) 可以使用这个模块。 assert.fail(actual, expected, message, operator) 使用参数…...
【Go】3、Go语言进阶与依赖管理
前言 本系列文章参考自稀土掘金上的 【字节内部课】公开课,做自我学习总结整理。 Go语言并发编程 Go语言原生支持并发编程,它的核心机制是 Goroutine 协程、Channel 通道,并基于CSP(Communicating Sequential Processes࿰…...
三体问题详解
从物理学角度,三体问题之所以不稳定,是因为三个天体在万有引力作用下相互作用,形成一个非线性耦合系统。我们可以从牛顿经典力学出发,列出具体的运动方程,并说明为何这个系统本质上是混沌的,无法得到一般解…...
MySQL中【正则表达式】用法
MySQL 中正则表达式通过 REGEXP 或 RLIKE 操作符实现(两者等价),用于在 WHERE 子句中进行复杂的字符串模式匹配。以下是核心用法和示例: 一、基础语法 SELECT column_name FROM table_name WHERE column_name REGEXP pattern; …...
图表类系列各种样式PPT模版分享
图标图表系列PPT模版,柱状图PPT模版,线状图PPT模版,折线图PPT模版,饼状图PPT模版,雷达图PPT模版,树状图PPT模版 图表类系列各种样式PPT模版分享:图表系列PPT模板https://pan.quark.cn/s/20d40aa…...
