feat: 第五阶段办公协同/统计报表/知识库模块

- 新增3个migration(9张表): office(6表)/report(1表)/kb(2表)
- 新增9个Model + 9个Controller
- 新增43条API路由(总计305条)
- 新增3个前端API模块 + 10个管理页面
- 迁移运行通过, vite build验证通过
This commit is contained in:
li
2026-03-13 21:43:10 +08:00
parent fb5e0daf1a
commit 058ee507fa
34 changed files with 2595 additions and 0 deletions
@@ -0,0 +1,33 @@
<?php
namespace App\Models\Office;
use App\Models\User;
use App\Traits\BelongsToStore;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
class Announcement extends Model
{
use BelongsToStore;
protected $fillable = [
'store_id', 'title', 'content', 'type', 'is_top',
'publish_status', 'published_at', 'author_id',
];
protected function casts(): array
{
return [
'type' => 'integer',
'publish_status' => 'integer',
'is_top' => 'boolean',
'published_at' => 'datetime',
];
}
public function author(): BelongsTo
{
return $this->belongsTo(User::class, 'author_id');
}
}
+43
View File
@@ -0,0 +1,43 @@
<?php
namespace App\Models\Office;
use App\Models\User;
use App\Traits\BelongsToStore;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\HasMany;
class Approval extends Model
{
use BelongsToStore;
protected $fillable = [
'store_id', 'template_id', 'title', 'applicant_id', 'form_data',
'status', 'current_node', 'related_type', 'related_id',
];
protected function casts(): array
{
return [
'status' => 'integer',
'current_node' => 'integer',
'form_data' => 'array',
];
}
public function template(): BelongsTo
{
return $this->belongsTo(ApprovalTemplate::class, 'template_id');
}
public function applicant(): BelongsTo
{
return $this->belongsTo(User::class, 'applicant_id');
}
public function nodes(): HasMany
{
return $this->hasMany(ApprovalNode::class);
}
}
@@ -0,0 +1,35 @@
<?php
namespace App\Models\Office;
use App\Models\User;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
class ApprovalNode extends Model
{
const UPDATED_AT = null;
protected $fillable = [
'approval_id', 'node_order', 'approver_id', 'action', 'comment', 'acted_at',
];
protected function casts(): array
{
return [
'node_order' => 'integer',
'action' => 'integer',
'acted_at' => 'datetime',
];
}
public function approval(): BelongsTo
{
return $this->belongsTo(Approval::class);
}
public function approver(): BelongsTo
{
return $this->belongsTo(User::class, 'approver_id');
}
}
@@ -0,0 +1,26 @@
<?php
namespace App\Models\Office;
use App\Traits\BelongsToStore;
use Illuminate\Database\Eloquent\Model;
class ApprovalTemplate extends Model
{
use BelongsToStore;
protected $fillable = [
'store_id', 'name', 'type', 'form_fields', 'flow_nodes', 'status', 'sort',
];
protected function casts(): array
{
return [
'type' => 'integer',
'status' => 'integer',
'sort' => 'integer',
'form_fields' => 'array',
'flow_nodes' => 'array',
];
}
}
+40
View File
@@ -0,0 +1,40 @@
<?php
namespace App\Models\Office;
use App\Models\User;
use App\Traits\BelongsToStore;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
class Handover extends Model
{
use BelongsToStore;
const UPDATED_AT = null;
protected $fillable = [
'store_id', 'shift_date', 'shift_type', 'handover_user_id',
'receiver_user_id', 'content', 'issues', 'status', 'confirmed_at',
];
protected function casts(): array
{
return [
'shift_type' => 'integer',
'status' => 'integer',
'shift_date' => 'date',
'confirmed_at' => 'datetime',
];
}
public function handoverUser(): BelongsTo
{
return $this->belongsTo(User::class, 'handover_user_id');
}
public function receiverUser(): BelongsTo
{
return $this->belongsTo(User::class, 'receiver_user_id');
}
}
@@ -0,0 +1,36 @@
<?php
namespace App\Models\Office;
use App\Models\User;
use App\Traits\BelongsToStore;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
class Notification extends Model
{
use BelongsToStore;
const UPDATED_AT = null;
protected $table = 'notifications';
protected $fillable = [
'store_id', 'user_id', 'title', 'content', 'type',
'related_type', 'related_id', 'is_read', 'read_at',
];
protected function casts(): array
{
return [
'type' => 'integer',
'is_read' => 'boolean',
'read_at' => 'datetime',
];
}
public function user(): BelongsTo
{
return $this->belongsTo(User::class);
}
}