JobsService.php 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389
  1. <?php
  2. namespace App\Services\Common;
  3. use App\Models\ActionLogModel;
  4. use App\Models\JobsModel;
  5. use App\Services\BaseService;
  6. /**
  7. * 招聘信息-服务类
  8. */
  9. class JobsService extends BaseService
  10. {
  11. public function __construct()
  12. {
  13. $this->model = new JobsModel();
  14. }
  15. public static function make()
  16. {
  17. if (!self::$instance) {
  18. self::$instance = (new static());
  19. }
  20. return self::$instance;
  21. }
  22. /**
  23. * 获取状态文本
  24. * @param int $status
  25. * @return string
  26. */
  27. private function getStatusText($status)
  28. {
  29. $statusMap = [
  30. 1 => '已发布',
  31. 2 => '待发布',
  32. 3 => '待审核',
  33. 4 => '审核失败'
  34. ];
  35. return isset($statusMap[$status]) ? $statusMap[$status] : '未知';
  36. }
  37. /**
  38. * 获取数据列表
  39. * @param array $params 请求参数
  40. * @param int $pageSize 分页大小
  41. * @param int $storeId 商家ID,用于数据隔离(0表示超级管理员,>0表示商户用户)
  42. */
  43. public function getDataList($params, $pageSize = 15, $storeId = 0)
  44. {
  45. $query = $this->model->where('mark', 1);
  46. // 数据隔离:商户用户只能查看自己的招聘信息
  47. if ($storeId > 0) {
  48. $query->where('store_id', $storeId);
  49. }
  50. // 状态筛选(使用 status 字段)
  51. if (isset($params['status']) && $params['status'] > 0) {
  52. $query->where('status', $params['status']);
  53. }
  54. // 分类筛选
  55. if (isset($params['category_id']) && $params['category_id']) {
  56. $query->where('category_id', $params['category_id']);
  57. }
  58. // 关键词搜索
  59. if (isset($params['keyword']) && $params['keyword']) {
  60. $keyword = $params['keyword'];
  61. $query->where(function ($q) use ($keyword) {
  62. $q->where('job_name', 'like', '%' . $keyword . '%')
  63. ->orWhere('job_title', 'like', '%' . $keyword . '%')
  64. ->orWhere('company', 'like', '%' . $keyword . '%');
  65. });
  66. }
  67. $list = $query->with(['category'])
  68. ->orderBy('sort', 'desc')
  69. ->orderBy('id', 'desc')
  70. ->paginate($pageSize);
  71. $list = $list ? $list->toArray() : [];
  72. if ($list && isset($list['data'])) {
  73. foreach ($list['data'] as &$item) {
  74. $item['create_time'] = $item['create_time'] ? date('Y-m-d H:i:s', strtotime($item['create_time'])) : '';
  75. $item['update_time'] = $item['update_time'] ? date('Y-m-d H:i:s', strtotime($item['update_time'])) : '';
  76. $item['logo'] = $item['logo'] ? get_image_url($item['logo']) : '';
  77. $item['category_name'] = $item['category']['name'] ?? '';
  78. $item['audit_status_text'] = $this->getStatusText($item['status'] ?? 3);
  79. }
  80. }
  81. return [
  82. 'msg' => '操作成功',
  83. 'code' => 0,
  84. 'data' => $list['data'] ?? [],
  85. 'count' => $list['total'] ?? 0,
  86. ];
  87. }
  88. /**
  89. * 添加
  90. * @param int $storeId 商家ID,用于数据隔离(0表示超级管理员,>0表示商户用户)
  91. */
  92. public function add($storeId = 0)
  93. {
  94. $data = request()->all();
  95. // 图片处理
  96. if (isset($data['logo'])) {
  97. $data['logo'] = get_image_path($data['logo']);
  98. }
  99. // 验证职位名称
  100. if (empty($data['job_name'])) {
  101. return message('请填写职位名称', false);
  102. }
  103. // 验证分类
  104. if (!isset($data['category_id']) || $data['category_id'] <= 0) {
  105. return message('请选择职位分类', false);
  106. }
  107. // 数据隔离:商户用户添加招聘时自动设置 store_id
  108. if ($storeId > 0) {
  109. $data['store_id'] = $storeId;
  110. } else {
  111. if (!isset($data['store_id'])) {
  112. $data['store_id'] = 0;
  113. }
  114. }
  115. // 确保不包含 id 字段(新增不应该有 id)
  116. unset($data['id']);
  117. // 设置默认值
  118. if (!isset($data['status'])) {
  119. $data['status'] = 3; // 默认待审核
  120. }
  121. if (!isset($data['sort'])) {
  122. $data['sort'] = 0;
  123. }
  124. // 确保所有可为空的字符串字段都存在,即使为空字符串也要保存
  125. $stringFields = [
  126. 'job_title',
  127. 'salary',
  128. 'num',
  129. 'recruiter',
  130. 'recruiter_position',
  131. 'recruiter_phone',
  132. 'company',
  133. 'logo',
  134. 'company_desc',
  135. 'content',
  136. 'tags',
  137. 'remark'
  138. ];
  139. foreach ($stringFields as $field) {
  140. if (!array_key_exists($field, $data)) {
  141. $data[$field] = '';
  142. }
  143. }
  144. return parent::edit($data);
  145. }
  146. /**
  147. * 添加或编辑
  148. * @param array $data 数据
  149. * @param int $storeId 商家ID,用于数据隔离(0表示超级管理员,>0表示商户用户)
  150. */
  151. public function edit($data = [], $storeId = 0)
  152. {
  153. if (empty($data)) {
  154. $data = request()->all();
  155. }
  156. // 数据隔离:商户用户只能编辑自己的招聘信息
  157. if ($storeId > 0) {
  158. // 如果是编辑,检查权限
  159. if (!empty($data['id'])) {
  160. $job = $this->model->where('id', $data['id'])->where('mark', 1)->first();
  161. if (!$job || $job->store_id != $storeId) {
  162. return ['code' => 1, 'msg' => '无权限操作'];
  163. }
  164. }
  165. // 自动设置 store_id
  166. $data['store_id'] = $storeId;
  167. } else {
  168. // 超级管理员:如果没有指定 store_id,默认为 0(平台)
  169. if (!isset($data['store_id'])) {
  170. $data['store_id'] = 0;
  171. }
  172. }
  173. // 确保所有可为空的字符串字段都存在,即使为空字符串也要保存
  174. $stringFields = [
  175. 'job_title',
  176. 'salary',
  177. 'num',
  178. 'recruiter',
  179. 'recruiter_position',
  180. 'recruiter_phone',
  181. 'company',
  182. 'logo',
  183. 'company_desc',
  184. 'content',
  185. 'tags',
  186. ];
  187. foreach ($stringFields as $field) {
  188. // 如果字段存在于请求中(包括空字符串),保持原值;否则设为空字符串
  189. if (!array_key_exists($field, $data)) {
  190. $data[$field] = '';
  191. }
  192. }
  193. // 图片处理
  194. if (isset($data['logo']) && $data['logo']) {
  195. $data['logo'] = get_image_path($data['logo']);
  196. }
  197. $data['update_time'] = time();
  198. ActionLogModel::setTitle("编辑招聘信息");
  199. ActionLogModel::record();
  200. // 编辑现有记录:直接使用 Eloquent update 确保空字符串能被保存
  201. if (!empty($data['id'])) {
  202. $id = $data['id'];
  203. unset($data['id']);
  204. unset($data['create_time']); // 编辑时不更新创建时间
  205. $this->model->where('id', $id)->update($data);
  206. return ['code' => 0, 'msg' => '编辑成功', 'data' => ['id' => $id]];
  207. }
  208. // 新增记录
  209. $data['create_time'] = time();
  210. return parent::edit($data);
  211. }
  212. /**
  213. * 删除
  214. * @param int $storeId 商家ID,用于数据隔离(0表示超级管理员,>0表示商户用户)
  215. */
  216. public function delete($storeId = 0)
  217. {
  218. $id = request()->post('id');
  219. if (!$id) {
  220. return ['code' => 1, 'msg' => '参数错误'];
  221. }
  222. // 数据隔离:商户用户只能删除自己的招聘信息
  223. $query = $this->model;
  224. if ($storeId > 0) {
  225. $query = $query->where('store_id', $storeId);
  226. }
  227. // 支持批量删除
  228. if (is_array($id)) {
  229. $result = $query->whereIn('id', $id)->update(['mark' => 0]);
  230. } else {
  231. $result = $query->where('id', $id)->update(['mark' => 0]);
  232. }
  233. if ($result) {
  234. ActionLogModel::setTitle("删除招聘信息");
  235. ActionLogModel::record();
  236. return ['code' => 0, 'msg' => '删除成功'];
  237. }
  238. return ['code' => 1, 'msg' => '删除失败'];
  239. }
  240. /**
  241. * 修改状态(发布/待发布互转)
  242. */
  243. public function status()
  244. {
  245. $params = request()->all();
  246. $id = isset($params['id']) ? intval($params['id']) : 0;
  247. $status = isset($params['status']) ? intval($params['status']) : 0;
  248. if (!$id) {
  249. return ['code' => 1, 'msg' => '招聘ID不能为空'];
  250. }
  251. if (!$status || ($status != 1 && $status != 2)) {
  252. return ['code' => 1, 'msg' => '状态参数错误'];
  253. }
  254. $info = $this->model->where(['id' => $id, 'mark' => 1])->first();
  255. if (!$info) {
  256. return ['code' => 1, 'msg' => '招聘信息不存在'];
  257. }
  258. // 只有已发布(1)和待发布(2)状态才能互转
  259. if ($info->status != 1 && $info->status != 2) {
  260. return ['code' => 1, 'msg' => '只有已发布和待发布状态才能切换'];
  261. }
  262. $this->model->where('id', $id)->update([
  263. 'status' => $status,
  264. 'update_time' => time()
  265. ]);
  266. ActionLogModel::setTitle("修改招聘状态");
  267. ActionLogModel::record();
  268. return ['code' => 0, 'msg' => '状态修改成功'];
  269. }
  270. /**
  271. * 审核
  272. */
  273. public function confirm()
  274. {
  275. $params = request()->all();
  276. $id = isset($params['id']) ? intval($params['id']) : 0;
  277. $status = isset($params['audit_status']) ? intval($params['audit_status']) : 0;
  278. $remark = isset($params['remark']) ? trim($params['remark']) : '';
  279. if (!$id) {
  280. return ['code' => 1, 'msg' => '招聘ID不能为空'];
  281. }
  282. $info = $this->model->where(['id' => $id, 'mark' => 1])->first();
  283. if (!$info) {
  284. return ['code' => 1, 'msg' => '招聘信息不存在'];
  285. }
  286. // 审核通过
  287. if ($status == 1) {
  288. $updateData = [
  289. 'status' => 1, // 1-已发布
  290. 'remark' => $remark ?: '审核通过',
  291. 'update_time' => time()
  292. ];
  293. $this->model->where('id', $id)->update($updateData);
  294. ActionLogModel::setTitle("审核通过招聘信息");
  295. ActionLogModel::record();
  296. return ['code' => 0, 'msg' => '审核通过成功'];
  297. }
  298. // 审核驳回
  299. elseif ($status == 4) {
  300. if (empty($remark)) {
  301. return ['code' => 1, 'msg' => '驳回理由不能为空'];
  302. }
  303. $this->model->where('id', $id)->update([
  304. 'status' => 4, // 4-审核失败
  305. 'remark' => $remark,
  306. 'update_time' => time()
  307. ]);
  308. ActionLogModel::setTitle("驳回招聘信息");
  309. ActionLogModel::record();
  310. return ['code' => 0, 'msg' => '审核驳回成功'];
  311. } else {
  312. return ['code' => 1, 'msg' => '审核状态参数错误'];
  313. }
  314. }
  315. /**
  316. * 获取详情
  317. * @param int $id 招聘信息ID
  318. * @param int $storeId 商家ID,用于数据隔离(0表示超级管理员,>0表示商户用户)
  319. */
  320. public function getInfo($id, $storeId = 0)
  321. {
  322. $query = $this->model->where('id', $id)->where('mark', 1);
  323. // 数据隔离:商户用户只能查看自己的招聘信息
  324. if ($storeId > 0) {
  325. $query->where('store_id', $storeId);
  326. }
  327. $info = $query->first();
  328. if (!$info) {
  329. return ['code' => 1, 'msg' => '数据不存在'];
  330. }
  331. $info = $info->toArray();
  332. $info['logo'] = $info['logo'] ? get_image_url($info['logo']) : '';
  333. return ['code' => 0, 'data' => $info];
  334. }
  335. }