Initial commit: X-Server Mobile enterprise tool system
- Frontend: React 18 + TypeScript + Vite + Ant Design Mobile - Backend: PHP 8.5 + Webman 2.x + MySQL + Redis - i18n support: Chinese, English, Russian, Spanish, French - Approval workflow engine - Docker development environment - Feishu integration Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,47 @@
|
||||
<?php
|
||||
|
||||
namespace App\Model;
|
||||
|
||||
use support\Model;
|
||||
|
||||
class ApprovalFlow extends Model
|
||||
{
|
||||
protected $table = 'approval_flow';
|
||||
|
||||
protected $fillable = [
|
||||
'business_type',
|
||||
'name',
|
||||
'description',
|
||||
'status',
|
||||
];
|
||||
|
||||
protected $casts = [
|
||||
'status' => 'integer',
|
||||
'created_at' => 'datetime',
|
||||
'updated_at' => 'datetime',
|
||||
];
|
||||
|
||||
/**
|
||||
* 关联审批节点
|
||||
*/
|
||||
public function nodes()
|
||||
{
|
||||
return $this->hasMany(ApprovalNode::class, 'flow_id')->orderBy('order');
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取启用的流程
|
||||
*/
|
||||
public function scopeActive($query)
|
||||
{
|
||||
return $query->where('status', 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据业务类型获取流程
|
||||
*/
|
||||
public function scopeByBusinessType($query, string $businessType)
|
||||
{
|
||||
return $query->where('business_type', $businessType);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
<?php
|
||||
|
||||
namespace App\Model;
|
||||
|
||||
use support\Model;
|
||||
|
||||
class ApprovalNode extends Model
|
||||
{
|
||||
protected $table = 'approval_node';
|
||||
|
||||
protected $fillable = [
|
||||
'flow_id',
|
||||
'type',
|
||||
'name',
|
||||
'order',
|
||||
'approvers',
|
||||
'conditions',
|
||||
];
|
||||
|
||||
protected $casts = [
|
||||
'approvers' => 'array',
|
||||
'conditions' => 'array',
|
||||
'order' => 'integer',
|
||||
'created_at' => 'datetime',
|
||||
'updated_at' => 'datetime',
|
||||
];
|
||||
|
||||
/**
|
||||
* 节点类型常量
|
||||
*/
|
||||
const TYPE_APPROVER = 'approver'; // 审批人(单人)
|
||||
const TYPE_AND_APPROVE = 'and_approve'; // 会签(需所有人通过)
|
||||
const TYPE_OR_APPROVE = 'or_approve'; // 或签(任一人通过)
|
||||
const TYPE_NOTIFY = 'notify'; // 抄送(通知用)
|
||||
|
||||
/**
|
||||
* 关联流程
|
||||
*/
|
||||
public function flow()
|
||||
{
|
||||
return $this->belongsTo(ApprovalFlow::class, 'flow_id');
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取指定顺序的节点
|
||||
*/
|
||||
public function scopeByOrder($query, int $order)
|
||||
{
|
||||
return $query->where('order', $order);
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断是否是审批节点
|
||||
*/
|
||||
public function isApprovalNode(): bool
|
||||
{
|
||||
return in_array($this->type, [
|
||||
self::TYPE_APPROVER,
|
||||
self::TYPE_AND_APPROVE,
|
||||
self::TYPE_OR_APPROVE,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断是否是会签
|
||||
*/
|
||||
public function isAndApprove(): bool
|
||||
{
|
||||
return $this->type === self::TYPE_AND_APPROVE;
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断是否是或签
|
||||
*/
|
||||
public function isOrApprove(): bool
|
||||
{
|
||||
return $this->type === self::TYPE_OR_APPROVE;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,91 @@
|
||||
<?php
|
||||
|
||||
namespace App\Model;
|
||||
|
||||
use support\Model;
|
||||
|
||||
class ApprovalOrder extends Model
|
||||
{
|
||||
protected $table = 'approval_order';
|
||||
|
||||
protected $fillable = [
|
||||
'business_type',
|
||||
'business_id',
|
||||
'title',
|
||||
'applicant_id',
|
||||
'status',
|
||||
'current_nodes',
|
||||
'flow_id',
|
||||
'form_data',
|
||||
'attachments',
|
||||
];
|
||||
|
||||
protected $casts = [
|
||||
'current_nodes' => 'array',
|
||||
'form_data' => 'array',
|
||||
'attachments' => 'array',
|
||||
'created_at' => 'datetime',
|
||||
'updated_at' => 'datetime',
|
||||
];
|
||||
|
||||
/**
|
||||
* 审批状态常量
|
||||
*/
|
||||
const STATUS_DRAFT = 'draft'; // 草稿
|
||||
const STATUS_PENDING = 'pending'; // 审批中
|
||||
const STATUS_APPROVED = 'approved'; // 已通过
|
||||
const STATUS_REJECTED = 'rejected'; // 已拒绝
|
||||
const STATUS_CANCELLED = 'cancelled'; // 已撤销
|
||||
|
||||
/**
|
||||
* 关联流程
|
||||
*/
|
||||
public function flow()
|
||||
{
|
||||
return $this->belongsTo(ApprovalFlow::class, 'flow_id');
|
||||
}
|
||||
|
||||
/**
|
||||
* 关联申请人
|
||||
*/
|
||||
public function applicant()
|
||||
{
|
||||
return $this->belongsTo(User::class, 'applicant_id');
|
||||
}
|
||||
|
||||
/**
|
||||
* 关联审批记录
|
||||
*/
|
||||
public function records()
|
||||
{
|
||||
return $this->hasMany(ApprovalRecord::class, 'order_id')->orderBy('created_at');
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断是否可以编辑
|
||||
*/
|
||||
public function canEdit(): bool
|
||||
{
|
||||
return $this->status === self::STATUS_DRAFT;
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断是否可以审批
|
||||
*/
|
||||
public function canApprove(): bool
|
||||
{
|
||||
return $this->status === self::STATUS_PENDING;
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断是否已结束
|
||||
*/
|
||||
public function isEnded(): bool
|
||||
{
|
||||
return in_array($this->status, [
|
||||
self::STATUS_APPROVED,
|
||||
self::STATUS_REJECTED,
|
||||
self::STATUS_CANCELLED,
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
<?php
|
||||
|
||||
namespace App\Model;
|
||||
|
||||
use support\Model;
|
||||
|
||||
class ApprovalRecord extends Model
|
||||
{
|
||||
protected $table = 'approval_record';
|
||||
|
||||
protected $fillable = [
|
||||
'order_id',
|
||||
'node_id',
|
||||
'node_type',
|
||||
'approver_id',
|
||||
'action',
|
||||
'comment',
|
||||
];
|
||||
|
||||
protected $casts = [
|
||||
'created_at' => 'datetime',
|
||||
];
|
||||
|
||||
/**
|
||||
* 操作类型常量
|
||||
*/
|
||||
const ACTION_SUBMIT = 'submit'; // 提交
|
||||
const ACTION_APPROVE = 'approve'; // 通过
|
||||
const ACTION_REJECT = 'reject'; // 拒绝
|
||||
const ACTION_CANCEL = 'cancel'; // 撤销
|
||||
|
||||
/**
|
||||
* 关联审批单
|
||||
*/
|
||||
public function order()
|
||||
{
|
||||
return $this->belongsTo(ApprovalOrder::class, 'order_id');
|
||||
}
|
||||
|
||||
/**
|
||||
* 关联审批人
|
||||
*/
|
||||
public function approver()
|
||||
{
|
||||
return $this->belongsTo(User::class, 'approver_id');
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断是否是批准操作
|
||||
*/
|
||||
public function isApproved(): bool
|
||||
{
|
||||
return $this->action === self::ACTION_APPROVE;
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断是否是拒绝操作
|
||||
*/
|
||||
public function isRejected(): bool
|
||||
{
|
||||
return $this->action === self::ACTION_REJECT;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
<?php
|
||||
|
||||
namespace App\Model;
|
||||
|
||||
use support\Model;
|
||||
|
||||
class Company extends Model
|
||||
{
|
||||
protected $table = 'company';
|
||||
|
||||
protected $fillable = [
|
||||
'name',
|
||||
'feishu_app_id',
|
||||
'feishu_app_secret',
|
||||
'feishu_tenant_key',
|
||||
'status',
|
||||
];
|
||||
|
||||
protected $casts = [
|
||||
'status' => 'integer',
|
||||
'created_at' => 'datetime',
|
||||
'updated_at' => 'datetime',
|
||||
];
|
||||
|
||||
protected $hidden = [
|
||||
'feishu_app_secret',
|
||||
];
|
||||
|
||||
/**
|
||||
* 获取启用的公司
|
||||
*/
|
||||
public function scopeActive($query)
|
||||
{
|
||||
return $query->where('status', 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据飞书租户Key查找
|
||||
*/
|
||||
public function scopeByFeishuTenantKey($query, string $tenantKey)
|
||||
{
|
||||
return $query->where('feishu_tenant_key', $tenantKey);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据飞书AppID查找
|
||||
*/
|
||||
public function scopeByFeishuAppId($query, string $appId)
|
||||
{
|
||||
return $query->where('feishu_app_id', $appId);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
<?php
|
||||
|
||||
namespace App\Model;
|
||||
|
||||
use support\Model;
|
||||
|
||||
class User extends Model
|
||||
{
|
||||
protected $table = 'user';
|
||||
|
||||
protected $fillable = [
|
||||
'company_id',
|
||||
'feishu_user_id',
|
||||
'feishu_union_id',
|
||||
'name',
|
||||
'email',
|
||||
'phone',
|
||||
'avatar',
|
||||
'status',
|
||||
];
|
||||
|
||||
protected $casts = [
|
||||
'company_id' => 'integer',
|
||||
'status' => 'integer',
|
||||
'created_at' => 'datetime',
|
||||
'updated_at' => 'datetime',
|
||||
];
|
||||
|
||||
/**
|
||||
* 关联公司
|
||||
*/
|
||||
public function company()
|
||||
{
|
||||
return $this->belongsTo(Company::class, 'company_id');
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取启用的用户
|
||||
*/
|
||||
public function scopeActive($query)
|
||||
{
|
||||
return $query->where('status', 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据飞书用户ID查找
|
||||
*/
|
||||
public function scopeByFeishuUserId($query, string $feishuUserId)
|
||||
{
|
||||
return $query->where('feishu_user_id', $feishuUserId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据飞书 UnionID 查找
|
||||
*/
|
||||
public function scopeByFeishuUnionId($query, string $feishuUnionId)
|
||||
{
|
||||
return $query->where('feishu_union_id', $feishuUnionId);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user