修改打印需求,并提供下载

This commit is contained in:
2025-09-04 07:00:15 +08:00
parent 128e3f9cea
commit d50e080448
6 changed files with 465 additions and 167 deletions

View File

@ -22,10 +22,57 @@ class Printaction extends Base
protected $fontPath = 'public/tsf/jc.ttf'; // 请替换为你的字体文件路径 protected $fontPath = 'public/tsf/jc.ttf'; // 请替换为你的字体文件路径
// 显示条形码生成页面 // 显示条形码生成页面
public function print_device_barcode_index() public function print_device_data_index()
{ {
$data = input();
if(array_key_exists('type',$data)){
return $this->print_device_data_index_action('down');
}else{
$result = $this->print_device_data_index_action('page');
$this->assign([
'data' => $result
]);
return $this->fetch(); return $this->fetch();
} }
}
public function print_device_data_index_action($data){
$zengjie = Db::connect('zengjie_db');
$pc = $zengjie->table('box_code_all')->order('id desc')->find();
// dump($pc);
$sql = "SELECT
a.mac_code,
a.sn_code,
b.box_code,
FORMAT(b.box_num, '000') AS box_num
FROM
sn_code_all AS a
LEFT JOIN
box_code_all AS b ON a.batch_id = b.id
WHERE
a.batch_id IS NOT NULL
AND b.box_code = ?
ORDER BY
a.batch_id";
$result = $zengjie->query($sql, [$pc['box_code']]);
if($data == 'page'){
return $result;
}else{
$result2 = [
['Mac码','Sn码','箱号']
];
for ($i=0; $i < count($result); $i++) {
$result2[] = [$result[$i]['mac_code'],$result[$i]['sn_code'],$result[$i]['box_code'].'-'.$result[$i]['box_num']];
}
$excel = new \app\download\controller\Excel();
$excel->export($result2, $pc['box_code']);
}
}
// 显示外箱码生成页面 // 显示外箱码生成页面
public function print_outside_box_index() public function print_outside_box_index()
{ {

View File

@ -18,11 +18,6 @@ class Savemsg extends Base{
]; ];
protected $name_default = 0; protected $name_default = 0;
protected $kitchenscale_db_msg = [
'cookbook'=>'app_user_cookbook',//菜谱表
'foodlist3'=>'app_z_national_standard_food_type_3',//食材列表3
'user'=>'app_user_data',//banner
];
// 加 bcadd(,,20) // 加 bcadd(,,20)
// 减 bcsub(,,20) // 减 bcsub(,,20)
@ -54,7 +49,7 @@ class Savemsg extends Base{
} }
public function save_sn_msg($data = ['sn_code'=>'564654564654654','bl_name'=>'bl_5520']){ public function save_sn_msg($data = ['sn_code'=>'564654564654654','mac_code'=>'ce:sh:yo:ng:d1','bl_name'=>'bl_5520']){
try { try {
// 你的业务逻辑 // 你的业务逻辑
if(count(input('post.')) > 0){ if(count(input('post.')) > 0){
@ -66,12 +61,18 @@ class Savemsg extends Base{
if(!array_key_exists('bl_name', $data)){ if(!array_key_exists('bl_name', $data)){
return $this->msg(10001); return $this->msg(10001);
} }
if(!array_key_exists('mac_code', $data)){
return $this->msg(10001);
}
if(!$this->verify_data_is_ok($data['sn_code'],'str')){ if(!$this->verify_data_is_ok($data['sn_code'],'str')){
return $this->msg(10005); return $this->msg(10005);
} }
if(!$this->verify_data_is_ok($data['bl_name'],'str')){ if(!$this->verify_data_is_ok($data['bl_name'],'str')){
return $this->msg(10005); return $this->msg(10005);
} }
if(!$this->verify_data_is_ok($data['mac_code'],'str')){
return $this->msg(10005);
}
$result = $this->save_sn_msg_action($data); $result = $this->save_sn_msg_action($data);
return $result; return $result;
} catch (\Exception $e) { } catch (\Exception $e) {
@ -217,6 +218,7 @@ class Savemsg extends Base{
$result = $zengjie->table('sn_code_all')->insert([ $result = $zengjie->table('sn_code_all')->insert([
'sn_code'=>$data['sn_code'], 'sn_code'=>$data['sn_code'],
'bluetooth_name'=>$data['bl_name'], 'bluetooth_name'=>$data['bl_name'],
'mac_code'=>$data['mac_code'],
'create_time'=>date('Y-m-d H:i:s'), 'create_time'=>date('Y-m-d H:i:s'),
]); ]);
if($result){ if($result){
@ -229,44 +231,79 @@ class Savemsg extends Base{
public function save_box_msg_action($data) { public function save_box_msg_action($data) {
$zengjie = Db::connect('zengjie_db'); $zengjie = Db::connect('zengjie_db');
$box_num = $zengjie->table('box_code_all')->where(['box_code'=>$data['box_serial_number']])->count(); // 1. 检查sn_code_all中是否有重复数据
$box_num = $box_num+1; $snCodes = explode(',', $data['sn_code_all']);
$result = $zengjie->table('box_code_all')->insert([ if (count($snCodes) !== count(array_unique($snCodes))) {
return $this->msg(10003, 'SN码列表中存在重复数据');
}
// 2. 检查这些SN码是否都存在于sn_code_all表中
$existCount = $zengjie->table('sn_code_all')
->where('sn_code', 'in', $snCodes)
->count();
if ($existCount !== count($snCodes)) {
return $this->msg(10004, '存在未登记的SN码');
}
Db::startTrans();
try{
$count = $zengjie->table('box_code_all')
->where(['box_code'=>$data['box_serial_number']])
->count();
$num = $count + 1;
$box_id = $zengjie->table('box_code_all')->insertGetId([
'box_code' => $data['box_serial_number'], 'box_code' => $data['box_serial_number'],
'box_num'=>$box_num, 'box_num' => $num,
'create_time' => date('Y-m-d H:i:s'), 'create_time' => date('Y-m-d H:i:s'),
'content_str' => $data['sn_code_all'], 'content_str' => $data['sn_code_all'],
]); ]);
if($result){ $affectedRows = $zengjie->table('sn_code_all')
return $this->msg([]); ->where('sn_code', 'in', $snCodes)
}else{ ->update(['batch_id' => $box_id]);
return $this->msg(10002,'录入失败');
}
// 检查更新是否影响了预期的行数
if ($affectedRows !== count($snCodes)) {
throw new \Exception('更新SN码数量不匹配');
}
Db::commit();
return $this->msg(['id'=>$box_id]);
} catch (\Exception $e) {
// 回滚事务
Db::rollback();
return $this->msg(10002, '录入失败: ' . $e->getMessage());
}
// // 显式事务控制
// $zengjie->startTrans();
// try { // try {
// // 使用事务闭包TP5会自动管理事务 // $count = $zengjie->table('box_code_all')
// $result = $zengjie->transaction(function() use ($zengjie, $data) { // ->where(['box_code'=>$data['box_serial_number']])
// $sn_code = $zengjie->table('box_code_all')->where(['box_code'=>$data['box_serial_number']])->count(); // ->count();
// $num = $sn_code+1; // $num = $count + 1;
// $box_id = $zengjie->table('box_code_all')->insertGetId([ // $box_id = $zengjie->table('box_code_all')->insertGetId([
// 'box_code' => $data['box_serial_number'], // 'box_code' => $data['box_serial_number'],
// 'box_num' => $num, // 'box_num' => $num,
// 'create_time' => date('Y-m-d H:i:s'), // 'create_time' => date('Y-m-d H:i:s'),
// 'content_str' => $data['sn_code_all'],
// ]); // ]);
// // 使用安全的参数绑定方式 // $affectedRows = $zengjie->table('sn_code_all')
// $snCodes = explode(',', $data['sn_code_all']);
// $zengjie->table('sn_code_all')
// ->where('sn_code', 'in', $snCodes) // ->where('sn_code', 'in', $snCodes)
// ->update(['batch_id' => $box_id]); // ->update(['batch_id' => $box_id]);
// return $box_id; // // 检查更新是否影响了预期的行数
// }); // if ($affectedRows !== count($snCodes)) {
// throw new \Exception('更新SN码数量不匹配');
// }
// return $this->msg(['id'=>$result]); // $zengjie->commit();
// return $this->msg(['id'=>$box_id]);
// } catch (\Exception $e) { // } catch (\Exception $e) {
// if ($zengjie->getPdo()->inTransaction()) {
// $zengjie->rollback();
// }
// trace('保存盒信息失败: ' . $e->getMessage(), 'error'); // trace('保存盒信息失败: ' . $e->getMessage(), 'error');
// return $this->msg(10002, '录入失败: ' . $e->getMessage()); // return $this->msg(10002, '录入失败: ' . $e->getMessage());
// } // }
@ -302,4 +339,60 @@ class Savemsg extends Base{
} }
} }
######################################################测试#########################################################
######################################################测试#########################################################
######################################################测试#########################################################
public function ceshiyong(){
// // 添加测试一维码数据
// $data = [];
// for ($i = 0; $i < 500; $i++) {
// // 生成15位随机数字作为sn_code
// $sn_code = '';
// for ($j = 0; $j < 15; $j++) {
// $sn_code .= mt_rand(0, 9);
// }
// // 生成随机的MAC地址
// $mac_parts = [];
// for ($k = 0; $k < 6; $k++) {
// $mac_parts[] = sprintf('%02x', mt_rand(0, 255));
// }
// $mac_code = implode(':', $mac_parts);
// // 构建数据数组
// $data[] = [
// 'sn_code' => $sn_code,
// 'mac_code' => $mac_code,
// 'create_time' => date('Y-m-d H:i:s'),
// 'is_print' => 1,
// 'bluetooth_name' => 'bl_5520'
// ];
// }
// $zengjie = Db::connect('zengjie_db');
// $result = $zengjie->table('sn_code_all')->insertAll($data);
// dump($result);
// die;
// // 添加测试一维码数据
// 添加测试打包数据
$zengjie = Db::connect('zengjie_db');
$records = $zengjie->table('sn_code_all')
->where('batch_id', 'null') // 或者使用 ->whereNull('batch_id')
->orderRaw('NEWID()') // SQL Server的随机排序函数
->limit(10)
->select();
$data['sn_code_all'] = [];
$data['box_serial_number'] = '3ST011527003';
for ($i=0; $i < count($records); $i++) {
$data['sn_code_all'][] = $records[$i]['sn_code'];
}
$data['sn_code_all'] = implode(',',$data['sn_code_all']);
$result = $this->save_box_msg_action($data);
dump($result);
dump($data);
// 添加测试打包数据
// return $data;
}
} }

View File

@ -1,122 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>标签打印系统</title>
<script src="../x_admin/js/jq.js"></script>
<style>
body {
margin: 0;
padding: 20px;
font-family: Arial, sans-serif;
background-color: white;
text-align: center;
}
h1 {
font-size: 24px;
font-weight: bold;
margin-bottom: 10px;
}
.description {
font-size: 16px;
margin-bottom: 20px;
}
#barcodeContainer {
margin: 20px auto;
padding: 10px;
border: 2px dashed black;
display: inline-block;
}
#barcodeImage {
width: 600px;
height: 200px;
display: block;
margin: 0 auto;
/* border: 1px solid red; */
}
#printBtn {
display: block;
width: 200px;
margin: 20px auto;
padding: 10px;
background-color: #1E88E5;
color: white;
border: none;
border-radius: 4px;
font-size: 16px;
cursor: pointer;
}
@media print {
body * {
visibility: hidden;
}
#barcodeContainer, #barcodeContainer * {
visibility: visible;
}
#barcodeContainer {
position: absolute;
left: 0;
top: 0;
border: none;
}
}
</style>
</head>
<body>
<h1>标签打印系统</h1>
<div class="description">440×147px图片打印到60×20mm标签纸</div>
<div id="barcodeContainer">
<img id="barcodeImage" src="">
</div>
<button id="printBtn" onclick="dayin()">直接打印</button>
<script>
$(document).ready(function() {
loadBarcode();
// $('#printBtn').click(function() {
// window.print();
// });
});
function loadBarcode() {
console.log(Date.now)
$.ajax({
url: "/z/print_device_barcode",
type: "POST",
dataType: "json",
success: function(response) {
if(response.code == 10002) {
setTimeout(loadBarcode, 1000);
}
else if(response.code == 10003) {
alert(response.msg);
}
else if(response.data) {
$('#barcodeImage').attr('src', response.data.image);
// setTimeout(() => {
// dayin()
// }, 500);
}
},
error: function(xhr, status, error) {
console.error("请求出错:", error);
setTimeout(loadBarcode, 3000);
}
});
}
function dayin(){
window.print();
}
</script>
</body>
</html>

View File

@ -0,0 +1,71 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>最近一次打印数据</title>
<script src="../x_admin/js/jq.js"></script>
<style>
body {
margin: 0 0;
padding: 0 0;
}
.big_box{
display: flex;
}
.down{
height: 30px;
width: 100px;
line-height: 30px;
text-align: center;
border: 1px solid black;
box-shadow: 1px 1px 1px;
margin-left: 10px;
cursor: pointer
}
</style>
</head>
<body>
<div class="big_box">
<table border="1" cellpadding="5">
<tr>
<th>MAC地址</th>
<th>SN码</th>
<th>箱号</th>
</tr>
{volist name="data" id="item"}
<tr>
<td>{$item.mac_code|default='未分配'}</td>
<td>{$item.sn_code}</td>
<td>{$item.box_code}-{$item.box_num}</td>
</tr>
{/volist}
</table>
<div class="down">点击下载</div>
</div>
<script>
$('.down').on('click',function(){
// $.ajax({
// url:"print_device_data_index_action", //请求的url地址
// dataType:"json", //返回格式为json
// async:true,//请求是否异步默认为异步这也是ajax重要特性
// data:{"id":"value"}, //参数值
// type:"POST", //请求方式
// beforeSend:function(){
// //请求前的处理
// },
// success:function(req){
// //请求成功时处理
// },
// complete:function(){
// //请求完成的处理
// },
// error:function(){
// //请求出错处理
// }});
// window.open('https://www.example.com', '_blank');
window.location.href('https://tc.pcxbc.com/z/print_device_data_index_action?type=down');
})
</script>
</body>
</html>

View File

@ -0,0 +1,205 @@
<?php
namespace app\download\controller;
use think\Controller;
use PhpOffice\PhpSpreadsheet\Spreadsheet;
use PhpOffice\PhpSpreadsheet\Writer\Xlsx;
use PhpOffice\PhpSpreadsheet\Style\Border;
use PhpOffice\PhpSpreadsheet\Style\Fill;
use PhpOffice\PhpSpreadsheet\Style\Alignment;
use PhpOffice\PhpSpreadsheet\Style\Color;
class Excel extends Controller
{
// public function exportWithCustomStyle()
// {
// $data = [
// ['订单号', '客户名称', '订单金额', '下单日期', '状态'],
// ['ORD20230001', '张三', 1580.00, '2023-05-10', '已完成'],
// ['ORD20230002', '李四', 2399.00, '2023-05-11', '已发货'],
// ['ORD20230003', '王五', 899.00, '2023-05-12', '待付款'],
// ];
// $options = [
// 'sheet_title' => '五月订单', // 工作表名称
// 'header_style' => [
// 'font' => [
// 'bold' => true,
// 'color' => ['argb' => 'FFFFFFFF'] // 白色文字
// ],
// 'fill' => [
// 'fillType' => Fill::FILL_SOLID,
// 'startColor' => ['argb' => 'FF0070C0'] // 蓝色背景
// ],
// 'alignment' => [
// 'horizontal' => Alignment::HORIZONTAL_CENTER,
// ],
// ],
// 'stripe_color1' => 'FFE6F1FF', // 浅蓝色
// 'stripe_color2' => 'FFD6E6FF', // 稍深一点的蓝色
// ];
// $excel = new \app\download\controller\Excel();
// $excel->export($data, '五月订单报表', $options);
// }
/**
* 导出 Excel 文件(带斑马纹效果)
*
* @param array $data 要导出的数据,格式为二维数组,第一行为表头
* @param string $filename 下载的文件名(不带扩展名)
* @param array $options 可选配置项
* - 'sheet_title' => string 工作表标题
* - 'header_style' => array 自定义表头样式
* - 'content_style' => array 自定义内容样式
* - 'zebra_stripe' => bool 是否启用斑马纹效果默认true
* - 'stripe_color1' => string 斑马纹第一种颜色(默认白色)
* - 'stripe_color2' => string 斑马纹第二种颜色(默认浅灰色)
* - 'auto_width' => bool 是否自动调整列宽
* @return void
*/
public function export(array $data, string $filename = 'export', array $options = [])
{
// 验证数据
if (empty($data) || !is_array($data) || !is_array($data[0])) {
throw new \InvalidArgumentException('导出数据格式不正确,应为二维数组且第一行为表头');
}
// 默认配置
$defaultOptions = [
'sheet_title' => 'Sheet1',
'header_style' => [
'font' => ['bold' => true],
'fill' => [
'fillType' => Fill::FILL_SOLID,
'startColor' => ['argb' => Color::COLOR_YELLOW],
],
'alignment' => ['horizontal' => Alignment::HORIZONTAL_CENTER],
'borders' => [
'outline' => ['borderStyle' => Border::BORDER_THIN],
'inside' => ['borderStyle' => Border::BORDER_THIN]
],
],
'content_style' => [
'alignment' => ['horizontal' => Alignment::HORIZONTAL_CENTER],
'borders' => [
'outline' => ['borderStyle' => Border::BORDER_THIN],
'inside' => ['borderStyle' => Border::BORDER_THIN]
],
],
'zebra_stripe' => true, // 默认启用斑马纹
'stripe_color1' => 'FFFFFFFF', // 白色
'stripe_color2' => 'FFEEEEEE', // 浅灰色
'auto_width' => true,
];
// 合并用户配置和默认配置
$options = array_merge($defaultOptions, $options);
// 创建 Spreadsheet 对象
$spreadsheet = new Spreadsheet();
$sheet = $spreadsheet->getActiveSheet();
$sheet->setTitle($options['sheet_title']);
// 获取列数和行数
$columnCount = count($data[0]);
$rowCount = count($data);
// 写入数据
foreach ($data as $rowIndex => $rowData) {
for ($colIndex = 0; $colIndex < $columnCount; $colIndex++) {
$sheet->setCellValueByColumnAndRow($colIndex + 1, $rowIndex + 1, $rowData[$colIndex]);
}
}
// 设置表头样式
$headerRange = 'A1:' . $this->getExcelColumnName($columnCount) . '1';
$sheet->getStyle($headerRange)->applyFromArray($options['header_style']);
// 设置内容样式
$contentRange = 'A2:' . $this->getExcelColumnName($columnCount) . $rowCount;
$sheet->getStyle($contentRange)->applyFromArray($options['content_style']);
// =============================================
// 重点:斑马纹效果实现
// =============================================
if ($options['zebra_stripe']) {
$this->applyZebraStripe(
$sheet,
$columnCount,
$rowCount,
$options['stripe_color1'],
$options['stripe_color2']
);
}
// 自动调整列宽
if ($options['auto_width']) {
for ($colIndex = 1; $colIndex <= $columnCount; $colIndex++) {
$sheet->getColumnDimensionByColumn($colIndex)->setAutoSize(true);
}
}
// 设置响应头以触发文件下载
header('Content-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet');
header('Content-Disposition: attachment;filename="' . $filename . '.xlsx"');
header('Cache-Control: max-age=0');
// 保存并输出 Excel 文件
$writer = new Xlsx($spreadsheet);
$writer->save('php://output');
exit;
}
/**
* 应用斑马纹效果(核心实现)
*
* @param \PhpOffice\PhpSpreadsheet\Worksheet\Worksheet $sheet
* @param int $columnCount 总列数
* @param int $totalRows 总行数(包括表头)
* @param string $color1 第一种颜色
* @param string $color2 第二种颜色
*/
protected function applyZebraStripe($sheet, $columnCount, $totalRows, $color1, $color2)
{
// 从第二行开始应用斑马纹(跳过表头)
for ($rowIndex = 2; $rowIndex <= $totalRows; $rowIndex++) {
// 计算当前行应该使用哪种颜色
$color = ($rowIndex % 2 == 0) ? $color1 : $color2;
// 设置行样式
$rowStyle = [
'fill' => [
'fillType' => Fill::FILL_SOLID,
'startColor' => ['argb' => $color],
],
];
// 应用样式到整行
$range = 'A' . $rowIndex . ':' . $this->getExcelColumnName($columnCount) . $rowIndex;
$sheet->getStyle($range)->applyFromArray($rowStyle);
}
}
/**
* 获取 Excel 列名
*
* @param int $index 列索引从1开始
* @return string Excel 列名
*/
protected function getExcelColumnName($index)
{
$columnName = '';
while ($index > 0) {
$remainder = ($index - 1) % 26;
$columnName = chr(65 + $remainder) . $columnName;
$index = intval(($index - 1) / 26);
}
return $columnName;
}
}

View File

@ -606,11 +606,13 @@ Route::any('/k/a/cookbook/stop_and_run', 'app/kitchenscale/admin.cookbook/stop_a
Route::any('/z/config_msg', 'app/ZengJieCode/app.savemsg/config_msg'); Route::any('/z/config_msg', 'app/ZengJieCode/app.savemsg/config_msg');
Route::any('/z/save_sn_msg', 'app/ZengJieCode/app.savemsg/save_sn_msg'); Route::any('/z/save_sn_msg', 'app/ZengJieCode/app.savemsg/save_sn_msg');
Route::any('/z/save_box_msg', 'app/ZengJieCode/app.savemsg/save_box_msg'); Route::any('/z/save_box_msg', 'app/ZengJieCode/app.savemsg/save_box_msg');
// 测试用
Route::any('/z/ceshiyong', 'app/ZengJieCode/app.savemsg/ceshiyong');
// 重新打印 // 重新打印
Route::any('/z/print_again', 'app/ZengJieCode/app.savemsg/print_again'); Route::any('/z/print_again', 'app/ZengJieCode/app.savemsg/print_again');
Route::any('/z/print_device_barcode_index', 'app/ZengJieCode/admin.printaction/print_device_barcode_index'); Route::any('/z/print_device_data_index', 'app/ZengJieCode/admin.printaction/print_device_data_index');
Route::any('/z/print_outside_box_index', 'app/ZengJieCode/admin.printaction/print_outside_box_index'); // Route::any('/z/print_outside_box_index', 'app/ZengJieCode/admin.printaction/print_outside_box_index');
// 获取蓝牙录入的未打印条码 // 获取蓝牙录入的未打印条码
Route::any('/z/print_device_barcode', 'app/ZengJieCode/admin.printaction/print_device_barcode'); Route::any('/z/print_device_barcode', 'app/ZengJieCode/admin.printaction/print_device_barcode');
@ -619,6 +621,8 @@ Route::any('/z/print_scan_barcode', 'app/ZengJieCode/admin.printaction/print_sca
// 获取大箱没打印的条码 // 获取大箱没打印的条码
Route::any('/z/print_combined_code', 'app/ZengJieCode/admin.printaction/print_combined_code'); Route::any('/z/print_combined_code', 'app/ZengJieCode/admin.printaction/print_combined_code');
################################################################下面是设备入库录入################################################################ ################################################################下面是设备入库录入################################################################
################################################################################################################################################ ################################################################################################################################################
// 默认配置 // 默认配置