diff --git a/app/common/controller/UsedCarController.php b/app/common/controller/UsedCarController.php index 13fd88d..3e4955d 100644 --- a/app/common/controller/UsedCarController.php +++ b/app/common/controller/UsedCarController.php @@ -6,9 +6,11 @@ use app\common\model\UsedCar; use app\common\model\UsedCarPdfLog; use app\common\model\User; use app\common\service\OssService; +use app\common\service\SparkService; use app\common\traits\crud\CrudControllerTrait; use app\common\service\UsedCarService; use app\common\utils\pdf\service\MpdfDriver; +use app\queue\utils\XunfeiFanyi; use support\exception\BusinessException; use support\Request; @@ -22,6 +24,19 @@ class UsedCarController extends BaseController protected $noNeedHeaderData = ['downloadPdf']; + protected $lang = [ + 'en' => '英语', + 'ru' => '俄语', + 'es' => '西班牙语', + 'ar' => '阿拉伯语', + ]; + protected $currency = [ + 'USD' => '$', + 'RUB' => '₽', + 'AED' => 'د.إ', + 'EUR' => '€', + ]; + public function __construct() { $this->service = new UsedCarService(); @@ -114,9 +129,17 @@ class UsedCarController extends BaseController public function producePdf(Request $request){ try { $price = $request->get('price'); + $lang = $request->get('lang'); + $currency = $request->get('currency'); if(empty($price)){ throw new BusinessException("请输入生成pdf中的价格"); } + if(empty($lang) || empty($this->lang[$lang])){ + throw new BusinessException("语种错误"); + } + if(empty($currency) || empty($this->currency[$currency])){ + throw new BusinessException("币种错误"); + } $raw = $this->service->serviceShow($request); $data = $this->transformData($raw, method_exists($this, 'showFormat') ? [$this, 'showFormat'] @@ -146,7 +169,12 @@ class UsedCarController extends BaseController $user['social_code'] = $ossService->generatePrivateUrl($user['social_code']); $user['social_code'] = $this->service->downloadImage($user['social_code']); } - $pdf = (new MpdfDriver())->exportUsedCarPdf($data,$user,$contact); + + $field = $this->field($lang);//字段相关外文 + $field['currency'] = $this->currency[$currency]; + $data = $this->fanyi($data, $lang);//车辆字段翻译外文 + $contactField = $this->contact($lang); //名片相关外文 + $pdf = (new MpdfDriver())->exportUsedCarPdf($field,$data,$user,$contactField,$contact,$lang); UsedCar::where('id', $data['id'])->update(['pdf_src' => $pdf]); array_map('unlink', glob(runtime_path('pdf/images/*.jpg'))); @@ -160,7 +188,7 @@ class UsedCarController extends BaseController ]); return $this->success($pdf); } catch (\Throwable $e) { - return $this->error($e->getMessage()); + return $this->error($e->getMessage().$e->getLine().$e->getFile()); } } @@ -178,6 +206,174 @@ class UsedCarController extends BaseController ); } + public function fanyi($data, $to){ + foreach ($data as $k => $v) { + if (in_array($k, ['product_name', 'source_place', 'body_color', 'condition_desc']) && !empty(trim($v))) { +// $xunfei = new XunfeiFanyi(); +// $data[$k] = $xunfei->fanyi($v, $from = 'cn', $to); + + $toLang = $this->lang[$to]; + $spark = new SparkService(); + $str = $spark->chat("将“{$v}”翻译为{$toLang},不要有多余的描述"); + if(!empty($str)){ + $str = preg_replace('/[\x{4e00}-\x{9fa5}]/u', '', $str); + $data[$k] =str_replace(['(',')','(',')','"'], '', $str); + }else{ + $data[$k] = ''; + } + } + } + return $data; + } + + /** + * 字段名 + * @param $data + * @param $to + * @return mixed + */ + public function field($to){ + $field = [ + 'cn' => [ + 'price' => '车价', + 'source_place' => '车源地', + 'plate_time' => '上牌时间', + 'displacement' => '排量', + 'mileage' => '里程', + 'power' => '马力', + 'body_color' => '车身颜色', + 'created_at' => '创建时间', + 'condition_desc' => '车况介绍', + 'images' => '产品图', + ], + + 'en' => [ + 'price' => 'Price', + 'source_place' => 'Vehicle Location', + 'plate_time' => 'Registration Date', + 'displacement' => 'Engine Displacement', + 'mileage' => 'Mileage', + 'power' => 'Horsepower', + 'body_color' => 'Body Color', + 'created_at' => 'Created At', + 'condition_desc' => 'Vehicle Condition', + 'images' => 'Product image', + ], + + 'ru' => [ + 'price' => 'Цена', + 'source_place' => 'Местонахождение автомобиля', + 'plate_time' => 'Дата регистрации', + 'displacement' => 'Объём двигателя', + 'mileage' => 'Пробег', + 'power' => 'Мощность', + 'body_color' => 'Цвет кузова', + 'created_at' => 'Дата создания', + 'condition_desc' => 'Состояние автомобиля', + 'images' => 'Фотографии', + ], + + 'es' => [ + 'price' => 'Precio', + 'source_place' => 'Ubicación del vehículo', + 'plate_time' => 'Fecha de matriculación', + 'displacement' => 'Cilindrada', + 'mileage' => 'Kilometraje', + 'power' => 'Potencia', + 'body_color' => 'Color de la carrocería', + 'created_at' => 'Fecha de creación', + 'condition_desc' => 'Estado del vehículo', + 'images' => 'Imagen del producto', + ], + + 'ar' => [ + 'price' => 'السعر', + 'source_place' => 'موقع السيارة', + 'plate_time' => 'تاريخ التسجيل', + 'displacement' => 'سعة المحرك', + 'mileage' => 'المسافة المقطوعة', + 'power' => 'قوة المحرك', + 'body_color' => 'لون الهيكل', + 'created_at' => 'تاريخ الإنشاء', + 'condition_desc' => 'حالة السيارة', + 'images' => 'خريطة المنتج', + ], + ]; + return $field[$to]; +// foreach ($field as $k => $v) { +//// $xunfei = new XunfeiFanyi(); +//// $field[$k] = $xunfei->fanyi($v, $from = 'cn', $to); +// $toLang = $this->lang[$to]; +// $spark = new SparkService(); +// $field[$k] = $spark->chat("“{$v}”翻译为{$toLang},不要有多余的描述"); +// } +// return $field; + } + + /** + * 名片外文 + */ + public function contact($to){ + $contactField = [ + 'cn' => [ + 'title' => '联系人名片', + 'name' => '姓名', + 'email' => '邮箱', + 'phone' => '电话', + 'WhatsApp' => 'WhatsApp', + 'code' => '二维码', + 'left' => '扫码即可联系本人', + 'right' => '本资料随PDF自动生成', + ], + + 'en' => [ + 'title' => 'Contact Name Card', + 'name' => 'Name', + 'email' => 'Email', + 'phone' => 'Phone', + 'WhatsApp' => 'WhatsApp', + 'code' => 'QR Code', + 'left' => 'Scan the code to contact me', + 'right' => 'This information is automatically generated with the PDF', + ], + + 'ru' => [ + 'title' => 'Контактная карточка', + 'name' => 'Имя', + 'email' => 'Электронная почта', + 'phone' => 'Телефон', + 'WhatsApp' => 'WhatsApp', + 'code' => 'QR-код', + 'left' => 'Код позволяет связаться с самим собой.', + 'right' => 'Эта информация автоматически генерируется с помощью PDF', + ], + + 'es' => [ + 'title' => 'Tarjeta de visita de contacto', + 'name' => 'Nombre', + 'email' => 'Correo electrónico', + 'phone' => 'Teléfono', + 'WhatsApp' => 'WhatsApp', + 'code' => 'Código QR', + 'left' => 'Escanee el Código para contactarme.', + 'right' => 'Esta información se genera automáticamente con pdf', + ], + + 'ar' => [ + 'title' => 'بطاقة الاتصال', + 'name' => 'الاسم', + 'email' => 'البريد الإلكتروني', + 'phone' => 'الهاتف', + 'WhatsApp' => 'واتساب', + 'code' => 'رمز QR', + 'left' => 'اكتساح رمز الاتصال بي', + 'right' => 'هذه المعلومات تلقائيا مع قوات الدفاع الشعبي', + ], + ]; + + return $contactField[$to]; + } + public function getPdf(Request $request) { try { @@ -199,9 +395,16 @@ class UsedCarController extends BaseController if (!file_exists($publicFile)) { copy($filePath, $publicFile); } + + // 从连接中获取协议(最可靠) + $connection = $request->connection; + $protocol = 'https'; + if ($connection && property_exists($connection, 'transport')) { + $protocol = $connection->transport === 'ssl' ? 'https' : 'http'; + } // 返回访问地址 - $baseUrl = 'http://' . request()->header('host'); + $baseUrl = $protocol.'://' . request()->header('host'); $url = $baseUrl . '/pdf/' . $raw['pdf_src']; return $this->success([ diff --git a/app/common/service/SparkService.php b/app/common/service/SparkService.php new file mode 100644 index 0000000..171eae5 --- /dev/null +++ b/app/common/service/SparkService.php @@ -0,0 +1,82 @@ +apiPassword = $config['api_password']; + $this->model = $config['model']; + + // 使用 Guzzle 客户端,base_uri 指向 Spark API + $this->client = new Client([ + 'base_uri' => $config['base_uri'], + 'timeout' => 30, + 'verify' => false, + ]); + } + + /** + * 发送聊天请求 + * + * @param string $message 用户输入文本 + * @param string|null $userId 可选的用户唯一 ID + * @param array $options 其他可选参数(temperature 等) + * @return 返回 API 解析后的结果 + */ + public function chat(string $message, ?string $userId = null, array $options = [],string $file = 'spark') + { + $payload = array_merge([ + 'model' => $this->model, + 'messages' => [ + [ + 'role' => 'user', + 'content' => $message, + ] + ], + // 可根据需要设置 + 'temperature' => 1.0, + 'top_k' => 4, + ], $options); + + if ($userId !== null) { + $payload['user'] = $userId; + } + + try { + $response = $this->client->post('chat/completions', [ + 'headers' => [ + 'Content-Type' => 'application/json', + 'Authorization' => "Bearer {$this->apiPassword}", + ], + 'json' => $payload, + ]); + + $body = (string) $response->getBody(); + $result = json_decode($body, true); + if($result['code'] != 0){ + flg('spark chat:'.$body,false,$file); + } + return $result['choices'][0]['message']['content']; + } catch (RequestException $e) { + // 错误处理 + $message = $e->getMessage(); + if ($e->hasResponse()) { + $message .= ' ' . $e->getResponse()->getBody(); + } + // log 或抛出异常都可以 + error_log("[SparkService] Chat Error: {$message}"); + return null; + } + } +} \ No newline at end of file diff --git a/app/common/service/UsedCarService.php b/app/common/service/UsedCarService.php index 804c980..0873d2b 100644 --- a/app/common/service/UsedCarService.php +++ b/app/common/service/UsedCarService.php @@ -60,7 +60,7 @@ class UsedCarService // 关键字 if (isset($p['keyword']) && $p['keyword']) { $k = '%' . $p['keyword'] . '%'; - foreach (['product_name'] as $col) { + foreach (['product_name','code'] as $col) { $config['orWhere'][] = [$col, 'like', $k]; } } @@ -107,6 +107,26 @@ class UsedCarService return $data; } + public function beforeServiceUpdate($data, Request $request): array + { + if (empty($data['product_name'])) { + throw new BusinessException('产品名称不能为空'); + } + if (empty($data['images'])) { + throw new BusinessException('产品图片不能为空'); + } + if (empty($data['price'])) { + $data['price'] = 0; + } + if (!empty($data['attachment'])) { + $data['attachment'] = json_encode($data['attachment']); + }else{ + $data['attachment'] = ''; + } + $data['mileage'] = str_replace(['K','M','k','m'], '', $data['mileage']); + return $data; + } + public function getcode($userId){ $userCount = Redis::get('used_car_count_'.$userId, 0); $todayStart = strtotime('today'); diff --git a/app/common/utils/XunfeiFanyi.php b/app/common/utils/XunfeiFanyi.php new file mode 100644 index 0000000..0b06ec2 --- /dev/null +++ b/app/common/utils/XunfeiFanyi.php @@ -0,0 +1,138 @@ + $header,'body' => $response); + return $data; + } + + + public function xfyun($text = "中华人民共和国于1949年成立", $from = "cn", $to = "en") + { + //在控制台-我的应用-机器翻译获取 + $app_id = "3d46198c"; + //在控制台-我的应用-机器翻译获取 + $api_sec = "ZWY2MmUyNjJjYmFkOTFlYTVmYWVhMGYy"; + //在控制台-我的应用-机器翻译获取 + $api_key = "b6d805f240176ecaea85130cb5f2bca1"; + // 机器翻译接口地址 + $url = "https://ntrans.xfyun.cn/v2/ots"; + //body组装 + // $text = "中华人民共和国于1949年成立";//待翻译文本 + $body = json_encode($this->getBody($app_id, $from, $to, $text)); + + // 组装http请求头 + $date =gmdate('D, d M Y H:i:s') . ' GMT'; + + $digestBase64 = "SHA-256=".base64_encode(hash("sha256", $body, true)); + $builder = sprintf("host: %s +date: %s +POST /v2/ots HTTP/1.1 +digest: %s", "ntrans.xfyun.cn", $date, $digestBase64); + // echo($builder); + $sha = base64_encode(hash_hmac("sha256", $builder, $api_sec, true)); + + $authorization = sprintf("api_key=\"%s\", algorithm=\"%s\", headers=\"%s\", signature=\"%s\"", $api_key,"hmac-sha256", + "host date request-line digest", $sha); + + $header = [ + "Authorization: ".$authorization, + 'Content-Type: application/json', + 'Accept: application/json,version=1.0', + 'Host: ntrans.xfyun.cn', + 'Date: ' .$date, + 'Digest: '.$digestBase64 + ]; + $response = $this->tocurl($url, $header, $body); + + // var_dump($response['body']); + return $response; + } + + + public function getBody($app_id, $from, $to, $text) + { + $common_param = [ + 'app_id' => $app_id + ]; + + $business = [ + 'from' => $from, + 'to' => $to, + ]; + + $data = [ + "text" => base64_encode($text) + ]; + + return $body = [ + 'common' => $common_param, + 'business' => $business, + 'data' => $data + ]; + } + + // 翻译 + public function fanyi($text = "", $from = "", $to = "") + { + try { + $res = $this->xfyun($text, $from, $to); + $data = json_decode($res["body"], true); + if ($data["code"] === 0) { + return $data["data"]["result"]; + } else { + $this->error = $data["message"]; + Log::error("XunfeiFanyi 失败: ".$data["message"],[$data]); + return false; + } + } catch (\Throwable $th) { + $this->error = $th->getMessage(); + Log::error("XunfeiFanyi 错误: ".$th->getMessage()); + return false; + } + } + + // 异常 + public function error() + { + return $this->error; + } + +} \ No newline at end of file diff --git a/app/common/utils/pdf/service/MpdfDriver.php b/app/common/utils/pdf/service/MpdfDriver.php index 436cb34..c25d0f9 100644 --- a/app/common/utils/pdf/service/MpdfDriver.php +++ b/app/common/utils/pdf/service/MpdfDriver.php @@ -116,7 +116,7 @@ class MpdfDriver return [$css, $html]; } - public function exportUsedCarPdf($car,$user,$contact) + public function exportUsedCarPdf($field,$car,$user,$contactField,$contact,$lang) { /*$car = [ 'title' => '奥迪Q3 2013款 35 TFSI 舒适型', @@ -157,7 +157,7 @@ class MpdfDriver $mpdf->SetProtection(//限制篡改或盗用 ['print'], // 允许的权限 copy:允许复制、print:允许打印 '', // 用户密码(可留空) - 'Admin@2026@!#' // 拥有者密码(一定要设置) + $car['code'] // 拥有者密码(一定要设置) ); //设置水印 @@ -186,7 +186,7 @@ class MpdfDriver $pdf = $mpdf->Output('车辆详情.pdf', 'S'); $dir = runtime_path('pdf'); if (!is_dir($dir)) mkdir($dir, 0777, true); - $pdfName = 'invoice-' . date('YmdHis').'-'.$car['id'] . '.pdf'; + $pdfName = 'invoice-' . date('YmdHis').'-'.$car['id'] . '-' . $lang . '.pdf'; $path = $dir . '/' . $pdfName; file_put_contents($path, $pdf); diff --git a/app/common/utils/pdf/template/contactCard.stub b/app/common/utils/pdf/template/contactCard.stub index 5b8c4f4..3c4f76c 100644 --- a/app/common/utils/pdf/template/contactCard.stub +++ b/app/common/utils/pdf/template/contactCard.stub @@ -52,17 +52,17 @@ -

联系人名片

+

-
姓名:
+
:
-
邮箱:
+
:
-
电话:
+
:
WhatsApp:
@@ -70,14 +70,14 @@
-
二维码
+
- 扫码即可联系本人 | 本资料随 PDF 自动生成 + |
diff --git a/app/common/utils/pdf/template/usedCar.stub b/app/common/utils/pdf/template/usedCar.stub index ed10ee5..06df83b 100644 --- a/app/common/utils/pdf/template/usedCar.stub +++ b/app/common/utils/pdf/template/usedCar.stub @@ -70,59 +70,85 @@ - - + + - + - + - + - + - + - + - +
车价¥
车源地
上牌时间
排量
里程
马力
车身颜色
创建时间
-

车况介绍

+ +

+ + -

产品图

- + + + + + + $img): ?> + + + + - - + + - - +
+
+ +
+
diff --git a/app/queue/utils/XunfeiFanyi.php b/app/queue/utils/XunfeiFanyi.php index e380d21..88783ba 100644 --- a/app/queue/utils/XunfeiFanyi.php +++ b/app/queue/utils/XunfeiFanyi.php @@ -82,7 +82,6 @@ digest: %s", "ntrans.xfyun.cn", $date, $digestBase64); ]; $response = $this->tocurl($url, $header, $body); - // var_dump($response['body']); return $response; } diff --git a/config/spark_lite.php b/config/spark_lite.php new file mode 100644 index 0000000..e21e8dd --- /dev/null +++ b/config/spark_lite.php @@ -0,0 +1,11 @@ + env('SPARK_API_PASSWORD', ''), + + // 请求基础 URL + 'base_uri' => 'https://spark-api-open.xf-yun.com/v1/', + + // 模型名称 + 'model' => 'lite', +];