= 0 ? true : false; } /** * @notes 检查文件是否可写 * @param string $dir * @return bool * @author 段誉 * @date 2021/12/28 18:27 */ function checkDirWrite(string $dir = '') : bool { $route = root_path() . '/' . $dir; return is_writable($route); } /** * 多级线性结构排序 * 转换前: * [{"id":1,"pid":0,"name":"a"},{"id":2,"pid":0,"name":"b"},{"id":3,"pid":1,"name":"c"}, * {"id":4,"pid":2,"name":"d"},{"id":5,"pid":4,"name":"e"},{"id":6,"pid":5,"name":"f"}, * {"id":7,"pid":3,"name":"g"}] * 转换后: * [{"id":1,"pid":0,"name":"a","level":1},{"id":3,"pid":1,"name":"c","level":2},{"id":7,"pid":3,"name":"g","level":3}, * {"id":2,"pid":0,"name":"b","level":1},{"id":4,"pid":2,"name":"d","level":2},{"id":5,"pid":4,"name":"e","level":3}, * {"id":6,"pid":5,"name":"f","level":4}] * @param array $data 线性结构数组 * @param string $symbol 名称前面加符号 * @param string $name 名称 * @param string $id_name 数组id名 * @param string $parent_id_name 数组祖先id名 * @param int $level 此值请勿给参数 * @param int $parent_id 此值请勿给参数 * @return array */ function linear_to_tree($data, $sub_key_name = 'sub', $id_name = 'id', $parent_id_name = 'pid', $parent_id = 0) { $tree = []; foreach ($data as $row) { if ($row[$parent_id_name] == $parent_id) { $temp = $row; $child = linear_to_tree($data, $sub_key_name, $id_name, $parent_id_name, $row[$id_name]); if($child){ $temp[$sub_key_name] = $child; } $tree[] = $temp; } } return $tree; } /** * @notes 生成编号 * @param $table * @param $field * @param string $prefix * @param int $rand_suffix_length * @param array $pool * @return string * @author ljj * @date 2022/2/15 3:47 下午 */ function generate_sn($table, $field, $prefix = '', $rand_suffix_length = 4, $pool = []) : string { $suffix = ''; for ($i = 0; $i < $rand_suffix_length; $i++) { if (empty($pool)) { $suffix .= rand(0, 9); } else { $suffix .= $pool[array_rand($pool)]; } } $sn = $prefix . date('YmdHis') . $suffix; if ($table->where($field, $sn)->find()) { return generate_sn($table, $field, $prefix, $rand_suffix_length, $pool); } return $sn; } /** * @notes 生成用户编码 * @param string $prefix * @param int $length * @return string * @throws \think\db\exception\DataNotFoundException * @throws \think\db\exception\DbException * @throws \think\db\exception\ModelNotFoundException * @author ljj * @date 2022/2/17 11:25 上午 */ function create_user_sn($prefix = '', $length = 8) { $rand_str = ''; for ($i = 0; $i < $length; $i++) { $rand_str .= mt_rand(0, 9); } $sn = $prefix . $rand_str; if (User::where(['sn' => $sn])->find()) { return create_user_sn($prefix, $length); } return $sn; } /** * @notes 随机生成邀请码 * @param $length * @return string * @author Tab * @date 2021/7/26 11:17 */ function generate_code($length = 6) { // 去除字母IO数字012 $letters = 'ABCDEFGHJKLMNPQRSTUVWXYZ3456789'; // 随机起始索引 $start = mt_rand(0, strlen($letters) - $length); // 打乱字符串 $shuffleStr = str_shuffle($letters); // 截取字符 $randomStr = substr($shuffleStr, $start, $length); // 判断是否已被使用 $user = User::where('code', $randomStr)->findOrEmpty(); if($user->isEmpty()) { return $randomStr; } generate_code($length); } /** * @notes 自定义长度纯数字随机编码 * @param $table * @param string $field * @param int $length * @param string $prefix * @return string * @author ljj * @date 2021/8/26 2:57 下午 */ function create_number_sn($table, $field = 'sn', $length = 8, $prefix = '') { $rand_str = ''; for ($i = 0; $i < $length; $i++) { $rand_str .= mt_rand(0, 9); } $sn = $prefix . $rand_str; if ($table->where($field, $sn)->find()) { return create_number_sn($table, $field, $length, $prefix); } return $sn; } /** * User: 意象信息科技 lr * Desc: 下载文件 * @param $url 文件url * @param $save_dir 保存目录 * @param $file_name 文件名 * @return string */ function download_file($url, $save_dir, $file_name) { if (!file_exists($save_dir)) { mkdir($save_dir, 0775, true); } $file_src = $save_dir . $file_name; file_exists($file_src) && unlink($file_src); $ch = curl_init(); curl_setopt($ch, CURLOPT_URL, $url); curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 30); $file = curl_exec($ch); curl_close($ch); $resource = fopen($file_src, 'a'); fwrite($resource, $file); fclose($resource); if (filesize($file_src) == 0) { unlink($file_src); return ''; } return $file_src; } /** * @notes 删除目标目录 * @param $path * @param $delDir * @return bool|void * @author 段誉 * @date 2022/4/8 16:30 */ function del_target_dir($path, $delDir) { //没找到,不处理 if (!file_exists($path)) { return false; } //打开目录句柄 $handle = opendir($path); if ($handle) { while (false !== ($item = readdir($handle))) { if ($item != "." && $item != "..") { if (is_dir("$path/$item")) { del_target_dir("$path/$item", $delDir); } else { unlink("$path/$item"); } } } closedir($handle); if ($delDir) { return rmdir($path); } } else { if (file_exists($path)) { return unlink($path); } return false; } } /** * @notes uri小写 * @param $data * @return array|string[] * @author 段誉 * @date 2022/7/19 14:50 */ function lower_uri($data) { if (!is_array($data)) { $data = [$data]; } return array_map(function ($item) { return strtolower(Str::camel($item)); }, $data); } /** * @notes 本地版本 * @return mixed * @author 段誉 * @date 2021/8/14 15:33 */ function local_version() { if(!file_exists('./upgrade/')) { // 若文件夹不存在,先创建文件夹 mkdir('./upgrade/', 0777, true); } if(!file_exists('./upgrade/version.json')) { // 获取本地版本号 $version = config('project.version'); $data = ['version' => $version]; $src = './upgrade/version.json'; // 新建文件 file_put_contents($src, json_encode($data, JSON_UNESCAPED_UNICODE)); } $json_string = file_get_contents('./upgrade/version.json'); // 用参数true把JSON字符串强制转成PHP数组 $data = json_decode($json_string, true); return $data; } /** * @notes 解压压缩包 * @param $file * @param $save_dir * @return bool * @author 段誉 * @date 2021/8/14 15:27 */ function unzip($file, $save_dir) { if (!file_exists($file)) { return false; } $zip = new \ZipArchive(); if ($zip->open($file) !== TRUE) {//中文文件名要使用ANSI编码的文件格式 return false; } $zip->extractTo($save_dir); $zip->close(); return true; } /** * @notes 遍历指定目录下的文件(目标目录,排除文件) * @param $dir //目标文件 * @param string $exclude_file //要排除的文件 * @param string $target_suffix //指定后缀 * @return array|false * @author 段誉 * @date 2021/8/14 14:44 */ function get_scandir($dir, $exclude_file = '', $target_suffix = '') { if (!file_exists($dir) || empty(trim($dir))) { return []; } $files = scandir($dir); $res = []; foreach ($files as $item) { if ($item == "." || $item == ".." || $item == $exclude_file) { continue; } if (!empty($target_suffix)) { if (get_extension($item) == $target_suffix) { $res[] = $item; } } else { $res[] = $item; } } if (empty($item)) { return false; } return $res; } /** * @notes 获取文件扩展名 * @param $file * @return array|string|string[] * @author 段誉 * @date 2021/8/14 15:24 */ function get_extension($file) { return pathinfo($file, PATHINFO_EXTENSION); } /** * @notes g * @param $timestamp 时间戳 * @return array * @throws Exception * @author cjhao * @date 2024/8/29 19:07 */ function get_hour_to_midnight($timestamp) { $date = date('Y-m-d H:i:s',$timestamp); $dateTime = new DateTime($date); $dateTime->setTime($dateTime->format('H'), $dateTime->format('i')); // 获取明天的日期,并设置时间为00:00:00 $tomorrow = (new DateTime($date))->modify('+1 day'); $tomorrow->setTime(0, 0, 0); // 如果当前时间不是30分钟的倍数,则向上取整到下一个30分钟 if (0 != $dateTime->format('i') % 30 ) { if($dateTime->format('i') > 30){ $surplusMinute = 60 - $dateTime->format('i'); $dateTime->modify('+'.$surplusMinute.' minutes'); }else{ $dateTime->modify('+30 minutes -' .$dateTime->format('i') . ' minutes'); } } // 初始化时间段数组 $intervals = []; // 循环直到到达明天0点 while ($dateTime < $tomorrow) { // 获取当前时间段的开始时间 // $start = clone$dateTime; // 获取当前时间段的结束时间(30分钟后) // $end = (clone$dateTime)->modify('+30 minutes'); // 将当前时间段添加到数组中 // $intervals[] = [ // 'start' => $start->format('H:i'), // 'end' => $end->format('H:i') // ]; $intervals[] = [ 'time' => $dateTime->format('H:i'), 'timestamp' => $dateTime->getTimestamp(), ]; // 移动到下一个时间段 $dateTime->modify('+30 minutes'); } return $intervals; } /** * @notes 返回两点的时间戳 * @param $startTimestamp * @param $secondsToAdd * @return array * @throws Exception * @author cjhao * @date 2024/9/20 00:50 */ function point_timestamps($startTimestamp,$secondsToAdd) { $date = date('Y-m-d H:i:s',$startTimestamp); $dateTime = new DateTime($date); // 获取明天的日期,并设置时间为00:00:00 $endDate = date('Y-m-d H:i:s',$startTimestamp+$secondsToAdd); $endDate = new DateTime($endDate); // 如果当前时间不是30分钟的倍数,则向上取整到下一个30分钟 if (0 != $dateTime->format('i') % 30 ) { if($dateTime->format('i') > 30){ $surplusMinute = 60 - $dateTime->format('i'); $dateTime->modify('+'.$surplusMinute.' minutes'); }else{ $dateTime->modify('+30 minutes -' .$dateTime->format('i') . ' minutes'); } } // 初始化时间段数组 $intervals = []; // 循环直到到达明天0点 while ($dateTime < $endDate) { $intervals[] = [ 'time' => $dateTime->format('H:i'), 'timestamp' => $dateTime->getTimestamp(), ]; // 移动到下一个时间段 $dateTime->modify('+30 minutes'); } $intervals[] = [ 'time' => $dateTime->format('H:i'), 'timestamp' => $dateTime->getTimestamp(), ]; return $intervals; } /** * @notes 将数字转成周几 * @param $number * @return string * @author cjhao * @date 2024/9/27 01:14 */ function getWeekdayByNumber($number) { $weekdays = [ 1 => '周一', 2 => '周二', 3 => '周三', 4 => '周四', 5 => '周五', 6 => '周六', 7 => '周日' ]; return $weekdays[$number] ?? $number; } /** * @notes 返回营业时间 * @param $hours * @return string * @author cjhao * @date 2024/11/19 12:13 */ function displayBusinessHours($hours) { $days = ['周一', '周二', '周三', '周四', '周五', '周六', '周日']; $formattedHours = []; $currentStart = null; $previousOpen = false; foreach ($days as$index => $day) { $isOpen =$hours[$day] == 1; if ($isOpen) { if (is_null($currentStart)) { $currentStart =$day; } if ($previousOpen &&$index > 0 && $hours[$days[$index - 1]] == 1) { // Continue the range if ($index == count($days) - 1 || $hours[$days[$index + 1]] != 1) { // End of range $formattedHours[] = ucfirst($currentStart) . '至' . ucfirst($day); $currentStart = null; } } else { // Single day or start of a new range if ($index == count($days) - 1 || $hours[$days[$index + 1]] != 1) { // No range, just a single day $formattedHours[] = ucfirst($day); $currentStart = null; } } } $previousOpen =$isOpen; } return implode(',', $formattedHours); } /** * @notes 获取时间格式转换 * @param $number * @return false|int * @author cjhao * @date 2024/11/26 22:34 */ function convert_to_time($number) { // 将数字转换为字符串,以便我们可以查找小数点 $numberStr = (string)$number; // 检查是否存在数点 if (strpos($numberStr, ':') !== false) { // 分割数字为小时和分钟 list($hours,$minutes) = explode(':', $numberStr); // 确保分钟是两位数 $minutes = str_pad($minutes, 2, '0', STR_PAD_RIGHT); } else { // 如果没有小数点,则小时数是数字本身,分钟数为00 $hours =$numberStr; $minutes = '00'; } // 返回格式化的时间字符串 $date = strtotime(date('Y-m-d '.sprintf('%02d:%02d', $hours,$minutes))); return $date; } /** * @notes 格式化时间 * @param $time * @return string * @author cjhao * @date 2025/2/27 10:33 */ function format_business_time($time) { // 去除空格 $time = trim($time); // 如果时间格式是单个数字(如 "9"),则补全为 "09:00" if (preg_match('/^\d{1}$/', $time)) { return sprintf("%02d:00", $time); } // 如果时间格式是 "9:00" 或 "09:00",则保持不变 if (preg_match('/^\d{1,2}:\d{2}$/', $time)) { // 分割小时和分钟 list($hour, $minute) = explode(':', $time); return sprintf("%02d:%02d", $hour, $minute); } // 如果输入的是 "9:00" 或类似格式,强制改为 "9:00" if (preg_match('/^\d{1,2}:\d{2}$/', $time)) { // 提取小时部分 list($hour, $minute) = explode(':', $time); return $hour . ':00'; } // 如果格式不符合预期,可以返回默认值或抛出异常 return $time; // 或者根据需求返回其他默认值 } /** * @notes 返回最近的时间段 * @param $inputDateTime * @return string * @author cjhao * @date 2025/3/30 15:50 */ function round_date_time($inputDateTime) { $dateTime = (new DateTime())->setTimestamp($inputDateTime); if (!$dateTime) { return false; } $hour = (int)$dateTime->format('H'); $minute = (int)$dateTime->format('i'); // 如果已经是 30 分钟或整点,直接返回 if ($minute == 30 || $minute == 0) { return $dateTime->getTimestamp(); } // 否则调整到最近的 30 分钟或整点 if ($minute < 30) { $dateTime->setTime($hour, 30); } else { $dateTime->modify('+1 hour')->setTime($hour + 1, 0); } return $dateTime->getTimestamp(); }