当前位置: 首页 > 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…...

JVM垃圾回收机制全解析

Java虚拟机&#xff08;JVM&#xff09;中的垃圾收集器&#xff08;Garbage Collector&#xff0c;简称GC&#xff09;是用于自动管理内存的机制。它负责识别和清除不再被程序使用的对象&#xff0c;从而释放内存空间&#xff0c;避免内存泄漏和内存溢出等问题。垃圾收集器在Ja…...

反射获取方法和属性

Java反射获取方法 在Java中&#xff0c;反射&#xff08;Reflection&#xff09;是一种强大的机制&#xff0c;允许程序在运行时访问和操作类的内部属性和方法。通过反射&#xff0c;可以动态地创建对象、调用方法、改变属性值&#xff0c;这在很多Java框架中如Spring和Hiberna…...

Python ROS2【机器人中间件框架】 简介

销量过万TEEIS德国护膝夏天用薄款 优惠券冠生园 百花蜂蜜428g 挤压瓶纯蜂蜜巨奇严选 鞋子除臭剂360ml 多芬身体磨砂膏280g健70%-75%酒精消毒棉片湿巾1418cm 80片/袋3袋大包清洁食品用消毒 优惠券AIMORNY52朵红玫瑰永生香皂花同城配送非鲜花七夕情人节生日礼物送女友 热卖妙洁棉…...

Docker 本地安装 mysql 数据库

Docker: Accelerated Container Application Development 下载对应操作系统版本的 docker &#xff1b;并安装。 基础操作不再赘述。 打开 macOS 终端&#xff0c;开始 docker 安装mysql之旅 第一步 docker search mysql 》〉docker search mysql NAME DE…...

VM虚拟机网络配置(ubuntu24桥接模式):配置静态IP

编辑-虚拟网络编辑器-更改设置 选择桥接模式&#xff0c;然后找到相应的网卡&#xff08;可以查看自己本机的网络连接&#xff09; windows连接的网络点击查看属性 编辑虚拟机设置更改网络配置&#xff0c;选择刚才配置的桥接模式 静态ip设置&#xff1a; 我用的ubuntu24桌…...

Linux 内存管理实战精讲:核心原理与面试常考点全解析

Linux 内存管理实战精讲&#xff1a;核心原理与面试常考点全解析 Linux 内核内存管理是系统设计中最复杂但也最核心的模块之一。它不仅支撑着虚拟内存机制、物理内存分配、进程隔离与资源复用&#xff0c;还直接决定系统运行的性能与稳定性。无论你是嵌入式开发者、内核调试工…...

搭建DNS域名解析服务器(正向解析资源文件)

正向解析资源文件 1&#xff09;准备工作 服务端及客户端都关闭安全软件 [rootlocalhost ~]# systemctl stop firewalld [rootlocalhost ~]# setenforce 0 2&#xff09;服务端安装软件&#xff1a;bind 1.配置yum源 [rootlocalhost ~]# cat /etc/yum.repos.d/base.repo [Base…...

Python 高效图像帧提取与视频编码:实战指南

Python 高效图像帧提取与视频编码:实战指南 在音视频处理领域,图像帧提取与视频编码是基础但极具挑战性的任务。Python 结合强大的第三方库(如 OpenCV、FFmpeg、PyAV),可以高效处理视频流,实现快速帧提取、压缩编码等关键功能。本文将深入介绍如何优化这些流程,提高处理…...

渗透实战PortSwigger靶场:lab13存储型DOM XSS详解

进来是需要留言的&#xff0c;先用做简单的 html 标签测试 发现面的</h1>不见了 数据包中找到了一个loadCommentsWithVulnerableEscapeHtml.js 他是把用户输入的<>进行 html 编码&#xff0c;输入的<>当成字符串处理回显到页面中&#xff0c;看来只是把用户输…...

消防一体化安全管控平台:构建消防“一张图”和APP统一管理

在城市的某个角落&#xff0c;一场突如其来的火灾打破了平静。熊熊烈火迅速蔓延&#xff0c;滚滚浓烟弥漫开来&#xff0c;周围群众的生命财产安全受到严重威胁。就在这千钧一发之际&#xff0c;消防救援队伍迅速行动&#xff0c;而豪越科技消防一体化安全管控平台构建的消防“…...