refactor: kb & station & terminal
This commit is contained in:
@@ -2,7 +2,6 @@
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||
@@ -24,25 +23,14 @@ class Document extends Model
|
||||
'file_name',
|
||||
'file_size',
|
||||
'mime_type',
|
||||
'type',
|
||||
'group_id',
|
||||
'uploaded_by',
|
||||
'description',
|
||||
'markdown_path',
|
||||
'markdown_preview',
|
||||
'conversion_status',
|
||||
'conversion_error',
|
||||
'knowledge_base_id',
|
||||
];
|
||||
|
||||
/**
|
||||
* 获取文档所属的分组
|
||||
*/
|
||||
public function group(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(Group::class);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取文档所属的知识库
|
||||
*/
|
||||
@@ -67,57 +55,9 @@ class Document extends Model
|
||||
return $this->hasMany(DownloadLog::class);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询作用域:获取用户可访问的文档
|
||||
* 包含全局文档和用户分组的专用文档,排除其他分组的专用文档
|
||||
*
|
||||
* @param Builder $query
|
||||
* @param User $user
|
||||
* @return Builder
|
||||
*/
|
||||
public function scopeAccessibleBy(Builder $query, User $user): Builder
|
||||
{
|
||||
// 获取用户所属的所有分组 ID
|
||||
$userGroupIds = $user->groups()->pluck('groups.id')->toArray();
|
||||
|
||||
return $query->where(function (Builder $query) use ($userGroupIds) {
|
||||
// 包含所有全局文档
|
||||
$query->where('type', 'global')
|
||||
// 或者包含用户所属分组的专用文档
|
||||
->orWhere(function (Builder $query) use ($userGroupIds) {
|
||||
$query->where('type', 'dedicated')
|
||||
->whereIn('group_id', $userGroupIds);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询作用域:仅获取全局文档
|
||||
*
|
||||
* @param Builder $query
|
||||
* @return Builder
|
||||
*/
|
||||
public function scopeGlobal(Builder $query): Builder
|
||||
{
|
||||
return $query->where('type', 'global');
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询作用域:仅获取专用文档
|
||||
*
|
||||
* @param Builder $query
|
||||
* @return Builder
|
||||
*/
|
||||
public function scopeDedicated(Builder $query): Builder
|
||||
{
|
||||
return $query->where('type', 'dedicated');
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取可搜索的数组数据
|
||||
* 用于 Meilisearch 索引
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function toSearchableArray(): array
|
||||
{
|
||||
@@ -127,8 +67,6 @@ class Document extends Model
|
||||
'file_name' => $this->file_name,
|
||||
'description' => $this->description,
|
||||
'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,
|
||||
@@ -138,8 +76,6 @@ class Document extends Model
|
||||
/**
|
||||
* 判断文档是否应该被索引
|
||||
* 只有转换完成的文档才会被索引
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function shouldBeSearchable(): bool
|
||||
{
|
||||
@@ -149,8 +85,6 @@ class Document extends Model
|
||||
/**
|
||||
* 获取完整的 Markdown 内容
|
||||
* 从文件系统读取 Markdown 文件
|
||||
*
|
||||
* @return string|null
|
||||
*/
|
||||
public function getMarkdownContent(): ?string
|
||||
{
|
||||
@@ -163,7 +97,6 @@ class Document extends Model
|
||||
return Storage::disk('markdown')->get($this->markdown_path);
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
// 记录错误但不抛出异常
|
||||
\Log::warning('Failed to read markdown content', [
|
||||
'document_id' => $this->id,
|
||||
'markdown_path' => $this->markdown_path,
|
||||
@@ -176,8 +109,6 @@ class Document extends Model
|
||||
|
||||
/**
|
||||
* 检查文档是否已转换为 Markdown
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function hasMarkdown(): bool
|
||||
{
|
||||
|
||||
@@ -2,13 +2,11 @@
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||
|
||||
class DownloadLog extends Model
|
||||
{
|
||||
use HasFactory;
|
||||
/**
|
||||
* 表示模型不使用 created_at 和 updated_at 时间戳
|
||||
* 因为我们使用自定义的 downloaded_at 字段
|
||||
|
||||
@@ -1,53 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
|
||||
use Illuminate\Database\Eloquent\Relations\HasMany;
|
||||
|
||||
class Group extends Model
|
||||
{
|
||||
use HasFactory;
|
||||
/**
|
||||
* 可批量赋值的属性
|
||||
*
|
||||
* @var array<int, string>
|
||||
*/
|
||||
protected $fillable = [
|
||||
'name',
|
||||
'description',
|
||||
];
|
||||
|
||||
/**
|
||||
* 模型的启动方法
|
||||
* 注册模型事件监听器
|
||||
*/
|
||||
protected static function boot()
|
||||
{
|
||||
parent::boot();
|
||||
|
||||
// 监听分组删除事件
|
||||
static::deleting(function (Group $group) {
|
||||
// 将该分组的所有专用文档的 group_id 设置为 null(孤立状态)
|
||||
$group->documents()->update(['group_id' => null]);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取分组的所有用户
|
||||
*/
|
||||
public function users(): BelongsToMany
|
||||
{
|
||||
return $this->belongsToMany(User::class);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取分组的所有文档
|
||||
*/
|
||||
public function documents(): HasMany
|
||||
{
|
||||
return $this->hasMany(Document::class);
|
||||
}
|
||||
}
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||
@@ -47,12 +48,9 @@ class Guide extends Model
|
||||
return $this->belongsTo(User::class, 'created_by');
|
||||
}
|
||||
|
||||
public function terminals()
|
||||
public function stations()
|
||||
{
|
||||
return $this->belongsToMany(Terminal::class, 'terminal_guides')
|
||||
->withPivot('priority')
|
||||
->withTimestamps()
|
||||
->orderBy('priority');
|
||||
return $this->belongsToMany(Station::class);
|
||||
}
|
||||
|
||||
public function scopePublished($query)
|
||||
@@ -65,6 +63,23 @@ class Guide extends Model
|
||||
return $query->where('category', $category);
|
||||
}
|
||||
|
||||
/**
|
||||
* 按用户线站过滤:全局 Guide(无线站关联)+ 用户线站关联的 Guide
|
||||
*/
|
||||
public function scopeAccessibleBy(Builder $query, User $user): Builder
|
||||
{
|
||||
if (!$user->hasStationRestriction()) {
|
||||
return $query;
|
||||
}
|
||||
|
||||
$stationIds = $user->getAccessibleStationIds();
|
||||
|
||||
return $query->where(function (Builder $q) use ($stationIds) {
|
||||
$q->whereDoesntHave('stations')
|
||||
->orWhereHas('stations', fn ($sq) => $sq->whereIn('stations.id', $stationIds));
|
||||
});
|
||||
}
|
||||
|
||||
public function getActivitylogOptions(): LogOptions
|
||||
{
|
||||
return LogOptions::defaults()
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||
@@ -30,4 +31,31 @@ class KnowledgeBase extends Model
|
||||
{
|
||||
return $this->hasMany(Document::class);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取知识库关联的线站
|
||||
*
|
||||
* @return \Illuminate\Database\Eloquent\Relations\BelongsToMany
|
||||
*/
|
||||
public function stations()
|
||||
{
|
||||
return $this->belongsToMany(Station::class);
|
||||
}
|
||||
|
||||
/**
|
||||
* 按用户线站过滤:全局 KB(无线站关联)+ 用户线站关联的 KB
|
||||
*/
|
||||
public function scopeAccessibleBy(Builder $query, User $user): Builder
|
||||
{
|
||||
if (!$user->hasStationRestriction()) {
|
||||
return $query;
|
||||
}
|
||||
|
||||
$stationIds = $user->getAccessibleStationIds();
|
||||
|
||||
return $query->where(function (Builder $q) use ($stationIds) {
|
||||
$q->whereDoesntHave('stations')
|
||||
->orWhereHas('stations', fn ($sq) => $sq->whereIn('stations.id', $stationIds));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
48
app/Models/Station.php
Normal file
48
app/Models/Station.php
Normal file
@@ -0,0 +1,48 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
|
||||
use Illuminate\Database\Eloquent\Relations\HasMany;
|
||||
|
||||
class Station extends Model
|
||||
{
|
||||
use HasFactory;
|
||||
|
||||
protected $fillable = [
|
||||
'name',
|
||||
'description',
|
||||
];
|
||||
|
||||
protected static function boot()
|
||||
{
|
||||
parent::boot();
|
||||
|
||||
static::deleting(function (Station $station) {
|
||||
$station->terminals()->update(['station_id' => null]);
|
||||
});
|
||||
}
|
||||
|
||||
public function terminals(): HasMany
|
||||
{
|
||||
return $this->hasMany(Terminal::class);
|
||||
}
|
||||
|
||||
public function knowledgeBases(): BelongsToMany
|
||||
{
|
||||
return $this->belongsToMany(KnowledgeBase::class);
|
||||
}
|
||||
|
||||
public function users(): BelongsToMany
|
||||
{
|
||||
return $this->belongsToMany(User::class);
|
||||
}
|
||||
|
||||
public function guides(): BelongsToMany
|
||||
{
|
||||
return $this->belongsToMany(Guide::class);
|
||||
}
|
||||
}
|
||||
@@ -47,16 +47,13 @@ class Terminal extends Model
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取终端关联的指引
|
||||
* 获取终端所属的线站
|
||||
*
|
||||
* @return \Illuminate\Database\Eloquent\Relations\BelongsToMany
|
||||
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo
|
||||
*/
|
||||
public function guides()
|
||||
public function station()
|
||||
{
|
||||
return $this->belongsToMany(Guide::class, 'terminal_guides')
|
||||
->withPivot('priority')
|
||||
->withTimestamps()
|
||||
->orderBy('priority');
|
||||
return $this->belongsTo(Station::class);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -2,14 +2,13 @@
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Spatie\Activitylog\Traits\LogsActivity;
|
||||
use Spatie\Activitylog\LogOptions;
|
||||
|
||||
class TerminalPrompt extends Model
|
||||
{
|
||||
use HasFactory, LogsActivity;
|
||||
use LogsActivity;
|
||||
/**
|
||||
* 可批量赋值的属性
|
||||
*
|
||||
|
||||
@@ -50,11 +50,28 @@ class User extends Authenticatable
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取用户所属的所有分组
|
||||
* 获取用户关联的线站
|
||||
*/
|
||||
public function groups(): BelongsToMany
|
||||
public function stations(): BelongsToMany
|
||||
{
|
||||
return $this->belongsToMany(Group::class);
|
||||
return $this->belongsToMany(Station::class);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取用户可访问的线站 IDs
|
||||
* 空数组表示无限制(管理员)
|
||||
*/
|
||||
public function getAccessibleStationIds(): array
|
||||
{
|
||||
return $this->stations()->pluck('stations.id')->toArray();
|
||||
}
|
||||
|
||||
/**
|
||||
* 用户是否受线站限制
|
||||
*/
|
||||
public function hasStationRestriction(): bool
|
||||
{
|
||||
return $this->stations()->exists();
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user