初始化项目

This commit is contained in:
2026-09-01 22:15:50 +08:00
commit b5a26a8848
11217 changed files with 1710987 additions and 0 deletions
+394
View File
@@ -0,0 +1,394 @@
<?php
declare (strict_types=1);
namespace app\store\controller;
use app\store\model\Card as CardModel;
use app\store\model\card\CardPrint as CardPrintModel;
use think\facade\Filesystem;
use think\response\Json;
use Picqer\Barcode\BarcodeGeneratorPNG;
use setasign\Fpdi\Fpdi;
use setasign\Fpdi\PdfReader\PdfReader;
/**
* 充值卡控制器
* Class Card
* @package app\store\controller
*/
class Card extends Controller
{
/**
* 充值卡列表
* @return mixed
* @throws \think\exception\DbException
*/
public function index()
{
$model = new CardModel;
$getData = $this->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;
}
}