当前位置: 首页 > news >正文

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

此功能较为繁琐我会从源头讲起 首先是数据库设置&#xff0c;下面是我的数据库结构 合同模版表 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、哨兵模式 哨兵可以有多个&#xff0c;从服务器也可以有多个&#xff0c;从服务器也可以有多个&#xff0c;在Redis3.0以前的版本要实现集群一般是借助哨兵sentinel工具来监控master节点的状态&#xff0c;如果master节点异常&#xff0c;则会实现主从切换&#x…...

linux桌面运维----第五天

1、创建用户命令useradd&#xff1a; 作用&#xff1a;创建用户 ​语法&#xff1a;useradd [选项名] 用户名 ​选项&#xff1a; -d<登入目录> 指定用户登入时的起始目录。 【掌握】 -g<群组> 指定用户所属的群组&#xff08;基本组&#xff09;。【掌握】…...

【SQL Server数据库】简单查询

目录 用SQL语句完成下列查询。使用数据库为SCHOOL数据库 1. 查询学生的姓名、性别、班级名称&#xff0c;并把结果存储在一张新表中。 2. 查询男生的资料。 3. 查询所有计算机系的班级信息。 4&#xff0e;查询艾老师所教的课程号。 5. 查询年龄小于30岁的女同学的学号和姓名。…...

Docker 从入门到精通(大全)

一、概述 1.1 基本概念 Docker 是一个开源的应用容器引擎&#xff0c;基于 Go 语言 并遵从 Apache2.0 协议开源。 Docker 可以让开发者打包他们的应用以及依赖包到一个轻量级、可移植的容器中&#xff0c;然后发布到任何流行的 Linux 机器上&#xff0c;也可以实现虚拟化。…...

基于JSP的在线教育资源管理系统

开头语&#xff1a; 你好呀&#xff0c;我是计算机学长猫哥&#xff01;如果你对在线教育资源管理系统感兴趣或者有相关需求&#xff0c;欢迎在文末找到我的联系方式。 开发语言&#xff1a;Java 数据库&#xff1a;MySQL 技术&#xff1a;JSP技术 工具&#xff1a;IDE、N…...

在java中代理http请求,如何避免陷入循环?

在 Java 中&#xff0c;代理 HTTP 请求时&#xff0c;如果不小心配置不当&#xff0c;可能会导致循环请求。循环请求通常发生在代理服务器将请求再次发送回自己&#xff0c;形成一个死循环。为了避免这种情况&#xff0c;可以采取以下几种方法&#xff1a; 将域名设置为指定的…...

国内镜像源网址

腾讯&#xff1a;腾讯软件源 (tencent.com) 阿里&#xff1a;阿里巴巴开源镜像站-OPSX镜像站-阿里云开发者社区 (aliyun.com) 清华&#xff1a;清华大学开源软件镜像站 | Tsinghua Open Source Mirror...

合适的智能猫砂盆到底怎么挑?开放式封闭式一次说清!

想当初我也是在网上看了各种测评&#xff0c;纠结了好久才下定决心入手了智能猫砂盆。封闭式和开放式都用过&#xff0c;各有各的利与弊&#xff0c;不过最后的我还是选择了开放式的智能猫砂盆&#xff0c;因为开放式的设计结构会更加方便我观察小猫&#xff0c;哪个铲屎官不喜…...

阿里云开启ssl证书过程记录 NGINX

&#x1f91e;作者简介&#xff1a;大家好&#xff0c;我是思无邪&#xff0c;2024 毕业生&#xff0c;某厂 Go 开发工程师.。 &#x1f402;我的网站&#xff1a;https://www.yishanicode.top/ &#xff0c;持续更新&#xff0c;希望对你有帮助。 &#x1f41e;如果文章或网站…...

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 的三种常用工具&#xff1a;Babel、TypeScript、ESLint 的历史背景、功能以及接入 Webpack 的步骤借助这些工具&#xff0c;我们能构建出更健壮、优雅的 JavaScript 应用 使用 Babel ECMAScript 6.0(简称 ES6) 版本补充了大量提升 JavaSc…...

孩子不想上学,父母应如何教育?“强迫教育”会激起孩子反抗心理

上周末朋友聚会&#xff0c;都是家有上学娃的年纪&#xff0c;闲聊中&#xff0c;话题自然少不了孩子的上学问题。其中&#xff0c;不少朋友都有抱怨过同一个问题&#xff1a;孩子不想上学&#xff0c;即使人到了学校&#xff0c;心也不在学校。   事实上&#xff0c;孩子出现…...

Python深度学习技术

原文链接&#xff1a;Python深度学习技术 近年来&#xff0c;伴随着以卷积神经网络&#xff08;CNN&#xff09;为代表的深度学习的快速发展&#xff0c;人工智能迈入了第三次发展浪潮&#xff0c;AI技术在各个领域中的应用越来越广泛。Transformer模型&#xff08;BERT、GPT-…...

ECharts 雷达图案例002 - 诈骗性质分析

ECharts 雷达图案例002 - 诈骗性质分析 &#x1f4ca; ECharts 雷达图案例002 - 诈骗性质分析 深入挖掘数据背后的故事&#xff0c;用可视化手段揭示诈骗行为的模式和趋势。 &#x1f50d; 案例亮点 创新的数据展示方式&#xff0c;让复杂的诈骗数据一目了然。定制化的雷达图…...

想远程控制手机,用哪个软件好?

