物品扫码领用与库存
This commit is contained in:
@@ -0,0 +1,186 @@
|
||||
<?php
|
||||
|
||||
namespace app\common\service;
|
||||
|
||||
use support\exception\BusinessException;
|
||||
|
||||
/**
|
||||
* 二维码生成服务
|
||||
*/
|
||||
class QrCodeService
|
||||
{
|
||||
/**
|
||||
* 生成物品二维码
|
||||
*
|
||||
* @param int $itemId 物品ID
|
||||
* @param string $appUrl 应用访问地址
|
||||
* @return string 二维码内容URL
|
||||
*/
|
||||
public function generateItemQrCode(int $itemId, string $appUrl): string
|
||||
{
|
||||
return rtrim($appUrl, '/') . '/mobile/inv/claim/' . $itemId;
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成二维码图片并上传到 OSS
|
||||
*
|
||||
* @param int $itemId 物品ID
|
||||
* @param string $content 二维码内容
|
||||
* @param string $fileName 文件名
|
||||
* @return array 返回OSS路径和完整URL
|
||||
* @throws BusinessException
|
||||
*/
|
||||
public function generateAndUploadQrCode(int $itemId, string $content, string $fileName): array
|
||||
{
|
||||
// 使用 endroid/qr-code 库生成二维码
|
||||
// 如果未安装,使用 API 方式生成
|
||||
|
||||
$tempPath = $this->generateQrCodeImage($content, $fileName);
|
||||
|
||||
if (!$tempPath) {
|
||||
throw new BusinessException('二维码生成失败');
|
||||
}
|
||||
|
||||
try {
|
||||
// 上传到 OSS
|
||||
$ossService = new OssService();
|
||||
$ossPath = 'qr/' . $fileName;
|
||||
$ossUrl = $ossService->uploadImage($tempPath, $ossPath);
|
||||
|
||||
// 删除临时文件
|
||||
if (file_exists($tempPath)) {
|
||||
unlink($tempPath);
|
||||
}
|
||||
|
||||
return [
|
||||
'path' => $ossPath,
|
||||
'url' => $ossUrl,
|
||||
];
|
||||
} catch (\Throwable $e) {
|
||||
// 删除临时文件
|
||||
if (file_exists($tempPath)) {
|
||||
unlink($tempPath);
|
||||
}
|
||||
throw new BusinessException('二维码上传失败:' . $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成二维码图片(使用 QR Server API 或本地库)
|
||||
*
|
||||
* @param string $content 二维码内容
|
||||
* @param string $fileName 文件名
|
||||
* @return string 临时文件路径,失败返回 false
|
||||
*/
|
||||
private function generateQrCodeImage(string $content, string $fileName)
|
||||
{
|
||||
$tempDir = runtime_path() . '/qr_temp/';
|
||||
if (!is_dir($tempDir)) {
|
||||
mkdir($tempDir, 0755, true);
|
||||
}
|
||||
|
||||
$tempPath = $tempDir . $fileName;
|
||||
|
||||
// 方式1: 使用 endroid/qr-code 库(推荐)
|
||||
if (class_exists('\Endroid\QrCode\QrCode')) {
|
||||
return $this->generateWithEndroid($content, $tempPath);
|
||||
}
|
||||
|
||||
// 方式2: 使用在线 API(备用方案)
|
||||
return $this->generateWithApi($content, $tempPath);
|
||||
}
|
||||
|
||||
/**
|
||||
* 使用 endroid/qr-code 生成二维码
|
||||
*/
|
||||
private function generateWithEndroid(string $content, string $tempPath): string
|
||||
{
|
||||
try {
|
||||
// 5.x 版本使用静态工厂方法
|
||||
if (method_exists(\Endroid\QrCode\QrCode::class, 'create')) {
|
||||
$qrCode = \Endroid\QrCode\QrCode::create($content)
|
||||
->setSize(300)
|
||||
->setMargin(10);
|
||||
} else {
|
||||
// 4.x 及以下版本
|
||||
$qrCode = new \Endroid\QrCode\QrCode($content);
|
||||
if (method_exists($qrCode, 'setSize')) {
|
||||
$qrCode->setSize(300);
|
||||
}
|
||||
if (method_exists($qrCode, 'setMargin')) {
|
||||
$qrCode->setMargin(10);
|
||||
}
|
||||
}
|
||||
|
||||
// 获取 Writer
|
||||
if (class_exists('\Endroid\QrCode\Writer\PngWriter')) {
|
||||
$writer = new \Endroid\QrCode\Writer\PngWriter();
|
||||
} else {
|
||||
// 旧版本可能使用不同的命名空间
|
||||
$writer = new \Endroid\QrCode\Writer();
|
||||
}
|
||||
|
||||
$result = $writer->write($qrCode);
|
||||
|
||||
// 保存文件
|
||||
if (method_exists($result, 'getString')) {
|
||||
file_put_contents($tempPath, $result->getString());
|
||||
} else {
|
||||
// 更旧版本可能直接返回字符串
|
||||
file_put_contents($tempPath, $result);
|
||||
}
|
||||
|
||||
return $tempPath;
|
||||
} catch (\Throwable $e) {
|
||||
// 如果 endroid 库使用失败,回退到在线 API
|
||||
error_log('endroid/qr-code 生成失败: ' . $e->getMessage() . ',使用在线 API 备用方案');
|
||||
return $this->generateWithApi($content, $tempPath);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 使用在线 API 生成二维码(备用方案)
|
||||
*/
|
||||
private function generateWithApi(string $content, string $tempPath): string
|
||||
{
|
||||
$apiUrl = 'https://api.qrserver.com/v1/create-qr-code/?';
|
||||
$params = [
|
||||
'size' => '300x300',
|
||||
'data' => $content,
|
||||
'margin' => '10',
|
||||
];
|
||||
|
||||
$url = $apiUrl . http_build_query($params);
|
||||
|
||||
$ch = curl_init();
|
||||
curl_setopt($ch, CURLOPT_URL, $url);
|
||||
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
||||
curl_setopt($ch, CURLOPT_TIMEOUT, 30);
|
||||
$imageData = curl_exec($ch);
|
||||
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
|
||||
curl_close($ch);
|
||||
|
||||
if ($httpCode !== 200 || !$imageData) {
|
||||
return false;
|
||||
}
|
||||
|
||||
file_put_contents($tempPath, $imageData);
|
||||
return $tempPath;
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除 OSS 上的二维码文件
|
||||
*
|
||||
* @param string $ossPath OSS路径
|
||||
* @return bool
|
||||
*/
|
||||
public function deleteQrCode(string $ossPath): bool
|
||||
{
|
||||
try {
|
||||
$ossService = new OssService();
|
||||
return $ossService->deleteFile($ossPath);
|
||||
} catch (\Throwable $e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user