feat: 打卡接口调整

master
yin5th 2023-01-11 10:06:01 +08:00
parent 34805d76d6
commit d102eb2844
5 changed files with 309 additions and 23 deletions

View File

@ -3,9 +3,13 @@
namespace app\controller\api\v1;
use app\controller\api\Base;
use app\exception\ApiException;
use app\exception\RepositoryException;
use app\model\Account;
use app\model\AccountRecord;
use app\model\ClockLog;
use app\model\PayLog;
use app\model\Worksite;
use app\repository\AccountRepository;
use app\service\File;
use app\service\Jwt;
@ -17,6 +21,7 @@ use think\Collection;
use think\db\exception\DataNotFoundException;
use think\db\exception\DbException;
use think\db\exception\ModelNotFoundException;
use think\facade\Config;
use think\facade\Log;
use think\response\Json;
@ -333,12 +338,12 @@ class User extends Base
{
$list = [];
$week = ['日', '一', '二', '三', '四', '五', '六'];
$week = ['日', '一', '二', '三', '四', '五', '六'];
$info = [
'today' => date('Y年m月d日'),
'week' => '星期'.$week[date('w')],
'now' => date('H:i:s'),
$info = [
'today' => date('Y年m月d日'),
'week' => '星期'.$week[date('w')],
'now' => date('H:i:s'),
'is_sign' => (int) !empty($list),
];
@ -390,10 +395,10 @@ class User extends Base
try {
$openid = input('openid/s');
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]);
} catch (Exception $e) {
@ -405,13 +410,13 @@ class User extends Base
public function monthSignLog(): Json
{
$accountId = $this->request->user['user_id'] ?? 0;
$date = input('date/d', date('Y-m'));
$ym = str_replace('-', '', $date);
$date = input('date/d', date('Y-m'));
$ym = str_replace('-', '', $date);
$list = [];
if ($accountId > 0) {
$where = [];
$where = [];
$where[] = ['cl.day', 'like', $ym.'%'];
$where[] = ['cl.account_id', '=', $accountId];
@ -442,4 +447,119 @@ class User extends Base
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;
}
}

View File

@ -188,10 +188,20 @@ class Worker extends Base
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) {
return $this->normalSign();
}
$input = input('post.');
$rules = [
'type|打卡类型' => 'require|in:in,out',
'type|打卡类型' => 'require|in:morning_on,morning_off,afternoon_on,afternoon_off',
'lat|维度' => 'require',
'lng|经度' => 'require',
'worksite_id|工地' => 'require|number',
@ -203,12 +213,6 @@ class Worker extends Base
return $validate;
}
$accountId = $this->request->user['user_id'] ?? 0;
if (!$customer = Account::findById($accountId)) {
return $this->json(6001, '请先登录');
}
if ($customer['role'] != Account::ROLE_WORKER) {
return $this->json(4003, '完成审核后方可打卡');
}
@ -250,6 +254,47 @@ class Worker extends Base
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
{

View File

@ -0,0 +1,10 @@
<?php
namespace app\exception;
use Exception;
class ApiException extends Exception
{
}

View File

@ -10,8 +10,13 @@ namespace app\model;
*/
class ClockLog extends Base
{
public const TYPE_IN = 'in';//上班
public const TYPE_OUT = 'out';//下班
public const TYPE_NORMAL = 'normal';//普通打卡 适用于普通用户打卡 不区分上下班 场地 位置等等
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_YES = 1;//通过
@ -25,8 +30,11 @@ class ClockLog extends Base
public static function typeText(): array
{
return [
self::TYPE_IN => '上班',
self::TYPE_OUT => '下班',
self::TYPE_NORMAL => '普通打卡',
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 => '审核拒绝',
];
}
/**
* 检查打卡频率
* 目前针对普通用户
*
* @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;
}
}

View File

@ -18,8 +18,8 @@ class Worksite extends Base
public static function statusText(): array
{
return [
self::STATUS_NO => '禁用',
self::STATUS_YES => '正常',
self::STATUS_NO => '禁用',
self::STATUS_YES => '正常',
];
}
// 获取指定距离内由近及远的N条记录
@ -86,4 +86,67 @@ class Worksite extends Base
{
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;
}
}