|
|
<?php
|
|
|
|
|
|
namespace App\Models;
|
|
|
|
|
|
class Blacklist extends SoftDeletesModel
|
|
|
{
|
|
|
protected $table = 'blacklists';
|
|
|
|
|
|
protected $casts = [
|
|
|
'file' => 'array',
|
|
|
'start_date' => 'date',
|
|
|
'end_date' => 'date',
|
|
|
'status' => 'boolean',
|
|
|
'credent' => 'integer',
|
|
|
];
|
|
|
|
|
|
// 证件类型常量
|
|
|
const CREDENT_ID_CARD = 1; // 身份证
|
|
|
const CREDENT_PASSPORT = 2; // 护照
|
|
|
|
|
|
// 状态常量
|
|
|
const STATUS_DISABLED = 0; // 禁用
|
|
|
const STATUS_ENABLED = 1; // 启用
|
|
|
|
|
|
/**
|
|
|
* 获取证件类型文本
|
|
|
*/
|
|
|
public function getCredentTextAttribute()
|
|
|
{
|
|
|
$credents = [
|
|
|
self::CREDENT_ID_CARD => '身份证',
|
|
|
self::CREDENT_PASSPORT => '护照',
|
|
|
];
|
|
|
return $credents[$this->credent] ?? '未知';
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* 获取状态文本
|
|
|
*/
|
|
|
public function getStatusTextAttribute()
|
|
|
{
|
|
|
return $this->status ? '启用' : '禁用';
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* 获取文件列表(多文件)
|
|
|
*/
|
|
|
public function getFilesAttribute()
|
|
|
{
|
|
|
if (!$this->file) {
|
|
|
return [];
|
|
|
}
|
|
|
|
|
|
return Upload::whereIn('id', $this->file)->get();
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* 检查是否在有效期内
|
|
|
*/
|
|
|
public function isActive()
|
|
|
{
|
|
|
if (!$this->status) {
|
|
|
return false;
|
|
|
}
|
|
|
|
|
|
$now = now();
|
|
|
|
|
|
// 检查开始时间
|
|
|
if ($this->start_date && $now->lt($this->start_date)) {
|
|
|
return false;
|
|
|
}
|
|
|
|
|
|
// 检查结束时间
|
|
|
if ($this->end_date && $now->gt($this->end_date)) {
|
|
|
return false;
|
|
|
}
|
|
|
|
|
|
return true;
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* 检查访客是否在黑名单中
|
|
|
*/
|
|
|
public static function checkVisitor($mobile, $idcard = null)
|
|
|
{
|
|
|
$query = self::where('status', self::STATUS_ENABLED)
|
|
|
->where(function ($q) use ($mobile, $idcard) {
|
|
|
$q->where('mobile', $mobile);
|
|
|
if ($idcard) {
|
|
|
$q->orWhere('idcard', $idcard);
|
|
|
}
|
|
|
});
|
|
|
|
|
|
$blacklist = $query->first();
|
|
|
|
|
|
if (!$blacklist) {
|
|
|
return null;
|
|
|
}
|
|
|
|
|
|
return $blacklist->isActive() ? $blacklist : null;
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* 添加黑名单记录
|
|
|
*/
|
|
|
public static function addToBlacklist($data)
|
|
|
{
|
|
|
// 检查是否已存在
|
|
|
$existing = self::where('mobile', $data['mobile'])
|
|
|
->orWhere('idcard', $data['idcard'] ?? '')
|
|
|
->first();
|
|
|
|
|
|
if ($existing) {
|
|
|
// 更新现有记录
|
|
|
$existing->update($data);
|
|
|
return $existing;
|
|
|
}
|
|
|
|
|
|
// 创建新记录
|
|
|
return self::create($data);
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* 从黑名单中移除
|
|
|
*/
|
|
|
public function removeFromBlacklist()
|
|
|
{
|
|
|
$this->status = self::STATUS_DISABLED;
|
|
|
$this->save();
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* 获取有效期文本
|
|
|
*/
|
|
|
public function getValidityPeriodText()
|
|
|
{
|
|
|
if (!$this->start_date && !$this->end_date) {
|
|
|
return '永久有效';
|
|
|
}
|
|
|
|
|
|
$start = $this->start_date ? $this->start_date->format('Y-m-d') : '开始';
|
|
|
$end = $this->end_date ? $this->end_date->format('Y-m-d') : '结束';
|
|
|
|
|
|
return $start . ' 至 ' . $end;
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* 获取剩余天数
|
|
|
*/
|
|
|
public function getRemainingDays()
|
|
|
{
|
|
|
if (!$this->end_date) {
|
|
|
return null; // 永久有效
|
|
|
}
|
|
|
|
|
|
$now = now();
|
|
|
if ($now->gt($this->end_date)) {
|
|
|
return 0; // 已过期
|
|
|
}
|
|
|
|
|
|
return $now->diffInDays($this->end_date);
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* 检查是否即将过期(7天内)
|
|
|
*/
|
|
|
public function isExpiringSoon()
|
|
|
{
|
|
|
$remainingDays = $this->getRemainingDays();
|
|
|
return $remainingDays !== null && $remainingDays <= 7;
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* 获取黑名单统计信息
|
|
|
*/
|
|
|
public static function getStatistics()
|
|
|
{
|
|
|
$total = self::count();
|
|
|
$active = self::where('status', self::STATUS_ENABLED)->count();
|
|
|
$expired = self::where('status', self::STATUS_ENABLED)
|
|
|
->where('end_date', '<', now())
|
|
|
->count();
|
|
|
$expiringSoon = self::where('status', self::STATUS_ENABLED)
|
|
|
->whereBetween('end_date', [now(), now()->addDays(7)])
|
|
|
->count();
|
|
|
|
|
|
return [
|
|
|
'total' => $total,
|
|
|
'active' => $active,
|
|
|
'expired' => $expired,
|
|
|
'expiring_soon' => $expiringSoon,
|
|
|
'disabled' => $total - $active,
|
|
|
];
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* 批量导入黑名单
|
|
|
*/
|
|
|
public static function batchImport($data)
|
|
|
{
|
|
|
$successCount = 0;
|
|
|
$errorCount = 0;
|
|
|
$errors = [];
|
|
|
|
|
|
foreach ($data as $index => $item) {
|
|
|
try {
|
|
|
// 验证必填字段
|
|
|
if (empty($item['mobile']) && empty($item['idcard'])) {
|
|
|
$errors[] = "第" . ($index + 1) . "行:手机号和证件号不能同时为空";
|
|
|
$errorCount++;
|
|
|
continue;
|
|
|
}
|
|
|
|
|
|
// 检查是否已存在
|
|
|
$existing = self::where('mobile', $item['mobile'] ?? '')
|
|
|
->orWhere('idcard', $item['idcard'] ?? '')
|
|
|
->first();
|
|
|
|
|
|
if ($existing) {
|
|
|
$existing->update($item);
|
|
|
} else {
|
|
|
self::create($item);
|
|
|
}
|
|
|
|
|
|
$successCount++;
|
|
|
} catch (\Exception $e) {
|
|
|
$errors[] = "第" . ($index + 1) . "行:" . $e->getMessage();
|
|
|
$errorCount++;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
return [
|
|
|
'success_count' => $successCount,
|
|
|
'error_count' => $errorCount,
|
|
|
'errors' => $errors,
|
|
|
];
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* 验证黑名单数据
|
|
|
*/
|
|
|
public function validate()
|
|
|
{
|
|
|
$errors = [];
|
|
|
|
|
|
if (empty($this->mobile) && empty($this->idcard)) {
|
|
|
$errors[] = '手机号和证件号不能同时为空';
|
|
|
}
|
|
|
|
|
|
if (!empty($this->mobile) && !preg_match('/^1[3-9]\d{9}$/', $this->mobile)) {
|
|
|
$errors[] = '手机号格式不正确';
|
|
|
}
|
|
|
|
|
|
if (!empty($this->idcard) && !preg_match('/^[1-9]\d{5}(18|19|20)\d{2}((0[1-9])|(1[0-2]))(([0-2][1-9])|10|20|30|31)\d{3}[0-9Xx]$/', $this->idcard)) {
|
|
|
$errors[] = '身份证号格式不正确';
|
|
|
}
|
|
|
|
|
|
if ($this->start_date && $this->end_date && $this->start_date > $this->end_date) {
|
|
|
$errors[] = '开始时间不能晚于结束时间';
|
|
|
}
|
|
|
|
|
|
return $errors;
|
|
|
}
|
|
|
}
|