Files
fdesk/app/functions.php
T
2025-11-03 18:16:51 +08:00

392 lines
11 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<?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()),
'source' => getenv('ENVIRONMENT')
];
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);
}
}