mirror of
https://github.com/cedar2025/Xboard.git
synced 2025-02-15 12:58:14 -05:00
feat: add one-click update feature to admin panel
This commit is contained in:
parent
1b728fffc7
commit
39456923d3
28
app/Http/Controllers/V2/Admin/UpdateController.php
Normal file
28
app/Http/Controllers/V2/Admin/UpdateController.php
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Controllers\V2\Admin;
|
||||||
|
|
||||||
|
use App\Http\Controllers\Controller;
|
||||||
|
use App\Services\UpdateService;
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
|
||||||
|
class UpdateController extends Controller
|
||||||
|
{
|
||||||
|
protected $updateService;
|
||||||
|
|
||||||
|
public function __construct(UpdateService $updateService)
|
||||||
|
{
|
||||||
|
$this->updateService = $updateService;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function checkUpdate()
|
||||||
|
{
|
||||||
|
return $this->success($this->updateService->checkForUpdates());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function executeUpdate()
|
||||||
|
{
|
||||||
|
$result = $this->updateService->executeUpdate();
|
||||||
|
return $result['success'] ? $this->success($result) : $this->fail([500, $result['message']]);
|
||||||
|
}
|
||||||
|
}
|
@ -16,6 +16,7 @@ use App\Http\Controllers\V2\Admin\KnowledgeController;
|
|||||||
use App\Http\Controllers\V2\Admin\PaymentController;
|
use App\Http\Controllers\V2\Admin\PaymentController;
|
||||||
use App\Http\Controllers\V2\Admin\SystemController;
|
use App\Http\Controllers\V2\Admin\SystemController;
|
||||||
use App\Http\Controllers\V2\Admin\ThemeController;
|
use App\Http\Controllers\V2\Admin\ThemeController;
|
||||||
|
use App\Http\Controllers\V2\Admin\UpdateController;
|
||||||
use Illuminate\Contracts\Routing\Registrar;
|
use Illuminate\Contracts\Routing\Registrar;
|
||||||
use Illuminate\Support\Facades\Route;
|
use Illuminate\Support\Facades\Route;
|
||||||
|
|
||||||
@ -194,6 +195,14 @@ class AdminRoute
|
|||||||
$router->get('/getSystemLog', [SystemController::class, 'getSystemLog']);
|
$router->get('/getSystemLog', [SystemController::class, 'getSystemLog']);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Update
|
||||||
|
$router->group([
|
||||||
|
'prefix' => 'update'
|
||||||
|
], function ($router) {
|
||||||
|
$router->get('/check', [UpdateController::class, 'checkUpdate']);
|
||||||
|
$router->post('/execute', [UpdateController::class, 'executeUpdate']);
|
||||||
|
});
|
||||||
|
|
||||||
// Theme
|
// Theme
|
||||||
$router->group([
|
$router->group([
|
||||||
'prefix' => 'theme'
|
'prefix' => 'theme'
|
||||||
|
19
app/Providers/OctaneVersionProvider.php
Normal file
19
app/Providers/OctaneVersionProvider.php
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Providers;
|
||||||
|
|
||||||
|
use App\Services\UpdateService;
|
||||||
|
use Illuminate\Support\ServiceProvider;
|
||||||
|
use Laravel\Octane\Events\WorkerStarting;
|
||||||
|
|
||||||
|
class OctaneVersionProvider extends ServiceProvider
|
||||||
|
{
|
||||||
|
public function boot(): void
|
||||||
|
{
|
||||||
|
if ($this->app->bound('octane')) {
|
||||||
|
$this->app['events']->listen(WorkerStarting::class, function () {
|
||||||
|
app(UpdateService::class)->updateVersionCache();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
439
app/Services/UpdateService.php
Normal file
439
app/Services/UpdateService.php
Normal file
@ -0,0 +1,439 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Services;
|
||||||
|
|
||||||
|
use App\Utils\CacheKey;
|
||||||
|
use Illuminate\Support\Facades\Cache;
|
||||||
|
use Illuminate\Support\Facades\Http;
|
||||||
|
use Illuminate\Support\Facades\Log;
|
||||||
|
use Illuminate\Support\Facades\Process;
|
||||||
|
use Illuminate\Support\Facades\File;
|
||||||
|
|
||||||
|
class UpdateService
|
||||||
|
{
|
||||||
|
const UPDATE_CHECK_INTERVAL = 86400; // 24 hours
|
||||||
|
const GITHUB_API_URL = 'https://api.github.com/repos/cedar2025/xboard/commits';
|
||||||
|
const CACHE_UPDATE_INFO = 'UPDATE_INFO';
|
||||||
|
const CACHE_LAST_CHECK = 'LAST_UPDATE_CHECK';
|
||||||
|
const CACHE_UPDATE_LOCK = 'UPDATE_LOCK';
|
||||||
|
const CACHE_VERSION = 'CURRENT_VERSION';
|
||||||
|
const CACHE_VERSION_DATE = 'CURRENT_VERSION_DATE';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get current version from cache or generate new one
|
||||||
|
*/
|
||||||
|
public function getCurrentVersion(): string
|
||||||
|
{
|
||||||
|
$date = Cache::get(self::CACHE_VERSION_DATE, date('Ymd'));
|
||||||
|
$hash = Cache::get(self::CACHE_VERSION, $this->getCurrentCommit());
|
||||||
|
return $date . '-' . $hash;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update version cache
|
||||||
|
*/
|
||||||
|
public function updateVersionCache(): void
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
$result = Process::run('git log -1 --format=%cd:%H --date=format:%Y%m%d');
|
||||||
|
if ($result->successful()) {
|
||||||
|
list($date, $hash) = explode(':', trim($result->output()));
|
||||||
|
Cache::forever(self::CACHE_VERSION_DATE, $date);
|
||||||
|
Cache::forever(self::CACHE_VERSION, substr($hash, 0, 7));
|
||||||
|
Log::info('Version cache updated: ' . $date . '-' . substr($hash, 0, 7));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
Log::error('Failed to get version with date: ' . $e->getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fallback
|
||||||
|
Cache::forever(self::CACHE_VERSION_DATE, date('Ymd'));
|
||||||
|
Cache::forever(self::CACHE_VERSION, $this->getCurrentCommit());
|
||||||
|
Log::info('Version cache updated (fallback): ' . date('Ymd') . '-' . $this->getCurrentCommit());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function checkForUpdates(): array
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
// Get current version commit
|
||||||
|
$currentCommit = $this->getCurrentCommit();
|
||||||
|
if ($currentCommit === 'unknown') {
|
||||||
|
// If unable to get current commit, try to get the first commit
|
||||||
|
$currentCommit = $this->getFirstCommit();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get local git logs
|
||||||
|
$localLogs = $this->getLocalGitLogs();
|
||||||
|
if (empty($localLogs)) {
|
||||||
|
Log::error('Failed to get local git logs');
|
||||||
|
return $this->getCachedUpdateInfo();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get remote latest commits
|
||||||
|
$response = Http::withHeaders([
|
||||||
|
'Accept' => 'application/vnd.github.v3+json',
|
||||||
|
'User-Agent' => 'XBoard-Update-Checker'
|
||||||
|
])->get(self::GITHUB_API_URL . '?sha=master&per_page=50');
|
||||||
|
|
||||||
|
if ($response->successful()) {
|
||||||
|
$commits = $response->json();
|
||||||
|
$latestCommit = $this->formatCommitHash($commits[0]['sha']);
|
||||||
|
|
||||||
|
// Find current version position in commit history
|
||||||
|
$currentIndex = -1;
|
||||||
|
$updateLogs = [];
|
||||||
|
$isLocalNewer = false;
|
||||||
|
|
||||||
|
// Check if local is newer than remote
|
||||||
|
foreach ($localLogs as $localCommit) {
|
||||||
|
$localHash = $this->formatCommitHash($localCommit['hash']);
|
||||||
|
if ($localHash === $latestCommit) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
// If local commit not in remote, local version is newer
|
||||||
|
$isLocalNewer = true;
|
||||||
|
$updateLogs[] = [
|
||||||
|
'version' => $localHash,
|
||||||
|
'message' => $localCommit['message'],
|
||||||
|
'author' => $localCommit['author'],
|
||||||
|
'date' => $localCommit['date'],
|
||||||
|
'is_local' => true
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$isLocalNewer) {
|
||||||
|
// If local is not newer, check remote updates
|
||||||
|
foreach ($commits as $index => $commit) {
|
||||||
|
$shortSha = $this->formatCommitHash($commit['sha']);
|
||||||
|
if ($shortSha === $currentCommit) {
|
||||||
|
$currentIndex = $index;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
// Collect update logs
|
||||||
|
$updateLogs[] = [
|
||||||
|
'version' => $shortSha,
|
||||||
|
'message' => $commit['commit']['message'],
|
||||||
|
'author' => $commit['commit']['author']['name'],
|
||||||
|
'date' => $commit['commit']['author']['date'],
|
||||||
|
'is_local' => false
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$hasUpdate = !$isLocalNewer && $currentIndex !== 0 && $currentIndex !== -1;
|
||||||
|
|
||||||
|
$updateInfo = [
|
||||||
|
'has_update' => $hasUpdate,
|
||||||
|
'is_local_newer' => $isLocalNewer,
|
||||||
|
'latest_version' => $isLocalNewer ? $currentCommit : $latestCommit,
|
||||||
|
'current_version' => $currentCommit,
|
||||||
|
'update_logs' => $updateLogs,
|
||||||
|
'download_url' => $commits[0]['html_url'] ?? '',
|
||||||
|
'published_at' => $commits[0]['commit']['author']['date'] ?? '',
|
||||||
|
'author' => $commits[0]['commit']['author']['name'] ?? '',
|
||||||
|
];
|
||||||
|
|
||||||
|
// Cache check results
|
||||||
|
$this->setLastCheckTime();
|
||||||
|
Cache::put(self::CACHE_UPDATE_INFO, $updateInfo, now()->addHours(24));
|
||||||
|
|
||||||
|
return $updateInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->getCachedUpdateInfo();
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
Log::error('Update check failed: ' . $e->getMessage());
|
||||||
|
return $this->getCachedUpdateInfo();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function executeUpdate(): array
|
||||||
|
{
|
||||||
|
// Check for new version first
|
||||||
|
$updateInfo = $this->checkForUpdates();
|
||||||
|
if ($updateInfo['is_local_newer']) {
|
||||||
|
return [
|
||||||
|
'success' => false,
|
||||||
|
'message' => __('update.local_newer')
|
||||||
|
];
|
||||||
|
}
|
||||||
|
if (!$updateInfo['has_update']) {
|
||||||
|
return [
|
||||||
|
'success' => false,
|
||||||
|
'message' => __('update.already_latest')
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check for update lock
|
||||||
|
if (Cache::get(self::CACHE_UPDATE_LOCK)) {
|
||||||
|
return [
|
||||||
|
'success' => false,
|
||||||
|
'message' => __('update.process_running')
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Set update lock
|
||||||
|
Cache::put(self::CACHE_UPDATE_LOCK, true, now()->addMinutes(30));
|
||||||
|
|
||||||
|
// 1. Backup database
|
||||||
|
$this->backupDatabase();
|
||||||
|
|
||||||
|
// 2. Pull latest code
|
||||||
|
$result = $this->pullLatestCode();
|
||||||
|
if (!$result['success']) {
|
||||||
|
throw new \Exception($result['message']);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3. Run database migrations
|
||||||
|
$this->runMigrations();
|
||||||
|
|
||||||
|
// 4. Clear cache
|
||||||
|
$this->clearCache();
|
||||||
|
|
||||||
|
// 5. Create update flag
|
||||||
|
$this->createUpdateFlag();
|
||||||
|
|
||||||
|
// 6. Restart Octane if running
|
||||||
|
$this->restartOctane();
|
||||||
|
|
||||||
|
// Remove update lock
|
||||||
|
Cache::forget(self::CACHE_UPDATE_LOCK);
|
||||||
|
|
||||||
|
// Format update logs
|
||||||
|
$logMessages = array_map(function($log) {
|
||||||
|
return sprintf("- %s (%s): %s",
|
||||||
|
$log['version'],
|
||||||
|
date('Y-m-d H:i', strtotime($log['date'])),
|
||||||
|
$log['message']
|
||||||
|
);
|
||||||
|
}, $updateInfo['update_logs']);
|
||||||
|
|
||||||
|
return [
|
||||||
|
'success' => true,
|
||||||
|
'message' => __('update.success', [
|
||||||
|
'from' => $updateInfo['current_version'],
|
||||||
|
'to' => $updateInfo['latest_version']
|
||||||
|
]),
|
||||||
|
'version' => $updateInfo['latest_version'],
|
||||||
|
'update_info' => [
|
||||||
|
'from_version' => $updateInfo['current_version'],
|
||||||
|
'to_version' => $updateInfo['latest_version'],
|
||||||
|
'update_logs' => $logMessages,
|
||||||
|
'author' => $updateInfo['author'],
|
||||||
|
'published_at' => $updateInfo['published_at']
|
||||||
|
]
|
||||||
|
];
|
||||||
|
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
Log::error('Update execution failed: ' . $e->getMessage());
|
||||||
|
Cache::forget(self::CACHE_UPDATE_LOCK);
|
||||||
|
|
||||||
|
return [
|
||||||
|
'success' => false,
|
||||||
|
'message' => __('update.failed', ['error' => $e->getMessage()])
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function getCurrentCommit(): string
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
$result = Process::run('git rev-parse HEAD');
|
||||||
|
$fullHash = trim($result->output());
|
||||||
|
return $fullHash ? $this->formatCommitHash($fullHash) : 'unknown';
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
Log::error('Failed to get current commit: ' . $e->getMessage());
|
||||||
|
return 'unknown';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function getFirstCommit(): string
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
// Get first commit hash
|
||||||
|
$result = Process::run('git rev-list --max-parents=0 HEAD');
|
||||||
|
$fullHash = trim($result->output());
|
||||||
|
return $fullHash ? $this->formatCommitHash($fullHash) : 'unknown';
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
Log::error('Failed to get first commit: ' . $e->getMessage());
|
||||||
|
return 'unknown';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function formatCommitHash(string $hash): string
|
||||||
|
{
|
||||||
|
// Use 7 characters for commit hash
|
||||||
|
return substr($hash, 0, 7);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function backupDatabase(): void
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
// Use existing backup command
|
||||||
|
Process::run('php artisan backup:database');
|
||||||
|
|
||||||
|
if (!Process::result()->successful()) {
|
||||||
|
throw new \Exception(__('update.backup_failed', ['error' => Process::result()->errorOutput()]));
|
||||||
|
}
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
Log::error('Database backup failed: ' . $e->getMessage());
|
||||||
|
throw $e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function pullLatestCode(): array
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
// Get current project root directory
|
||||||
|
$basePath = base_path();
|
||||||
|
|
||||||
|
// Ensure git configuration is correct
|
||||||
|
Process::run(sprintf('git config --global --add safe.directory %s', $basePath));
|
||||||
|
|
||||||
|
// Pull latest code
|
||||||
|
Process::run('git fetch origin master');
|
||||||
|
Process::run('git reset --hard origin/master');
|
||||||
|
|
||||||
|
// Update dependencies
|
||||||
|
Process::run('composer install --no-dev --optimize-autoloader');
|
||||||
|
|
||||||
|
// Update version cache after pulling new code
|
||||||
|
$this->updateVersionCache();
|
||||||
|
|
||||||
|
return ['success' => true];
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
return [
|
||||||
|
'success' => false,
|
||||||
|
'message' => __('update.code_update_failed', ['error' => $e->getMessage()])
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function runMigrations(): void
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
Process::run('php artisan migrate --force');
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
Log::error('Migration failed: ' . $e->getMessage());
|
||||||
|
throw new \Exception(__('update.migration_failed', ['error' => $e->getMessage()]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function clearCache(): void
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
$commands = [
|
||||||
|
'php artisan config:clear',
|
||||||
|
'php artisan cache:clear',
|
||||||
|
'php artisan view:clear',
|
||||||
|
'php artisan route:clear'
|
||||||
|
];
|
||||||
|
|
||||||
|
foreach ($commands as $command) {
|
||||||
|
Process::run($command);
|
||||||
|
}
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
Log::error('Cache clearing failed: ' . $e->getMessage());
|
||||||
|
throw new \Exception(__('update.cache_clear_failed', ['error' => $e->getMessage()]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function createUpdateFlag(): void
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
// Create update flag file for external script to detect and restart container
|
||||||
|
$flagFile = storage_path('update_pending');
|
||||||
|
File::put($flagFile, date('Y-m-d H:i:s'));
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
Log::error('Failed to create update flag: ' . $e->getMessage());
|
||||||
|
throw new \Exception(__('update.flag_create_failed', ['error' => $e->getMessage()]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function restartOctane(): void
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
if (!config('octane.server')) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check Octane running status
|
||||||
|
$statusResult = Process::run('php artisan octane:status');
|
||||||
|
if (!$statusResult->successful()) {
|
||||||
|
Log::info('Octane is not running, skipping restart.');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$output = $statusResult->output();
|
||||||
|
if (str_contains($output, 'Octane server is running')) {
|
||||||
|
Log::info('Restarting Octane server after update...');
|
||||||
|
// Update version cache before restart
|
||||||
|
$this->updateVersionCache();
|
||||||
|
Process::run('php artisan octane:reload');
|
||||||
|
Log::info('Octane server restarted successfully.');
|
||||||
|
} else {
|
||||||
|
Log::info('Octane is not running, skipping restart.');
|
||||||
|
}
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
Log::error('Failed to restart Octane server: ' . $e->getMessage());
|
||||||
|
// Non-fatal error, don't throw exception
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getLastCheckTime()
|
||||||
|
{
|
||||||
|
return Cache::get(self::CACHE_LAST_CHECK, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function setLastCheckTime(): void
|
||||||
|
{
|
||||||
|
Cache::put(self::CACHE_LAST_CHECK, now()->timestamp, now()->addDays(30));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getCachedUpdateInfo(): array
|
||||||
|
{
|
||||||
|
return Cache::get(self::CACHE_UPDATE_INFO, [
|
||||||
|
'has_update' => false,
|
||||||
|
'latest_version' => $this->getCurrentCommit(),
|
||||||
|
'current_version' => $this->getCurrentCommit(),
|
||||||
|
'update_logs' => [],
|
||||||
|
'download_url' => '',
|
||||||
|
'published_at' => '',
|
||||||
|
'author' => '',
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function getLocalGitLogs(int $limit = 50): array
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
// 获取本地git log
|
||||||
|
$result = Process::run(
|
||||||
|
sprintf('git log -%d --pretty=format:"%%H||%%s||%%an||%%ai"', $limit)
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!$result->successful()) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
$logs = [];
|
||||||
|
$lines = explode("\n", trim($result->output()));
|
||||||
|
foreach ($lines as $line) {
|
||||||
|
$parts = explode('||', $line);
|
||||||
|
if (count($parts) === 4) {
|
||||||
|
$logs[] = [
|
||||||
|
'hash' => $parts[0],
|
||||||
|
'message' => $parts[1],
|
||||||
|
'author' => $parts[2],
|
||||||
|
'date' => $parts[3]
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return $logs;
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
Log::error('Failed to get local git logs: ' . $e->getMessage());
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -177,6 +177,7 @@ return [
|
|||||||
App\Providers\SettingServiceProvider::class,
|
App\Providers\SettingServiceProvider::class,
|
||||||
App\Providers\OctaneSchedulerProvider::class,
|
App\Providers\OctaneSchedulerProvider::class,
|
||||||
App\Providers\PluginServiceProvider::class,
|
App\Providers\PluginServiceProvider::class,
|
||||||
|
App\Providers\OctaneVersionProvider::class,
|
||||||
|
|
||||||
],
|
],
|
||||||
|
|
||||||
|
2
public/assets/admin/assets/index.css
vendored
2
public/assets/admin/assets/index.css
vendored
File diff suppressed because one or more lines are too long
8
public/assets/admin/assets/index.js
vendored
8
public/assets/admin/assets/index.js
vendored
File diff suppressed because one or more lines are too long
180
public/assets/admin/assets/vendor.js
vendored
180
public/assets/admin/assets/vendor.js
vendored
File diff suppressed because one or more lines are too long
11
public/assets/admin/locales/en-US.js
vendored
11
public/assets/admin/locales/en-US.js
vendored
@ -874,6 +874,17 @@ window.XBOARD_TRANSLATIONS['en-US'] = {
|
|||||||
"nextPage": "Next page",
|
"nextPage": "Next page",
|
||||||
"lastPage": "Go to last page"
|
"lastPage": "Go to last page"
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"update": {
|
||||||
|
"title": "System Update",
|
||||||
|
"newVersion": "New Version Available",
|
||||||
|
"currentVersion": "Current Version",
|
||||||
|
"latestVersion": "Latest Version",
|
||||||
|
"updateLater": "Update Later",
|
||||||
|
"updateNow": "Update Now",
|
||||||
|
"updating": "Updating...",
|
||||||
|
"updateSuccess": "Update successful, system will restart shortly",
|
||||||
|
"updateFailed": "Update failed, please try again later"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"dashboard": {
|
"dashboard": {
|
||||||
|
11
public/assets/admin/locales/ko-KR.js
vendored
11
public/assets/admin/locales/ko-KR.js
vendored
@ -870,6 +870,17 @@ window.XBOARD_TRANSLATIONS['ko-KR'] = {
|
|||||||
"nextPage": "다음 페이지",
|
"nextPage": "다음 페이지",
|
||||||
"lastPage": "마지막 페이지로 이동"
|
"lastPage": "마지막 페이지로 이동"
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"update": {
|
||||||
|
"title": "시스템 업데이트",
|
||||||
|
"newVersion": "새 버전 발견",
|
||||||
|
"currentVersion": "현재 버전",
|
||||||
|
"latestVersion": "최신 버전",
|
||||||
|
"updateLater": "나중에 업데이트",
|
||||||
|
"updateNow": "지금 업데이트",
|
||||||
|
"updating": "업데이트 중...",
|
||||||
|
"updateSuccess": "업데이트 성공, 시스템이 곧 재시작됩니다",
|
||||||
|
"updateFailed": "업데이트 실패, 나중에 다시 시도해주세요"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"dashboard": {
|
"dashboard": {
|
||||||
|
11
public/assets/admin/locales/zh-CN.js
vendored
11
public/assets/admin/locales/zh-CN.js
vendored
@ -879,6 +879,17 @@ window.XBOARD_TRANSLATIONS['zh-CN'] = {
|
|||||||
"nextPage": "下一页",
|
"nextPage": "下一页",
|
||||||
"lastPage": "跳转到最后一页"
|
"lastPage": "跳转到最后一页"
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"update": {
|
||||||
|
"title": "系统更新",
|
||||||
|
"newVersion": "发现新版本",
|
||||||
|
"currentVersion": "当前版本",
|
||||||
|
"latestVersion": "最新版本",
|
||||||
|
"updateLater": "稍后更新",
|
||||||
|
"updateNow": "立即更新",
|
||||||
|
"updating": "更新中...",
|
||||||
|
"updateSuccess": "更新成功,系统将在稍后自动重启",
|
||||||
|
"updateFailed": "更新失败,请稍后重试"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"dashboard": {
|
"dashboard": {
|
||||||
|
@ -119,5 +119,15 @@
|
|||||||
"Monthly": "Monthly",
|
"Monthly": "Monthly",
|
||||||
"Never": "Never",
|
"Never": "Never",
|
||||||
"First Day of Year": "First Day of Year",
|
"First Day of Year": "First Day of Year",
|
||||||
"Yearly": "Yearly"
|
"Yearly": "Yearly",
|
||||||
|
"update.local_newer": "Current version is newer than remote version, please commit your changes first",
|
||||||
|
"update.already_latest": "Already on the latest version",
|
||||||
|
"update.process_running": "Update process is already running",
|
||||||
|
"update.success": "Update successful, from :from to :to, system will restart automatically later",
|
||||||
|
"update.failed": "Update failed: :error",
|
||||||
|
"update.backup_failed": "Database backup failed: :error",
|
||||||
|
"update.code_update_failed": "Code update failed: :error",
|
||||||
|
"update.migration_failed": "Database migration failed: :error",
|
||||||
|
"update.cache_clear_failed": "Cache clearing failed: :error",
|
||||||
|
"update.flag_create_failed": "Failed to create update flag: :error"
|
||||||
}
|
}
|
||||||
|
@ -119,5 +119,15 @@
|
|||||||
"Monthly": "按月",
|
"Monthly": "按月",
|
||||||
"Never": "不重置",
|
"Never": "不重置",
|
||||||
"First Day of Year": "每年1月1日",
|
"First Day of Year": "每年1月1日",
|
||||||
"Yearly": "按年"
|
"Yearly": "按年",
|
||||||
|
"update.local_newer": "当前版本比远程版本更新,请先提交您的更改",
|
||||||
|
"update.already_latest": "当前已经是最新版本",
|
||||||
|
"update.process_running": "更新进程正在运行中",
|
||||||
|
"update.success": "更新成功,从 :from 更新到 :to, 系统将在稍后自动重启",
|
||||||
|
"update.failed": "更新失败: :error",
|
||||||
|
"update.backup_failed": "数据库备份失败: :error",
|
||||||
|
"update.code_update_failed": "代码更新失败: :error",
|
||||||
|
"update.migration_failed": "数据库迁移失败: :error",
|
||||||
|
"update.cache_clear_failed": "缓存清理失败: :error",
|
||||||
|
"update.flag_create_failed": "创建更新标记失败: :error"
|
||||||
}
|
}
|
||||||
|
@ -119,5 +119,15 @@
|
|||||||
"Monthly": "按月",
|
"Monthly": "按月",
|
||||||
"Never": "不重置",
|
"Never": "不重置",
|
||||||
"First Day of Year": "每年1月1日",
|
"First Day of Year": "每年1月1日",
|
||||||
"Yearly": "按年"
|
"Yearly": "按年",
|
||||||
|
"update.local_newer": "當前版本比遠程版本更新,請先提交您的更改",
|
||||||
|
"update.already_latest": "當前已經是最新版本",
|
||||||
|
"update.process_running": "更新進程正在運行中",
|
||||||
|
"update.success": "更新成功,從 :from 更新到 :to, 系統將在稍後自動重啟",
|
||||||
|
"update.failed": "更新失敗: :error",
|
||||||
|
"update.backup_failed": "數據庫備份失敗: :error",
|
||||||
|
"update.code_update_failed": "代碼更新失敗: :error",
|
||||||
|
"update.migration_failed": "數據庫遷移失敗: :error",
|
||||||
|
"update.cache_clear_failed": "緩存清理失敗: :error",
|
||||||
|
"update.flag_create_failed": "創建更新標記失敗: :error"
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
use App\Services\ThemeService;
|
use App\Services\ThemeService;
|
||||||
|
use App\Services\UpdateService;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
use Illuminate\Support\Facades\Route;
|
use Illuminate\Support\Facades\Route;
|
||||||
use Illuminate\Support\Facades\Log;
|
use Illuminate\Support\Facades\Log;
|
||||||
@ -57,7 +58,7 @@ Route::get('/', function (Request $request) {
|
|||||||
$renderParams = [
|
$renderParams = [
|
||||||
'title' => admin_setting('app_name', 'Xboard'),
|
'title' => admin_setting('app_name', 'Xboard'),
|
||||||
'theme' => $theme,
|
'theme' => $theme,
|
||||||
'version' => config('app.version'),
|
'version' => app(UpdateService::class)->getCurrentVersion(),
|
||||||
'description' => admin_setting('app_description', 'Xboard is best'),
|
'description' => admin_setting('app_description', 'Xboard is best'),
|
||||||
'logo' => admin_setting('logo'),
|
'logo' => admin_setting('logo'),
|
||||||
'theme_config' => $themeService->getConfig($theme)
|
'theme_config' => $themeService->getConfig($theme)
|
||||||
@ -80,7 +81,7 @@ Route::get('/' . admin_setting('secure_path', admin_setting('frontend_admin_path
|
|||||||
'theme_header' => admin_setting('frontend_theme_header', 'dark'),
|
'theme_header' => admin_setting('frontend_theme_header', 'dark'),
|
||||||
'theme_color' => admin_setting('frontend_theme_color', 'default'),
|
'theme_color' => admin_setting('frontend_theme_color', 'default'),
|
||||||
'background_url' => admin_setting('frontend_background_url'),
|
'background_url' => admin_setting('frontend_background_url'),
|
||||||
'version' => config('app.version'),
|
'version' => app(UpdateService::class)->getCurrentVersion(),
|
||||||
'logo' => admin_setting('logo'),
|
'logo' => admin_setting('logo'),
|
||||||
'secure_path' => admin_setting('secure_path', admin_setting('frontend_admin_path', hash('crc32b', config('app.key'))))
|
'secure_path' => admin_setting('secure_path', admin_setting('frontend_admin_path', hash('crc32b', config('app.key'))))
|
||||||
]);
|
]);
|
||||||
|
Loading…
Reference in New Issue
Block a user