diff --git a/application/api/controller/Order.php b/application/api/controller/Order.php index e25246f..b3613c7 100644 --- a/application/api/controller/Order.php +++ b/application/api/controller/Order.php @@ -81,26 +81,87 @@ class Order extends base{ if(!$rule->check($data)){ return jsonError($rule->getError()); } - $time = time(); $param = "pi=616562&ms=".$data['ms']; - - $hmac = hash_hmac('sha512', $time."paystation".$param, Env::get("paystation.hmac")); - $url = "https://payments.paystation.co.nz/lookup?".$param."&pstn_HMAC=".$hmac."&pstn_HMACTimestamp=".$time; + $url = "https://payments.paystation.co.nz/lookup?".$param; $res = myGet($url); return jsonSuccess($res); } - public function testtest(){ + public function testPaystationLookup1(){ + $data = $this->request->post(); $rule = new Validate([ - "id"=>"require" + "transaction_id"=>"require" ]); if(!$rule->check($data)){ return jsonError($rule->getError()); } - $res = paystationLookup($data['id']); - return jsonSuccess(object_to_array(json_decode($res))); +// $accessToken = createPayStationToken(); +// $curl = curl_init(); +// curl_setopt_array($curl, array( +// CURLOPT_URL => 'https://api.paystation.co.nz/v1/transactions/'.$data['transaction_id'], +// CURLOPT_RETURNTRANSFER => true, +// CURLOPT_ENCODING => '', +// CURLOPT_MAXREDIRS => 10, +// CURLOPT_TIMEOUT => 0, +// CURLOPT_FOLLOWLOCATION => true, +// CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1, +// CURLOPT_CUSTOMREQUEST => 'GET', +// CURLOPT_HTTPHEADER => array( +// 'Content-Type: application/json', +// 'Authorization: Bearer '.$accessToken +// ) +// )); +// $response = curl_exec($curl); +// curl_close($curl); + $response = paystationLookup($data['transaction_id']); + + $res = object_to_array(json_decode($response)); + return jsonSuccess($res); + } + + public function testPays(){ + $data = $this->request->post(); + $rule = new Validate([ + "ms"=>"require" + ]); + if(!$rule->check($data)){ + return jsonError($rule->getError()); + } + + $url = "https://payments.paystation.co.nz/lookup/"; + $time = time(); + $params = [ + "pi" => "616562", + "ms" => $data['ms'], + "pstn_HMACTimestamp" => $time + ]; + $secret_key = Env::get("paystation.hmac");// 使用提供的HMAC认证密钥 +// function calculate_hmac($key, $message) { +// return hash_hmac('sha256', $message, $key); +// } + $query_string = http_build_query($params); + $hmac_signature = hash_hmac('sha256', $time."paystation".$query_string,$secret_key); + $params["pstn_HMAC"] = $hmac_signature; + $url_with_params = $url . '?' . http_build_query($params); + + echo $url_with_params; + + $ch = curl_init(); + curl_setopt($ch, CURLOPT_URL, $url_with_params); + curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); + $response = curl_exec($ch); + if(curl_errno($ch)) { + echo 'Error:' . curl_error($ch); + } else { + echo "Response: " . $response; + } + curl_close($ch); + + return jsonSuccess($response); + + } @@ -263,12 +324,6 @@ class Order extends base{ return jsonSuccess($frag); } - public function myPrin(){ - echo prin(600); - } - - - private function creatPaystation($article_id){ $article_info = $this->article_obj->where("article_id",$article_id)->find(); $journal_info = $this->journal_obj->where("journal_id",$article_info['journal_id'])->find(); @@ -377,20 +432,6 @@ class Order extends base{ return jsonSuccess([]); } - public function mytest(){ - $data = $this->request->post(); - $rule = new Validate([ - "order_id"=>"require" - ]); - if(!$rule->check($data)){ - return jsonError($rule->getError()); - } - $info = $this->order_obj->where("order_id",$data['order_id'])->find(); - $re = $this->getOrderStatus($info['paypal_order_id']); - return jsonSuccess($re); - } - - private function getOrderStatus($orderId){ $client = $this->createClient(); return $client->getOrdersController()->ordersGet(["id"=>$orderId]); diff --git a/application/api/controller/Preaccept.php b/application/api/controller/Preaccept.php index 9f08e11..0d13b83 100644 --- a/application/api/controller/Preaccept.php +++ b/application/api/controller/Preaccept.php @@ -733,7 +733,14 @@ class Preaccept extends Base } - + /**预接收前对文章的支付信息,审核以及相关操作 + * @return \think\response\Json + * @throws \think\Exception + * @throws \think\db\exception\DataNotFoundException + * @throws \think\db\exception\ModelNotFoundException + * @throws \think\exception\DbException + * @throws \think\exception\PDOException + */ public function getPreacceptPayment(){ $data = $this->request->post(); $rule = new Validate([ @@ -744,28 +751,44 @@ class Preaccept extends Base } $article_info = $this->article_obj->where("article_id",$data['article_id'])->find(); $journal_info = $this->journal_obj->where("journal_id",$article_info['journal_id'])->find(); - if(intval($journal_info['fee'])==0||$article_info['ctime']<1735660800){ + if(intval($journal_info['fee'])==0||$article_info['ctime']<1735660800){//非收费期刊的文章直接返回 $re['state'] = 1; $re['order'] = null; $re["fee"] = 0; return jsonSuccess($re); } $order_info = $this->order_obj->where("article_id",$article_info['article_id'])->find(); - if($order_info['pay_type']==2){ + if($order_info==null){ + $re['state'] = 0; + $re['order'] = null; + $re["fee"] = 0; + return jsonSuccess($re); + } +// if($order_info['pay_type']==2){ $paystation = $this->paystation_obj->where("ps_id",$order_info['ps_id'])->find(); + $order_info['paystation'] = $paystation; if($order_info['state']==0){ $res = object_to_array(json_decode(paystationLookup($paystation['transaction_id']))); if(isset($res['result']['success'])&&$res['result']['success']){ $this->article_obj->where("article_id",$order_info['article_id'])->update(['is_buy'=>1]); $this->order_obj->where("order_id",$order_info['order_id'])->update(['state'=>1]); + $re['state'] = 1; + $re['fee'] = $journal_info['fee']; + $re['order'] = $order_info; + return jsonSuccess($re); + }else{ + $re['state'] = 0; + $re['fee'] = $journal_info['fee']; + $re['order'] = $order_info; + return jsonSuccess($re); } + }else{ + $re['state'] = 1; + $re['fee'] = $journal_info['fee']; + $re['order'] = $order_info; + return jsonSuccess($re); } - $order_info['paystation'] = $paystation; - } - $re['state'] = $order_info?$order_info['state']:$article_info['is_buy']; - $re['fee'] = $journal_info['fee']; - $re['order'] = $order_info; - return jsonSuccess($re); +// } } diff --git a/application/api/controller/Production.php b/application/api/controller/Production.php index 83fe7d2..036d26e 100644 --- a/application/api/controller/Production.php +++ b/application/api/controller/Production.php @@ -1247,6 +1247,338 @@ class Production extends Base // return jsonSuccess([]); // } +/** + * 生成LaTeX文档并转换为PDF + * @return \think\response\Json + */ +public function generateLatexPdf() +{ + $data = $this->request->post(); + $rule = new Validate([ + 'p_article_id' => 'require|number' + ]); + + if (!$rule->check($data)) { + return jsonError($rule->getError()); + } + + try { + // 获取文章信息 + $p_info = $this->production_article_obj->where('p_article_id', $data['p_article_id'])->find(); + if (!$p_info) { + return jsonError('文章实例不存在'); + } + + // 获取作者信息 + $authors = $this->production_article_author_obj->where('p_article_id', $data['p_article_id'])->where('state', 0)->select(); + + // 获取机构信息 + $organs = $this->production_article_organ_obj->where('p_article_id', $data['p_article_id'])->where('state', 0)->select(); + + // 获取正文内容 + $main_contents = $this->production_article_main_obj->where('p_article_id', $data['p_article_id'])->where('state', 0)->order('p_main_id')->select(); + + // 获取参考文献 + $references = $this->production_article_refer_obj->where('p_article_id', $data['p_article_id'])->where('state', 0)->order('index')->select(); + + // 构建LaTeX内容 + $latex_content = $this->buildLatexContent($p_info, $authors, $organs, $main_contents, $references); + + // 创建临时目录 + $temp_dir = ROOT_PATH . 'public' . DS . 'temp_latex' . DS; + if (!is_dir($temp_dir)) { + mkdir($temp_dir, 0755, true); + } + + // 生成唯一的文件名 + $filename = 'article_' . $p_info['p_article_id'] . '_' . time(); + $tex_file = $temp_dir . $filename . '.tex'; + $pdf_file = $temp_dir . $filename . '.pdf'; + + // 写入LaTeX文件 + file_put_contents($tex_file, $latex_content); + + // 执行LaTeX编译命令生成PDF + $command = sprintf( + 'cd %s && pdflatex -interaction=nonstopmode -output-directory=%s %s', + escapeshellarg($temp_dir), + escapeshellarg($temp_dir), + escapeshellarg($tex_file) + ); + + // 执行命令 + $output = []; + $return_var = 0; + exec($command, $output, $return_var); + + // 检查PDF是否生成成功 + if (!file_exists($pdf_file) || filesize($pdf_file) == 0) { + return jsonError('PDF生成失败,请检查LaTeX内容或系统环境'); + } + + // 移动PDF到正式目录 + $pdf_dir = ROOT_PATH . 'public' . DS . 'latex_pdfs' . DS; + if (!is_dir($pdf_dir)) { + mkdir($pdf_dir, 0755, true); + } + + $final_pdf_path = $pdf_dir . $filename . '.pdf'; + rename($pdf_file, $final_pdf_path); + + // 清理临时文件 + if (file_exists($tex_file)) { + unlink($tex_file); + } + + // 清理辅助文件(.aux, .log等) + $aux_file = $temp_dir . $filename . '.aux'; + $log_file = $temp_dir . $filename . '.log'; + if (file_exists($aux_file)) unlink($aux_file); + if (file_exists($log_file)) unlink($log_file); + + // 返回PDF路径 + $relative_path = 'latex_pdfs/' . $filename . '.pdf'; + return jsonSuccess([ + 'pdf_url' => $relative_path, + 'message' => 'PDF生成成功' + ]); + + } catch (\Exception $e) { + return jsonError('生成过程中发生错误: ' . $e->getMessage()); + } +} + +/** + * 构建LaTeX文档内容 + * @param $p_info + * @param $authors + * @param $organs + * @param $main_contents + * @param $references + * @return string + */ +private function buildLatexContent($p_info, $authors, $organs, $main_contents, $references) +{ + // 构建机构映射 + $organ_map = []; + foreach ($organs as $index => $organ) { + $organ_map[$organ['p_article_organ_id']] = $index + 1; + } + + // LaTeX文档开始 + $latex = '\documentclass[twocolumn]{article}' . "\n"; + $latex .= '\usepackage[utf8]{inputenc}' . "\n"; + $latex .= '\usepackage[T1]{fontenc}' . "\n"; + $latex .= '\usepackage{geometry}' . "\n"; + $latex .= '\usepackage{graphicx}' . "\n"; + $latex .= '\usepackage{amsmath}' . "\n"; + $latex .= '\usepackage{amsfonts}' . "\n"; + $latex .= '\usepackage{amssymb}' . "\n"; + $latex .= '\usepackage{setspace}' . "\n"; + $latex .= '\usepackage{titlesec}' . "\n"; + $latex .= '\usepackage{hyperref}' . "\n"; + $latex .= '\usepackage{caption}' . "\n"; + $latex .= '\usepackage{multicol}' . "\n"; + $latex .= '\usepackage{abstract}' . "\n"; + + $latex .= '\geometry{left=1.5cm,right=1.5cm,top=2.5cm,bottom=2.5cm}' . "\n"; + $latex .= '\setstretch{1.5}' . "\n"; + + $latex .= '\title{' . $this->escapeLatexText($p_info['title']) . '}' . "\n"; + + // 处理作者和机构 + if (!empty($authors)) { + $author_text = ''; + $affiliations = []; + + foreach ($authors as $author) { + if ($author_text !== '') { + $author_text .= ', '; + } + $author_text .= $this->escapeLatexText($author['first_name'] . ' ' . $author['last_name']); + + // 获取作者的机构 + $author_organs = $this->production_article_author_to_organ_obj + ->where('p_article_author_id', $author['p_article_author_id']) + ->where('state', 0) + ->select(); + + foreach ($author_organs as $ao) { + if (isset($organ_map[$ao['p_article_organ_id']])) { + $author_text .= '$^{' . $organ_map[$ao['p_article_organ_id']] . '}$'; + } + } + + if ($author['is_report'] == 1) { + $author_text .= '$^{*}$'; + } + } + + $latex .= '\author{' . $author_text . "\n"; + + // 添加机构信息 + foreach ($organs as $index => $organ) { + $latex .= '\\\\$' . ($index + 1) . '$ ' . $this->escapeLatexText($organ['organ_name']) . "\n"; + } + if (!empty($authors)) { + // 查找通讯作者 + $corresponding_authors = array_filter($authors, function($author) { + return $author['is_report'] == 1; + }); + + if (!empty($corresponding_authors)) { + $corr_author = reset($corresponding_authors); + $latex .= '\\\\$*$ Corresponding author: ' . + $this->escapeLatexText($corr_author['email']) . "\n"; + } + } + + $latex .= '}' . "\n"; + } + + $latex .= '\date{}' . "\n"; + $latex .= '\begin{document}' . "\n"; + $latex .= '\maketitle' . "\n"; + + // 摘要 + if (!empty($p_info['abstract'])) { + $latex .= '\begin{abstract}' . "\n"; + $latex .= $this->escapeLatexText($p_info['abstract']) . "\n"; + $latex .= '\end{abstract}' . "\n"; + } + + // 关键词 + if (!empty($p_info['keywords'])) { + $latex .= '\textbf{Keywords:} ' . $this->escapeLatexText($p_info['keywords']) . "\n"; + $latex .= '\sectionbreak' . "\n"; + } + + // 正文内容 + $in_section = false; + $section_count = 0; + + foreach ($main_contents as $content) { + $text = trim($content['content']); + + // 跳过空内容 + if (empty($text)) { + continue; + } + + // 检查是否是标题 + $clean_text = strip_tags($text); + $lower_text = strtolower($clean_text); + + // 判断是否为章节标题 + if (stripos($lower_text, 'introduction') === 0 || + stripos($lower_text, 'methods') === 0 || + stripos($lower_text, 'results') === 0 || + stripos($lower_text, 'discussion') === 0 || + stripos($lower_text, 'conclusion') === 0 || + stripos($lower_text, 'references') === 0) { + + // 结束前一节 + if ($in_section) { + $latex .= "\n" . '\sectionbreak' . "\n"; + } + + // 开始新节 + $section_count++; + $section_title = $this->escapeLatexText($clean_text); + $latex .= '\section{' . $section_title . '}' . "\n"; + $in_section = true; + } + // 检查是否是图片或表格占位符 + else if (preg_match('/]*imageId=[\'"]([^\'"]+)[\'"][^>]*>/i', $text, $img_matches)) { + $image_id = $img_matches[1]; + // 这里可以添加图片处理逻辑 + $latex .= '% 图片插入位置 (ID: ' . $image_id . ')' . "\n"; + $latex .= '\begin{figure}[htbp]' . "\n"; + $latex .= '\centering' . "\n"; + $latex .= '\includegraphics[width=0.8\textwidth]{image_' . $image_id . '}' . "\n"; + $latex .= '\caption{图片说明}' . "\n"; + $latex .= '\end{figure}' . "\n"; + } + else if (preg_match('/]*tableId=[\'"]([^\'"]+)[\'"][^>]*>/i', $text, $table_matches)) { + $table_id = $table_matches[1]; + // 这里可以添加表格处理逻辑 + $latex .= '% 表格插入位置 (ID: ' . $table_id . ')' . "\n"; + $latex .= '\begin{table}[htbp]' . "\n"; + $latex .= '\centering' . "\n"; + $latex .= '\caption{表格说明}' . "\n"; + $latex .= '\begin{tabular}{|c|c|c|}' . "\n"; + $latex .= '\hline' . "\n"; + $latex .= '列1 & 列2 & 列3 \\\\' . "\n"; + $latex .= '\hline' . "\n"; + $latex .= '% 表格数据' . "\n"; + $latex .= '\hline' . "\n"; + $latex .= '\end{tabular}' . "\n"; + $latex .= '\end{table}' . "\n"; + } + // 普通段落文本 + else { + // 移除HTML标签并转义特殊字符 + $plain_text = $this->escapeLatexText(strip_tags($text)); + $latex .= $plain_text . "\n\n"; + } + } + + // 参考文献 + if (!empty($references)) { + $latex .= '\section*{References}' . "\n"; + $latex .= '\begin{thebibliography}{99}' . "\n"; + + foreach ($references as $index => $ref) { + $ref_text = isset($ref['refer_frag']) ? $ref['refer_frag'] : $ref['refer_content']; + $latex .= '\bibitem{} ' . $this->escapeLatexText($ref_text) . "\n"; + } + + $latex .= '\end{thebibliography}' . "\n"; + } + + $latex .= '\end{document}' . "\n"; + + return $latex; +} + +/** + * 转义LaTeX特殊字符 + * @param string $text + * @return string + */ +private function escapeLatexText($text) +{ + // 移除HTML标签 + $text = strip_tags($text); + + // 转义LaTeX特殊字符 + $escape_chars = [ + '\\' => '\\textbackslash{}', + '&' => '\\&', + '%' => '\\%', + '$' => '\\$', + '#' => '\\#', + '_' => '\\_', + '{' => '\\{', + '}' => '\\}', + '~' => '\\textasciitilde{}', + '^' => '\\textasciicircum{}', + '"' => '\\"{}', + '\'' => '\\\'{}', + '<' => '\\textless{}', + '>' => '\\textgreater{}', + ]; + + foreach ($escape_chars as $char => $replacement) { + $text = str_replace($char, $replacement, $text); + } + + return $text; +} + + + + public function addProductTopic(){ $data = $this->request->post(); $rule = new Validate([