391 lines
11 KiB
PHP
391 lines
11 KiB
PHP
<?php
|
||
/**
|
||
* Here is your custom functions.
|
||
*/
|
||
|
||
use Webman\RedisQueue\Redis as RedisQueueRedis;
|
||
|
||
/**
|
||
* 标准化账号参数
|
||
*
|
||
* @param string $account 用户输入的账号(可能是手机号或邮箱)
|
||
* @return array 返回 ['phone' => $account] 或 ['email' => $account]
|
||
*/
|
||
if (!function_exists('normalizeAccount')) {
|
||
function normalizeAccount(string $account): array
|
||
{
|
||
// 使用FILTER_VALIDATE_EMAIL验证邮箱格式
|
||
if (filter_var($account, FILTER_VALIDATE_EMAIL)) {
|
||
return ['email' => $account];
|
||
}
|
||
|
||
// 清理手机号中的非数字字符
|
||
$cleanPhone = preg_replace('/[^0-9]/', '', $account);
|
||
|
||
// 验证手机号格式(简单版:11位数字)
|
||
if (preg_match('/^1[3-9]\d{9}$/', $cleanPhone)) {
|
||
return ['phone' => $cleanPhone];
|
||
}
|
||
|
||
// 如果既不是邮箱也不是手机号,根据业务需求处理
|
||
// 这里默认按手机号处理(可根据实际需求调整)
|
||
return ['phone' => $cleanPhone];
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 公共html页面
|
||
*/
|
||
if (!function_exists('htmlpage')) {
|
||
function htmlpage()
|
||
{
|
||
static $html;
|
||
if (!$html) {
|
||
$html = file_get_contents(public_path('mzl.html'));
|
||
}
|
||
return $html;
|
||
}
|
||
}
|
||
/**
|
||
* 获取配置
|
||
*/
|
||
if (!function_exists('getConfig')) {
|
||
function getConfig($filePath = null)
|
||
{
|
||
// 构建文件路径
|
||
$config_file = app_path($filePath);
|
||
// 检查文件是否存在
|
||
if (!file_exists($config_file)) {
|
||
return [];
|
||
}
|
||
// 包含文件并获取返回的数组
|
||
$config = include $config_file;
|
||
// 验证是否为数组
|
||
if (!is_array($config)) {
|
||
return [];
|
||
}
|
||
return $config;
|
||
}
|
||
}
|
||
|
||
/*
|
||
* 询单号生成
|
||
*/
|
||
if (!function_exists('orderNum')) {
|
||
function orderNum()
|
||
{
|
||
return "SN".date('Ymd') . str_pad(mt_rand(1, 99999), 5, '0', STR_PAD_LEFT);
|
||
}
|
||
}
|
||
|
||
/*
|
||
* 调试用(console)
|
||
*/
|
||
if (!function_exists('dpr')) {
|
||
function dpr(\Throwable $e)
|
||
{
|
||
$contents = "=== === 报错打印 === ===\n";
|
||
$contents .= "文件:".$e->getFile()."\n";
|
||
$contents .= "行数:".$e->getLine()."\n";
|
||
$contents .= "详情:".$e->getMessage()."\n";
|
||
$contents .= "=== === 报错打印 === ===\n";
|
||
var_dump($contents);
|
||
return $contents;
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 调试用(file)
|
||
*/
|
||
if (!function_exists('flg')) {
|
||
function flg($eventData = '', $isFs = true, $fileName = 'flg', $fileCatalog = 'flg')
|
||
{
|
||
if ($eventData == '') {
|
||
return false;
|
||
}
|
||
|
||
if (is_array($eventData) || is_object($eventData)) {
|
||
$eventData = json_encode($eventData);
|
||
}
|
||
|
||
$fileCatalog = substr(__FILE__, 0, strpos(__FILE__, 'app/')) . "runtime/" . $fileCatalog;
|
||
if (!is_dir($fileCatalog)) {
|
||
mkdir($fileCatalog, 0777, true);
|
||
exec('chown -R nginx:nginx ' . $fileCatalog);
|
||
}
|
||
|
||
$fileName = $fileName . '-' . date('Ymd') . '.log';
|
||
|
||
if ($isFs) {
|
||
$data = [
|
||
'content' => $eventData,
|
||
'time' => date('Y-m-d H:i:s', time())
|
||
];
|
||
RedisQueueRedis::send("server", $data);
|
||
}
|
||
|
||
return file_put_contents($fileCatalog . "/" . $fileName, date("Y-m-d H:i:s", time()) . "::" . $eventData . "\n", FILE_APPEND);
|
||
}
|
||
}
|
||
|
||
/***
|
||
* 发送飞书文本消息
|
||
*/
|
||
if (!function_exists('sendFeishuTextMessage')) {
|
||
function sendFeishuTextMessage($webhookUrl, $message) {
|
||
$data = [
|
||
'msg_type' => 'text',
|
||
'content' => [
|
||
'text' => $message
|
||
]
|
||
];
|
||
|
||
$ch = curl_init();
|
||
curl_setopt($ch, CURLOPT_URL, $webhookUrl);
|
||
curl_setopt($ch, CURLOPT_POST, 1);
|
||
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));
|
||
curl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: application/json']);
|
||
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
||
|
||
$response = curl_exec($ch);
|
||
curl_close($ch);
|
||
|
||
return $response;
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 替换模板
|
||
*/
|
||
if (!function_exists('replaceTpl')) {
|
||
function replaceTpl(array $data = [], string $tplKey = 'email')
|
||
{
|
||
if (!$data || !$tplKey) return '';
|
||
$templatePath = tplUrl($tplKey);
|
||
$templatePath = app_path($templatePath);
|
||
$content = file_get_contents($templatePath);
|
||
foreach ($data as $key => $value) {
|
||
$content = str_replace('{{'.$key.'}}', $value, $content);
|
||
}
|
||
return $content;
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 模板路径
|
||
*/
|
||
if (!function_exists('tplUrl')) {
|
||
function tplUrl(string $tplKey = '')
|
||
{
|
||
$urlArray = [
|
||
'email' => 'common/utils/scaffold/templates/Email.stub',
|
||
'work_order' => 'common/utils/scaffold/templates/workOrder.stub',
|
||
'payment_files' => 'common/utils/scaffold/templates/paymentFiles.stub',
|
||
];
|
||
return $urlArray[$tplKey];
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 替换模板
|
||
*/
|
||
if (!function_exists('InquiryFormat')) {
|
||
function InquiryFormat(array $data = [])
|
||
{
|
||
if (!$data) return '';
|
||
$content = '';
|
||
// foreach ($data as $key => $value) {
|
||
// $content .= $key . ':' . $value . "\r\n";
|
||
// }
|
||
$content .= '编号:'.$data['order_no'] . "\r\n";
|
||
$content .= '询单质量:'.$data['quality'] . "\r\n";
|
||
$content .= '渠道:'.$data['channel'] . "\r\n";
|
||
$content .= '邮箱:'.$data['email'] . "\r\n";
|
||
$content .= '电话:'.$data['tel'] . "\r\n";
|
||
$content .= 'WhatsApp:'.$data['whatsapp'] . "\r\n";
|
||
$content .= '国家:'.$data['country'] . "\r\n";
|
||
$content .= '联系人:'.$data['contacts'] . "\r\n";
|
||
$content .= '录单人:'.$data['enter_user_id'] . "\r\n";
|
||
$content .= '录单时间:'.$data['r_time'] . "\r\n";
|
||
$content .= '内容:'.$data['content'];
|
||
return $content;
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 移除字符串中的括号及其内部内容(仅移除第一个匹配项)
|
||
*
|
||
* @param string $str 要处理的字符串
|
||
* @return string 处理后的字符串
|
||
*/
|
||
if (!function_exists('removeParentheses')) {
|
||
function removeParentheses(string $str): string
|
||
{
|
||
// 匹配模式:半角括号或全角括号及其内部内容
|
||
$pattern = '/
|
||
(?: # 非捕获分组开始
|
||
\( # 匹配半角左括号
|
||
[^)]* # 匹配除半角右括号外的任意字符
|
||
\) # 匹配半角右括号
|
||
)|(?: # 或
|
||
\( # 匹配全角左括号
|
||
[^)]* # 匹配除全角右括号外的任意字符
|
||
\) # 匹配全角右括号
|
||
) # 非捕获分组结束
|
||
/xu'; // x: 忽略空白 u: Unicode模式
|
||
|
||
return trim(preg_replace($pattern, '', $str, 1));
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 规范hmtl富文本
|
||
*/
|
||
if (!function_exists('normalizeRichText')) {
|
||
function normalizeRichText(string $html): string
|
||
{
|
||
$dom = new DOMDocument();
|
||
|
||
// 处理UTF-8编码和HTML5标签
|
||
@$dom->loadHTML('<?xml encoding="UTF-8">' . $html,
|
||
LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD);
|
||
|
||
// 设置编码并规范化文档
|
||
$dom->encoding = 'UTF-8';
|
||
$dom->normalizeDocument();
|
||
|
||
// 统一处理空白字符
|
||
$xpath = new DOMXPath($dom);
|
||
foreach ($xpath->query('//text()') as $node) {
|
||
$normalized = preg_replace('/\s+/u', ' ', trim($node->nodeValue));
|
||
$node->nodeValue = $normalized;
|
||
}
|
||
|
||
// 标准化属性顺序(可选)
|
||
foreach ($xpath->query('//*[@*]') as $element) {
|
||
$attributes = $element->attributes;
|
||
$sorted = [];
|
||
foreach ($attributes as $attr) {
|
||
$sorted[$attr->nodeName] = $attr->nodeValue;
|
||
}
|
||
ksort($sorted);
|
||
|
||
// 移除所有属性后按排序后顺序重新添加
|
||
while ($attributes->length) {
|
||
$element->removeAttributeNode($attributes->item(0));
|
||
}
|
||
foreach ($sorted as $name => $value) {
|
||
$element->setAttribute($name, $value);
|
||
}
|
||
}
|
||
|
||
// 返回规范化后的HTML
|
||
$result = trim($dom->saveHTML());
|
||
// 替换所有空白实体为普通空格
|
||
return preg_replace('/\s+/u', ' ', $result);
|
||
}
|
||
}
|
||
|
||
|
||
/**
|
||
* 生成消息编号(唯一业务标识)
|
||
* 格式:年月日时分秒 + 微秒 + 随机数
|
||
* 例如:20250820175530987654321
|
||
*
|
||
* @return string
|
||
*/
|
||
if (!function_exists('generateMsgId')) {
|
||
function generateMsgId(): string
|
||
{
|
||
// 时间部分(精确到微秒)
|
||
$time = microtime(true);
|
||
$micro = sprintf("%06d", ($time - floor($time)) * 1e6);
|
||
$date = date('YmdHis', (int)$time);
|
||
|
||
// 随机部分(3位)
|
||
$rand = mt_rand(100, 999);
|
||
|
||
// 拼接:日期时间 + 微秒 + 随机数
|
||
return $date . $micro . $rand;
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 生成sku_code
|
||
* 格式:年月日时分秒 + 微秒 + 随机数
|
||
* 例如:20250820175530987654321
|
||
*
|
||
* @return string
|
||
*/
|
||
if (!function_exists('skuCode')) {
|
||
function skuCode(): string
|
||
{
|
||
// 时间部分(精确到微秒)
|
||
$time = microtime(true);
|
||
$micro = sprintf("%06d", ($time - floor($time)) * 1e6);
|
||
$date = date('YmdHis', (int)$time);
|
||
|
||
// 随机部分(3位)
|
||
$rand = mt_rand(100, 999);
|
||
|
||
// 拼接:日期时间 + 微秒 + 随机数
|
||
return $date . $micro . $rand;
|
||
}
|
||
}
|
||
|
||
|
||
/**
|
||
* 生成备货单编号(预占式,每天从1开始)
|
||
*
|
||
* @return string
|
||
*/
|
||
if (!function_exists('generateStockNo')) {
|
||
function generateStockNo(string $prefix = 'BH', int $serialLength = 3): string
|
||
{
|
||
$date = date('Ymd');
|
||
$key = "stock:order:serial:{$date}";
|
||
|
||
// 原子递增获取当日流水号
|
||
$serial = \support\Redis::incr($key);
|
||
|
||
// 首次创建时设置过期时间:到明天凌晨 + 1小时(容错)
|
||
if ($serial === 1) {
|
||
$tomorrow = strtotime(date('Y-m-d', strtotime('+1 day')));
|
||
$expireSeconds = $tomorrow - time() + 3600; // 多加1小时
|
||
\support\Redis::expire($key, $expireSeconds);
|
||
}
|
||
|
||
// 格式化流水号(补零)
|
||
$paddedSerial = str_pad($serial, $serialLength, '0', STR_PAD_LEFT);
|
||
|
||
return $prefix . $date . $paddedSerial;
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 发送通知
|
||
*
|
||
* @param string $title
|
||
* @param string $content
|
||
* @param string $url
|
||
* @param string $type
|
||
* @return void
|
||
*/
|
||
if (!function_exists('noticePush')) {
|
||
function noticePush(array $notice = [])
|
||
{
|
||
/*
|
||
消息字段:
|
||
'sender_id' //发送人
|
||
'sender_type' //发送人类型
|
||
'title' //标题
|
||
'content' //内容
|
||
'scene' //场景
|
||
'recipient' //接收人
|
||
'push_method' //推送方式
|
||
// 如果需要同时 邮箱推送 增加推送邮箱字段
|
||
'email' //邮箱
|
||
*/
|
||
\Webman\RedisQueue\Redis::send('notice', $notice);
|
||
}
|
||
} |