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…...
渲染学进阶内容——模型
最近在写模组的时候发现渲染器里面离不开模型的定义,在渲染的第二篇文章中简单的讲解了一下关于模型部分的内容,其实不管是方块还是方块实体,都离不开模型的内容 🧱 一、CubeListBuilder 功能解析 CubeListBuilder 是 Minecraft Java 版模型系统的核心构建器,用于动态创…...
【C语言练习】080. 使用C语言实现简单的数据库操作
080. 使用C语言实现简单的数据库操作 080. 使用C语言实现简单的数据库操作使用原生APIODBC接口第三方库ORM框架文件模拟1. 安装SQLite2. 示例代码:使用SQLite创建数据库、表和插入数据3. 编译和运行4. 示例运行输出:5. 注意事项6. 总结080. 使用C语言实现简单的数据库操作 在…...

CMake 从 GitHub 下载第三方库并使用
有时我们希望直接使用 GitHub 上的开源库,而不想手动下载、编译和安装。 可以利用 CMake 提供的 FetchContent 模块来实现自动下载、构建和链接第三方库。 FetchContent 命令官方文档✅ 示例代码 我们将以 fmt 这个流行的格式化库为例,演示如何: 使用 FetchContent 从 GitH…...

(转)什么是DockerCompose?它有什么作用?
一、什么是DockerCompose? DockerCompose可以基于Compose文件帮我们快速的部署分布式应用,而无需手动一个个创建和运行容器。 Compose文件是一个文本文件,通过指令定义集群中的每个容器如何运行。 DockerCompose就是把DockerFile转换成指令去运行。 …...
JVM暂停(Stop-The-World,STW)的原因分类及对应排查方案
JVM暂停(Stop-The-World,STW)的完整原因分类及对应排查方案,结合JVM运行机制和常见故障场景整理而成: 一、GC相关暂停 1. 安全点(Safepoint)阻塞 现象:JVM暂停但无GC日志,日志显示No GCs detected。原因:JVM等待所有线程进入安全点(如…...
Web 架构之 CDN 加速原理与落地实践
文章目录 一、思维导图二、正文内容(一)CDN 基础概念1. 定义2. 组成部分 (二)CDN 加速原理1. 请求路由2. 内容缓存3. 内容更新 (三)CDN 落地实践1. 选择 CDN 服务商2. 配置 CDN3. 集成到 Web 架构 …...
08. C#入门系列【类的基本概念】:开启编程世界的奇妙冒险
C#入门系列【类的基本概念】:开启编程世界的奇妙冒险 嘿,各位编程小白探险家!欢迎来到 C# 的奇幻大陆!今天咱们要深入探索这片大陆上至关重要的 “建筑”—— 类!别害怕,跟着我,保准让你轻松搞…...
掌握 HTTP 请求:理解 cURL GET 语法
cURL 是一个强大的命令行工具,用于发送 HTTP 请求和与 Web 服务器交互。在 Web 开发和测试中,cURL 经常用于发送 GET 请求来获取服务器资源。本文将详细介绍 cURL GET 请求的语法和使用方法。 一、cURL 基本概念 cURL 是 "Client URL" 的缩写…...

高分辨率图像合成归一化流扩展
大家读完觉得有帮助记得关注和点赞!!! 1 摘要 我们提出了STARFlow,一种基于归一化流的可扩展生成模型,它在高分辨率图像合成方面取得了强大的性能。STARFlow的主要构建块是Transformer自回归流(TARFlow&am…...

2025-05-08-deepseek本地化部署
title: 2025-05-08-deepseek 本地化部署 tags: 深度学习 程序开发 2025-05-08-deepseek 本地化部署 参考博客 本地部署 DeepSeek:小白也能轻松搞定! 如何给本地部署的 DeepSeek 投喂数据,让他更懂你 [实验目的]:理解系统架构与原…...