AccountController.php 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681
  1. <?php
  2. namespace App\Http\Controllers\Coach;
  3. use Illuminate\Http\Request;
  4. use App\Traits\ResponseTrait;
  5. use App\Traits\LocationDataTrait;
  6. use Illuminate\Support\Facades\Log;
  7. use App\Http\Controllers\Controller;
  8. use Illuminate\Support\Facades\Auth;
  9. use App\Enums\TechnicianLocationType;
  10. use App\Services\Coach\AccountService;
  11. use App\Http\Requests\Coach\SetLocationRequest;
  12. use App\Http\Requests\Coach\SetScheduleRequest;
  13. use App\Http\Requests\Coach\SendVerifyCodeRequest;
  14. use App\Http\Requests\Coach\SubmitBaseInfoRequest;
  15. use App\Http\Requests\Coach\SubmitRealNameRequest;
  16. use App\Http\Requests\Coach\UpdateBasicInfoRequest;
  17. use App\Http\Requests\Coach\SubmitQualificationRequest;
  18. /**
  19. * @group 技师端
  20. *
  21. * 技师账户相关的API接口
  22. */
  23. class AccountController extends Controller
  24. {
  25. use ResponseTrait;
  26. use LocationDataTrait;
  27. protected AccountService $service;
  28. public function __construct(AccountService $service)
  29. {
  30. $this->service = $service;
  31. }
  32. /**
  33. * [账户]提交基本信息
  34. *
  35. * @description 提交技师的基本个人信息,包括头像、生活照片、个人资料等
  36. *
  37. * 业务流程:
  38. * 1. 验证提交的数据
  39. * 2. 调用服务层处理业务逻辑
  40. * 3. 返回处理结果
  41. *
  42. * 注意事项:
  43. * - 同一时间只能有一条待审核记录
  44. * - 审核不通过可以重新提交
  45. * - 头像和生活照片支持任意格式的图片数据
  46. * - 除性别和手机号外,其他字段均为可选
  47. * - 生活照片为可选,支持多张
  48. *
  49. * @authenticated 需要技师身份认证
  50. *
  51. * @bodyParam nickname string nullable 昵称(2-20个字符) Example: 张三
  52. * @bodyParam avatar string nullable 头像图片 Example: base64或其他格式的图片数据
  53. * @bodyParam life_photos array nullable 生活照片数组
  54. * @bodyParam life_photos.* string required 生活照片 Example: base64或其他格式的图片数据
  55. * @bodyParam gender string required 性别(1:男 2:女) Example: 1
  56. * @bodyParam mobile string required 手机号 Example: 13800138000
  57. * @bodyParam birthday date nullable 出生日期(年龄需满18岁) Example: 1990-01-01
  58. * @bodyParam work_years integer nullable 工作年限(0-99) Example: 5
  59. * @bodyParam intention_city string nullable 意向城市 Example: 北京
  60. * @bodyParam introduction string nullable 个人简介(10-255个字符) Example: 专业按摩师,从业5年
  61. *
  62. * @response 200 {
  63. * "status": true,
  64. * "message": "基本信息提交成功"
  65. * }
  66. * @response 404 {
  67. * "message": "技师信息不存在"
  68. * }
  69. * @response 422 {
  70. * "message": "已有待审核的基本信息记录"
  71. * }
  72. * @response 422 {
  73. * "message": "验证错误",
  74. * "errors": {
  75. * "nickname": ["昵称不能少于2个字符"],
  76. * "gender": ["性别不能为空"],
  77. * "mobile": ["手机号不能为空"],
  78. * "life_photos.*": ["生活照片格式不正确"]
  79. * }
  80. * }
  81. */
  82. public function submitBaseInfo(SubmitBaseInfoRequest $request)
  83. {
  84. // 获取验证后的数据
  85. $data = $request->validated();
  86. // 调用服务层处理业务逻辑
  87. // 传入当前认证用户和验证后的数据
  88. return $this->success(
  89. $this->service->submitBaseInfo(Auth::user(), $data)
  90. );
  91. }
  92. /**
  93. * [账户]提交资质信息
  94. *
  95. * @description 提交技师的资质认证信息,包括资质照片、营业执照和健康证
  96. *
  97. * @authenticated
  98. *
  99. * @bodyParam qual_type int required 资质类型(1:初级按摩师 2:中级按摩师 3:高级按摩师) Example: 1
  100. * @bodyParam qual_photo array required 资质证书照片数组
  101. * @bodyParam qual_photo.* string required 资质证书照片 Example: base64或其他格式的图片数据
  102. * @bodyParam business_license array required 营业执照照片数组
  103. * @bodyParam business_license.* string required 营业执照照片 Example: base64或其他格式的图片数据
  104. * @bodyParam health_cert array required 健康证照片数组
  105. * @bodyParam health_cert.* string required 健康证照片 Example: base64或其他格式的图片数据
  106. *
  107. * @response {
  108. * "message": "资质信息提交成功",
  109. * "data": {
  110. * "qual_type": 1,
  111. * "qual_photo": ["path/to/photo1.jpg", "path/to/photo2.jpg"],
  112. * "business_license": ["path/to/license1.jpg", "path/to/license2.jpg"],
  113. * "health_cert": ["path/to/cert1.jpg", "path/to/cert2.jpg"],
  114. * "state": 1,
  115. * "updated_at": "2024-03-22 10:00:00"
  116. * }
  117. * }
  118. */
  119. public function submitQualification(SubmitQualificationRequest $request)
  120. {
  121. $data = $request->validated();
  122. return $this->success($this->service->submitQualification(Auth::user(), $data));
  123. }
  124. /**
  125. * [账户]提交实名认证
  126. *
  127. * @description 提交技师的实名认证信息
  128. *
  129. * @authenticated
  130. *
  131. * @bodyParam real_name string nullable 姓名(2-20个字符) Example: 张三
  132. * @bodyParam id_card string nullable 身份证号(18位) Example: 370602199001011234
  133. * @bodyParam id_card_front_photo string required 身份证正面照片 Example: base64或其他格式的图片数据
  134. * @bodyParam id_card_back_photo string required 身份证反面照片 Example: base64或其他格式的图片数据
  135. * @bodyParam id_card_hand_photo string required 手持身份证照片 Example: base64或其他格式的图片数据
  136. *
  137. * @response {
  138. * "message": "实名认证信息提交成功"
  139. * }
  140. */
  141. public function submitRealName(SubmitRealNameRequest $request)
  142. {
  143. $data = $request->validated();
  144. return $this->success($this->service->submitRealName(Auth::user(), $data));
  145. }
  146. /**
  147. * [账户]获取技师认证信息
  148. *
  149. * @description 获取技师的基本信息、资质信息和实名认证信息
  150. *
  151. * @authenticated
  152. *
  153. * @response {
  154. * "data": {
  155. * "base_info": {
  156. * "nickname": "张三",
  157. * "avatar": "base64或其他格式的图片数据",
  158. * "life_photos": [
  159. * "base64或其他格式的图片数据1",
  160. * "base64或其他格式的图片数据2"
  161. * ],
  162. * "gender": "1",
  163. * "mobile": "138****8000",
  164. * "birthday": "1990-01-01",
  165. * "work_years": 5,
  166. * "intention_city": "北京",
  167. * "introduction": "专业按摩师,从业5年",
  168. * "state": 1,
  169. * "state_text": "已通过",
  170. * "audit_remark": "审核通过"
  171. * },
  172. * "qualification": {
  173. * "qual_type": "高级按摩师",
  174. * "qual_photo": "base64或其他格式的图片数据",
  175. * "business_license": "base64或其他格式的图片数据",
  176. * "health_cert": "base64或其他格式的图片数据",
  177. * "state": 1,
  178. * "state_text": "已通过",
  179. * "audit_remark": "审核通过"
  180. * },
  181. * "real_name": {
  182. * "real_name": "张三",
  183. * "id_card": "370602****1234",
  184. * "id_card_front_photo": "base64或其他格式的图片数据",
  185. * "id_card_back_photo": "base64或其他格式的图片数据",
  186. * "id_card_hand_photo": "base64或其他格式的图片数据",
  187. * "state": 1,
  188. * "state_text": "已通过",
  189. * "audit_remark": "审核通过"
  190. * }
  191. * }
  192. * }
  193. * @response 404 {
  194. * "message": "用户不存在"
  195. * }
  196. * @response 404 {
  197. * "message": "技师信息不存在"
  198. * }
  199. */
  200. public function info()
  201. {
  202. return $this->success($this->service->getCoachInfo(Auth::user()));
  203. }
  204. /**
  205. * [账户]设置技师位置信息
  206. *
  207. * @description 设置技师的当前位置或常用位置
  208. *
  209. * @authenticated
  210. *
  211. * @bodyParam latitude float required 纬度 Example: 39.9042
  212. * @bodyParam longitude float required 经度 Example: 116.4074
  213. * @bodyParam type int nullable 位置类型(1:当前位置 2:常用位置) Example: 2
  214. * @bodyParam province string nullable 省份 Example: 北京市
  215. * @bodyParam city string nullable 城市 Example: 北京市
  216. * @bodyParam district string nullable 区县 Example: 朝阳区
  217. * @bodyParam address string nullable 详细地址 Example: 建国路93号万达广场
  218. * @bodyParam adcode string nullable 行政区划代码 Example: 110105
  219. *
  220. * @response {
  221. * "message": "位置信息设置成功"
  222. * }
  223. */
  224. public function setLocation(SetLocationRequest $request)
  225. {
  226. // 获取验证后的数据
  227. $validated = $request->validated();
  228. // 确保用户和技师存在
  229. $user = Auth::user();
  230. abort_if(!$user->coach, 404, '技师信息不存在');
  231. // 提取位置信息
  232. $locationInfo = $this->extractLocationInfo($validated);
  233. // 传递技师ID给服务层
  234. $this->service->setLocation(
  235. $user->coach->id,
  236. $validated['latitude'],
  237. $validated['longitude'],
  238. $validated['type'] ?? TechnicianLocationType::COMMON->value,
  239. $locationInfo
  240. );
  241. return $this->success(['message' => '位置信息设置成功']);
  242. }
  243. /**
  244. * [账户]获取技师位置信息
  245. *
  246. * @description 获取技师的位置信息
  247. *
  248. * @authenticated
  249. *
  250. * @queryParam type int 位置类型(1:当前位置 2:常用位置) Example: 2
  251. *
  252. * @response {
  253. * "data": {
  254. * "province": "浙江省",
  255. * "city": "杭州市",
  256. * "district": "西湖区",
  257. * "address": "文三路478号",
  258. * "adcode": "330106",
  259. * "longitude": 120.12345,
  260. * "latitude": 30.12345,
  261. * "updated_at": "2024-03-22 10:00:00"
  262. * }
  263. * }
  264. */
  265. public function getLocation(Request $request)
  266. {
  267. $validated = $request->validate([
  268. 'type' => 'required|integer|in:1,2'
  269. ]);
  270. return $this->success(
  271. $this->service->getLocation(Auth::user(), $validated['type'])
  272. );
  273. }
  274. /**
  275. * [账户]设置排班时间
  276. *
  277. * @description 设置技师每天通用的排班时间段
  278. *
  279. * @authenticated
  280. *
  281. * @bodyParam time_ranges array required 时间段数组
  282. * @bodyParam time_ranges[].start_time string required 开始时间(HH:mm格式) Example: "09:00"
  283. * @bodyParam time_ranges[].end_time string required 结束时间(HH:mm格式) Example: "24:00"
  284. *
  285. * @response {
  286. * "status": true,
  287. * "message": "排班设置成功",
  288. * "data": {
  289. * "coach_id": 1,
  290. * "time_ranges": [
  291. * {
  292. * "start_time": "09:00",
  293. * "end_time": "12:00"
  294. * }
  295. * ],
  296. * "updated_at": "2024-03-21 10:00:00"
  297. * }
  298. * }
  299. */
  300. public function setSchedule(SetScheduleRequest $request)
  301. {
  302. return $this->success(
  303. $this->service->setSchedule(Auth::user()->coach, $request->validated()['time_ranges'])
  304. );
  305. }
  306. /**
  307. * [账户]更改技师工作状态
  308. *
  309. * @description 更改技师的工作状态(休息中/工作中),工作状态会自动判断为空闲或忙碌
  310. *
  311. * 业务流程:
  312. * 1. 验证请求参数
  313. * 2. 检查技师认证状态
  314. * 3. 验证排班时间
  315. * 4. 根据订单状态自动判断工作状态
  316. * 5. 更新状态并返回结果
  317. *
  318. * @authenticated 需要技师身份认证
  319. *
  320. * @bodyParam status int required 状态(1:休息中 2:工作中) Example: 2
  321. *
  322. * @response 200 {
  323. * "status": true,
  324. * "message": "状态更新成功",
  325. * "data": {
  326. * "work_status": 2, // 工作状态值(1:休息中 2:空闲中 3:忙碌中)
  327. * "work_status_text": "空闲中", // 工作状态文本
  328. * "updated_at": "2024-03-20 10:00:00" // 更新时间
  329. * }
  330. * }
  331. * @response 400 {
  332. * "message": "无效的状态值"
  333. * }
  334. * @response 422 {
  335. * "message": "当前状态不能更改为休息状态"
  336. * }
  337. * @response 422 {
  338. * "message": "当前时间不在排班时间内,无法切换到工作状态"
  339. * }
  340. */
  341. public function updateWorkStatus(Request $request)
  342. {
  343. // 验证请求参数
  344. $validated = $request->validate([
  345. 'status' => 'required|integer|in:1,2', // 1:休息中 2:工作中
  346. ], [
  347. 'status.required' => '状态不能为空',
  348. 'status.integer' => '状态必须是整数',
  349. 'status.in' => '无效的状态值',
  350. ]);
  351. // 调用服务层处理状态更新,直接传入技师对象
  352. return $this->success(
  353. $this->service->updateWorkStatus(Auth::user()->coach, $validated['status'])
  354. );
  355. }
  356. /**
  357. * [账户]获取技师工作状态
  358. *
  359. * @description 获取技师当前工作状态
  360. *
  361. * @authenticated
  362. *
  363. * @response {
  364. * "data": {
  365. * "work_status": 2,
  366. * "work_status_text": "空闲中",
  367. * "updated_at": "2024-03-22 10:00:00"
  368. * }
  369. * }
  370. * @response 404 {
  371. * "message": "技师不存在"
  372. * }
  373. */
  374. public function getWorkStatus()
  375. {
  376. return $this->success(
  377. $this->service->getWorkStatus(Auth::user()->coach->id)
  378. );
  379. }
  380. /**
  381. * [排班]获取技师排班信息
  382. *
  383. * @description 获取技师当前的排班时间段设置
  384. *
  385. * @authenticated 需要技师身份认证
  386. *
  387. * @response 200 {
  388. * "status": true,
  389. * "message": "获取成功",
  390. * "data": {
  391. * "time_ranges": [ // 工作时间段列表
  392. * {
  393. * "start_time": "09:00", // 开始时间
  394. * "end_time": "12:00" // 结束时间
  395. * }
  396. * ],
  397. * "updated_at": "2024-03-21 10:00:00" // 最后更新时间
  398. * }
  399. * }
  400. * @response 404 {
  401. * "message": "技师信息不存在"
  402. * }
  403. */
  404. public function getSchedule()
  405. {
  406. return $this->success(
  407. $this->service->getSchedule(Auth::user()->coach)
  408. );
  409. }
  410. /**
  411. * [账户]获取技师详细信息
  412. *
  413. * @description 获取当前登录技师的详细信息,包括基本信息、认证状态、位置信息、统计数据等
  414. *
  415. * 业务流程:
  416. * 1. 获取技师基本信息和关联数据
  417. * 2. 生成技师工号和邀请码
  418. * 3. 获取钱包和认证状态信息
  419. * 4. 获取位置和店铺信息
  420. * 5. 获取统计数据
  421. * 6. 组装返回数据
  422. *
  423. * @authenticated 需要技师身份认证
  424. *
  425. * @group 技师端-账户
  426. *
  427. * @responseFile 200 responses/coach/account/detail.json
  428. * @response 200 {
  429. * "status": true,
  430. * "message": "获取成功",
  431. * "data": {
  432. * "coach_no": "00000001", // 技师工号
  433. * "mobile": "138****8000", // 手机号(脱敏)
  434. * "nickname": "张三", // 昵称
  435. * "avatar": "https://example.com/avatar.jpg", // 头像URL
  436. * "age": 25, // 年龄
  437. * "gender": 1, // 性别(1:男 2:女)
  438. * "work_years": 5, // 工作年限
  439. * "intention_city": "杭州", // 意向城市
  440. * "life_photos": [ // 生活照片数组
  441. * "https://example.com/photo1.jpg",
  442. * "https://example.com/photo2.jpg"
  443. * ],
  444. * "introduction": "专业按摩师,从业5年", // 个人简介
  445. * "state": 1, // 状态值
  446. * "state_text": "正常", // 状态文本
  447. * "work_status": 2, // 工作状态(1:休息中 2:工作中-空闲 3:工作中-忙碌)
  448. * "work_status_text": "空闲中", // 工作状态文本
  449. * "invite_code": "C1", // 邀请码
  450. * "wallet": { // 钱包信息
  451. * "balance": 1000.00, // 余额
  452. * "frozen": 200.00, // 冻结金额
  453. * "total_income": 5000.00, // 总收入
  454. * "today_income": 300.00, // 今日收入
  455. * "withdrawable": 800.00 // 可提现金额
  456. * },
  457. * "auth_status": { // 认证状态信息
  458. * "base_info": { // 基本信息认证
  459. * "state": 1, // 状态值
  460. * "state_text": "已通过", // 状态文本
  461. * "audit_remark": "审核通过", // 审核备注
  462. * "updated_at": "2024-03-22 10:00:00" // 更新时间
  463. * },
  464. * "real_name": { // 实名认证
  465. * "state": 1,
  466. * "state_text": "已通过",
  467. * "audit_remark": "审核通过",
  468. * "updated_at": "2024-03-22 10:00:00"
  469. * },
  470. * "qualification": { // 资质认证
  471. * "state": 1,
  472. * "state_text": "已通过",
  473. * "audit_remark": "审核通过",
  474. * "updated_at": "2024-03-22 10:00:00"
  475. * }
  476. * },
  477. * "location": { // 位置信息
  478. * "province": "浙江省", // 省份
  479. * "city": "杭州市", // 城市
  480. * "district": "西湖区", // 区县
  481. * "address": "文三路478号", // 详细地址
  482. * "adcode": "330106", // 行政区划代码
  483. * "longitude": 120.12345, // 经度
  484. * "latitude": 30.12345 // 纬度
  485. * },
  486. * "shop": { // 店铺信息
  487. * "id": 1, // 店铺ID
  488. * "name": "示例店铺", // 店铺名称
  489. * "address": "杭州市西湖区文三路478号", // 店铺地址
  490. * "phone": "0571-88888888" // 联系电话
  491. * },
  492. * "statistics": { // 统计数据
  493. * "order_count": 100, // 总订单数
  494. * "completed_order_count": 80, // 已完成订单数
  495. * "pending_order_count": 5, // 未完成订单数
  496. * "level": 2, // 技师等级
  497. * "level_text": "中级技师", // 等级文本
  498. * "rating": 4.8, // 评分
  499. * "grab_order_count": 50, // 抢单数量
  500. * "carrying_order_count": 3 // 带接单数量(已支付但未被接单的订单数)
  501. * }
  502. * }
  503. * }
  504. * @response 404 {
  505. * "status": false,
  506. * "message": "技师信息不存在"
  507. * }
  508. */
  509. public function detail()
  510. {
  511. // 获取技师详细信息
  512. $data = $this->service->getCoachDetail();
  513. // 返回成功响应
  514. return $this->success($data, '获取成功');
  515. }
  516. /**
  517. * [账户]更新基础信息
  518. *
  519. * @description 更新技师的基础信息,包括昵称、性别和手机号。修改手机号时需要先获取验证码进行验证。
  520. *
  521. * 业务流程:
  522. * 1. 验证提交的数据
  523. * 2. 验证手机验证码(如果修改手机号)
  524. * 3. 调用服务层处理更新
  525. * 4. 返回更新结果
  526. *
  527. * 注意事项:
  528. * - 可以单独更新某个字段,不需要同时提交所有字段
  529. * - 修改手机号时必须提供验证码
  530. * - 同一时间只能有一条待审核记录
  531. *
  532. * @authenticated 需要技师身份认证
  533. *
  534. * @bodyParam nickname string nullable 昵称(2-20个字符) Example: 张三
  535. * @bodyParam gender integer nullable 性别(1:男 2:女) Example: 1
  536. * @bodyParam mobile string nullable 手机号 Example: 13800138000
  537. * @bodyParam code string required if:mobile 验证码(修改手机号时必填) Example: 123456
  538. *
  539. * @response {
  540. * "status": true,
  541. * "message": "基础信息修改申请已提交",
  542. * "data": {
  543. * "record_id": 1,
  544. * "updated_fields": ["nickname", "gender"]
  545. * }
  546. * }
  547. *
  548. * @response {
  549. * "status": true,
  550. * "message": "基础信息修改申请已更新",
  551. * "data": {
  552. * "record_id": 1,
  553. * "updated_fields": ["mobile"]
  554. * }
  555. * }
  556. *
  557. * @response 404 {
  558. * "message": "未找到有效的基础信息记录"
  559. * }
  560. * @response 422 {
  561. * "message": "没有需要更新的字段"
  562. * }
  563. * @response 422 {
  564. * "message": "验证码错误或已过期"
  565. * }
  566. * @response 422 {
  567. * "message": "验证错误",
  568. * "errors": {
  569. * "nickname": ["昵称不能少于2个字符"],
  570. * "gender": ["性别只能是1(男)或2(女)"],
  571. * "mobile": ["手机号格式不正确"],
  572. * "code": ["验证码不能为空"]
  573. * }
  574. * }
  575. */
  576. public function updateBasicInfo(UpdateBasicInfoRequest $request)
  577. {
  578. Log::error($request);
  579. return $this->success(
  580. $this->service->updateBasicInfo(Auth::user()->coach, $request->validated())
  581. );
  582. }
  583. /**
  584. * [账户]发送验证码
  585. *
  586. * @description 发送手机验证码,用于修改手机号等操作
  587. *
  588. * @authenticated 需要技师身份认证
  589. *
  590. * @bodyParam mobile string required 手机号 Example: 13800138000
  591. * @bodyParam type string required 验证码类型(update:修改手机号) Example: "update"
  592. *
  593. * @response {
  594. * "status": true,
  595. * "message": "验证码发送成功",
  596. * "data": {
  597. * "mobile": "138****8000",
  598. * "expire_time": 300
  599. * }
  600. * }
  601. *
  602. * @response 422 {
  603. * "message": "该手机号已被使用"
  604. * }
  605. */
  606. public function sendVerifyCode(SendVerifyCodeRequest $request)
  607. {
  608. return $this->success(
  609. $this->service->sendVerifyCode($request->validated())
  610. );
  611. }
  612. /**
  613. * [账户]获取已开通项目
  614. *
  615. * @description 获取技师已开通的服务项目列表
  616. *
  617. * @authenticated 需要技师身份认证
  618. *
  619. * @response {
  620. * "status": true,
  621. * "message": "获取成功",
  622. * "data": {
  623. * "total": 2,
  624. * "list": [
  625. * {
  626. * "id": 1,
  627. * "project_id": 100,
  628. * "project_name": "全身按摩",
  629. * "category_id": 1,
  630. * "category_name": "按摩",
  631. * "duration": 60,
  632. * "price": 200.00,
  633. * "discount_amount": 20.00,
  634. * "final_price": 180.00,
  635. * "service_gender": "all",
  636. * "service_distance": 5000,
  637. * "traffic_fee_type": "round_trip",
  638. * "traffic_fee": 10.00,
  639. * "created_at": "2024-03-16 10:00:00",
  640. * "updated_at": "2024-03-16 10:00:00"
  641. * }
  642. * ]
  643. * }
  644. * }
  645. */
  646. public function enabledProjects()
  647. {
  648. return $this->success(
  649. $this->service->getEnabledProjects(Auth::user()->coach->id)
  650. );
  651. }
  652. }