很多人都想知道安卓系统或iOS系统要如何实现手机远程控制手机、电脑远程控制手机&#xff0c;分别需要用到什么软件&#xff0c;这篇文章一次说清楚。 注意&#xff0c;安卓系统需要是7.0及以上版本&#xff0c;iOS系统需要是11及以上版本。具体使用步骤请点击关注&#xff0c;…...

数字内容“遍地开花”,AI技术如何创新“造梦”?

文 | 智能相对论 作者 | 陈泊丞 这是春晚舞台西安分会场《山河诗长安》的一幕&#xff1a;“李白”现世&#xff0c;带领观众齐颂《将进酒》&#xff0c;将中国人骨子里的豪情与浪漫演绎得淋漓尽致。 这又是浙江义乌商品市场里的另一幕&#xff1a;只会说几个英文单词的女老板…...

MySQL集群如何实现读写分离

数据源配置&#xff1a;定义了主从数据库的连接池。读写分离规则&#xff1a;通过MasterSlaveRuleConfiguration定义了主从数据库的读写分离规则。负载均衡算法&#xff1a;定义了从数据库的负载均衡算法。创建ShardingDataSource&#xff1a;使用数据源和读写分离规则创建了Sh…...

一分钟剪辑1000条视频的云微客矩阵,怎么做到的?

当我们打开短视频软件时&#xff0c;就会有大量风格迥异的短视频犹如潮水般涌现在我们面前&#xff0c;这些短视频不仅配置了加粗的标题&#xff0c;下方还配置了字幕&#xff0c;中间则播放着视频&#xff0c;就是这样简易的视频&#xff0c;往往总能获得较高的播放量&#xf…...

简单案例比较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…...

华为云AI开发平台ModelArts

华为云ModelArts&#xff1a;重塑AI开发流程的“智能引擎”与“创新加速器”&#xff01; 在人工智能浪潮席卷全球的2025年&#xff0c;企业拥抱AI的意愿空前高涨&#xff0c;但技术门槛高、流程复杂、资源投入巨大的现实&#xff0c;却让许多创新构想止步于实验室。数据科学家…...

国防科技大学计算机基础课程笔记02信息编码

1.机内码和国标码 国标码就是我们非常熟悉的这个GB2312,但是因为都是16进制&#xff0c;因此这个了16进制的数据既可以翻译成为这个机器码&#xff0c;也可以翻译成为这个国标码&#xff0c;所以这个时候很容易会出现这个歧义的情况&#xff1b; 因此&#xff0c;我们的这个国…...

Docker 离线安装指南

参考文章 1、确认操作系统类型及内核版本 Docker依赖于Linux内核的一些特性&#xff0c;不同版本的Docker对内核版本有不同要求。例如&#xff0c;Docker 17.06及之后的版本通常需要Linux内核3.10及以上版本&#xff0c;Docker17.09及更高版本对应Linux内核4.9.x及更高版本。…...

【人工智能】神经网络的优化器optimizer(二):Adagrad自适应学习率优化器

一.自适应梯度算法Adagrad概述 Adagrad&#xff08;Adaptive Gradient Algorithm&#xff09;是一种自适应学习率的优化算法&#xff0c;由Duchi等人在2011年提出。其核心思想是针对不同参数自动调整学习率&#xff0c;适合处理稀疏数据和不同参数梯度差异较大的场景。Adagrad通…...

shell脚本--常见案例

1、自动备份文件或目录 2、批量重命名文件 3、查找并删除指定名称的文件&#xff1a; 4、批量删除文件 5、查找并替换文件内容 6、批量创建文件 7、创建文件夹并移动文件 8、在文件夹中查找文件...

python/java环境配置

环境变量放一起 python&#xff1a; 1.首先下载Python Python下载地址&#xff1a;Download Python | Python.org downloads ---windows -- 64 2.安装Python 下面两个&#xff0c;然后自定义&#xff0c;全选 可以把前4个选上 3.环境配置 1&#xff09;搜高级系统设置 2…...

Python爬虫实战:研究feedparser库相关技术

1. 引言 1.1 研究背景与意义 在当今信息爆炸的时代,互联网上存在着海量的信息资源。RSS(Really Simple Syndication)作为一种标准化的信息聚合技术,被广泛用于网站内容的发布和订阅。通过 RSS,用户可以方便地获取网站更新的内容,而无需频繁访问各个网站。 然而,互联网…...

【笔记】WSL 中 Rust 安装与测试完整记录

#工作记录 WSL 中 Rust 安装与测试完整记录 1. 运行环境 系统&#xff1a;Ubuntu 24.04 LTS (WSL2)架构&#xff1a;x86_64 (GNU/Linux)Rust 版本&#xff1a;rustc 1.87.0 (2025-05-09)Cargo 版本&#xff1a;cargo 1.87.0 (2025-05-06) 2. 安装 Rust 2.1 使用 Rust 官方安…...

JS手写代码篇----使用Promise封装AJAX请求

15、使用Promise封装AJAX请求 promise就有reject和resolve了&#xff0c;就不必写成功和失败的回调函数了 const BASEURL ./手写ajax/test.jsonfunction promiseAjax() {return new Promise((resolve, reject) > {const xhr new XMLHttpRequest();xhr.open("get&quo…...

es6+和css3新增的特性有哪些

一&#xff1a;ECMAScript 新特性&#xff08;ES6&#xff09; ES6 (2015) - 革命性更新 1&#xff0c;记住的方法&#xff0c;从一个方法里面用到了哪些技术 1&#xff0c;let /const块级作用域声明2&#xff0c;**默认参数**&#xff1a;函数参数可以设置默认值。3&#x…...