refactor: 修复知识库和操作指引

This commit is contained in:
2026-03-13 14:32:37 +08:00
parent bbe8e60646
commit 58f42de9df
88 changed files with 3387 additions and 2472 deletions

View File

@@ -32,6 +32,7 @@ class Document extends Model
'markdown_preview',
'conversion_status',
'conversion_error',
'knowledge_base_id',
];
/**
@@ -42,6 +43,14 @@ class Document extends Model
return $this->belongsTo(Group::class);
}
/**
* 获取文档所属的知识库
*/
public function knowledgeBase(): BelongsTo
{
return $this->belongsTo(KnowledgeBase::class);
}
/**
* 获取文档的上传者
*/
@@ -120,6 +129,7 @@ class Document extends Model
'markdown_content' => $this->getMarkdownContent(),
'type' => $this->type,
'group_id' => $this->group_id,
'knowledge_base_id' => $this->knowledge_base_id,
'uploaded_by' => $this->uploaded_by,
'created_at' => $this->created_at?->timestamp,
];

75
app/Models/Guide.php Normal file
View File

@@ -0,0 +1,75 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
use Spatie\Activitylog\Traits\LogsActivity;
use Spatie\Activitylog\LogOptions;
class Guide extends Model
{
use HasFactory, SoftDeletes, LogsActivity;
protected $fillable = [
'name',
'description',
'category',
'tags',
'status',
'created_by',
'published_at',
];
protected function casts(): array
{
return [
'tags' => 'array',
'published_at' => 'datetime',
];
}
public function pages()
{
return $this->hasMany(GuidePage::class)->orderBy('sort_order');
}
public function trunkPages()
{
return $this->hasMany(GuidePage::class)
->where('parent_id', -1)
->orderBy('sort_order');
}
public function creator()
{
return $this->belongsTo(User::class, 'created_by');
}
public function terminals()
{
return $this->belongsToMany(Terminal::class, 'terminal_guides')
->withPivot('priority')
->withTimestamps()
->orderBy('priority');
}
public function scopePublished($query)
{
return $query->where('status', 'published');
}
public function scopeCategory($query, string $category)
{
return $query->where('category', $category);
}
public function getActivitylogOptions(): LogOptions
{
return LogOptions::defaults()
->logOnly(['name', 'description', 'category', 'status'])
->logOnlyDirty()
->setDescriptionForEvent(fn(string $eventName) => "指引已{$eventName}");
}
}

58
app/Models/GuidePage.php Normal file
View File

@@ -0,0 +1,58 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use SolutionForest\FilamentTree\Concern\ModelTree;
class GuidePage extends Model
{
use ModelTree;
protected $fillable = [
'guide_id',
'page_number',
'title',
'html_url',
'sort_order',
'parent_id',
'options',
'branch_option',
];
protected $casts = [
'options' => 'array',
'parent_id' => 'int',
];
// filament-tree column name mapping
public function determineParentColumnName(): string
{
return 'parent_id';
}
public function determineOrderColumnName(): string
{
return 'sort_order';
}
public function determineTitleColumnName(): string
{
return 'title';
}
public function guide()
{
return $this->belongsTo(Guide::class);
}
public function branchChildren()
{
return $this->hasMany(self::class, 'parent_id')->orderBy('sort_order');
}
public function parentPage()
{
return $this->belongsTo(self::class, 'parent_id');
}
}

View File

@@ -33,4 +33,14 @@ class KnowledgeBase extends Model
->withTimestamps()
->orderBy('priority');
}
/**
* 获取知识库下的文档
*
* @return \Illuminate\Database\Eloquent\Relations\HasMany
*/
public function documents()
{
return $this->hasMany(Document::class);
}
}

View File

@@ -1,46 +0,0 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class SopInteractiveTask extends Model
{
/**
* 可批量赋值的属性
*
* @var array<string>
*/
protected $fillable = [
'sop_step_id',
'task_type',
'task_config',
'validation_rules',
'timeout_seconds',
'is_required',
];
/**
* 属性类型转换
*
* @return array<string, string>
*/
protected function casts(): array
{
return [
'task_config' => 'array',
'validation_rules' => 'array',
'is_required' => 'boolean',
];
}
/**
* 获取任务所属的步骤
*
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo
*/
public function step()
{
return $this->belongsTo(SopStep::class, 'sop_step_id');
}
}

