|
|
|
|
@ -57,79 +57,79 @@ class UserController extends BaseController
|
|
|
|
|
$all = request()->all();
|
|
|
|
|
$list = $this->model->with(underlineToHump($all['show_relation'] ?? []))
|
|
|
|
|
->with([
|
|
|
|
|
'courseSigns' => function ($query) use ($all) {
|
|
|
|
|
$query->where('status', 1)->with('course.teacher', 'course.typeDetail');
|
|
|
|
|
}
|
|
|
|
|
])->where(function ($query) use ($all) {
|
|
|
|
|
if (isset($all['keyword'])) {
|
|
|
|
|
$query->whereHas('courses', function ($q) use ($all) {
|
|
|
|
|
$q->where('name', 'like', '%' . $all['keyword'] . '%');
|
|
|
|
|
})->orWhere('name', 'like', '%' . $all['keyword'] . '%');
|
|
|
|
|
}
|
|
|
|
|
if (isset($all['has_course']) && $all['has_course'] == 1) {
|
|
|
|
|
$query->whereHas('courseSigns', function ($q) {
|
|
|
|
|
$q->where('status', 1);
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
if (isset($all['filter']) && !empty($all['filter'])) {
|
|
|
|
|
foreach ($all['filter'] as $condition) {
|
|
|
|
|
$key = $condition['key'] ?? null;
|
|
|
|
|
$op = $condition['op'] ?? null;
|
|
|
|
|
$value = $condition['value'] ?? null;
|
|
|
|
|
if (!isset($key) || !isset($op) || !isset($value)) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
// 等于
|
|
|
|
|
if ($op == 'eq') {
|
|
|
|
|
$query->where($key, $value);
|
|
|
|
|
}
|
|
|
|
|
// 不等于
|
|
|
|
|
if ($op == 'neq') {
|
|
|
|
|
$query->where($key, '!=', $value);
|
|
|
|
|
}
|
|
|
|
|
// 大于
|
|
|
|
|
if ($op == 'gt') {
|
|
|
|
|
$query->where($key, '>', $value);
|
|
|
|
|
}
|
|
|
|
|
// 大于等于
|
|
|
|
|
if ($op == 'egt') {
|
|
|
|
|
$query->where($key, '>=', $value);
|
|
|
|
|
}
|
|
|
|
|
// 小于
|
|
|
|
|
if ($op == 'lt') {
|
|
|
|
|
$query->where($key, '<', $value);
|
|
|
|
|
}
|
|
|
|
|
// 小于等于
|
|
|
|
|
if ($op == 'elt') {
|
|
|
|
|
$query->where($key, '<=', $value);
|
|
|
|
|
}
|
|
|
|
|
// 模糊搜索
|
|
|
|
|
if ($op == 'like') {
|
|
|
|
|
$query->where($key, 'like', '%' . $value . '%');
|
|
|
|
|
}
|
|
|
|
|
// 否定模糊搜索
|
|
|
|
|
if ($op == 'notlike') {
|
|
|
|
|
$query->where($key, 'not like', '%' . $value . '%');
|
|
|
|
|
}
|
|
|
|
|
// null搜索
|
|
|
|
|
if ($op == 'null') {
|
|
|
|
|
$query->whereNull($key);
|
|
|
|
|
}
|
|
|
|
|
// notnull搜索
|
|
|
|
|
if ($op == 'notnull') {
|
|
|
|
|
$query->whereNotNull($key);
|
|
|
|
|
}
|
|
|
|
|
// 范围搜索
|
|
|
|
|
if ($op == 'range') {
|
|
|
|
|
list($from, $to) = explode(',', $value);
|
|
|
|
|
if (empty($from) || empty($to)) {
|
|
|
|
|
'courseSigns' => function ($query) use ($all) {
|
|
|
|
|
$query->where('status', 1)->with('course.teacher', 'course.typeDetail');
|
|
|
|
|
}
|
|
|
|
|
])->where(function ($query) use ($all) {
|
|
|
|
|
if (isset($all['keyword'])) {
|
|
|
|
|
$query->whereHas('courses', function ($q) use ($all) {
|
|
|
|
|
$q->where('name', 'like', '%' . $all['keyword'] . '%');
|
|
|
|
|
})->orWhere('name', 'like', '%' . $all['keyword'] . '%');
|
|
|
|
|
}
|
|
|
|
|
if (isset($all['has_course']) && $all['has_course'] == 1) {
|
|
|
|
|
$query->whereHas('courseSigns', function ($q) {
|
|
|
|
|
$q->where('status', 1);
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
if (isset($all['filter']) && !empty($all['filter'])) {
|
|
|
|
|
foreach ($all['filter'] as $condition) {
|
|
|
|
|
$key = $condition['key'] ?? null;
|
|
|
|
|
$op = $condition['op'] ?? null;
|
|
|
|
|
$value = $condition['value'] ?? null;
|
|
|
|
|
if (!isset($key) || !isset($op) || !isset($value)) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
$query->whereBetween($key, [$from, $to]);
|
|
|
|
|
// 等于
|
|
|
|
|
if ($op == 'eq') {
|
|
|
|
|
$query->where($key, $value);
|
|
|
|
|
}
|
|
|
|
|
// 不等于
|
|
|
|
|
if ($op == 'neq') {
|
|
|
|
|
$query->where($key, '!=', $value);
|
|
|
|
|
}
|
|
|
|
|
// 大于
|
|
|
|
|
if ($op == 'gt') {
|
|
|
|
|
$query->where($key, '>', $value);
|
|
|
|
|
}
|
|
|
|
|
// 大于等于
|
|
|
|
|
if ($op == 'egt') {
|
|
|
|
|
$query->where($key, '>=', $value);
|
|
|
|
|
}
|
|
|
|
|
// 小于
|
|
|
|
|
if ($op == 'lt') {
|
|
|
|
|
$query->where($key, '<', $value);
|
|
|
|
|
}
|
|
|
|
|
// 小于等于
|
|
|
|
|
if ($op == 'elt') {
|
|
|
|
|
$query->where($key, '<=', $value);
|
|
|
|
|
}
|
|
|
|
|
// 模糊搜索
|
|
|
|
|
if ($op == 'like') {
|
|
|
|
|
$query->where($key, 'like', '%' . $value . '%');
|
|
|
|
|
}
|
|
|
|
|
// 否定模糊搜索
|
|
|
|
|
if ($op == 'notlike') {
|
|
|
|
|
$query->where($key, 'not like', '%' . $value . '%');
|
|
|
|
|
}
|
|
|
|
|
// null搜索
|
|
|
|
|
if ($op == 'null') {
|
|
|
|
|
$query->whereNull($key);
|
|
|
|
|
}
|
|
|
|
|
// notnull搜索
|
|
|
|
|
if ($op == 'notnull') {
|
|
|
|
|
$query->whereNotNull($key);
|
|
|
|
|
}
|
|
|
|
|
// 范围搜索
|
|
|
|
|
if ($op == 'range') {
|
|
|
|
|
list($from, $to) = explode(',', $value);
|
|
|
|
|
if (empty($from) || empty($to)) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
$query->whereBetween($key, [$from, $to]);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
})->orderBy($all['sort_name'] ?? 'id', $all['sort_type'] ?? 'desc');
|
|
|
|
|
})->orderBy($all['sort_name'] ?? 'id', $all['sort_type'] ?? 'desc');
|
|
|
|
|
if (isset($all['is_export']) && !empty($all['is_export'])) {
|
|
|
|
|
$list = $list->get()->toArray();
|
|
|
|
|
$export_fields = $all['export_fields'] ?? [];
|
|
|
|
|
@ -187,6 +187,7 @@ class UserController extends BaseController
|
|
|
|
|
* @OA\Parameter(name="is_black", in="query", @OA\Schema(type="string"), required=true, description="是否黑名单0否1是"),
|
|
|
|
|
* @OA\Parameter(name="is_yh_invested", in="query", @OA\Schema(type="string"), required=true, description="是否元和已投企业0否1是"),
|
|
|
|
|
* @OA\Parameter(name="company_tag", in="query", @OA\Schema(type="string"), required=true, description="企业标签"),
|
|
|
|
|
* @OA\Parameter(name="talent_tags", in="query", @OA\Schema(type="string"), required=false, description="人才标签,多个英文逗号分隔"),
|
|
|
|
|
* @OA\Parameter(name="token", in="query", @OA\Schema(type="string"), required=true, description="token"),
|
|
|
|
|
* @OA\Response(
|
|
|
|
|
* response="200",
|
|
|
|
|
@ -209,10 +210,10 @@ class UserController extends BaseController
|
|
|
|
|
'company'
|
|
|
|
|
)
|
|
|
|
|
->with([
|
|
|
|
|
'courseSigns' => function ($query) {
|
|
|
|
|
$query->with('course.typeDetail')->orderBy('fee_status', 'desc');
|
|
|
|
|
}
|
|
|
|
|
])->withCount([
|
|
|
|
|
'courseSigns' => function ($query) {
|
|
|
|
|
$query->with('course.typeDetail')->orderBy('fee_status', 'desc');
|
|
|
|
|
}
|
|
|
|
|
])->withCount([
|
|
|
|
|
'appointments' => function ($query) {
|
|
|
|
|
$query->whereIn('status', [0, 1]);
|
|
|
|
|
}
|
|
|
|
|
@ -379,6 +380,14 @@ class UserController extends BaseController
|
|
|
|
|
->orWhere('speciality', 'like', '%' . $all['keyword'] . '%')
|
|
|
|
|
->orWhere('introduce', 'like', '%' . $all['keyword'] . '%');
|
|
|
|
|
}
|
|
|
|
|
if (isset($all['talent_tags'])) {
|
|
|
|
|
$talentTags = explode(',', $all['talent_tags']);
|
|
|
|
|
$query->where(function ($q) use ($talentTags) {
|
|
|
|
|
foreach ($talentTags as $tag) {
|
|
|
|
|
$q->orWhereRaw('FIND_IN_SET(?, talent_tags)', [trim($tag)]);
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
})->orderBy($all['sort_name'] ?? 'id', $all['sort_type'] ?? 'desc');
|
|
|
|
|
if (isset($all['is_export']) && !empty($all['is_export'])) {
|
|
|
|
|
$list = $list->limit(5000)->get()->toArray();
|
|
|
|
|
@ -812,13 +821,28 @@ class UserController extends BaseController
|
|
|
|
|
$tableName = $this->model->getTable();
|
|
|
|
|
$rowTableFieldByComment = (new CustomFormField)->getRowTableFieldsByComment($tableName);
|
|
|
|
|
|
|
|
|
|
// 获取 Excel 文件中的表头(从第一行数据中提取)
|
|
|
|
|
$excelHeaders = [];
|
|
|
|
|
if (!empty($dataArray)) {
|
|
|
|
|
$firstRow = reset($dataArray);
|
|
|
|
|
$excelHeaders = array_keys($firstRow);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 只保留 Excel 中存在的字段的表头信息
|
|
|
|
|
$filteredHeaders = [];
|
|
|
|
|
foreach ($rowTableFieldByComment as $fieldName => $comment) {
|
|
|
|
|
if (in_array($comment, $excelHeaders)) {
|
|
|
|
|
$filteredHeaders[$fieldName] = $comment;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$list = [];
|
|
|
|
|
$unmatchedUsers = []; // 记录未匹配到的用户
|
|
|
|
|
foreach ($dataArray as $key => $value) {
|
|
|
|
|
// 获取姓名、公司名称、职位
|
|
|
|
|
$name = $value['姓名'] ?? $value['name'] ?? '';
|
|
|
|
|
$companyName = $value['公司名称'] ?? $value['company_name'] ?? '';
|
|
|
|
|
$companyPosition = $value['职位'] ?? $value['company_position'] ?? '';
|
|
|
|
|
$companyName = $value['公司'] ?? $value['company_name'] ?? '';
|
|
|
|
|
$companyPosition = $value['职务'] ?? $value['company_position'] ?? '';
|
|
|
|
|
|
|
|
|
|
// 通过姓名、公司名称、职位匹配用户
|
|
|
|
|
$matchedUser = null;
|
|
|
|
|
@ -839,18 +863,17 @@ class UserController extends BaseController
|
|
|
|
|
];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 构建返回数据(使用手机号作为唯一标识)
|
|
|
|
|
// 构建返回数据(使用ID作为唯一标识)
|
|
|
|
|
$list[$key] = [
|
|
|
|
|
'name' => $name,
|
|
|
|
|
'company_name' => $companyName,
|
|
|
|
|
'company_position' => $companyPosition,
|
|
|
|
|
'matched' => $matchedUser ? true : false,
|
|
|
|
|
'mobile' => $matchedUser ? $matchedUser->mobile : null, // 使用手机号作为唯一标识
|
|
|
|
|
'id' => $matchedUser ? $matchedUser->id : null, // 使用ID作为唯一标识
|
|
|
|
|
'existing_data' => $matchedUser ? [
|
|
|
|
|
'id' => $matchedUser->id,
|
|
|
|
|
'username' => $matchedUser->username,
|
|
|
|
|
'name' => $matchedUser->name,
|
|
|
|
|
'mobile' => $matchedUser->mobile,
|
|
|
|
|
'company_name' => $matchedUser->company_name,
|
|
|
|
|
'company_position' => $matchedUser->company_position,
|
|
|
|
|
] : null,
|
|
|
|
|
@ -876,6 +899,7 @@ class UserController extends BaseController
|
|
|
|
|
|
|
|
|
|
// 构建返回结果
|
|
|
|
|
$result = [
|
|
|
|
|
'headers' => $filteredHeaders, // 表头信息,只包含 Excel 中存在的字段,键为字段名,值为中文注释
|
|
|
|
|
'list' => $list,
|
|
|
|
|
'matched_count' => count($list) - count($unmatchedUsers),
|
|
|
|
|
'unmatched_count' => count($unmatchedUsers),
|
|
|
|
|
@ -922,109 +946,80 @@ class UserController extends BaseController
|
|
|
|
|
$filteredRecords = $all['data'];
|
|
|
|
|
$suc = 0;
|
|
|
|
|
$updateCount = 0;
|
|
|
|
|
$unmatchedUsers = []; // 记录未匹配到的用户
|
|
|
|
|
$failedRecords = []; // 记录导入失败的记录
|
|
|
|
|
|
|
|
|
|
DB::beginTransaction();
|
|
|
|
|
try {
|
|
|
|
|
foreach ($filteredRecords as $index => $record) {
|
|
|
|
|
// 获取匹配的手机号(如果预览时已匹配到)
|
|
|
|
|
$mobile = $record['mobile'] ?? null;
|
|
|
|
|
|
|
|
|
|
// 如果没有mobile,尝试通过姓名、公司、职位再次匹配
|
|
|
|
|
if (!$mobile) {
|
|
|
|
|
$name = $record['name'] ?? '';
|
|
|
|
|
$companyName = $record['company_name'] ?? '';
|
|
|
|
|
$companyPosition = $record['company_position'] ?? '';
|
|
|
|
|
|
|
|
|
|
if (!empty($name) && !empty($companyName) && !empty($companyPosition)) {
|
|
|
|
|
$matchedUser = $this->model->where('username', $name)
|
|
|
|
|
->where('company_name', $companyName)
|
|
|
|
|
->where('company_position', $companyPosition)
|
|
|
|
|
->first();
|
|
|
|
|
if ($matchedUser) {
|
|
|
|
|
$mobile = $matchedUser->mobile;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
// 获取匹配的用户ID(如果预览时已匹配到)
|
|
|
|
|
$userId = $record['id'] ?? null;
|
|
|
|
|
|
|
|
|
|
// 如果仍未匹配到手机号,记录并跳过
|
|
|
|
|
if (!$mobile) {
|
|
|
|
|
$unmatchedUsers[] = [
|
|
|
|
|
// 如果没有ID,记录失败并跳过
|
|
|
|
|
if (!$userId) {
|
|
|
|
|
$failedRecords[] = [
|
|
|
|
|
'row' => $index + 1,
|
|
|
|
|
'name' => $record['name'] ?? '',
|
|
|
|
|
'company_name' => $record['company_name'] ?? '',
|
|
|
|
|
'company_position' => $record['company_position'] ?? '',
|
|
|
|
|
'reason' => '缺少用户ID'
|
|
|
|
|
];
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 去除匹配相关的字段,避免更新到数据库
|
|
|
|
|
unset($record['matched'], $record['existing_data']);
|
|
|
|
|
unset($record['matched'], $record['existing_data'], $record['id']);
|
|
|
|
|
|
|
|
|
|
// 去除空值
|
|
|
|
|
$record = array_filter($record, function ($value) {
|
|
|
|
|
return $value != '';
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// 通过手机号查找并更新用户
|
|
|
|
|
$user = $this->model->where('mobile', $mobile)->first();
|
|
|
|
|
if ($user) {
|
|
|
|
|
// 设置username(如果name字段存在)
|
|
|
|
|
if (isset($record['name'])) {
|
|
|
|
|
$record['username'] = $record['name'];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 所有数据通过追加的形式更新(参考importStudy的逻辑)
|
|
|
|
|
foreach ($record as $k => &$v) {
|
|
|
|
|
if (!in_array($k, User::$coverFields)) {
|
|
|
|
|
// 追加更新
|
|
|
|
|
$tempArray = explode(',', ($user->$k ?? '') . ',' . $v);
|
|
|
|
|
$tempArray = array_unique(array_filter($tempArray));
|
|
|
|
|
$v = implode(',', $tempArray);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
$user->fill($record);
|
|
|
|
|
$user->save();
|
|
|
|
|
$updateCount++;
|
|
|
|
|
$suc++;
|
|
|
|
|
// 通过ID查找并更新用户
|
|
|
|
|
$user = $this->model->find($userId);
|
|
|
|
|
if (!$user) {
|
|
|
|
|
// 用户不存在,记录失败并跳过
|
|
|
|
|
$failedRecords[] = [
|
|
|
|
|
'row' => $index + 1,
|
|
|
|
|
'name' => $record['name'] ?? '',
|
|
|
|
|
'company_name' => $record['company_name'] ?? '',
|
|
|
|
|
'company_position' => $record['company_position'] ?? '',
|
|
|
|
|
'reason' => '用户不存在(ID: ' . $userId . ')'
|
|
|
|
|
];
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 写入报名表(如果有课程信息)
|
|
|
|
|
if (isset($record['course_id']) && !empty($record['course_id'])) {
|
|
|
|
|
$whereSign = ['course_id' => $record['course_id'], 'user_id' => $user->id];
|
|
|
|
|
$dataSign = [
|
|
|
|
|
'course_id' => $record['course_id'],
|
|
|
|
|
'user_id' => $user->id,
|
|
|
|
|
'is_import' => 1,
|
|
|
|
|
'status' => $record['status'] ?? 1,
|
|
|
|
|
'fee_status' => $record['fee_status'] ?? 0
|
|
|
|
|
];
|
|
|
|
|
$courseSign = CourseSign::updateOrCreate($whereSign, $dataSign);
|
|
|
|
|
// 加导入次数,加预约次数
|
|
|
|
|
if ($courseSign->status == 1) {
|
|
|
|
|
CourseAppointmentTotal::add($courseSign->user_id, $courseSign->id);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
// 设置username(如果name字段存在)
|
|
|
|
|
if (isset($record['name'])) {
|
|
|
|
|
$record['username'] = $record['name'];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 如果有未匹配到的用户,返回错误
|
|
|
|
|
if (count($unmatchedUsers) > 0) {
|
|
|
|
|
DB::rollBack();
|
|
|
|
|
$unmatchedNames = array_map(function ($user) {
|
|
|
|
|
return "第{$user['row']}行:{$user['name']}({$user['company_name']} - {$user['company_position']})";
|
|
|
|
|
}, $unmatchedUsers);
|
|
|
|
|
return $this->fail([
|
|
|
|
|
ResponseCode::ERROR_BUSINESS,
|
|
|
|
|
'以下用户未匹配到,无法更新:' . implode(';', $unmatchedNames)
|
|
|
|
|
]);
|
|
|
|
|
// 直接覆盖更新
|
|
|
|
|
$user->fill($record);
|
|
|
|
|
$user->save();
|
|
|
|
|
$updateCount++;
|
|
|
|
|
$suc++;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
DB::commit();
|
|
|
|
|
return $this->success([
|
|
|
|
|
|
|
|
|
|
// 构建返回结果
|
|
|
|
|
$result = [
|
|
|
|
|
'total' => count($filteredRecords),
|
|
|
|
|
'suc' => $suc,
|
|
|
|
|
'update_count' => $updateCount
|
|
|
|
|
]);
|
|
|
|
|
'update_count' => $updateCount,
|
|
|
|
|
'failed_count' => count($failedRecords),
|
|
|
|
|
'failed_records' => $failedRecords
|
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
// 如果有失败的记录,添加提示信息
|
|
|
|
|
if (count($failedRecords) > 0) {
|
|
|
|
|
$failedNames = array_map(function ($record) {
|
|
|
|
|
return "第{$record['row']}行:{$record['name']}({$record['company_name']} - {$record['company_position']})- {$record['reason']}";
|
|
|
|
|
}, $failedRecords);
|
|
|
|
|
$result['message'] = '以下记录导入失败:' . implode(';', $failedNames);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return $this->success($result);
|
|
|
|
|
} catch (\Exception $exception) {
|
|
|
|
|
DB::rollBack();
|
|
|
|
|
return $this->fail([$exception->getCode(), $exception->getMessage()]);
|
|
|
|
|
|