You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

492 lines
17 KiB

9 months ago
<?php
namespace App\Models;
3 months ago
use App\Repositories\YuanheRepository;
9 months ago
class Company extends SoftDeletesModel
{
5 months ago
5 months ago
protected $casts = ['project_users' => 'json', 'partners' => 'json'];
5 months ago
protected $appends = ['is_yh_invested_text'];
public function getIsYhInvestedTextAttribute()
{
3 months ago
if (empty($this->is_yh_invested)) {
3 months ago
return '';
3 months ago
}
3 months ago
return $this->is_yh_invested == 1 ? '被投企业' : '';
5 months ago
}
5 months ago
9 months ago
public function users()
{
return $this->hasMany(User::class, 'company_id', 'id');
}
9 months ago
3 months ago
/**
* 限制只返回有关联学员且至少有一条审核通过的报名记录的公司
* 用于列表查询和统计查询
* @param \Illuminate\Database\Eloquent\Builder $query
* @return \Illuminate\Database\Eloquent\Builder
*/
public function scopeApprovedStudents($query)
{
return $query->whereHas('users', function ($q) {
$q->whereHas('courseSigns', function ($signQuery) {
$signQuery->where('status', 1);
});
});
}
8 months ago
2 months ago
/**
* 根据区域名称筛选公司
* 支持区域名称映射和特殊逻辑(如"苏州市外"
* @param \Illuminate\Database\Eloquent\Builder $query
* @param string|array $companyArea 区域名称,多个用英文逗号分隔或传入数组
* @return \Illuminate\Database\Eloquent\Builder
*/
public function scopeFilterByArea($query, $companyArea)
{
if (empty($companyArea)) {
return $query;
}
// 如果是字符串,转换为数组
if (is_string($companyArea)) {
$company_area = array_filter(array_map('trim', explode(',', $companyArea)));
} else {
$company_area = array_filter(array_map('trim', (array) $companyArea));
}
if (empty($company_area)) {
return $query;
}
// 区域名称映射:搜索参数 -> 数据库值
$areaMapping = [
'高新区' => '虎丘',
];
// 检查是否包含"苏州市外"
$hasSuzhouOut = in_array('苏州市外', $company_area);
if ($hasSuzhouOut) {
// 苏州市外:排除 company_area 参数接口返回的苏州市内选项,以及虎丘区
$excludeAreas = Parameter::where('number', 'company_area')
->with(['detail' => fn ($q) => $q->orderBy('sort', 'asc')])
->first();
$excludeList = [];
if ($excludeAreas && $excludeAreas->detail) {
foreach ($excludeAreas->detail as $d) {
$v = trim((string) ($d->value ?? ''));
if ($v !== '' && $v !== '苏州市外') {
$excludeList[] = $v;
// 高新区映射为虎丘(数据库可能存虎丘)
if ($v === '高新区') {
$excludeList[] = '虎丘';
}
}
}
}
$excludeList = array_unique(array_merge($excludeList, ['虎丘区']));
$query->whereNotNull('company_area')->where('company_area', '!=', '');
if (!empty($excludeList)) {
foreach ($excludeList as $v) {
$query->where('company_area', 'not like', '%' . $v . '%');
}
}
return $query;
2 months ago
} else {
// 将搜索参数转换为数据库值
$company_area = array_map(function ($v) use ($areaMapping) {
return isset($areaMapping[$v]) ? $areaMapping[$v] : $v;
}, $company_area);
return $query->where(function ($q) use ($company_area) {
foreach ($company_area as $v) {
$q->orWhere('company_area', 'like', '%' . $v . '%');
}
});
}
}
8 months ago
/**
* 地址转经纬度
*/
public static function addressTolocation($address)
{
$map = Config::getValueByKey('map_server');
$map = json_decode($map, true);
$url = "https://restapi.amap.com/v3/geocode/geo";
$params = [
'key' => $map['key'],
'address' => $address,
];
try {
$result = httpCurl($url, 'GET', $params);
$result = json_decode($result, true);
if ($result['status'] == 1) {
$location = $result['geocodes'][0]['location'];
$location = explode(',', $location);
return [
'lng' => $location[0],
'lat' => $location[1],
];
}
return [
'lng' => null,
'lat' => null,
];
} catch (\Exception $e) {
return [
'lng' => null,
'lat' => null,
];
}
}
3 months ago
/**
3 months ago
* 根据用户信息更新/同步公司信息
3 months ago
* @param User $user 用户对象
* @return array 返回结果 ['success' => bool, 'message' => string, 'company' => Company|null]
*/
3 months ago
public static function updateCompanyFromUser($user)
3 months ago
{
if (!$user || empty($user->company_name)) {
return ['success' => false, 'message' => '用户或公司名称为空', 'company' => null];
}
3 months ago
// 如果已经有有效的公司关联company_id > 0跳过
// 允许处理 company_id = -1待更新或 null初始状态的情况
3 months ago
if ($user->company_id && $user->company_id > 0) {
3 months ago
return ['success' => false, 'message' => '用户已有公司关联', 'company' => null];
}
3 months ago
// 清理公司名称:去除首尾空格、换行符、制表符等异常字符
$cleanedCompanyName = trim($user->company_name);
// 去除换行符、回车符、制表符等空白字符
$cleanedCompanyName = preg_replace('/[\r\n\t]+/', '', $cleanedCompanyName);
// 将多个连续空格替换为单个空格
$cleanedCompanyName = preg_replace('/\s+/', ' ', $cleanedCompanyName);
// 再次去除首尾空格
$cleanedCompanyName = trim($cleanedCompanyName);
// 如果清理后为空,返回错误
if (empty($cleanedCompanyName)) {
return ['success' => false, 'message' => '公司名称无效', 'company' => null];
}
3 months ago
$YuanheRepository = new YuanheRepository();
3 months ago
// 获取公司详细信息,使用清理后的公司名称
$result = $YuanheRepository->companyInfo(['enterpriseName' => $cleanedCompanyName]);
3 months ago
if (!$result) {
// 标识一下未匹配到公司,后续可以根据这个字段筛选出未匹配到公司的用户
3 months ago
$user->company_id = 0;
$user->save();
3 months ago
return ['success' => false, 'message' => '公司不存在', 'company' => null];
}
// 如果$result['enterpriseName']存在数字,跳过
if (preg_match('/\d/', $result['enterpriseName'])) {
3 months ago
$user->company_id = 0;
$user->save();
3 months ago
return ['success' => false, 'message' => '公司名称包含数字,跳过', 'company' => null];
}
if ($result['status'] == '未注册') {
3 months ago
$user->company_id = 0;
$user->save();
3 months ago
return ['success' => false, 'message' => '公司未注册,跳过', 'company' => null];
}
$where = ['company_name' => $result['enterpriseName']];
$data = [
'business_scope' => $result['businessScope'],
'company_city' => $result['city'],
'contact_mail' => $result['contactMail'],
'contact_phone' => $result['contactPhone'],
'company_area' => $result['country'],
'credit_code' => $result['creditCode'],
'enterprise_id' => $result['enterpriseId'],
'company_name' => $result['enterpriseName'],
'is_abroad' => $result['isAbroad'],
'company_market' => $result['isOnStock'],
'is_yh_invested' => $result['isYhInvested'],
'logo' => $result['logo'],
'company_legal_representative' => $result['operName'],
'company_province' => $result['province'],
'company_industry' => combineKeyValue($result['qccIndustry']),
'regist_amount' => $result['registAmount'],
'regist_capi_type' => $result['registCapiType'],
'company_date' => $result['startDate'],
'status' => $result['status'],
'stock_date' => $result['stockDate'],
'currency_type' => $result['currencyType'],
'stock_number' => $result['stockNumber'],
'stock_type' => $result['stockType'],
'company_tag' => implode(',', $result['tagList']),
// 更新日期
'update_date' => $result['updatedDate'] ?? null,
// 管理平台
'project_users' => $result['projectUsers'] ?? null,
// 股东信息
'partners' => $result['partners'] ?? null,
3 months ago
// 更新地址
'company_address' => $result['address'],
3 months ago
];
$company = Company::updateOrCreate($where, $data);
// 更新用户关联
$user->company_id = $company->id;
$user->save();
// 更新上市状态
self::updateMarketStatus($company->id);
3 months ago
// 更新位置(经纬度)
self::updateLocation($company->id);
3 months ago
return ['success' => true, 'message' => '更新成功', 'company' => $company];
}
3 months ago
/**
3 months ago
* 直接同步公司信息(根据公司名称从接口获取最新信息更新)
* @param Company $company 公司对象
3 months ago
* @return array 返回结果 ['success' => bool, 'message' => string, 'company' => Company|null]
*/
3 months ago
public static function syncCompanyInfo($company)
3 months ago
{
3 months ago
if (!$company || empty($company->company_name)) {
return ['success' => false, 'message' => '公司或公司名称为空', 'company' => null];
}
// 清理公司名称
$cleanedCompanyName = trim($company->company_name);
$cleanedCompanyName = preg_replace('/[\r\n\t]+/', '', $cleanedCompanyName);
$cleanedCompanyName = preg_replace('/\s+/', ' ', $cleanedCompanyName);
$cleanedCompanyName = trim($cleanedCompanyName);
if (empty($cleanedCompanyName)) {
return ['success' => false, 'message' => '公司名称无效', 'company' => null];
}
$YuanheRepository = new YuanheRepository();
// 获取公司详细信息
$result = $YuanheRepository->companyInfo(['enterpriseName' => $cleanedCompanyName]);
if (!$result) {
return ['success' => false, 'message' => '公司不存在', 'company' => null];
}
// 如果$result['enterpriseName']存在数字,跳过
if (preg_match('/\d/', $result['enterpriseName'])) {
return ['success' => false, 'message' => '公司名称包含数字,跳过', 'company' => null];
}
if ($result['status'] == '未注册') {
return ['success' => false, 'message' => '公司未注册,跳过', 'company' => null];
}
// 更新公司数据(不包含地址和经纬度)
$data = [
'business_scope' => $result['businessScope'],
'company_city' => $result['city'],
'contact_mail' => $result['contactMail'],
'contact_phone' => $result['contactPhone'],
'company_area' => $result['country'],
'credit_code' => $result['creditCode'],
'enterprise_id' => $result['enterpriseId'],
'company_name' => $result['enterpriseName'],
'is_abroad' => $result['isAbroad'],
'company_market' => $result['isOnStock'],
'is_yh_invested' => $result['isYhInvested'],
'logo' => $result['logo'],
'company_legal_representative' => $result['operName'],
'company_province' => $result['province'],
'company_industry' => combineKeyValue($result['qccIndustry']),
'regist_amount' => $result['registAmount'],
'regist_capi_type' => $result['registCapiType'],
'company_date' => $result['startDate'],
'status' => $result['status'],
'stock_date' => $result['stockDate'],
'currency_type' => $result['currencyType'],
'stock_number' => $result['stockNumber'],
'stock_type' => $result['stockType'],
'company_tag' => implode(',', $result['tagList']),
'update_date' => $result['updatedDate'] ?? null,
'project_users' => $result['projectUsers'] ?? null,
'partners' => $result['partners'] ?? null,
];
$company->fill($data);
$company->save();
// 更新上市状态
self::updateMarketStatus($company->id);
return ['success' => true, 'message' => '更新成功', 'company' => $company];
3 months ago
}
3 months ago
/**
* 更新经纬度信息
* @param int $companyId 公司ID
* @return bool
*/
public static function updateLocation($companyId)
{
$company = Company::find($companyId);
if (!$company || empty($company->company_address) || $company->company_longitude) {
return false;
}
$local = Company::addressTolocation($company->company_address);
$company->company_longitude = $local['lng'];
$company->company_latitude = $local['lat'];
$company->save();
return true;
}
/**
* 根据 company_tag 更新上市状态
* 判断是否包含上市代码标签,如 688001.SH、000001.SZ、830001.BJ 等
* @param int $companyId 公司ID
* @return bool 是否更新成功
*/
public static function updateMarketStatus($companyId)
{
$company = Company::find($companyId);
if (!$company || empty($company->company_tag)) {
return false;
}
// 上市代码正则:匹配全球各地上市公司股票代码后缀
$stockCodePattern = '/\.(SWR|SW|WR|SS|RS|SB|PK|TO|AX|WS|PR|DB|UN|RT|WT|SH|SZ|BJ|TW|HK|SG|US|DE|FR|JP|KR|A|B|C|D|E|F|G|H|I|J|K|L|M|N|O|P|Q|R|S|U|V|W|X|Y|Z)(?![A-Za-z0-9])/i';
$hasStockCode = preg_match($stockCodePattern, $company->company_tag);
3 months ago
// 不属于新三板上市公司的关键字(需要排除)
$excludeXinsanbanKeywords = [
'新三板摘牌',
'新三板挂牌审核',
'新三板终止',
'新三板退市',
'新三板撤销',
'新三板注销',
'新三板中止',
];
// 检查是否包含排除关键字
$hasExcludeKeyword = array_reduce($excludeXinsanbanKeywords, function ($carry, $keyword) use ($company) {
return $carry || strpos($company->company_tag, $keyword) !== false;
}, false);
// 检查是否包含"新三板",且不包含排除关键字
$hasXinsanban = !$hasExcludeKeyword && strpos($company->company_tag, '新三板') !== false;
// 如果匹配到股票代码或包含"新三板"(且非排除关键字),则标记为上市
3 months ago
$newMarketStatus = ($hasStockCode || $hasXinsanban) ? 1 : 0;
// 只有状态变化才更新
if ($company->company_market != $newMarketStatus) {
$company->company_market = $newMarketStatus;
$company->save();
return true;
}
return false;
}
4 months ago
3 months ago
/**
* 验证公司名称是否包含特殊符号
* @param string $companyName 公司名称
* @return array 返回结果 ['valid' => bool, 'message' => string]
*/
public static function validateCompanyName($companyName)
{
if (empty($companyName)) {
return ['valid' => true, 'message' => ''];
}
// 定义不允许的特殊符号(包含中英文标点符号,键盘上能打出来的所有标点符号)
$forbiddenChars = [
// 英文标点符号
'/',
'\\',
'.',
',',
';',
':',
"'",
'"',
'?',
'!',
'@',
'#',
'$',
'%',
'^',
'&',
'*',
'(',
')',
'[',
']',
'{',
'}',
'|',
'`',
'~',
'-',
'_',
'+',
'=',
'<',
'>',
// 中文标点符号
'。',
'',
'、',
'',
'',
'',
'',
'…',
'—',
'·',
'',
'¥',
'',
'',
'【',
'】',
'《',
'》',
'〈',
'〉',
'「',
'」',
'『',
'』',
'',
'',
];
// 添加中文引号字符(使用十六进制编码避免语法错误)
$chineseQuotes = ["\xE2\x80\x9C", "\xE2\x80\x9D", "\xE2\x80\x98", "\xE2\x80\x99"]; // " " ' '
$forbiddenChars = array_merge($forbiddenChars, $chineseQuotes);
foreach ($forbiddenChars as $char) {
if (strpos($companyName, $char) !== false) {
return ['valid' => false, 'message' => '公司名称不能包含特殊符号'];
}
}
return ['valid' => true, 'message' => ''];
}
9 months ago
}