vue 使用docx-preview 预览替换文档内的特定变量
在开发合同管理中,需要使用到此功能,就是替换合同模板内的一些字符串,如:甲乙方名称,金额日期等,合同内容不变。效果如下:
使用docx-preview 好处是只预览不可编辑内容。
前端vue
import { renderAsync } from 'docx-preview';
// 替换文件内容
function onWordSave(){
axios({
method: "post",
responseType: "blob", // 因为是流文件,所以要指定blob类型
url: Http.getBaseURL() + "/contract/Index/setWord", // 自己的服务器,提供的一个word下载文件接口
data:{'fieldData':select_field.value,'tem_id':form.value.tem_id}
}).then(response => {
if (response.status === 200) {
// 检查Content-Type是否是预期的类型
const contentType = response.headers['content-type'] || response.headers['Content-Type'];
if (contentType === 'application/vnd.openxmlformats-officedocument.wordprocessingml.document') {
// 数据正确,处理blob数据
ElMessage({type:'success', message:'替换模板内容成功'})
file_url.value = response.data
}else {
// 数据类型不匹配
ElMessage({type:'error', message: '模板内容替换失败'})
}
} else {
// 响应状态不是200
ElMessage({type:'error', message: 'failed to open stream: No such file or directory'})
}
}).catch(error => {
// 请求失败,处理错误
ElMessage({type:'error', message:error})
});
}
// 预览文件
function docxRender() {
ContractFileRef.value.innerHTML = ''; // 清空之前的内容
if(file_url.value != ''){
let blob = new Blob([file_url.value]); // 将 OSS 文件转为 Blob 对象
// 渲染文档并获取内容控件
renderAsync(blob, ContractFileRef.value);
}
}
后端 控制器方法:
/**
* @名称:模板内容替换
* User: congxion
* Date: 2024/10/31 16:44
*/
public function setWord(){
try{
$param = $this->request->param();
if(empty($param['tem_id'])){
return jsonError('请选择合同模板');
}
if(empty($param['fieldData'])){
return jsonError('没有可替换的内容');
}
return $res = ContractService::setWord($param['fieldData'], $param['tem_id']);
}catch(\Exception $e){
return jsonError($e->getMessage());
}
}
后端逻辑层方法
public static function setWord($data,$met_id){
$template = Db::name('template')->where(['id'=>$met_id])->find();
if(empty($template['file_url'])){
throw new Exception('没有模板文件');
}
// 加载Word文档
$template_path = public_path().'storage/'.$template['file_url'];
if(!file_exists($template_path)){
throw new Exception(public_path().'storage/'.$template['file_url']);
}
//读取模版word的版本最好是docx,要不然可能会读取不了
$templateProcessor = new TemplateProcessor($template_path);
$data_str = "";
foreach ($data as $k => $v) { //读取模版word的版本最好是docx,要不然可能会读取不了
$newname = !empty($v['newname']) ? $v['newname']: '';
$templateProcessor->setValue($v['key'], $newname); //替换模板中的变量,对应word里的 ${xxxx}
$data_str .= $v['key'].$newname;
}
$save_name = GetRandStr(5).'_'.time() . '.docx'; //保存的文件名
$return_path = 'storage/temword/'.date('Ymd').'/'; //保存的文件路径
$savepath = public_path() . $return_path;
if (!is_dir($savepath)) {
@mkdir($savepath,0777);
}
$templateProcessor->saveAs($savepath.$save_name); //将内容保存到生成新的word中
$data_md5 = md5($met_id.$data_str);
// 缓存文件名
Cache::set($data_md5, $return_path.$save_name, 3600);
// 或输出到浏览器
header('Content-Description: File Transfer');
header('Content-Type: application/vnd.openxmlformats-officedocument.wordprocessingml.document');
header('Content-Disposition: attachment; filename="output.docx"');
header('Cache-Control: must-revalidate');
header('Pragma: public');
header('Expires: 0');
readfile($savepath.$save_name);
exit;
}
接口返回的是文件流,前端插件可直接使用