OneBot: Leantime 改造版源码(BOM/Univer 表格/AI 接管/品牌替换等)
This commit is contained in:
463
app/Domain/Canvas/Repositories/Canvas.php
Normal file
463
app/Domain/Canvas/Repositories/Canvas.php
Normal file
@@ -0,0 +1,463 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* canvas class - DEPRECATED backwards-compatibility adapter.
|
||||
*/
|
||||
|
||||
namespace Leantime\Domain\Canvas\Repositories;
|
||||
|
||||
use Illuminate\Database\ConnectionInterface;
|
||||
use Leantime\Core\Db\DatabaseHelper;
|
||||
use Leantime\Core\Db\Db as DbCore;
|
||||
use Leantime\Core\Language as LanguageCore;
|
||||
use Leantime\Domain\Blueprints\Repositories\Blueprints as BlueprintsRepository;
|
||||
use Leantime\Domain\Tickets\Repositories\Tickets;
|
||||
|
||||
/**
|
||||
* Thin backwards-compatibility shim over the Blueprints repository.
|
||||
*
|
||||
* The canvas system was consolidated into Leantime\Domain\Blueprints. This class
|
||||
* is kept ONLY so plugins (and any code) that still extend or instantiate the old
|
||||
* canvas repository keep working: its data methods now delegate to the Blueprints
|
||||
* repository, deriving the canvas type from the subclass CANVAS_NAME constant.
|
||||
*
|
||||
* @deprecated Use Leantime\Domain\Blueprints\Repositories\Blueprints instead.
|
||||
* Do not build new features on this class.
|
||||
*/
|
||||
class Canvas extends BlueprintsRepository
|
||||
{
|
||||
/**
|
||||
* Constant that must be redefined
|
||||
*/
|
||||
protected const CANVAS_NAME = '??';
|
||||
|
||||
/***
|
||||
* icon - Icon associated with canvas (must be extended)
|
||||
*
|
||||
* @access protected
|
||||
* @var string Fontawesome icone
|
||||
*/
|
||||
protected string $icon = 'fa-x';
|
||||
|
||||
/***
|
||||
* disclaimer - Disclaimer (may be extended)
|
||||
*
|
||||
* @access protected
|
||||
* @var string Disclaimer (including href)
|
||||
*/
|
||||
protected string $disclaimer = '';
|
||||
|
||||
/**
|
||||
* canvasTypes - Canvas elements / boxes (must be extended)
|
||||
*
|
||||
* @acces protected
|
||||
*/
|
||||
protected array $canvasTypes = [
|
||||
// '??_' => [ 'icon' => 'fa-????', 'title' => 'box.??.????' ],
|
||||
];
|
||||
|
||||
/**
|
||||
* statusLabels - Status labels (may be extended)
|
||||
*
|
||||
* @acces protected
|
||||
*/
|
||||
protected array $statusLabels = [
|
||||
'status_draft' => ['icon' => 'fa-circle-question', 'color' => 'blue', 'title' => 'status.draft', 'dropdown' => 'info', 'active' => true],
|
||||
'status_review' => ['icon' => 'fa-circle-exclamation', 'color' => 'orange', 'title' => 'status.review', 'dropdown' => 'warning', 'active' => true],
|
||||
'status_valid' => ['icon' => 'fa-circle-check', 'color' => 'green', 'title' => 'status.valid', 'dropdown' => 'success', 'active' => true],
|
||||
'status_hold' => ['icon' => 'fa-circle-h', 'color' => 'red', 'title' => 'status.hold', 'dropdown' => 'danger', 'active' => true],
|
||||
'status_invalid' => ['icon' => 'fa-circle-xmark', 'color' => 'red', 'title' => 'status.invalid', 'dropdown' => 'danger', 'active' => true],
|
||||
];
|
||||
|
||||
/**
|
||||
* relatesLabels - Relates to label (same structure as `statusLabels`)
|
||||
*
|
||||
* @acces public
|
||||
*/
|
||||
protected array $relatesLabels = [
|
||||
'relates_none' => ['icon' => 'fa-border-none', 'color' => 'grey', 'title' => 'relates.none', 'dropdown' => 'default', 'active' => true],
|
||||
'relates_customers' => ['icon' => 'fa-users', 'color' => 'green', 'title' => 'relates.customers', 'dropdown' => 'success', 'active' => true],
|
||||
'relates_offerings' => ['icon' => 'fa-barcode', 'color' => 'red', 'title' => 'relates.offerings', 'dropdown' => 'danger', 'active' => true],
|
||||
'relates_capabilities' => ['icon' => 'fa-pen-ruler', 'color' => 'blue', 'title' => 'relates.capabilities', 'dropdown' => 'info', 'active' => true],
|
||||
'relates_financials' => ['icon' => 'fa-money-bill', 'color' => 'yellow', 'title' => 'relates.financials', 'dropdown' => 'warning', 'active' => true],
|
||||
'relates_markets' => ['icon' => 'fa-shop', 'color' => 'brown', 'title' => 'relates.markets', 'dropdown' => 'default', 'active' => true],
|
||||
'relates_environment' => ['icon' => 'fa-tree', 'color' => 'darkgreen', 'title' => 'relates.environment', 'dropdown' => 'default', 'active' => true],
|
||||
'relates_firm' => ['icon' => 'fa-building', 'color' => 'darkblue', 'title' => 'relates.firm', 'dropdown' => 'info', 'active' => true],
|
||||
];
|
||||
|
||||
/**
|
||||
* dataLabels - Data labels (may be extended)
|
||||
*
|
||||
* @acces protected
|
||||
*/
|
||||
protected array $dataLabels = [
|
||||
1 => ['title' => 'label.assumptions', 'field' => 'assumptions', 'active' => true],
|
||||
2 => ['title' => 'label.data', 'field' => 'data', 'active' => true],
|
||||
3 => ['title' => 'label.conclusion', 'field' => 'conclusion', 'active' => true],
|
||||
];
|
||||
|
||||
public ?object $result = null;
|
||||
|
||||
public ?object $tickets = null;
|
||||
|
||||
protected ?DbCore $db = null;
|
||||
|
||||
protected ConnectionInterface $connection;
|
||||
|
||||
protected DatabaseHelper $dbHelper;
|
||||
|
||||
private LanguageCore $language;
|
||||
|
||||
/**
|
||||
* __construct - get db connection and initialise the underlying Blueprints repository
|
||||
*/
|
||||
public function __construct(
|
||||
DbCore $db,
|
||||
LanguageCore $language,
|
||||
Tickets $ticketRepo,
|
||||
DatabaseHelper $dbHelper
|
||||
) {
|
||||
// Initialise the Blueprints parent so the delegated methods have a connection.
|
||||
parent::__construct($db, $ticketRepo, $dbHelper);
|
||||
|
||||
// Keep local copies for the config accessors and goal-specific queries below.
|
||||
$this->db = $db;
|
||||
$this->connection = $db->getConnection();
|
||||
$this->language = $language;
|
||||
$this->dbHelper = $dbHelper;
|
||||
}
|
||||
|
||||
/**
|
||||
* getIcon() - Retrieve canvas icon
|
||||
*
|
||||
* @return string Canvas icon
|
||||
*/
|
||||
public function getIcon(): string
|
||||
{
|
||||
return $this->icon;
|
||||
}
|
||||
|
||||
/**
|
||||
* getDisclaimer() - Retrieve disclaimer
|
||||
*
|
||||
* @return string Canvas disclaimer
|
||||
*/
|
||||
public function getDisclaimer(): string
|
||||
{
|
||||
if (empty($this->disclaimer)) {
|
||||
return '';
|
||||
}
|
||||
|
||||
return $this->language->__($this->disclaimer);
|
||||
}
|
||||
|
||||
/**
|
||||
* getCanvasTypes() - Retrieve translated canvaas items
|
||||
*
|
||||
* @return array Array of data
|
||||
*/
|
||||
public function getCanvasTypes(): array
|
||||
{
|
||||
$canvasTypes = $this->canvasTypes;
|
||||
foreach ($canvasTypes as $key => $data) {
|
||||
if (isset($data['title'])) {
|
||||
$canvasTypes[$key]['title'] = $this->language->__($data['title']);
|
||||
}
|
||||
}
|
||||
|
||||
return $canvasTypes;
|
||||
}
|
||||
|
||||
/**
|
||||
* getStatusLabels() - Retrieve translated status labels
|
||||
*
|
||||
* @return array Array of data
|
||||
*/
|
||||
public function getStatusLabels(): array
|
||||
{
|
||||
$statusLabels = $this->statusLabels;
|
||||
|
||||
foreach ($statusLabels as $key => $data) {
|
||||
if (isset($data['title'])) {
|
||||
$statusLabels[$key]['title'] = $this->language->__($data['title']);
|
||||
}
|
||||
}
|
||||
|
||||
return $statusLabels;
|
||||
}
|
||||
|
||||
/**
|
||||
* getRelatesLabels() - Retrieve translated relates labels
|
||||
*
|
||||
* @return array Array of data
|
||||
*/
|
||||
public function getRelatesLabels(): array
|
||||
{
|
||||
$relatesLabels = $this->relatesLabels;
|
||||
foreach ($relatesLabels as $key => $data) {
|
||||
if (isset($data['title'])) {
|
||||
$relatesLabels[$key]['title'] = $this->language->__($data['title']);
|
||||
}
|
||||
}
|
||||
|
||||
return $relatesLabels;
|
||||
}
|
||||
|
||||
/**
|
||||
* getDataLabels() - Retrieve translated data labels
|
||||
*
|
||||
* @return array Array of data
|
||||
*/
|
||||
public function getDataLabels(): array
|
||||
{
|
||||
$dataLabels = $this->dataLabels;
|
||||
foreach ($dataLabels as $key => $data) {
|
||||
if (isset($data['title'])) {
|
||||
$dataLabels[$key]['title'] = $this->language->__($data['title']);
|
||||
}
|
||||
}
|
||||
|
||||
return $dataLabels;
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated delegate to Blueprints repository
|
||||
*/
|
||||
public function getAllCanvas($projectId, $type = null): false|array
|
||||
{
|
||||
$canvasType = ($type === null || $type === '') ? static::CANVAS_NAME.'canvas' : $type;
|
||||
|
||||
return parent::getAllCanvas((int) $projectId, $canvasType);
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated delegate to Blueprints repository
|
||||
*/
|
||||
public function getSingleCanvas($canvasId, $canvasType = null): false|array
|
||||
{
|
||||
return parent::getSingleCanvas((int) $canvasId, $canvasType ?: static::CANVAS_NAME.'canvas');
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated delegate to Blueprints repository
|
||||
*/
|
||||
public function addCanvas($values, $type = null): false|string
|
||||
{
|
||||
$canvasType = ($type === null || $type === '') ? static::CANVAS_NAME.'canvas' : $type;
|
||||
|
||||
return parent::addCanvas($values, $canvasType);
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated delegate to Blueprints repository
|
||||
*/
|
||||
public function getCanvasItemsById($id, $commentModule = null): false|array
|
||||
{
|
||||
return parent::getCanvasItemsById((int) $id, $commentModule ?: static::CANVAS_NAME.'canvasitem');
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated delegate to Blueprints repository
|
||||
*/
|
||||
public function getNumberOfCanvasItems($projectId = null, $canvasType = null): mixed
|
||||
{
|
||||
return parent::getNumberOfCanvasItems($projectId !== null ? (int) $projectId : null, $canvasType ?: static::CANVAS_NAME.'canvas');
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated delegate to Blueprints repository
|
||||
*/
|
||||
public function getNumberOfBoards($projectId = null, $canvasType = null): mixed
|
||||
{
|
||||
return parent::getNumberOfBoards($projectId !== null ? (int) $projectId : null, $canvasType ?: static::CANVAS_NAME.'canvas');
|
||||
}
|
||||
|
||||
/**
|
||||
* existCanvas - return if a canvas exists with a given title in the specified project
|
||||
*
|
||||
* @param int $projectId Project identifier
|
||||
* @param string $canvasTitle Canvas title
|
||||
* @return bool True if canvas exists
|
||||
*
|
||||
* @deprecated delegate to Blueprints repository
|
||||
*/
|
||||
public function existCanvas(int $projectId, string $canvasTitle, $canvasType = null): bool
|
||||
{
|
||||
return parent::existCanvas($projectId, $canvasTitle, $canvasType ?: static::CANVAS_NAME.'canvas');
|
||||
}
|
||||
|
||||
/***
|
||||
* copyCanvas - create a copy of an existing canvas
|
||||
*
|
||||
* @deprecated delegate to Blueprints repository
|
||||
*/
|
||||
public function copyCanvas(int $projectId, int $canvasId, int $authorId, string $canvasTitle, $canvasType = null): int
|
||||
{
|
||||
return parent::copyCanvas($projectId, $canvasId, $authorId, $canvasTitle, $canvasType ?: static::CANVAS_NAME.'canvas');
|
||||
}
|
||||
|
||||
/**
|
||||
* getCanvasItemsByKPI - goal-specific KPI hierarchy query (not part of Blueprints).
|
||||
*/
|
||||
public function getCanvasItemsByKPI($id): false|array
|
||||
{
|
||||
$results = $this->connection->table('zp_canvas_items')
|
||||
->select([
|
||||
'zp_canvas_items.id',
|
||||
'zp_canvas_items.title',
|
||||
'zp_canvas_items.kpi',
|
||||
'zp_canvas_items.startDate',
|
||||
'zp_canvas_items.endDate',
|
||||
'zp_canvas_items.setting',
|
||||
'zp_canvas_items.metricType',
|
||||
'zp_canvas_items.startValue',
|
||||
'zp_canvas_items.currentValue',
|
||||
'zp_canvas_items.endValue',
|
||||
'zp_canvas_items.canvasId',
|
||||
'zp_canvas.title as boardTitle',
|
||||
'zp_canvas.projectId as projectId',
|
||||
'zp_projects.name as projectName',
|
||||
'childrenLvl1.id as childId',
|
||||
'childrenLvl1.title as childTitle',
|
||||
'childrenLvl1.kpi as childKpi',
|
||||
'childrenLvl1.startDate as childStartDate',
|
||||
'childrenLvl1.endDate as childEndDate',
|
||||
'childrenLvl1.setting as childSetting',
|
||||
'childrenLvl1.metricType as childMetricType',
|
||||
'childrenLvl1.startValue as childStartValue',
|
||||
'childrenLvl1.currentValue as childCurrentValue',
|
||||
'childrenLvl1.endValue as childEndValue',
|
||||
'childrenLvl1.canvasId as childCanvasId',
|
||||
'childrenLvl1Board.title as childBoardTitle',
|
||||
'childrenLvl1Project.name as childProjectName',
|
||||
])
|
||||
->leftJoin('zp_canvas', 'zp_canvas_items.canvasId', '=', 'zp_canvas.id')
|
||||
->leftJoin('zp_projects', 'zp_canvas.projectId', '=', 'zp_projects.id')
|
||||
->leftJoin('zp_canvas_items as childrenLvl1', 'childrenLvl1.kpi', '=', 'zp_canvas_items.id')
|
||||
->leftJoin('zp_canvas as childrenLvl1Board', 'childrenLvl1.canvasId', '=', 'childrenLvl1Board.id')
|
||||
->leftJoin('zp_projects as childrenLvl1Project', 'childrenLvl1Board.projectId', '=', 'childrenLvl1Project.id')
|
||||
->where('zp_canvas_items.box', 'goal')
|
||||
->where('zp_canvas_items.kpi', $id)
|
||||
->get();
|
||||
|
||||
return array_map(fn ($item) => (array) $item, $results->toArray());
|
||||
}
|
||||
|
||||
/**
|
||||
* getAllAvailableParents - goal-specific parent lookup (not part of Blueprints).
|
||||
*/
|
||||
public function getAllAvailableParents($projectId): false|array
|
||||
{
|
||||
$results = $this->connection->table('zp_canvas_items')
|
||||
->select([
|
||||
'zp_canvas_items.id',
|
||||
'zp_canvas_items.description',
|
||||
'zp_canvas_items.title',
|
||||
'zp_canvas_items.assumptions',
|
||||
'zp_canvas_items.data',
|
||||
'zp_canvas_items.conclusion',
|
||||
'zp_canvas_items.box',
|
||||
'zp_canvas_items.author',
|
||||
'zp_canvas_items.created',
|
||||
'zp_canvas_items.modified',
|
||||
'zp_canvas_items.canvasId',
|
||||
'zp_canvas_items.sortindex',
|
||||
'zp_canvas_items.status',
|
||||
'zp_canvas_items.relates',
|
||||
'zp_canvas_items.milestoneId',
|
||||
'zp_canvas_items.kpi',
|
||||
'zp_canvas_items.data1',
|
||||
'zp_canvas_items.data2',
|
||||
'zp_canvas_items.data3',
|
||||
'zp_canvas_items.data4',
|
||||
'zp_canvas_items.data5',
|
||||
'zp_canvas_items.startDate',
|
||||
'zp_canvas_items.endDate',
|
||||
'zp_canvas_items.setting',
|
||||
'zp_canvas_items.metricType',
|
||||
'zp_canvas_items.startValue',
|
||||
'zp_canvas_items.currentValue',
|
||||
'zp_canvas_items.endValue',
|
||||
'zp_canvas_items.impact',
|
||||
'zp_canvas_items.effort',
|
||||
'zp_canvas_items.probability',
|
||||
'zp_canvas_items.action',
|
||||
'zp_canvas_items.assignedTo',
|
||||
'zp_canvas_items.parent',
|
||||
'zp_canvas_items.tags',
|
||||
'board.title as boardTitle',
|
||||
'parentKPI.description as parentKPIDescription',
|
||||
'parentGoal.description as parentGoalDescription',
|
||||
't1.firstname as authorFirstname',
|
||||
't1.lastname as authorLastname',
|
||||
'milestone.headline as milestoneHeadline',
|
||||
'milestone.editTo as milestoneEditTo',
|
||||
])
|
||||
->leftJoin('zp_canvas as board', 'board.id', '=', 'zp_canvas_items.canvasId')
|
||||
->leftJoin('zp_canvas_items as parentKPI', 'zp_canvas_items.kpi', '=', 'parentKPI.id')
|
||||
->leftJoin('zp_canvas_items as parentGoal', 'zp_canvas_items.parent', '=', 'parentGoal.id')
|
||||
->leftJoin('zp_tickets as milestone', function ($join) {
|
||||
$join->on('zp_canvas_items.milestoneId', '=', $this->connection->raw($this->dbHelper->castAs($this->dbHelper->wrapColumn('milestone.id'), 'text')));
|
||||
})
|
||||
->leftJoin('zp_user as t1', 'zp_canvas_items.author', '=', 't1.id')
|
||||
->where('board.projectId', $projectId)
|
||||
->groupBy(['id', 'board.id', 'board.title', 'parentKPI.description', 'parentGoal.description', 't1.firstname', 't1.lastname', 'milestone.headline', 'milestone.editTo'])
|
||||
->orderBy('board.id')
|
||||
->get();
|
||||
|
||||
return array_map(fn ($item) => (array) $item, $results->toArray());
|
||||
}
|
||||
|
||||
/**
|
||||
* getAllAvailableKPIs - goal-specific KPI lookup across parent projects (not part of Blueprints).
|
||||
*/
|
||||
public function getAllAvailableKPIs($projectId): false|array
|
||||
{
|
||||
// First, get parent project IDs (cross-database compatible approach)
|
||||
$parentProjectIds = [];
|
||||
|
||||
$parentProject = $this->connection->table('zp_projects')
|
||||
->select('parent')
|
||||
->where('id', $projectId)
|
||||
->first();
|
||||
|
||||
if ($parentProject && $parentProject->parent) {
|
||||
$parentProjectIds[] = $parentProject->parent;
|
||||
|
||||
// Check for grandparent
|
||||
$grandparent = $this->connection->table('zp_projects')
|
||||
->select('parent')
|
||||
->where('id', $parentProject->parent)
|
||||
->first();
|
||||
|
||||
if ($grandparent && $grandparent->parent) {
|
||||
$parentProjectIds[] = $grandparent->parent;
|
||||
}
|
||||
}
|
||||
|
||||
// If no parent projects found, return empty array
|
||||
if (empty($parentProjectIds)) {
|
||||
return [];
|
||||
}
|
||||
|
||||
// Now query canvas items from parent projects
|
||||
$results = $this->connection->table('zp_canvas_items')
|
||||
->select([
|
||||
'zp_canvas_items.id',
|
||||
'zp_canvas_items.description',
|
||||
'project.name as projectName',
|
||||
'zp_canvas.title as boardTitle',
|
||||
])
|
||||
->leftJoin('zp_canvas', 'zp_canvas.id', '=', 'zp_canvas_items.canvasId')
|
||||
->leftJoin('zp_projects as project', 'zp_canvas.projectId', '=', 'project.id')
|
||||
->whereIn('zp_canvas.projectId', $parentProjectIds)
|
||||
->where(function ($query) {
|
||||
$query->where('zp_canvas_items.setting', 'linkAndReport')
|
||||
->orWhere('zp_canvas_items.setting', 'linkonly');
|
||||
})
|
||||
->orderBy('zp_canvas.id')
|
||||
->get();
|
||||
|
||||
return array_map(fn ($item) => (array) $item, $results->toArray());
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user