View File

@@ -1,54 +0,0 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class SopStep extends Model
{
/**
* 可批量赋值的属性
*
* @var array<string>
*/
protected $fillable = [
'sop_template_id',
'step_number',
'title',
'content',
'sort_order',
'is_required',
];
/**
* 属性类型转换
*
* @return array<string, string>
*/
protected function casts(): array
{
return [
'is_required' => 'boolean',
];
}
/**
* 获取步骤所属的模板
*
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo
*/
public function template()
{
return $this->belongsTo(SopTemplate::class, 'sop_template_id');
}
/**
* 获取步骤的交互任务列表
*
* @return \Illuminate\Database\Eloquent\Relations\HasMany
*/
public function interactiveTasks()
{
return $this->hasMany(SopInteractiveTask::class);
}
}

View File

@@ -1,90 +0,0 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
use Spatie\Activitylog\Traits\LogsActivity;
use Spatie\Activitylog\LogOptions;
class SopTemplate extends Model
{
use HasFactory, SoftDeletes, LogsActivity;
/**
* 可批量赋值的属性
*
* @var array<string>
*/
protected $fillable = [
'name',
'description',
'category',
'tags',
'version',
'status',
'applicable_departments',
'applicable_positions',
'published_at',
'created_by',
];
/**
* 属性类型转换
*
* @return array<string, string>
*/
protected function casts(): array
{
return [
'tags' => 'array',
'applicable_departments' => 'array',
'applicable_positions' => 'array',
'published_at' => 'datetime',
];
}
/**
* 获取模板的步骤列表
*
* @return \Illuminate\Database\Eloquent\Relations\HasMany
*/
public function steps()
{
return $this->hasMany(SopStep::class)->orderBy('sort_order');
}
/**
* 获取模板的版本历史
*
* @return \Illuminate\Database\Eloquent\Relations\HasMany
*/
public function versions()
{
return $this->hasMany(SopTemplateVersion::class);
}
/**
* 获取模板的创建者
*
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo
*/
public function creator()
{
return $this->belongsTo(User::class, 'created_by');
}
/**
* 配置活动日志选项
*
* @return \Spatie\Activitylog\LogOptions
*/
public function getActivitylogOptions(): LogOptions
{
return LogOptions::defaults()
->logOnly(['name', 'description', 'category', 'status', 'version'])
->logOnlyDirty()
->setDescriptionForEvent(fn(string $eventName) => "SOP模板已{$eventName}");
}
}

View File

@@ -1,62 +0,0 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class SopTemplateVersion extends Model
{
/**
* 表示模型是否应该被打上时间戳
* 注意: 只有created_at字段,没有updated_at
*
* @var bool
*/
public $timestamps = false;
/**
* 可批量赋值的属性
*
* @var array<string>
*/
protected $fillable = [
'sop_template_id',
'version',
'change_log',
'content_snapshot',
'created_by',
];
/**
* 属性类型转换
*
* @return array<string, string>
*/
protected function casts(): array
{
return [
'content_snapshot' => 'array',
'created_at' => 'datetime',
];
}
/**
* 获取版本所属的模板
*
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo
*/
public function template()
{
return $this->belongsTo(SopTemplate::class, 'sop_template_id');
}
/**
* 获取版本的创建者
*
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo
*/
public function creator()
{
return $this->belongsTo(User::class, 'created_by');
}
}

View File

@@ -21,8 +21,11 @@ class Terminal extends Model
'name',
'code',
'ip_address',
'mac_address',
'station_id',
'diagram_url',
'scada_data_url',
'scada_tags_url',
'display_config',
'is_online',
'last_online_at',
@@ -55,6 +58,19 @@ class Terminal extends Model
->orderBy('priority');
}
/**
* 获取终端关联的指引
*
* @return \Illuminate\Database\Eloquent\Relations\BelongsToMany
*/
public function guides()
{
return $this->belongsToMany(Guide::class, 'terminal_guides')
->withPivot('priority')
->withTimestamps()
->orderBy('priority');
}
/**
* 获取终端的提示词配置
*