此功能较为繁琐我会从源头讲起
首先是数据库设置,下面是我的数据库结构
合同模版表
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" />
<meta
name="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留在下节讲解