request->param(); $data = []; if (isset($getData['card_number']) && !empty($getData['card_number'])) { $data[] = ['card_number', 'like', "%{$getData['card_number']}%"]; } if (isset($getData['batch']) && !empty($getData['batch'])) { $data[] = ['batch', 'like', "%{$getData['batch']}%"]; } if (isset($getData['user_id']) && $getData['user_id']) { $data[] = ['user_id', 'like', "%{$getData['user_id']}%"]; } if (isset($getData['is_used']) && $getData['is_used'] > 0) { $data[] = ['is_used', '=', "{$getData['is_used']}"]; } if (isset($getData['is_print']) && $getData['is_print'] > -1) { $data[] = ['is_print', '=', "{$getData['is_print']}"]; } $data[] = ['is_delete', '=', 0]; $list = $model->getList($data); return $this->renderSuccess(['list'=>$list]); } /** * 获取所有充值卡 * @return mixed * @throws \think\exception\DbException */ public function all(): Json { $user = $this->store['user']; $list = CardModel::getAll($user); return $this->renderSuccess(compact('list','user')); } /** * 充值卡详情 * @param int $cardId * @return Json * @throws BaseException * @throws \think\db\exception\DataNotFoundException * @throws \think\db\exception\DbException * @throws \think\db\exception\ModelNotFoundException * @throws \cores\exception\BaseException */ public function detail(int $cardId): Json { $cardInfo = CardModel::detail($cardId); return $this->renderSuccess(compact('cardInfo')); } /** * 删除充值卡 * @return Json * @throws \think\exception\DbException */ public function delete(): Json { $arr = $this->postData(); foreach ((array)$arr as $val){ $model = CardModel::detail($val); $model->setDelete(); } return $this->renderSuccess('删除成功'); } public function generateRandomString($length = 12, $big = false) { $bytes = openssl_random_pseudo_bytes($length * 2); // 生成足够长的字节数 return $big ? strtoupper(substr(bin2hex($bytes), 0, $length)) : substr(bin2hex($bytes), 0, $length); // 转换并截取所需长度 } /** * 添加充值卡 * @return array|mixed * @throws \think\Exception * @throws \think\db\exception\DataNotFoundException * @throws \think\db\exception\ModelNotFoundException * @throws \think\exception\DbException */ public function addCards() { $data = $this->postForm(); $pattern = '/^[1-9]\d*$/'; $amount = $data['amount']; if(!preg_match($pattern,(string)$amount)){ return $this->renderError('充值卡金额必须是正整数'); } if($amount <= 0){ return $this->renderError('充值卡金额不能小于等于0'); } if($amount > 1000){ return $this->renderError('充值卡金额不能大于1000'); } $cards = []; $data = []; $batch = $this->generateBatchNumber(); for ($i = 1;$i <= 18;$i++){ $cardNumber = $this->generateCardNumber(12,$cards); // 生成12位卡号 $plainSecretKey = $this->generateRandomString(16, true); // 生成16个字符长度的大写密钥 $data[] = [ 'batch' => $batch, 'card_number' => $cardNumber, 'secret_key' => $plainSecretKey, 'amount' => $amount, 'file_path' => $this->generateBarcode($plainSecretKey), ]; $cards[] = $cardNumber; } $model = new CardModel; // 新增记录 if (!$model->add($data,$this->store['user'])) { return $this->renderError('添加充值卡失败'); } $this->pdf($cards, $amount, $batch); return $this->renderSuccess('成功添加18张充值卡'); } /** 生成12位卡号 * @param int $length * @param array $cards * @return false|string */ public function generateCardNumber($length = 12, $cards = []) { $timestamp = substr((string)(microtime(true) * 10000), -6); // 从时间戳中获取6位数 $randomNumber = str_pad((string)rand(0, 999999), 6, '0', STR_PAD_LEFT); // 随机生成6位数 // 合成卡号 $cardNumber = $timestamp . $randomNumber; // 确保长度 $cardNumber = substr((string)$cardNumber, 0, $length); // 校验数据库是否存在该卡号 if ($this->checkCardExists($cardNumber, $cards)) { return $this->generateCardNumber($length, $cards); // 如果卡号已存在,重新生成 } return $cardNumber; } /** 检查卡号是否存在 * @param string $cardNumber * @param array $cards * @return bool */ public function checkCardExists($cardNumber, $cards) { return !(!in_array($cardNumber, $cards) && !CardModel::detail(['card_number'=>$cardNumber])); } /** 生成批次号 * @param string $prefix * @return string */ function generateBatchNumber($prefix = 'CARD') { $date = date('Ymd'); $randomNumber = str_pad((string)rand(0, 9999), 4, '0', STR_PAD_LEFT); // 合成批次号,前缀 + 日期 + 随机数 return $prefix . $date . $randomNumber; } /** * 修改充值卡使用状态 * @return String */ public function generateBarcode($key) { // 确保密钥长度一致 $key = str_pad($key, 16, '0', STR_PAD_LEFT); $generator = new BarcodeGeneratorPNG(); // 选择适当的条形码类型,例如 C128 $barcode = $generator->getBarcode($key, $generator::TYPE_CODE_128); $name = $key.'.png'; $path = $this->getCardPath().$name; // 在图像上绘制条形码 $barcodeImage = imagecreatefromstring($barcode); // 创建一个空白图像,用于绘制条形码和编码文本 $barcodeWidth = imagesx($barcodeImage)+5; $barcodeHeight = imagesy($barcodeImage); $fontSize = 18; // 字体大小 $letterSpacing = 5; // 设置字符间距 $text = $key; $image = imagecreate($barcodeWidth, $barcodeHeight + 20); // 额外留出20px高度用于编码文本 $backgroundColor = imagecolorallocate($image, 255, 255, 255); // 白色背景 $textColor = imagecolorallocate($image, 0, 0, 0); // 黑色文字 imagecopy($image, $barcodeImage, 0, 0, 0, 0, imagesx($barcodeImage), imagesy($barcodeImage)); // 在图像下方绘制编码文本 // 计算文本的总宽度(考虑字符间距) $textWidth = (imagefontwidth($fontSize) + $letterSpacing) * strlen($text) - $letterSpacing; // 计算文本的起始X坐标,使文本居中 $textX = ($barcodeWidth - $textWidth) / 2; $textY = $barcodeHeight; //imagestring($image, $fontSize, $textX, $textY, $text, $textColor); // 绘制文本,逐个字符添加间距 for ($i = 0; $i < strlen($text); $i++) { $xPos = intval($textX + ($i * (imagefontwidth($fontSize) + $letterSpacing))); imagestring($image, $fontSize, $xPos, $textY, $text[$i], $textColor); } // 将图像保存为文件 imagepng($image, public_path().$path); // 销毁图像资源 imagedestroy($image); imagedestroy($barcodeImage); // 将条形码保存为文件或输出 //file_put_contents(public_path().$path, $barcode); return $path; } /** * 获取兑换卡保存路径 * @return string */ private function getCardPath(): string { $filePath = 'uploads/card/' . date("Ymd") . '/'; !is_dir($filePath) && mkdir($filePath, 0755, true); return $filePath; } /** * 修改充值卡使用状态 * @return Json */ public function changeState(): Json { $post = $this->postData(); $is_used = $post['state']?20:10; // 商品详情 foreach ((array)$post['cardIds'] as $card_id) { $model = CardModel::detail($card_id); if (!$model->changeStatus($is_used)) { return $this->renderError('修改状态失败'); } } return $this->renderSuccess($post); } /** 填充pdf * @param $cards * @param $amount * @param $batch * @return string */ public function pdf($cards, $amount, $batch) { /*$sum = 0; $money = 0; // 商品详情 foreach ((array)$cards as $card_number) { $model = CardModel::detail(['card_number'=>$card_number]); if($money == 0){ $money = $model['amount']; } if($model['amount'] != $money){ return $this->renderError('请选择同一面额的兑换卡进行打印'); } if ($model['is_used'] == 10 && $model['is_delete'] == 0 && $model['is_print'] == 0) { $sum++; } } if($sum != 18){ return $this->renderError('请选择18张兑换卡'); }*/ $result = []; // 商品详情 foreach ((array)$cards as $card_number) { $model = CardModel::detail(['card_number'=>$card_number]); if ($model['is_used'] == 10 && $model['is_delete'] == 0 && $model['is_print'] == 0) { $result[] = ['card_number'=>$model['card_number'],'file_path'=>$model['file_path'],'amount'=>(int)$model['amount']]; } } $url = $this->fillPdfTemplate($result, $amount); CardPrintModel::add([ 'file_path' => $url, 'amount' => $amount, 'batch' => $batch, 'num' => 18, 'store_user_id' => $this->store['user']['store_user_id'], 'store_id' => $this->storeId, ]); return $url; } public function fillPdfTemplate($result, $amount) { // 创建 FPDI 对象 $pdf = new FPDI(); // 设置要导入的 PDF 模板文件路径 $templateFile = public_path().'uploads/template/template_'.$amount.'.pdf'; // 设置要导入的 PDF 模板文件 $pageCount = $pdf->setSourceFile($templateFile); // import page 1 $tplIdx = $pdf->importPage(1); // get the width and height of the template $specs = $pdf->getTemplateSize($tplIdx); // add a page $pdf->AddPage($specs['orientation'], array($specs['width'], $specs['height'])); // use the imported page as the template $pdf->useTemplate($tplIdx, 0, 0); // now write some text above the imported page $chunkedArray = array_chunk($result, 3); // 初始坐标 $numberX = 24; $numberY = 45; $nxIncrement = 88.5; $nyIncrement = 56.5; $keyX = 46; $keyY = 44; // x坐标和y坐标的增量 $kxIncrement = 88.5; $kyIncrement = 56.5; // 循环每一排 for ($row = 0; $row < 6; $row++) { // 计算当前行的y坐标 $ny = $numberY + $row * $nyIncrement; $ky = $keyY + $row * $kyIncrement; // 循环每一列 for ($col = 0; $col < 3; $col++) { // 计算当前列的x坐标 $nx = $numberX + $col * $nxIncrement; $kx = $keyX + $col * $kxIncrement; // 输出结果 // 设置字体并填充文本 $pdf->SetFont('Arial', 'B', 7); $pdf->SetXY($nx, $ny); $pdf->Cell(0, 10, $chunkedArray[$row][$col]['card_number']); // 填充图片 $imageFile = public_path().$chunkedArray[$row][$col]['file_path']; $pdf->Image($imageFile, $kx, $ky, 55, 8); } } $url = 'uploads/pdf/'.time().'.pdf'; // 输出填充后的 PDF $pdf->Output('F', public_path().$url); return $url; } }