|
|
|
|
@ -178,6 +178,8 @@ class UserController extends BaseController
|
|
|
|
|
* @OA\Parameter(name="end_company_date", in="query", @OA\Schema(type="string"), required=true, description="结束成立日期"),
|
|
|
|
|
* @OA\Parameter(name="start_birthday", in="query", @OA\Schema(type="string"), required=true, description="开始出生日期"),
|
|
|
|
|
* @OA\Parameter(name="end_birthday", in="query", @OA\Schema(type="string"), required=true, description="结束出生日期"),
|
|
|
|
|
* @OA\Parameter(name="sign_start_date", in="query", @OA\Schema(type="string"), required=false, description="报名开始时间"),
|
|
|
|
|
* @OA\Parameter(name="sign_end_date", in="query", @OA\Schema(type="string"), required=false, description="报名结束时间"),
|
|
|
|
|
* @OA\Parameter(name="company_need_fund", in="query", @OA\Schema(type="string"), required=true, description="是否需要融资"),
|
|
|
|
|
* @OA\Parameter(name="is_fee", in="query", @OA\Schema(type="string"), required=true, description="是否缴费0否1是"),
|
|
|
|
|
* @OA\Parameter(name="has_openid", in="query", @OA\Schema(type="string"), required=true, description="是否绑定小程序0否1是"),
|
|
|
|
|
@ -211,10 +213,10 @@ class UserController extends BaseController
|
|
|
|
|
$query->with('course.typeDetail')->orderBy('fee_status', 'desc');
|
|
|
|
|
}
|
|
|
|
|
])->withCount([
|
|
|
|
|
'appointments' => function ($query) {
|
|
|
|
|
$query->whereIn('status', [0, 1]);
|
|
|
|
|
}
|
|
|
|
|
]);
|
|
|
|
|
'appointments' => function ($query) {
|
|
|
|
|
$query->whereIn('status', [0, 1]);
|
|
|
|
|
}
|
|
|
|
|
]);
|
|
|
|
|
// 是否被投企业
|
|
|
|
|
if (isset($all['is_yh_invested'])) {
|
|
|
|
|
$list = $list->whereHas('company', function ($query) use ($all) {
|
|
|
|
|
@ -253,6 +255,14 @@ class UserController extends BaseController
|
|
|
|
|
if (isset($all['status'])) {
|
|
|
|
|
$query->where('status', $all['status']);
|
|
|
|
|
}
|
|
|
|
|
// 报名时间筛选
|
|
|
|
|
if (isset($all['sign_start_date']) && isset($all['sign_end_date'])) {
|
|
|
|
|
$query->whereBetween('created_at', [$all['sign_start_date'], $all['sign_end_date']]);
|
|
|
|
|
} elseif (isset($all['sign_start_date'])) {
|
|
|
|
|
$query->where('created_at', '>=', $all['sign_start_date']);
|
|
|
|
|
} elseif (isset($all['sign_end_date'])) {
|
|
|
|
|
$query->where('created_at', '<=', $all['sign_end_date']);
|
|
|
|
|
}
|
|
|
|
|
$query->whereHas('course', function ($q) use ($all) {
|
|
|
|
|
if (isset($all['year'])) {
|
|
|
|
|
$q->where('year', $all['year']);
|
|
|
|
|
@ -542,7 +552,8 @@ class UserController extends BaseController
|
|
|
|
|
} else {
|
|
|
|
|
if (in_array($k, ['company_type', 'type'])) {
|
|
|
|
|
$list[$key][$k] = str_replace('、', ',', $value[$v]);
|
|
|
|
|
$list[$key][$k] = str_replace(',', ',', $list[$key][$k]);;
|
|
|
|
|
$list[$key][$k] = str_replace(',', ',', $list[$key][$k]);
|
|
|
|
|
;
|
|
|
|
|
} else {
|
|
|
|
|
$list[$key][$k] = $value[$v];
|
|
|
|
|
}
|
|
|
|
|
@ -693,11 +704,331 @@ class UserController extends BaseController
|
|
|
|
|
if (isset($all['is_schoolmate'])) {
|
|
|
|
|
$data['is_schoolmate'] = $all['is_schoolmate'];
|
|
|
|
|
}
|
|
|
|
|
// if (isset($all['is_black'])) {
|
|
|
|
|
// $data['is_black'] = $all['is_black'];
|
|
|
|
|
// }
|
|
|
|
|
$this->model->whereIn('id', $idsArray)->update($data);
|
|
|
|
|
return $this->success('批量更新成功');
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @OA\Post(
|
|
|
|
|
* path="/api/admin/users/batch-update",
|
|
|
|
|
* tags={"用户信息"},
|
|
|
|
|
* summary="批量更新用户信息",
|
|
|
|
|
* description="",
|
|
|
|
|
* @OA\Parameter(name="ids", in="query", @OA\Schema(type="string"), required=true, description="英文逗号分隔的用户id"),
|
|
|
|
|
* @OA\Parameter(name="data", in="query", @OA\Schema(type="object"), required=true, description="需要更新的字段对象,键为字段名,值为字段值,例如:{\"is_vip\":\"1\",\"is_schoolmate\":\"1\",\"talent_tags\":\"标签1,标签2\"}"),
|
|
|
|
|
* @OA\Parameter(name="token", in="query", @OA\Schema(type="string"), required=true, description="token"),
|
|
|
|
|
* @OA\Response(
|
|
|
|
|
* response="200",
|
|
|
|
|
* description="暂无"
|
|
|
|
|
* )
|
|
|
|
|
* )
|
|
|
|
|
*/
|
|
|
|
|
public function batchUpdate()
|
|
|
|
|
{
|
|
|
|
|
$all = \request()->all();
|
|
|
|
|
$messages = [
|
|
|
|
|
'ids.required' => '用户ID必填',
|
|
|
|
|
'data.required' => '更新数据必填',
|
|
|
|
|
];
|
|
|
|
|
$validator = Validator::make($all, [
|
|
|
|
|
'ids' => 'required',
|
|
|
|
|
'data' => 'required|array',
|
|
|
|
|
], $messages);
|
|
|
|
|
|
|
|
|
|
if ($validator->fails()) {
|
|
|
|
|
return $this->fail([StarterResponseCode::START_ERROR_PARAMETER, implode(',', $validator->errors()->all())]);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 获取可更新的字段列表(fillable字段)
|
|
|
|
|
$fillableFields = $this->model->getFillable();
|
|
|
|
|
|
|
|
|
|
// 构建更新数据,只保留fillable中的字段
|
|
|
|
|
$data = [];
|
|
|
|
|
foreach ($all['data'] as $field => $value) {
|
|
|
|
|
// 只允许更新fillable中的字段
|
|
|
|
|
if (in_array($field, $fillableFields)) {
|
|
|
|
|
$data[$field] = $value;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (empty($data)) {
|
|
|
|
|
return $this->fail([StarterResponseCode::START_ERROR_PARAMETER, '没有可更新的有效字段']);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 解析用户ID
|
|
|
|
|
$idsArray = explode(',', $all['ids']);
|
|
|
|
|
$idsArray = array_filter(array_map('trim', $idsArray));
|
|
|
|
|
|
|
|
|
|
if (empty($idsArray)) {
|
|
|
|
|
return $this->fail([StarterResponseCode::START_ERROR_PARAMETER, '用户ID不能为空']);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
DB::beginTransaction();
|
|
|
|
|
try {
|
|
|
|
|
$this->model->whereIn('id', $idsArray)->update($data);
|
|
|
|
|
DB::commit();
|
|
|
|
|
return $this->success('批量更新成功,共更新 ' . count($idsArray) . ' 条记录');
|
|
|
|
|
} catch (\Exception $exception) {
|
|
|
|
|
DB::rollBack();
|
|
|
|
|
return $this->fail([$exception->getCode(), $exception->getMessage()]);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @OA\Post(
|
|
|
|
|
* path="/api/admin/users/excel-show-special",
|
|
|
|
|
* tags={"用户信息"},
|
|
|
|
|
* summary="特殊导入规则预览(通过姓名、公司、职位匹配,仅更新不创建)",
|
|
|
|
|
* description="通过姓名、公司名称、职位三个字段匹配现有用户,未匹配到的用户会在返回结果中提示",
|
|
|
|
|
* @OA\Parameter(name="file", in="query", @OA\Schema(type="string"), required=true, description="文件"),
|
|
|
|
|
* @OA\Parameter(name="token", in="query", @OA\Schema(type="string"), required=true, description="token"),
|
|
|
|
|
* @OA\Response(
|
|
|
|
|
* response="200",
|
|
|
|
|
* description="返回匹配结果,包含未匹配用户列表"
|
|
|
|
|
* )
|
|
|
|
|
* )
|
|
|
|
|
*/
|
|
|
|
|
public function excelShowSpecial()
|
|
|
|
|
{
|
|
|
|
|
$file = \request()->file('file');
|
|
|
|
|
//判断文件是否有效
|
|
|
|
|
if (!(\request()->hasFile('file') && $file->isValid())) {
|
|
|
|
|
return $this->fail([ResponseCode::ERROR_BUSINESS, '文件不存在或无效']);
|
|
|
|
|
}
|
|
|
|
|
//获取文件大小
|
|
|
|
|
$img_size = floor($file->getSize() / 1024);
|
|
|
|
|
if ($img_size >= 50 * 1024) {
|
|
|
|
|
return $this->fail([ResponseCode::ERROR_BUSINESS, '文件必须小于50M']);
|
|
|
|
|
}
|
|
|
|
|
//过滤文件后缀
|
|
|
|
|
$ext = $file->getClientOriginalExtension();
|
|
|
|
|
if (!in_array($ext, ['xls', 'xlsx', 'csv'])) {
|
|
|
|
|
return $this->fail([ResponseCode::ERROR_BUSINESS, '仅支持xls/xlsx/csv格式']);
|
|
|
|
|
}
|
|
|
|
|
$tempFile = $file->getRealPath();
|
|
|
|
|
$dataArray = (new FastExcel)->import($tempFile)->toArray();
|
|
|
|
|
|
|
|
|
|
// 数据过滤,只能导入数据表有的字段
|
|
|
|
|
$tableName = $this->model->getTable();
|
|
|
|
|
$rowTableFieldByComment = (new CustomFormField)->getRowTableFieldsByComment($tableName);
|
|
|
|
|
|
|
|
|
|
$list = [];
|
|
|
|
|
$unmatchedUsers = []; // 记录未匹配到的用户
|
|
|
|
|
foreach ($dataArray as $key => $value) {
|
|
|
|
|
// 获取姓名、公司名称、职位
|
|
|
|
|
$name = $value['姓名'] ?? $value['name'] ?? '';
|
|
|
|
|
$companyName = $value['公司名称'] ?? $value['company_name'] ?? '';
|
|
|
|
|
$companyPosition = $value['职位'] ?? $value['company_position'] ?? '';
|
|
|
|
|
|
|
|
|
|
// 通过姓名、公司名称、职位匹配用户
|
|
|
|
|
$matchedUser = null;
|
|
|
|
|
if (!empty($name) && !empty($companyName) && !empty($companyPosition)) {
|
|
|
|
|
$matchedUser = $this->model->where('username', $name)
|
|
|
|
|
->where('company_name', $companyName)
|
|
|
|
|
->where('company_position', $companyPosition)
|
|
|
|
|
->first();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 记录未匹配到的用户
|
|
|
|
|
if (!$matchedUser) {
|
|
|
|
|
$unmatchedUsers[] = [
|
|
|
|
|
'row' => $key + 1, // Excel行号(从1开始)
|
|
|
|
|
'name' => $name,
|
|
|
|
|
'company_name' => $companyName,
|
|
|
|
|
'company_position' => $companyPosition,
|
|
|
|
|
];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 构建返回数据(使用手机号作为唯一标识)
|
|
|
|
|
$list[$key] = [
|
|
|
|
|
'name' => $name,
|
|
|
|
|
'company_name' => $companyName,
|
|
|
|
|
'company_position' => $companyPosition,
|
|
|
|
|
'matched' => $matchedUser ? true : false,
|
|
|
|
|
'mobile' => $matchedUser ? $matchedUser->mobile : null, // 使用手机号作为唯一标识
|
|
|
|
|
'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,
|
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
// 处理其他字段
|
|
|
|
|
foreach ($rowTableFieldByComment as $k => $v) {
|
|
|
|
|
if (isset($value[$v])) {
|
|
|
|
|
// 日期格式
|
|
|
|
|
if ($value[$v] instanceof \DateTimeImmutable) {
|
|
|
|
|
$list[$key][$k] = Carbon::parse($value[$v])->toDateString();
|
|
|
|
|
} else {
|
|
|
|
|
if (in_array($k, ['company_type', 'type'])) {
|
|
|
|
|
$list[$key][$k] = str_replace('、', ',', $value[$v]);
|
|
|
|
|
$list[$key][$k] = str_replace(',', ',', $list[$key][$k]);
|
|
|
|
|
} else {
|
|
|
|
|
$list[$key][$k] = $value[$v];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 构建返回结果
|
|
|
|
|
$result = [
|
|
|
|
|
'list' => $list,
|
|
|
|
|
'matched_count' => count($list) - count($unmatchedUsers),
|
|
|
|
|
'unmatched_count' => count($unmatchedUsers),
|
|
|
|
|
'unmatched_users' => $unmatchedUsers,
|
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
// 如果有未匹配到的用户,添加提示信息
|
|
|
|
|
if (count($unmatchedUsers) > 0) {
|
|
|
|
|
$unmatchedNames = array_map(function ($user) {
|
|
|
|
|
return "第{$user['row']}行:{$user['name']}({$user['company_name']} - {$user['company_position']})";
|
|
|
|
|
}, $unmatchedUsers);
|
|
|
|
|
$result['message'] = '以下用户未匹配到,请检查数据:' . implode(';', $unmatchedNames);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return $this->success($result);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @OA\Post(
|
|
|
|
|
* path="/api/admin/users/import-special",
|
|
|
|
|
* tags={"用户信息"},
|
|
|
|
|
* summary="特殊导入规则导入(通过姓名、公司、职位匹配,仅更新不创建)",
|
|
|
|
|
* description="仅更新已匹配到的用户,如果存在未匹配到的用户,将返回错误并回滚事务",
|
|
|
|
|
* @OA\Parameter(name="data", in="query", @OA\Schema(type="string"), required=true, description="导入分析获取到的二维数组"),
|
|
|
|
|
* @OA\Parameter(name="token", in="query", @OA\Schema(type="string"), required=true, description="token"),
|
|
|
|
|
* @OA\Response(
|
|
|
|
|
* response="200",
|
|
|
|
|
* description="返回更新结果"
|
|
|
|
|
* )
|
|
|
|
|
* )
|
|
|
|
|
*/
|
|
|
|
|
public function importSpecial()
|
|
|
|
|
{
|
|
|
|
|
$all = \request()->all();
|
|
|
|
|
$messages = [
|
|
|
|
|
'data.required' => '数据必填',
|
|
|
|
|
];
|
|
|
|
|
$validator = Validator::make($all, [
|
|
|
|
|
'data' => 'required',
|
|
|
|
|
], $messages);
|
|
|
|
|
if ($validator->fails()) {
|
|
|
|
|
return $this->fail([ResponseCode::ERROR_PARAMETER, implode(',', $validator->errors()->all())]);
|
|
|
|
|
}
|
|
|
|
|
$filteredRecords = $all['data'];
|
|
|
|
|
$suc = 0;
|
|
|
|
|
$updateCount = 0;
|
|
|
|
|
$unmatchedUsers = []; // 记录未匹配到的用户
|
|
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 如果仍未匹配到手机号,记录并跳过
|
|
|
|
|
if (!$mobile) {
|
|
|
|
|
$unmatchedUsers[] = [
|
|
|
|
|
'row' => $index + 1,
|
|
|
|
|
'name' => $record['name'] ?? '',
|
|
|
|
|
'company_name' => $record['company_name'] ?? '',
|
|
|
|
|
'company_position' => $record['company_position'] ?? '',
|
|
|
|
|
];
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 去除匹配相关的字段,避免更新到数据库
|
|
|
|
|
unset($record['matched'], $record['existing_data']);
|
|
|
|
|
|
|
|
|
|
// 去除空值
|
|
|
|
|
$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++;
|
|
|
|
|
|
|
|
|
|
// 写入报名表(如果有课程信息)
|
|
|
|
|
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);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 如果有未匹配到的用户,返回错误
|
|
|
|
|
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)
|
|
|
|
|
]);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
DB::commit();
|
|
|
|
|
return $this->success([
|
|
|
|
|
'total' => count($filteredRecords),
|
|
|
|
|
'suc' => $suc,
|
|
|
|
|
'update_count' => $updateCount
|
|
|
|
|
]);
|
|
|
|
|
} catch (\Exception $exception) {
|
|
|
|
|
DB::rollBack();
|
|
|
|
|
return $this->fail([$exception->getCode(), $exception->getMessage()]);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|