feat: 打卡接口调整
parent
34805d76d6
commit
d102eb2844
|
@ -3,9 +3,13 @@
|
||||||
namespace app\controller\api\v1;
|
namespace app\controller\api\v1;
|
||||||
|
|
||||||
use app\controller\api\Base;
|
use app\controller\api\Base;
|
||||||
|
use app\exception\ApiException;
|
||||||
use app\exception\RepositoryException;
|
use app\exception\RepositoryException;
|
||||||
use app\model\Account;
|
use app\model\Account;
|
||||||
use app\model\AccountRecord;
|
use app\model\AccountRecord;
|
||||||
|
use app\model\ClockLog;
|
||||||
|
use app\model\PayLog;
|
||||||
|
use app\model\Worksite;
|
||||||
use app\repository\AccountRepository;
|
use app\repository\AccountRepository;
|
||||||
use app\service\File;
|
use app\service\File;
|
||||||
use app\service\Jwt;
|
use app\service\Jwt;
|
||||||
|
@ -17,6 +21,7 @@ use think\Collection;
|
||||||
use think\db\exception\DataNotFoundException;
|
use think\db\exception\DataNotFoundException;
|
||||||
use think\db\exception\DbException;
|
use think\db\exception\DbException;
|
||||||
use think\db\exception\ModelNotFoundException;
|
use think\db\exception\ModelNotFoundException;
|
||||||
|
use think\facade\Config;
|
||||||
use think\facade\Log;
|
use think\facade\Log;
|
||||||
use think\response\Json;
|
use think\response\Json;
|
||||||
|
|
||||||
|
@ -390,10 +395,10 @@ class User extends Base
|
||||||
try {
|
try {
|
||||||
$openid = input('openid/s');
|
$openid = input('openid/s');
|
||||||
if (empty($openid)) {
|
if (empty($openid)) {
|
||||||
return $this->json(0,'success', ['status' => 0]);
|
return $this->json(0, 'success', ['status' => 0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
$isActive = (int)Account::where('openid', $openid)->value('is_active');
|
$isActive = (int) Account::where('openid', $openid)->value('is_active');
|
||||||
|
|
||||||
return $this->json(0, 'success', ['status' => $isActive]);
|
return $this->json(0, 'success', ['status' => $isActive]);
|
||||||
} catch (Exception $e) {
|
} catch (Exception $e) {
|
||||||
|
@ -442,4 +447,119 @@ class User extends Base
|
||||||
|
|
||||||
return $this->json(0, 'success', ['list' => $list]);
|
return $this->json(0, 'success', ['list' => $list]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 打卡
|
||||||
|
* 普通用户打卡不需要任何参数
|
||||||
|
* 员工和负责人打卡 参数相同
|
||||||
|
*/
|
||||||
|
public function sign(): Json
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
$accountId = $this->request->user['user_id'] ?? 0;
|
||||||
|
|
||||||
|
if (!$customer = Account::findById($accountId)) {
|
||||||
|
return $this->json(6001, '请先登录');
|
||||||
|
}
|
||||||
|
|
||||||
|
// 工人打卡
|
||||||
|
if ($customer['role'] == Account::ROLE_NORMAL && $this->normalSign($accountId)) {
|
||||||
|
return $this->json();
|
||||||
|
}
|
||||||
|
|
||||||
|
$input = input('post.');
|
||||||
|
|
||||||
|
$rules = [
|
||||||
|
'type|打卡类型' => 'require|in:morning_on,morning_off,afternoon_on,afternoon_off',
|
||||||
|
'lat|维度' => 'require',
|
||||||
|
'lng|经度' => 'require',
|
||||||
|
'worksite_id|工地' => 'require|number',
|
||||||
|
];
|
||||||
|
|
||||||
|
$validate = $this->validateByApi($input, $rules, ['type.in' => '打卡类型错误']);
|
||||||
|
|
||||||
|
if ($validate !== true) {
|
||||||
|
return $validate;
|
||||||
|
}
|
||||||
|
|
||||||
|
Config::load('extra/base', 'base');
|
||||||
|
$baseConfig = config('base');
|
||||||
|
$signArea = $baseConfig['sign_area'] ?? 200;
|
||||||
|
$worksite = Worksite::getNearest($input['lng'], $input['lat'], $signArea);
|
||||||
|
if (empty($worksite) || $worksite['id'] != $input['worksite_id']) {
|
||||||
|
return $this->json(4004, '不在打卡范围!');
|
||||||
|
}
|
||||||
|
|
||||||
|
$time = time();
|
||||||
|
// $time = $time - 86401 * 3;
|
||||||
|
$now = date('Y-m-d H:i:s', $time);
|
||||||
|
$day = date('Ymd', $time);
|
||||||
|
|
||||||
|
if (ClockLog::hasSign($accountId, $input['type'], $input['worksite_id'])) {
|
||||||
|
return $this->json(4001, '今日已打过此卡');
|
||||||
|
}
|
||||||
|
|
||||||
|
$data = [
|
||||||
|
'account_id' => $accountId,
|
||||||
|
'type' => $input['type'],
|
||||||
|
'worksite_id' => $input['worksite_id'],
|
||||||
|
'created_at' => $now,
|
||||||
|
'create_time' => $time,
|
||||||
|
'day' => $day,
|
||||||
|
'indexs' => $accountId.'-'.$input['worksite_id'].'-'.$day,
|
||||||
|
];
|
||||||
|
|
||||||
|
// 工人
|
||||||
|
if ($customer['role'] == Account::ROLE_WORKER) {
|
||||||
|
$data['need_statistic'] = Account::COMMON_ON;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 负责人
|
||||||
|
if ($customer['role'] == Account::ROLE_MANAGER) {
|
||||||
|
$data['status'] = Account::COMMON_ON;
|
||||||
|
$data['need_statistic'] = Account::COMMON_OFF;
|
||||||
|
}
|
||||||
|
ClockLog::create($data);
|
||||||
|
|
||||||
|
// 创建当日工资初始记录
|
||||||
|
PayLog::createWhenNotExists($accountId, $input['worksite_id'], $day);
|
||||||
|
} catch (ApiException $e) {
|
||||||
|
return $this->json(4000, $e->getMessage());
|
||||||
|
} catch (Exception $e) {
|
||||||
|
Log::error('打卡失败'.$e->getMessage());
|
||||||
|
return $this->json(5000, '打卡失败!');
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->json();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 普通用户打卡
|
||||||
|
*
|
||||||
|
* @param int $accountId
|
||||||
|
* @return bool
|
||||||
|
* @throws \app\exception\ApiException
|
||||||
|
* @throws \think\db\exception\DbException
|
||||||
|
*/
|
||||||
|
private function normalSign(int $accountId): bool
|
||||||
|
{
|
||||||
|
$time = time();
|
||||||
|
// $time = $time - 86401 * 3;
|
||||||
|
$now = date('Y-m-d H:i:s', $time);
|
||||||
|
$day = date('Ymd', $time);
|
||||||
|
|
||||||
|
if (ClockLog::checkRate($accountId)) {
|
||||||
|
throw new ApiException('打卡频率过快!');
|
||||||
|
}
|
||||||
|
|
||||||
|
ClockLog::create([
|
||||||
|
'account_id' => $accountId,
|
||||||
|
'type' => ClockLog::TYPE_NORMAL,
|
||||||
|
'created_at' => $now,
|
||||||
|
'create_time' => $time,
|
||||||
|
'day' => $day,
|
||||||
|
]);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -188,10 +188,20 @@ class Worker extends Base
|
||||||
public function sign(): Json
|
public function sign(): Json
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
|
$accountId = $this->request->user['user_id'] ?? 0;
|
||||||
|
|
||||||
|
if (!$customer = Account::findById($accountId)) {
|
||||||
|
return $this->json(6001, '请先登录');
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($customer['role'] == Account::ROLE_NORMAL) {
|
||||||
|
return $this->normalSign();
|
||||||
|
}
|
||||||
|
|
||||||
$input = input('post.');
|
$input = input('post.');
|
||||||
|
|
||||||
$rules = [
|
$rules = [
|
||||||
'type|打卡类型' => 'require|in:in,out',
|
'type|打卡类型' => 'require|in:morning_on,morning_off,afternoon_on,afternoon_off',
|
||||||
'lat|维度' => 'require',
|
'lat|维度' => 'require',
|
||||||
'lng|经度' => 'require',
|
'lng|经度' => 'require',
|
||||||
'worksite_id|工地' => 'require|number',
|
'worksite_id|工地' => 'require|number',
|
||||||
|
@ -203,12 +213,6 @@ class Worker extends Base
|
||||||
return $validate;
|
return $validate;
|
||||||
}
|
}
|
||||||
|
|
||||||
$accountId = $this->request->user['user_id'] ?? 0;
|
|
||||||
|
|
||||||
if (!$customer = Account::findById($accountId)) {
|
|
||||||
return $this->json(6001, '请先登录');
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($customer['role'] != Account::ROLE_WORKER) {
|
if ($customer['role'] != Account::ROLE_WORKER) {
|
||||||
return $this->json(4003, '完成审核后方可打卡');
|
return $this->json(4003, '完成审核后方可打卡');
|
||||||
}
|
}
|
||||||
|
@ -250,6 +254,47 @@ class Worker extends Base
|
||||||
return $this->json();
|
return $this->json();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function normalSign($customer)
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
|
||||||
|
Config::load('extra/base', 'base');
|
||||||
|
$baseConfig = config('base');
|
||||||
|
$signArea = $baseConfig['sign_area'] ?? 200;
|
||||||
|
$worksite = Worksite::getNearest($input['lng'], $input['lat'], $signArea);
|
||||||
|
if (empty($worksite) || $worksite['id'] != $input['worksite_id']) {
|
||||||
|
return $this->json(4004, '不在打卡范围!');
|
||||||
|
}
|
||||||
|
|
||||||
|
$time = time();
|
||||||
|
// $time = $time - 86401 * 3;
|
||||||
|
$now = date('Y-m-d H:i:s', $time);
|
||||||
|
$day = date('Ymd', $time);
|
||||||
|
|
||||||
|
if (ClockLog::where('account_id', $accountId)->where('type', $input['type'])->where('create_time', '>', time() - 60)->count()) {
|
||||||
|
return $this->json(4001, '打卡频率过快!');
|
||||||
|
}
|
||||||
|
|
||||||
|
ClockLog::create([
|
||||||
|
'account_id' => $accountId,
|
||||||
|
'type' => $input['type'],
|
||||||
|
'worksite_id' => $input['worksite_id'],
|
||||||
|
'created_at' => $now,
|
||||||
|
'create_time' => $time,
|
||||||
|
'day' => $day,
|
||||||
|
'indexs' => $accountId.'-'.$input['worksite_id'].'-'.$day,
|
||||||
|
]);
|
||||||
|
|
||||||
|
// 创建当日工资初始记录
|
||||||
|
PayLog::createWhenNotExists($accountId, $input['worksite_id'], $day);
|
||||||
|
} catch (Exception $e) {
|
||||||
|
Log::error('工人打卡失败'.$e->getMessage());
|
||||||
|
return $this->json(5000, '打卡失败!');
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->json();
|
||||||
|
}
|
||||||
|
|
||||||
// 我的打卡
|
// 我的打卡
|
||||||
public function clockList(): Json
|
public function clockList(): Json
|
||||||
{
|
{
|
||||||
|
|
|
@ -0,0 +1,10 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace app\exception;
|
||||||
|
|
||||||
|
use Exception;
|
||||||
|
|
||||||
|
class ApiException extends Exception
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
|
@ -10,8 +10,13 @@ namespace app\model;
|
||||||
*/
|
*/
|
||||||
class ClockLog extends Base
|
class ClockLog extends Base
|
||||||
{
|
{
|
||||||
public const TYPE_IN = 'in';//上班
|
public const TYPE_NORMAL = 'normal';//普通打卡 适用于普通用户打卡 不区分上下班 场地 位置等等
|
||||||
public const TYPE_OUT = 'out';//下班
|
|
||||||
|
public const TYPE_MORNING_ON = 'morning_on';//上午上班
|
||||||
|
public const TYPE_MORNING_OFF = 'morning_off';//上午下班
|
||||||
|
|
||||||
|
public const TYPE_AFTERNOON_ON = 'afternoon_on';//下午上班
|
||||||
|
public const TYPE_AFTERNOON_OFF = 'afternoon_off';//下午下班
|
||||||
|
|
||||||
public const STATUS_TODO = 0;//待审核
|
public const STATUS_TODO = 0;//待审核
|
||||||
public const STATUS_YES = 1;//通过
|
public const STATUS_YES = 1;//通过
|
||||||
|
@ -25,8 +30,11 @@ class ClockLog extends Base
|
||||||
public static function typeText(): array
|
public static function typeText(): array
|
||||||
{
|
{
|
||||||
return [
|
return [
|
||||||
self::TYPE_IN => '上班',
|
self::TYPE_NORMAL => '普通打卡',
|
||||||
self::TYPE_OUT => '下班',
|
self::TYPE_MORNING_ON => '上午上班',
|
||||||
|
self::TYPE_MORNING_OFF => '上午下班',
|
||||||
|
self::TYPE_AFTERNOON_ON => '下午上班',
|
||||||
|
self::TYPE_AFTERNOON_OFF => '下午下班',
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -38,4 +46,44 @@ class ClockLog extends Base
|
||||||
self::STATUS_NO => '审核拒绝',
|
self::STATUS_NO => '审核拒绝',
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 检查打卡频率
|
||||||
|
* 目前针对普通用户
|
||||||
|
*
|
||||||
|
* @param int $accountId 用户ID
|
||||||
|
* @param string $type 打卡类型
|
||||||
|
* @param int $worksiteId 工地ID 默认0
|
||||||
|
* @param int $seconds 时间限制,秒 即多少秒内只能打一次 默认60
|
||||||
|
* @return bool true=单位时间有打卡 false=单位时间未打卡
|
||||||
|
* @throws \think\db\exception\DbException
|
||||||
|
*/
|
||||||
|
public static function checkRate(int $accountId, string $type = self::TYPE_NORMAL, int $worksiteId = 0, int $seconds = 60): bool
|
||||||
|
{
|
||||||
|
return self::where('account_id', $accountId)
|
||||||
|
->where('type', $type)
|
||||||
|
->where('worksite_id', $worksiteId)
|
||||||
|
->where('create_time', '>', time() - $seconds)
|
||||||
|
->count() > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 检查当天是否已打卡
|
||||||
|
* 目前针对工人和负责人
|
||||||
|
*
|
||||||
|
* @param int $accountId 用户ID
|
||||||
|
* @param string $type 打卡类型
|
||||||
|
* @param int $worksiteId 工地ID 默认0
|
||||||
|
* @return bool
|
||||||
|
* @throws \think\db\exception\DbException
|
||||||
|
*/
|
||||||
|
public static function hasSign(int $accountId, string $type, int $worksiteId): bool
|
||||||
|
{
|
||||||
|
return self::where('account_id', $accountId)
|
||||||
|
->where('type', $type)
|
||||||
|
->where('worksite_id', $worksiteId)
|
||||||
|
->where('create_time', '>=', strtotime(date('Y-m-d')))
|
||||||
|
->where('create_time', '<=', strtotime(date('Y-m-d 23:59:59')))
|
||||||
|
->count() > 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -86,4 +86,67 @@ class Worksite extends Base
|
||||||
{
|
{
|
||||||
return self::order('sort', 'desc')->order('id', 'desc')->column('name', 'id');
|
return self::order('sort', 'desc')->order('id', 'desc')->column('name', 'id');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 验证是否在打卡时间
|
||||||
|
public static function checkSignTime(int $worksiteId, string $type): bool
|
||||||
|
{
|
||||||
|
if (!$item = self::find($worksiteId)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
$morningBegin = $item['old_morning_begin'];
|
||||||
|
$morningEnd = $item['old_morning_end'];
|
||||||
|
$afternoonBegin = $item['old_afternoon_begin'];
|
||||||
|
$afternoonEnd = $item['old_afternoon_end'];
|
||||||
|
|
||||||
|
$now = time();
|
||||||
|
|
||||||
|
if ($now > $item['start_at']) {
|
||||||
|
$morningBegin = $item['morning_begin'];
|
||||||
|
$morningEnd = $item['morning_end'];
|
||||||
|
$afternoonBegin = $item['afternoon_begin'];
|
||||||
|
$afternoonEnd = $item['afternoon_end'];
|
||||||
|
}
|
||||||
|
|
||||||
|
// 时间戳
|
||||||
|
$morningBeginTs = strtotime($morningBegin);
|
||||||
|
$morningEndTs = strtotime($morningEnd);
|
||||||
|
$afternoonBeginTs = strtotime($afternoonBegin);
|
||||||
|
$afternoonEndTs = strtotime($afternoonEnd);
|
||||||
|
|
||||||
|
$result = false;
|
||||||
|
switch ($type) {
|
||||||
|
// 普通用户打卡 不限制时间
|
||||||
|
case ClockLog::TYPE_NORMAL:
|
||||||
|
$result = true;
|
||||||
|
break;
|
||||||
|
// 上午上班时间 打卡时间在上班前的10分钟
|
||||||
|
case ClockLog::TYPE_MORNING_ON:
|
||||||
|
if (($morningBeginTs - 10 * 60) <= $now && $now <= $morningBeginTs) {
|
||||||
|
$result = true;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
// 上午下班时间 打卡时间在下班时间后 下次上班时间以前
|
||||||
|
case ClockLog::TYPE_MORNING_OFF:
|
||||||
|
if (($morningEndTs) <= $now && $now < $afternoonBeginTs) {
|
||||||
|
$result = true;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
// 下午上班时间 打卡时间在上班前的10分钟
|
||||||
|
case ClockLog::TYPE_AFTERNOON_ON:
|
||||||
|
if (($afternoonBeginTs - 10 * 60) <= $now && $now <= $afternoonBeginTs) {
|
||||||
|
$result = true;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
// 下午下班时间 打卡时间在下班时间后 当天23:59:59以前
|
||||||
|
case ClockLog::TYPE_AFTERNOON_OFF:
|
||||||
|
if (($afternoonEndTs) <= $now && $now < strtotime('23:59:59')) {
|
||||||
|
$result = true;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue