PHP+laravel 生成word
此功能较为繁琐我会从源头讲起
首先是数据库设置,下面是我的数据库结构
合同模版表
CREATE TABLE `contract_tpl` (`id` bigint unsigned NOT NULL AUTO_INCREMENT,`name` varchar(191) COLLATE utf8_unicode_ci DEFAULT NULL COMMENT '合同名称',`file` varchar(191) COLLATE utf8_unicode_ci DEFAULT NULL COMMENT '合同文件',`created_at` timestamp NULL DEFAULT NULL,`updated_at` timestamp NULL DEFAULT NULL,PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8mb3 COLLATE=utf8_unicode_ci;
生成word,可以参考phpword使用整理-CSDN博客
实现思路:
编写一个合同模版,将word文件中变量使用“${变量名}”的格式填写如下图所示:

执行命令安装phpword:
composer require phpoffice/phpword
代码如下图:
static public function word(){$order_id = request()->get('order_id');$tpl_id = request()->get('tpl_id');$saleData = SaleItem::where('order_id',$order_id)->get()->toArray();if ($saleData == null){return '此订单没有选择产品';}$sale_order = SaleOrderModel::with(['customer','items','user.employee','amount'])->where('id',$order_id)->first();$modelcontract = ContractTplModel::where('id',$tpl_id)->first();if ($sale_order->user == null){return '此订单没有负责人';}$folderPath = storage_path('app/public/contract');if (!file_exists($folderPath)) {// 文件夹不存在,创建文件夹mkdir($folderPath, 0777, true); // 第一个参数是路径,第二个参数是权限,第三个参数表示递归创建}$file = $modelcontract->file;if ($file == null){return '请上传合同模版';}foreach($sale_order->items as $key => $val){
// $unit = GoodsSkuModel::UNIT_MAP[$items->sku->unit];$item_data[$key]['id'] = $key+1;$item_data[$key]['item_id'] = $val->sku_id;$item_data[$key]['goods_name'] = $val->sku->goods_name ?? '';$item_data[$key]['sku_name'] = $val->sku->sku_name ?? '';$item_data[$key]['num'] = $val->should_num ?? '';$item_data[$key]['after_tax_price'] = $val->after_tax_price ?? '';$item_data[$key]['point_price'] = $val->point_price ?? '';$item_data[$key]['point'] = $val->point ?? '';$goods_name[] = $val->sku->goods_name ?? '';}$trade_name = implode("、", array_unique($goods_name));$file_path = storage_path('app/public/' . $file);
// dd($file_path);if (!file_exists($file_path)) {return '该合同模版文件不存在,请重新上传模版文件';}$templateProcessor = new TemplateProcessor($file_path);$party_a = $sale_order->customer->name;//甲方名称$product_name = $trade_name;//产品名称$total_amount = $sale_order->total_amount ?? ''; //含税总价$first_price = $total_amount * 0.7;$tow_price = $total_amount * 0.2;$price3 = $total_amount *0.1;$support = new Support();$first_price_cn = $support->convertAmountToCn($first_price);$tow_price_cn = $support->convertAmountToCn($tow_price);$price3_cn = $support->convertAmountToCn($price3);$prefix = str_replace('-','','sk'.$sale_order->user->prefix.build_ws_no()) ?? '';//合同前缀$templateProcessor->setValues(array('合同编号'=>$prefix,'甲方名称'=>$party_a,'产品名称'=>$product_name,'含税总价'=>$sale_order->total_amount,'大写总价'=>$support->convertAmountToCn($sale_order->total_amount),'第一笔金额'=>$first_price,'第一笔金额大写'=>$first_price_cn,'一笔货款发出时间'=>3,'收到货物工作日'=>2,'收到货物百分比'=>30,'第二笔金额'=>$tow_price,'第二笔金额大写'=>$tow_price_cn,'第二笔货款工作日'=>$tow_price,'第三笔货款'=>$price3,'第三笔货款大写'=>$price3_cn,'甲方负责人姓名'=>$sale_order->customer->contacts_name??'','甲方负责人电话'=>$sale_order->customer->contacts_mobile ?? '','乙方负责人姓名'=>$sale_order->user->employee->name ?? '','乙方负责人电话'=>$sale_order->user->employee->mobile ?? '','增值税专用发票'=> 6 ?? '',));if (count($item_data)){$templateProcessor->cloneRow('id',count($item_data));foreach ($item_data as $k => $v) {$templateProcessor->setValue('id#'. ($k + 1), $v['id']);$templateProcessor->setValue('goods_name#'. ($k + 1), $v['goods_name']);$templateProcessor->setValue('sku_name#'. ($k + 1), $v['sku_name']);$templateProcessor->setValue('num#' . ($k + 1), $v['num']);$templateProcessor->setValue('after_tax_price#' . ($k + 1), $v['after_tax_price']);$templateProcessor->setValue('point#' . ($k + 1), $v['point']);$templateProcessor->setValue('point_price#' . ($k + 1), $v['point_price']);}}$word_name = $sale_order->customer->name;$templateProcessor->saveAs( storage_path("app/public/contract/".$word_name.".docx"));$file_path = "/contract/".$word_name.".docx"; // 文件的路径和名称SaleOrderModel::query()->where('id',$order_id)->update(['tpl_id'=>$tpl_id,'contract'=>$file_path,]);$tpl = ContractTplModel::query()->get()->toArray();$file_name = get_file_path($file_path);return view('page/generate_office',compact('order_id','tpl_id','file_name','tpl'));}
word文件在页面展示:
这里用到的是amis前端框架网址可参考:amis - 低代码前端框架
创建一个视图文件如下图所示:

文件代码:
<!DOCTYPE html>
<html lang="{{ app()->getLocale() }}">
<head><meta charset="UTF-8" /><title>@yield('title')</title><meta http-equiv="Content-Type" content="text/html; charset=utf-8" /><metaname="viewport"content="width=device-width, initial-scale=1, maximum-scale=1"/><meta http-equiv="X-UA-Compatible" content="IE=Edge" /><!-- amis --><link rel="stylesheet" href="{{ asset('static/css/sdk.css') }}" /><link rel="stylesheet" href="{{ asset('static/css/helper.css') }}" /><link rel="stylesheet" href="{{ asset('static/css/iconfont.css') }}" /><link rel="stylesheet" href="{{ asset('static/css/main.css?v='.config('admin.version')) }}" /><!-- 这是默认主题所需的,如果是其他主题则不需要 --><!-- 从 1.1.0 开始 sdk.css 将不支持 IE 11,如果要支持 IE11 请引用这个 css,并把前面那个删了 --><!-- <link rel="stylesheet" href="sdk-ie11.css" /> --><!-- 不过 amis 开发团队几乎没测试过 IE 11 下的效果,所以可能有细节功能用不了,如果发现请报 issue --><style>html,body,.app-wrapper {position: relative;width: 100%;height: 100%;margin: 0;padding: 0;}</style>@yield('head')
</head>
<body>
<div id="root" class="app-wrapper"></div>
<script src="{{ asset('static/js/sdk.js') }}"></script>
<script src="{{ asset('static/js/charts.js') }}"></script>
<script src="{{ asset('static/js/office-viewer.js') }}"></script>
<script src="{{ asset('static/js/papaparse.js') }}"></script>
<script src="{{ asset('static/js/pdf-viewer.js') }}"></script>
<script src="{{ asset('static/js/tinymce.js') }}"></script>
@yield('foot')
</body>
</html>
创建一个视图文件,使用下图方式引入模版文件
@extends('layouts.amis')
@section('title','生产工单时间线')
@section('foot')@endsection
完整代码
@extends('layouts.amis')
@section('title','生产工单时间线')
@section('foot')<script type="text/javascript">(function () {let amis = amisRequire('amis/embed');// 通过替换下面这个配置来生成不同页面let amisJSON = {"type": "page",//侧边栏"aside": {"type": "nav","name": "nav","stacked": true,"source": "{{admin_url('tpl_info?order_id='.$order_id)}}",},"body": [{"type": "nav","stacked": true,"source": "${nav}",},@if(isset($error) && $error == 2){"type": "page","body": "请点击左侧合同模版"},@endif@if($file_name != null ){"type": "button-toolbar","buttons": [{"type": "action","label": "下载word文档","cssVars": {"--primary-padding": "10px 200px",},"onEvent": {"click": {"actions": [{"actionType": "saveAs","componentId": "office-viewer-download",},],}}},{"type": "office-viewer","id": "office-viewer-download","display": false,"src": "{{$file_name}}","padding": "10px 200px","ignoreWidth": true,},{"type": "link",'body':'PDF下载',"className" : "pdf_span span","href": "{{admin_url('sale-order/wordToPdf?order_id='.$order_id)}}","style": {"margin-left": "80px","margin-top" : "5px","padding" : "3px 12px",}},]},{"type": "office-viewer",'name':'word','id':'word',"src": "{{$file_name}}","wordOptions": {"padding": "10px 200px","ignoreWidth": true,}},@else{"type": "page","body": "请点击左侧合同模版"}@endif]};// window.location.reload()let amisScoped = amis.embed('#root', amisJSON);})();</script>
@endsection
侧边栏是一个单独的接口/或者说也可以写为固定值
public function tpl_info(){$line = ContractTplModel::query()->get();$order_id = request()->get('order_id');foreach ($line as $item){$options[] = ['label'=>$item->name,'value'=>$item->id,'to'=> admin_url("sale-order/word?order_id=".$order_id."&"."tpl_id=".$item->id),];}$this->amis_res(['options'=>$options]);}
最终效果如图所示:
生成PDF留在下节讲解
相关文章:
PHP+laravel 生成word
此功能较为繁琐我会从源头讲起 首先是数据库设置,下面是我的数据库结构 合同模版表 CREATE TABLE contract_tpl (id bigint unsigned NOT NULL AUTO_INCREMENT,name varchar(191) COLLATE utf8_unicode_ci DEFAULT NULL COMMENT 合同名称,file varchar(191) COLL…...
redis集群简单介绍及其搭建过程
Redis集群 1、哨兵模式 哨兵可以有多个,从服务器也可以有多个,从服务器也可以有多个,在Redis3.0以前的版本要实现集群一般是借助哨兵sentinel工具来监控master节点的状态,如果master节点异常,则会实现主从切换&#x…...
linux桌面运维----第五天
1、创建用户命令useradd: 作用:创建用户 语法:useradd [选项名] 用户名 选项: -d<登入目录> 指定用户登入时的起始目录。 【掌握】 -g<群组> 指定用户所属的群组(基本组)。【掌握】…...
【SQL Server数据库】简单查询
目录 用SQL语句完成下列查询。使用数据库为SCHOOL数据库 1. 查询学生的姓名、性别、班级名称,并把结果存储在一张新表中。 2. 查询男生的资料。 3. 查询所有计算机系的班级信息。 4.查询艾老师所教的课程号。 5. 查询年龄小于30岁的女同学的学号和姓名。…...
Docker 从入门到精通(大全)
一、概述 1.1 基本概念 Docker 是一个开源的应用容器引擎,基于 Go 语言 并遵从 Apache2.0 协议开源。 Docker 可以让开发者打包他们的应用以及依赖包到一个轻量级、可移植的容器中,然后发布到任何流行的 Linux 机器上,也可以实现虚拟化。…...
基于JSP的在线教育资源管理系统
开头语: 你好呀,我是计算机学长猫哥!如果你对在线教育资源管理系统感兴趣或者有相关需求,欢迎在文末找到我的联系方式。 开发语言:Java 数据库:MySQL 技术:JSP技术 工具:IDE、N…...
在java中代理http请求,如何避免陷入循环?
在 Java 中,代理 HTTP 请求时,如果不小心配置不当,可能会导致循环请求。循环请求通常发生在代理服务器将请求再次发送回自己,形成一个死循环。为了避免这种情况,可以采取以下几种方法: 将域名设置为指定的…...
国内镜像源网址
腾讯:腾讯软件源 (tencent.com) 阿里:阿里巴巴开源镜像站-OPSX镜像站-阿里云开发者社区 (aliyun.com) 清华:清华大学开源软件镜像站 | Tsinghua Open Source Mirror...
合适的智能猫砂盆到底怎么挑?开放式封闭式一次说清!
想当初我也是在网上看了各种测评,纠结了好久才下定决心入手了智能猫砂盆。封闭式和开放式都用过,各有各的利与弊,不过最后的我还是选择了开放式的智能猫砂盆,因为开放式的设计结构会更加方便我观察小猫,哪个铲屎官不喜…...
阿里云开启ssl证书过程记录 NGINX
🤞作者简介:大家好,我是思无邪,2024 毕业生,某厂 Go 开发工程师.。 🐂我的网站:https://www.yishanicode.top/ ,持续更新,希望对你有帮助。 🐞如果文章或网站…...
C语言程序设计 9.37 调用随机函数为5x4的矩阵置 100以内的整数,输出该矩阵,求出每行元素之和,并把和的最大的那一行与第一行的元素对调
void count_sum(int sum[]) {int i;printf("每行相加的情况如下\n");for (i 0;i < 5; i){printf("%d ", sum[i]);}printf("\n"); } void test(int arr[5][4]) {int i, j;srand((unsigned)time(NULL));//添加这个可以每次不同的随机数&#x…...
Webpack: 借助 Babel+TS+ESLint 构建现代 JS 工程环境
概述 Webpack 场景下处理 JavaScript 的三种常用工具:Babel、TypeScript、ESLint 的历史背景、功能以及接入 Webpack 的步骤借助这些工具,我们能构建出更健壮、优雅的 JavaScript 应用 使用 Babel ECMAScript 6.0(简称 ES6) 版本补充了大量提升 JavaSc…...
孩子不想上学,父母应如何教育?“强迫教育”会激起孩子反抗心理
上周末朋友聚会,都是家有上学娃的年纪,闲聊中,话题自然少不了孩子的上学问题。其中,不少朋友都有抱怨过同一个问题:孩子不想上学,即使人到了学校,心也不在学校。 事实上,孩子出现…...
Python深度学习技术
原文链接:Python深度学习技术 近年来,伴随着以卷积神经网络(CNN)为代表的深度学习的快速发展,人工智能迈入了第三次发展浪潮,AI技术在各个领域中的应用越来越广泛。Transformer模型(BERT、GPT-…...
ECharts 雷达图案例002 - 诈骗性质分析
ECharts 雷达图案例002 - 诈骗性质分析 📊 ECharts 雷达图案例002 - 诈骗性质分析 深入挖掘数据背后的故事,用可视化手段揭示诈骗行为的模式和趋势。 🔍 案例亮点 创新的数据展示方式,让复杂的诈骗数据一目了然。定制化的雷达图…...
想远程控制手机,用哪个软件好?
很多人都想知道安卓系统或iOS系统要如何实现手机远程控制手机、电脑远程控制手机,分别需要用到什么软件,这篇文章一次说清楚。 注意,安卓系统需要是7.0及以上版本,iOS系统需要是11及以上版本。具体使用步骤请点击关注,…...
数字内容“遍地开花”,AI技术如何创新“造梦”?
文 | 智能相对论 作者 | 陈泊丞 这是春晚舞台西安分会场《山河诗长安》的一幕:“李白”现世,带领观众齐颂《将进酒》,将中国人骨子里的豪情与浪漫演绎得淋漓尽致。 这又是浙江义乌商品市场里的另一幕:只会说几个英文单词的女老板…...
MySQL集群如何实现读写分离
数据源配置:定义了主从数据库的连接池。读写分离规则:通过MasterSlaveRuleConfiguration定义了主从数据库的读写分离规则。负载均衡算法:定义了从数据库的负载均衡算法。创建ShardingDataSource:使用数据源和读写分离规则创建了Sh…...
一分钟剪辑1000条视频的云微客矩阵,怎么做到的?
当我们打开短视频软件时,就会有大量风格迥异的短视频犹如潮水般涌现在我们面前,这些短视频不仅配置了加粗的标题,下方还配置了字幕,中间则播放着视频,就是这样简易的视频,往往总能获得较高的播放量…...
简单案例比较Lambda和方法引用的差别
1.打印列表元素 正常使用 List<String> list Arrays.asList("a", "b", "c");for (String str: list){System.out.println(str);}Lambda表达式 list.forEach(e -> System.out.println(e));方法引用 list.forEach(System.out::println…...
eNSP-Cloud(实现本地电脑与eNSP内设备之间通信)
说明: 想象一下,你正在用eNSP搭建一个虚拟的网络世界,里面有虚拟的路由器、交换机、电脑(PC)等等。这些设备都在你的电脑里面“运行”,它们之间可以互相通信,就像一个封闭的小王国。 但是&#…...
智慧医疗能源事业线深度画像分析(上)
引言 医疗行业作为现代社会的关键基础设施,其能源消耗与环境影响正日益受到关注。随着全球"双碳"目标的推进和可持续发展理念的深入,智慧医疗能源事业线应运而生,致力于通过创新技术与管理方案,重构医疗领域的能源使用模式。这一事业线融合了能源管理、可持续发…...
<6>-MySQL表的增删查改
目录 一,create(创建表) 二,retrieve(查询表) 1,select列 2,where条件 三,update(更新表) 四,delete(删除表…...
[Java恶补day16] 238.除自身以外数组的乘积
给你一个整数数组 nums,返回 数组 answer ,其中 answer[i] 等于 nums 中除 nums[i] 之外其余各元素的乘积 。 题目数据 保证 数组 nums之中任意元素的全部前缀元素和后缀的乘积都在 32 位 整数范围内。 请 不要使用除法,且在 O(n) 时间复杂度…...
浅谈不同二分算法的查找情况
二分算法原理比较简单,但是实际的算法模板却有很多,这一切都源于二分查找问题中的复杂情况和二分算法的边界处理,以下是博主对一些二分算法查找的情况分析。 需要说明的是,以下二分算法都是基于有序序列为升序有序的情况…...
精益数据分析(97/126):邮件营销与用户参与度的关键指标优化指南
精益数据分析(97/126):邮件营销与用户参与度的关键指标优化指南 在数字化营销时代,邮件列表效度、用户参与度和网站性能等指标往往决定着创业公司的增长成败。今天,我们将深入解析邮件打开率、网站可用性、页面参与时…...
算法岗面试经验分享-大模型篇
文章目录 A 基础语言模型A.1 TransformerA.2 Bert B 大语言模型结构B.1 GPTB.2 LLamaB.3 ChatGLMB.4 Qwen C 大语言模型微调C.1 Fine-tuningC.2 Adapter-tuningC.3 Prefix-tuningC.4 P-tuningC.5 LoRA A 基础语言模型 A.1 Transformer (1)资源 论文&a…...
Java毕业设计:WML信息查询与后端信息发布系统开发
JAVAWML信息查询与后端信息发布系统实现 一、系统概述 本系统基于Java和WML(无线标记语言)技术开发,实现了移动设备上的信息查询与后端信息发布功能。系统采用B/S架构,服务器端使用Java Servlet处理请求,数据库采用MySQL存储信息࿰…...
排序算法总结(C++)
目录 一、稳定性二、排序算法选择、冒泡、插入排序归并排序随机快速排序堆排序基数排序计数排序 三、总结 一、稳定性 排序算法的稳定性是指:同样大小的样本 **(同样大小的数据)**在排序之后不会改变原始的相对次序。 稳定性对基础类型对象…...
CSS | transition 和 transform的用处和区别
省流总结: transform用于变换/变形,transition是动画控制器 transform 用来对元素进行变形,常见的操作如下,它是立即生效的样式变形属性。 旋转 rotate(角度deg)、平移 translateX(像素px)、缩放 scale(倍数)、倾斜 skewX(角度…...
