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
+42
View File
@@ -0,0 +1,42 @@
<?php
namespace App\Models\Kb;
use App\Models\User;
use App\Traits\BelongsToStore;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
class KbArticle extends Model
{
use BelongsToStore;
protected $fillable = [
'store_id', 'category_id', 'title', 'content', 'author_id',
'status', 'visibility', 'cover_image', 'attachments',
'views', 'likes', 'favorites', 'published_at',
];
protected function casts(): array
{
return [
'status' => 'integer',
'visibility' => 'integer',
'views' => 'integer',
'likes' => 'integer',
'favorites' => 'integer',
'attachments' => 'array',
'published_at' => 'datetime',
];
}
public function category(): BelongsTo
{
return $this->belongsTo(KbCategory::class, 'category_id');
}
public function author(): BelongsTo
{
return $this->belongsTo(User::class, 'author_id');
}
}
+40
View File
@@ -0,0 +1,40 @@
<?php
namespace App\Models\Kb;
use App\Traits\BelongsToStore;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\HasMany;
class KbCategory extends Model
{
use BelongsToStore;
protected $fillable = [
'store_id', 'parent_id', 'name', 'sort', 'status',
];
protected function casts(): array
{
return [
'sort' => 'integer',
'status' => 'integer',
];
}
public function children(): HasMany
{
return $this->hasMany(self::class, 'parent_id');
}
public function parent(): BelongsTo
{
return $this->belongsTo(self::class, 'parent_id');
}
public function articles(): HasMany
{
return $this->hasMany(KbArticle::class, 'category_id');
}
}
@@ -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);
}
}
@@ -0,0 +1,32 @@
<?php
namespace App\Models\Report;
use App\Models\User;
use App\Traits\BelongsToStore;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
class ReportExport extends Model
{
use BelongsToStore;
const UPDATED_AT = null;
protected $fillable = [
'store_id', 'name', 'type', 'params', 'file_path', 'status', 'operator_id',
];
protected function casts(): array
{
return [
'params' => 'array',
'status' => 'integer',
];
}
public function operator(): BelongsTo
{
return $this->belongsTo(User::class, 'operator_id');
}
}