记录一次使用thinkphp使用PhpSpreadsheet扩展导出数据,解决身份证号码等信息科学计数法问题处理
PhpSpreadsheet官网
PhpSpreadsheet安装
composer require phpoffice/phpspreadsheet
使用composer安装时一定要下载php对应的版本,下载之前使用php -v检查当前php版本
简单使用
<?php
require 'vendor/autoload.php';use PhpOffice\PhpSpreadsheet\Spreadsheet;
use PhpOffice\PhpSpreadsheet\Writer\Xlsx;
use PhpOffice\PhpSpreadsheet\Style\NumberFormat;// 创建Spreadsheet对象
$spreadsheet = new Spreadsheet();
$sheet = $spreadsheet->getActiveSheet();// 动态表头
$headers = ['ID', '姓名', '性别', '职业', '新增字段', '新增字段2', '新增字段3', '新增字段4', '新增字段5', '新增字段6', '新增字段7', '新增字段8', '新增字段9', '新增字段10', '新增字段11', '新增字段12', '新增字段13', '新增字段14', '新增字段15', '新增字段16', '新增字段17', '新增字段18', '新增字段19', '新增字段20', '新增字段21', '新增字段22', '新增字段23', '新增字段24', '新增字段25', '新增字段26', '新增字段27', '新增字段28', '新增字段29', '新增字段30'];// 动态数据
$data = [[1, '李云龙', '男', '军人', '1427141544485854854485', '字段1', '字段2', '字段3', '字段4', '字段5', '字段6', '字段7', '字段8', '字段9', '字段10', '字段11', '字段12', '字段13', '字段14', '字段15', '字段16', '字段17', '字段18', '字段19', '字段20', '字段21', '字段22', '字段23', '字段24', '字段25', '字段26', '字段27', '字段28', '字段29', '字段30'],[2, '苏乞儿', '男', '乞丐', '值2', '字段1', '字段2', '字段3', '字段4', '字段5', '字段6', '字段7', '字段8', '字段9', '字段10', '字段11', '字段12', '字段13', '字段14', '字段15', '字段16', '字段17', '字段18', '字段19', '字段20', '字段21', '字段22', '字段23', '字段24', '字段25', '字段26', '字段27', '字段28', '字段29', '字段30'],[3, '周星驰', '男', '导演', '值3', '字段1', '字段2', '字段3', '字段4', '字段5', '字段6', '字段7', '字段8', '字段9', '字段10', '字段11', '字段12', '字段13', '字段14', '字段15', '字段16', '字段17', '字段18', '字段19', '字段20', '字段21', '字段22', '字段23', '字段24', '字段25', '字段26', '字段27', '字段28', '字段29', '字段30'],[4, '林允儿', '女', '演员', '值4', '字段1', '字段2', '字段3', '字段4', '字段5', '字段6', '字段7', '字段8', '字段9', '字段10', '字段11', '字段12', '字段13', '字段14', '字段15', '字段16', '字段17', '字段18', '字段19', '字段20', '字段21', '字段22', '字段23', '字段24', '字段25', '字段26', '字段27', '字段28', '字段29', '字段30'],
];// 设置表头和数据
$allData = array_merge([$headers], $data);
$sheet->fromArray($allData, null, 'A1');// 设置表头样式
$styleArray = ['alignment' => ['horizontal' => 'center','vertical' => 'center',],'font' => ['name' => '宋体',// 'bold' => true,// 'size' => 22]
];$headerRange = 'A1:' . chr(ord('A') + count($headers) - 1) . '1';
$sheet->getStyle($headerRange)->getNumberFormat() // 先获取NumberFormat对象->setFormatCode(NumberFormat::FORMAT_TEXT)->applyFromArray($styleArray);// 保存文件
$writer = new Xlsx($spreadsheet);
$writer->save('dynamic_example.xlsx');?>
在thinkphp项目中使用
// 如果将该扩展直接安装到thinkphp6项目中提示找不到Class 'PhpOffice\\PhpSpreadsheet\\Spreadsheet' not found,将该扩展放置项目根目录的extend文件夹中(参考下图),随后打开下行代码
// require_once app()->getRootPath() . 'extend/PhpSpreadsheet/autoload.php';
use PhpOffice\PhpSpreadsheet\Spreadsheet;
use PhpOffice\PhpSpreadsheet\Writer\Xlsx;
use PhpOffice\PhpSpreadsheet\Style\NumberFormat;
use PhpOffice\PhpSpreadsheet\IOFactory;
use PhpOffice\PhpSpreadsheet\Cell\Coordinate;
use PhpOffice\PhpSpreadsheet\Cell\DataType;public function export_data($data){// 获取所有要查询的字段和名称$header_arr = [];$fields_arr = [];foreach($data['export_data'] as $key=>$val){array_push($header_arr, $val['label']);array_push($fields_arr, $val['field']);} // 文件存储目录$public = app()->getRootPath().'public/';$path = 'uploads/export_data/';if(!file_exists($path)){mkdir($path, 0777);}// 文件名$res_file = $file_name . '_all.xlsx';$finalFile = $public . $path . $res_file;$currentRow = 1; // 当前写入行$spreadsheet = new Spreadsheet();$sheet = $spreadsheet->getActiveSheet();// 3. 计算列范围 - 安全方法$lastColumn = Coordinate::stringFromColumnIndex(count($header_arr));$headerRange = 'A:' . $lastColumn;// $sheet->setTitle('Sheet1');// 如果是第一次运行,创建新文件并写入头部if (!file_exists($finalFile)) {$spreadsheet = new Spreadsheet();$sheet = $spreadsheet->getActiveSheet();$sheet->getStyle($headerRange)->getNumberFormat()->setFormatCode(NumberFormat::FORMAT_TEXT);// 写入头部$sheet->fromArray([$header_arr], null, 'A1');$currentRow = 2;// 设置表头样式$styleArray = ['alignment' => ['horizontal' => 'center','vertical' => 'center',],// 'font' => [// 'name' => '宋体',// 'bold' => true,// 'size' => 22// ]];// $headerRange = 'A1:' . chr(ord('A') + count($header_arr) - 1) . '1';$sheet->getStyle($headerRange)->applyFromArray($styleArray);// 保存文件$writer = new Xlsx($spreadsheet);$writer->save($finalFile);// echo "创建新文件并写入头部\n";}// 分批导出并追加数据$totalBatches = 3; // 假设总共3批for ($batch = 1; $batch <= $totalBatches; $batch++) {// 加载现有文件$reader = IOFactory::createReader('Xlsx');$spreadsheet = $reader->load($finalFile);$sheet = $spreadsheet->getActiveSheet();// 获取当前最后一行$currentRow = $sheet->getHighestRow() + 1;// 生成测试数据 - 实际应用中从数据库获取$data = [];$perBatch = 10000;$start = ($batch - 1) * $perBatch + 1;$end = $batch * $perBatch;for ($i = $start; $i <= $end; $i++) {$data[] = [$i,"姓名{$i}",($i % 2) ? '男' : '女',"职业{$i}"];}// 追加数据$stringContent = array_map(function($row) use ($sheet, $currentRow) {return array_map(function($cell) {return (string)$cell; // 只返回值,不返回类型}, $row);}, $data);// 先设置数据$sheet->fromArray($stringContent, null, "A{$currentRow}");// 部分列强制文本格式$forceTextColumns = ['CI', 'AQ', 'AH']; // 需要强制文本的列for ($row = $currentRow; $row <= $highestRow; $row++) {foreach ($forceTextColumns as $col) {$cell = $sheet->getCell($col.$row);$cell->setValueExplicit($cell->getValue(),DataType::TYPE_STRING);$sheet->getStyle($col.$row)->getNumberFormat()->setFormatCode('@');}}// 保存文件$writer = new Xlsx($spreadsheet);$writer->save($finalFile);echo "批次 {$batch} 数据已追加到 {$finalFile} (行 {$currentRow}-" . ($currentRow + count($data) - 1) . ")\n";}echo "所有数据已导出到 {$finalFile}\n";
}
相关文章:
记录一次使用thinkphp使用PhpSpreadsheet扩展导出数据,解决身份证号码等信息科学计数法问题处理
PhpSpreadsheet官网 PhpSpreadsheet安装 composer require phpoffice/phpspreadsheet使用composer安装时一定要下载php对应的版本,下载之前使用php -v检查当前php版本 简单使用 <?php require vendor/autoload.php;use PhpOffice\PhpSpreadsheet\Spreadshee…...
为什么业务总是被攻击?使用游戏盾解决方案
业务频繁遭受攻击的核心原因在于攻防资源不对等,攻击者利用技术漏洞、利益驱动及企业防护短板发起攻击,而游戏盾通过针对性架构设计实现高效防御。以下是具体分析与解决方案: 一、业务被攻击的根源 利益驱动攻击 勒索与数…...
4.1【LLaMA-Factory 实战】医疗领域大模型:从数据到部署的全流程实践
【LLaMA-Factory实战】医疗领域大模型:从数据到部署的全流程实践 一、引言 在医疗AI领域,构建专业的疾病诊断助手需要解决数据稀缺、知识专业性强、安全合规等多重挑战。本文基于LLaMA-Factory框架,详细介绍如何从0到1打造一个垂直领域的医…...
二维旋转矩阵:让图形动起来的数学魔法 ✨
大家好!今天我们要聊一个超酷的数学工具——旋转矩阵。它就像数学中的"旋转魔法",能让图形在平面上优雅地转圈圈。别被"矩阵"这个词吓到,其实它就是一个数字表格,但功能超级强大! 一、什么是旋转…...
go语言封装、继承与多态:
1.封装: 封装是通过将数据和操作数据的方法绑定在一起来实现的。在Go语言中,封装通过结构体(struct)和方法(method)来实现。结构体的字段可以通过大小写来控制访问权限。 package stutype Person struct …...
golang -- 如何获取变量类型
目录 前言获取变量类型一、fmt.Printf二、类型断言三、类型选择四、反射 reflect.TypeOf五、reflect.Value的Type()方法 前言 在学习反射的时候,对reflect包中获取变量类型的函数很迷惑 比如下面这个 用Type获取变量类型的方法(在下面提到) …...
Missashe考研日记-day36(改版说明)
Missashe考研日记-day36 改版说明 经过一天的思考、纠结和尝试,博主决定对更新内容进行改版,如下:1.不再每天都发一篇日记,改为一周发一篇包含一周七天学习进度的周记,但为了标题和以前相同(强迫症&#…...
opencv中的图像特征提取
图像的特征,一般是指图像所表达出的该图像的特有属性,其实就是事物的图像特征,由于图像获得的多样性(拍摄器材、角度等),事物的图像特征有时并不特别突出或与无关物体混杂在一起,因此图像的特征…...
一文了解氨基酸的分类、代谢和应用
氨基酸(Amino acids)是在分子中含有氨基和羧基的一类化合物。氨基酸是生命的基石,人类所有的疾病与健康状况都与氨基酸有直接或间接的关系。氨基酸失衡可引起肝硬化、神经系统感染性疾病、糖尿病、免疫性疾病、心血管疾病、肾病、肿瘤等各类疾…...
Linux 系统安装Minio详细教程
一、🔍 MinIO 简介 MinIO 是一个高性能的对象存储服务,兼容 Amazon S3 接口,适用于大数据、AI、云原生等场景,支持分布式部署和高可用性,可作为轻量级的私有云对象存储解决方案。 二、📦 安装准备 ✅ 系…...
排序算法-归并排序
归并排序是一种分治算法(Divide and Conquer)。对于给定的一组数据,利用递归与分治技术将数据序列划分成为越来越小的半子表,在对半子表排序后,再用递归方法将排好序的半子表合并成为越来越大的有序序列。 核心思想 分…...
js 两个数组中的指定参数(id)相同,为某个对象设置disabled属性
在JavaScript中,如果想要比较两个数组并根据它们的id属性来设置某个对象的disabled属性为true,你可以使用几种不同的方法。这里我将介绍几种常用的方法: 方法1:使用循环和条件判断 const array1 [{ id: 1, name: Item 1 },{ id…...
【Java基础】——集合篇
目标: 1.每个集合用的场景 2.每个集合的底层 一.概述 二. 三.Collection 1.通用方法 其中,contains方法,它的底层一定调用了equals方法进行比对,而且一定重写了equals方法,如果不重写equals方法,就是调用…...
小红书视频无水印下载方法
下载小红书(RED/Xiaohongshu)视频并去除水印可以通过以下几种方法实现,但请注意尊重原创作者版权,下载内容仅限个人使用,避免侵权行为。 方法一:使用在线解析工具(推荐) 复制视频链…...
代发考试战报:思科华为HCIP HCSE CCNP 考试通过
CCNP 300-410考试通过战报,HCIP云计算通过,HCIP数通 H12-821考试通过,H12-831考试通过,HCSP金融 H19-611考试通过,HCSE金融 H21-293 考试通过 报名考试一定要找正规报名,避免后续考试成绩被取消࿰…...
辉芒微离线烧录器“文件格式错误”问题解决
最近在使用辉芒微离线烧录器烧录程序时,提示“文件格式错误”,记录一下解决方法。 一、问题现象 经过多次尝试和排查,发现以下几种情况: 情况一:使用离线烧录器导入固件1(boot程序),…...
系统的从零开始学习电子的相关知识,该如何规划?
一、基础理论奠基(6-12个月) 1.1 数学与物理基础 核心内容: 微积分与线性代数(高频电路建模必备)复变函数与概率论(信号处理与通信系统基础)电磁场基础(麦克斯韦方程组的物理意义&…...
网络研讨会开发注册中, 5月15日特励达力科,“了解以太网”
在线研讨会主题 Understanding Ethernet - from basics to testing & optimization 了解以太网 - 从基础知识到测试和优化 注册链接# https://register.gotowebinar.com/register/2823468241337063262 时间 北京时间 2025 年 5 月 15 日 星期四 下午 3:30 - 4:30 适宜…...
LSTM的简单模型
好的,我来用通俗易懂的语言解释一下这个 LSTMTagger 类是如何工作的。 1️⃣ 类的目的 这个 LSTMTagger 类是一个用于自然语言处理(NLP)任务的模型,目的是标注输入的句子,通常用于词性标注(例如ÿ…...
聊聊Spring AI autoconfigure模块的拆分
序 本文主要研究一下Spring AI autoconfigure模块的拆分 v1.0.0-M6版本 (base) ➜ spring-ai-spring-boot-autoconfigure git:(v1.0.0-M6) tree -L 9 . ├── pom.xml ├── src │ ├── main │ │ ├── java │ │ │ └── org │ │ │ └…...
LVGL源码学习之渲染、更新过程(3)---绘制和刷写
LVGL版本:8.1 往期回顾: LVGL源码学习之渲染、更新过程(1)---标记和激活 LVGL源码学习之渲染、更新过程(2)---无效区域的处理 前文提到,在处理完无效区域后,会得到一个个需要重新绘制的对象,这些对象将在DRAW事件中…...
CTF-DAY11
[NSSRound#16 Basic]了解过PHP特性吗 题目: <?php error_reporting(0); highlight_file(__FILE__); include("rce.php"); $checker_1 FALSE; $checker_2 FALSE; $checker_3 FALSE; $checker_4 FALSE; $num $_GET[num]; if (preg_match("/…...
手动修改uart16550的FIFO深度?
参考:修改AXI UART D16550 FIFO深度的过程记录 - lmore - 博客园...
Unity按钮事件冒泡
今天unity写程序时,我做了一个透明按钮,没图片,只绑了点击事件,把子对象文字组件也删了,空留一个透明按钮,此时运行时点击按钮是没有反应的,网上的教程说必须指定target graphic(目标…...
基于Llama3的开发应用(一):Llama模型的简单部署
Llama模型的简单部署 0 前言1 环境准备1.1 硬件环境1.2 软件环境 2 Meta-Llama-3-8B-Instruct 模型简介2.1 Instruct含义2.2 模型下载 3 简单调用4 FastAPI 部署4.1 通过FastAPI简单部署4.2 测试 5 使用 streamlit 构建简易聊天界面6 总结 0 前言 本系列文章是基于Meta-Llama-…...
人工智能 机器学习期末考试题
自测试卷2 一、选择题 1.下面哪个属性不是NumPy中数组的属性( )。 A.ndim B.size C.shape D.add 2.一个简单的Series是由( )的数据组成的。 A.两…...
修改docker为国内源
一、编辑docker配置文件 vi /etc/docker/daemon.json二、配置国内源和修改docker数据目录 {"registry-mirrors":["http://hub-mirror.c.163.com","https://mirrors.tuna.tsinghua.edu.cn","http://mirrors.sohu.com","https://u…...
C++八股 —— vector底层
vector底层为动态数组 类构成 class vector : protected _Vector_base_Vector_base: _M_start:容器元素开始的位置_M_finish:容器元素结束的位置_M_end_of_storage:动态内存最后一个元素的下一个位置 构造函数 无参构造 根据性能优先规则&a…...
postgresql 参数wal_level
wal_level决定多少信息写入到 WAL 中。默认值是replica,它会写入足够的数据以支持WAL归档和复制,包括在后备服务器上运行只读查询。minimal会去掉除从崩溃或者立即关机中进行恢复所需的信息之外的所有记录。最后,logical会增加支持逻辑解码所…...
Lightweight App Alternatives
The tech industry’s business model thrives on constant churn: new features, fancier designs, and heavier apps — not because they’re essential, but because they keep consumers upgrading. Stripping your phone back to basics is an act of tech self-defense.…...
SpringAI--基于MySQL的持久化对话记忆实现
SpringAI–基于MySQL的持久化对话记忆实现 项目源码 对话记忆官方介绍 SpringAI目前提供了一些将对话保存到不同数据源中的实现,比如: InMemoryChatMemory 基于内存存储CassandraChatMemory 在Cassandra中带有过期时间的持久化存储。Neo4jChatMemory 在Neo4j中没…...
【教学类-34-12】20250509(通义万相)4*3蝴蝶拼图(圆形、三角、正方、半圆的凹凸小块+数字提示+参考图灰色)
背景介绍 制作了四款异形角拼图,初步实现效果 【教学类-34-10】20250503(通义万相)4*3蝴蝶拼图(圆形、三角、正方、半圆的凹凸小块+参考图灰色)-CSDN博客文章浏览阅读1.4k次,点赞46次,收藏15次。【教学类-34-10】20250503(通义万相)4*3蝴蝶拼图(圆形、三角、正方、…...
C++编程语言:标准库:标准库概观(Bjarne Stroustrup)
第30章 标准库概观(Standard-Library Overview) 目录 30.1 引言 30.1.1 标准库设施 30.1.2 设计约束 30.1.3 描述风格 30.2 头文件 30.3 语言支持 30.3.1 对initializer_list的支持 30.3.2 对范围for的支持 30.4 异常处理 30.4.1 异常 30.4.1…...
Springboot+Vue+Mybatis-plus-Maven-Mysql项目部署
目录 VScode 1插件 2快捷键修改 3图标主题设置 4常用设置1 5设置自动换行 6颜色主题 7创建站点 8新建一个html文件 window系统设置 ps 1取色 2测量 3修改单位为像素 4放大图片 5拖动放大之后的图片 6文字大小测量 7测量文字的行高 8矩形选框切图1 9矩形选框…...
【C/C++】C++中noexcept的妙用与性能提升
文章目录 C中noexcept的妙用与性能提升1 什么情况下会抛出异常2 标记noexcept作用3 何时使用noexcept4 无异常行为标记场景5 一句话总结 C中noexcept的妙用与性能提升 在C中,noexcept修饰符用于指示函数不会抛出异常 1 什么情况下会抛出异常 在 C 中,异…...
增强学习(Reinforcement Learning)简介
增强学习(Reinforcement Learning)简介 增强学习是机器学习的一种范式,其核心目标是让智能体(Agent)通过与环境的交互,基于试错机制和延迟奖励反馈,学习如何选择最优动作以最大化长期累积回报。…...
如何优化系统启动时间--基于米尔瑞萨MYD-YG2LX开发板
1.概述 MYD-YG2LX采用瑞萨RZ/G2L作为核心处理器,该处理器搭载双核Cortex-A551.2GHzCortex-M33200MHz处理器,其内部集成高性能3D加速引擎Mail-G31 GPU(500MHz)和视频处理单元(支持H.264硬件编解码),16位的DDR4-1600 / DDR3L-1333内…...
.Net HttpClient 概述
HttpClient 概述 作用 HttpClient是一个用于发送HTTP请求和接收HTTP响应的类。它提供了一种现代化、灵活和强大的方式来与Web服务进行通信。HttpClient类位于System.Net.Http命名空间下,可以通过NuGet包管理器进行安装。 整体理解 HttpClient是应用程序进程中&am…...
明远智睿SSD2351开发板:仪器仪表与智慧农业的创新利器
在仪器仪表和智慧农业领域,对设备的精度、稳定性和智能化程度有着较高的要求。明远智睿的SSD2351开发板以其独特的优势,成为这两个领域的创新利器。 在仪器仪表方面,SSD2351开发板的四核1.4GHz处理器能够快速处理仪器仪表采集到的各种数据&am…...
VBA -- 学习Day4
数组 创建数组: Dim 数组名(数组元素上下角标)[As 元素类型] eg. Dim MyArray (1 To 3) As Integer 注意:1.如果不指定元素类型,则是Variant类型 向数组赋值: eg. MyArray(1) 100 MyArray(2) 200…...
Nacos源码—7.Nacos升级gRPC分析四
大纲 5.服务变动时如何通知订阅的客户端 6.微服务实例信息如何同步集群节点 6.微服务实例信息如何同步集群节点 (1)服务端处理服务注册时会发布一个ClientChangedEvent事件 (2)ClientChangedEvent事件的处理源码 (3)集群节点处理数据同步请求的源码 (1)服务端处理服务注册…...
Linux 学习笔记2
Linux 学习笔记2 一、定时任务调度操作流程注意事项 二、磁盘分区与管理添加新硬盘流程磁盘管理命令 三、进程管理进程操作命令服务管理(Ubuntu) 四、注意事项 一、定时任务调度 操作流程 创建脚本 vim /path/to/script.sh # 编写脚本内容设置可执行权…...
一、每日Github软件分享----QuickGo外链直达工具
QuickGo 是一款专注于提升网页浏览效率的浏览器扩展工具,其核心功能是自动绕过网站的安全跳转限制,让用户点击外链时无需手动确认,直接跳转至目标页面。以下是详细功能介绍与分析: 一、核心功能与亮点 极速跳转 通过优化浏览器 AP…...
【软件测试】软件缺陷(Bug)的详细描述
目录 一、软件缺陷(Bug) 1.1 缺陷的判定标准 1.2 缺陷的生命周期 1.3 软件缺陷的描述 1.3.1 提交缺陷的要素 1.3.2 Bug 的级别 1.4 如何发现更多的 Bug? 1.5 缺陷的有效管理 1.5.1 缺陷的编写 1.5.2 缺陷管理工具 1.5.2.1 缺陷管理 1.5.2.2 用例管理 一、软件缺陷…...
C++ stl中的list的相关函数用法
文章目录 list的介绍list的使用定义方式 插入和删除迭代器的使用获取元素容器中元素个数和容量的控制其它操作函数 list的使用,首先要包含头文件 #include <list>list的介绍 1.list是一种可以在常数范围内在链表中的任意位置进行插入和删除的序列式容器&…...
Cmd命令大全,从入门到放弃
1、文件和目录操作 dir /p:分页显示目录内容。 dir /w:以单行显示目录内容。 dir /s:显示指定目录及子目录下的所有文件。 dir /b:仅显示文件和目录名称。 dir /a:显示具有特定属性的文件和目录。 cd /d:改变当前驱动器。 pushd:将当前目录压入堆栈,并切换到指定…...
数据同步选择推Push还是拉Pull
数据同步选择“推”(Push)还是“拉”(Pull”,要根据实际场景、系统架构和对实时性、资源消耗、安全性的需求来决定。下面是两种方式的对比分析,帮你更好地判断: 文章目录 推模式(Pushÿ…...
Kafka集群加入新Broker节点会发生什么
Kafka集群加入新Broker节点会发生什么 当向现有的Kafka集群添加新的Broker节点时,会触发一系列自动和手动的过程。以下是详细的流程和影响: 自动发生的流程 集群发现与注册 新Broker启动时会向ZooKeeper注册自己加入集群的/brokers/ids路径下其他Broke…...
【LeetCode Solutions】LeetCode 176 ~ 180 题解
CONTENTS LeetCode 176. 第二高的薪水(SQL 中等)LeetCode 177. 第 N 高的薪水(SQL 中等)LeetCode 178. 分数排名(SQL 中等)LeetCode 179. 最大数(中等)LeetCode 180. 连续出现的数字…...
Sourcetree安装使用的详细教程
Sourcetree 是由 Atlassian 推出的 免费 Git 图形化客户端,支持 Git 和 Mercurial 仓库管理,适用于 Windows 和 macOS。 一、安装教程 1. 下载 官网地址:Sourcetree | Free Git GUI for Mac and Windows 选择你的平台下载安装包࿰…...