feat: add system information drawer (#44)
This commit is contained in:
@@ -85,6 +85,11 @@
|
|||||||
v-tooltip.top="'Журнал событий'"
|
v-tooltip.top="'Журнал событий'"
|
||||||
@click="showLogsDrawer = true"
|
@click="showLogsDrawer = true"
|
||||||
/>
|
/>
|
||||||
|
<Button
|
||||||
|
icon="fa fa-info-circle"
|
||||||
|
v-tooltip.top="'Системная информация'"
|
||||||
|
@click="showSystemInfoDrawer = true"
|
||||||
|
/>
|
||||||
</ButtonGroup>
|
</ButtonGroup>
|
||||||
<ButtonGroup>
|
<ButtonGroup>
|
||||||
<Button
|
<Button
|
||||||
@@ -121,24 +126,96 @@
|
|||||||
>
|
>
|
||||||
<LogsViewer/>
|
<LogsViewer/>
|
||||||
</Drawer>
|
</Drawer>
|
||||||
|
|
||||||
|
<Drawer
|
||||||
|
v-model:visible="showSystemInfoDrawer"
|
||||||
|
header="Системная информация"
|
||||||
|
position="right"
|
||||||
|
:baseZIndex="1000"
|
||||||
|
class="tw:!w-full tw:md:!w-1/2"
|
||||||
|
>
|
||||||
|
<div class="tw:flex tw:flex-col tw:gap-4 tw:h-full">
|
||||||
|
<div class="tw:flex tw:justify-end">
|
||||||
|
<Button
|
||||||
|
label="Скопировать"
|
||||||
|
icon="fa fa-copy"
|
||||||
|
@click="copySystemInfo"
|
||||||
|
:disabled="!systemInfo"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<Textarea
|
||||||
|
v-model="systemInfo"
|
||||||
|
readonly
|
||||||
|
class="tw:w-full tw:h-full tw:font-mono tw:text-sm"
|
||||||
|
style="font-family: monospace;"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</Drawer>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import {useSettingsStore} from "@/stores/settings.js";
|
import {useSettingsStore} from "@/stores/settings.js";
|
||||||
import {useStatsStore} from "@/stores/stats.js";
|
import {useStatsStore} from "@/stores/stats.js";
|
||||||
import {onMounted, ref} from "vue";
|
import {onMounted, ref, watch} from "vue";
|
||||||
import OcImagePicker from "@/components/OcImagePicker.vue";
|
import OcImagePicker from "@/components/OcImagePicker.vue";
|
||||||
import {apiGet} from "@/utils/http.js";
|
import {apiGet} from "@/utils/http.js";
|
||||||
import ResetCacheBtn from "@/components/Form/ResetCacheBtn.vue";
|
import ResetCacheBtn from "@/components/Form/ResetCacheBtn.vue";
|
||||||
import {Button, ButtonGroup, Drawer} from "primevue";
|
import {Button, ButtonGroup, Drawer} from "primevue";
|
||||||
|
import Textarea from 'primevue/textarea';
|
||||||
import {rub} from "@/utils/helpers.js";
|
import {rub} from "@/utils/helpers.js";
|
||||||
import LogsViewer from "@/components/LogsViewer.vue";
|
import LogsViewer from "@/components/LogsViewer.vue";
|
||||||
|
import {useToast} from "primevue/usetoast";
|
||||||
|
|
||||||
const settings = useSettingsStore();
|
const settings = useSettingsStore();
|
||||||
const stats = useStatsStore();
|
const stats = useStatsStore();
|
||||||
|
const toast = useToast();
|
||||||
const tgMe = ref(null);
|
const tgMe = ref(null);
|
||||||
const showLogsDrawer = ref(false);
|
const showLogsDrawer = ref(false);
|
||||||
|
const showSystemInfoDrawer = ref(false);
|
||||||
|
const systemInfo = ref('');
|
||||||
|
|
||||||
|
const fetchSystemInfo = async () => {
|
||||||
|
try {
|
||||||
|
const response = await apiGet('getSystemInfo');
|
||||||
|
if (response.success) {
|
||||||
|
systemInfo.value = response.data;
|
||||||
|
} else {
|
||||||
|
systemInfo.value = 'Ошибка при получении системной информации: ' + (response.error || 'Unknown error');
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
systemInfo.value = 'Ошибка при получении системной информации: ' + (error.message || 'Unknown error');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const copySystemInfo = async () => {
|
||||||
|
if (!systemInfo.value) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
await navigator.clipboard.writeText(systemInfo.value);
|
||||||
|
toast.add({
|
||||||
|
severity: 'success',
|
||||||
|
summary: 'Скопировано',
|
||||||
|
detail: 'Системная информация скопирована в буфер обмена',
|
||||||
|
life: 3000
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
toast.add({
|
||||||
|
severity: 'error',
|
||||||
|
summary: 'Ошибка',
|
||||||
|
detail: 'Не удалось скопировать информацию',
|
||||||
|
life: 3000
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
watch(showSystemInfoDrawer, (newValue) => {
|
||||||
|
if (newValue && !systemInfo.value) {
|
||||||
|
fetchSystemInfo();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
await stats.fetchStats();
|
await stats.fetchStats();
|
||||||
|
|||||||
@@ -182,4 +182,61 @@ class SettingsHandler
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getSystemInfo(): JsonResponse
|
||||||
|
{
|
||||||
|
$info = [];
|
||||||
|
|
||||||
|
$info['PHP Version'] = PHP_VERSION;
|
||||||
|
$info['PHP SAPI'] = PHP_SAPI;
|
||||||
|
$info['PHP Memory Limit'] = ini_get('memory_limit');
|
||||||
|
$info['PHP Memory Usage'] = $this->formatBytes(memory_get_usage(true));
|
||||||
|
$info['PHP Peak Memory Usage'] = $this->formatBytes(memory_get_peak_usage(true));
|
||||||
|
$info['PHP Max Execution Time'] = ini_get('max_execution_time') . 's';
|
||||||
|
$info['PHP Upload Max Filesize'] = ini_get('upload_max_filesize');
|
||||||
|
$info['PHP Post Max Size'] = ini_get('post_max_size');
|
||||||
|
|
||||||
|
try {
|
||||||
|
$mysqlVersion = $this->connection->select('SELECT VERSION() as version');
|
||||||
|
$info['MySQL Version'] = $mysqlVersion[0]['version'] ?? 'Unknown';
|
||||||
|
} catch (Exception $e) {
|
||||||
|
$info['MySQL Version'] = 'Error: ' . $e->getMessage();
|
||||||
|
}
|
||||||
|
|
||||||
|
$cacheDriver = env('TELECART_CACHE_DRIVER', 'mysql');
|
||||||
|
$cacheClass = get_class($this->cache);
|
||||||
|
$info['Cache Driver'] = $cacheDriver . ' (' . basename(str_replace('\\', '/', $cacheClass)) . ')';
|
||||||
|
|
||||||
|
$info['Module Version'] = module_version();
|
||||||
|
$info['OpenCart Version'] = defined('VERSION') ? VERSION : 'Unknown';
|
||||||
|
$info['OpenCart Core Version'] = defined('VERSION_CORE') ? VERSION_CORE : 'Unknown';
|
||||||
|
|
||||||
|
$info['Operating System'] = PHP_OS;
|
||||||
|
$info['Server Software'] = $_SERVER['SERVER_SOFTWARE'] ?? 'Unknown';
|
||||||
|
$info['Document Root'] = $_SERVER['DOCUMENT_ROOT'] ?? 'Unknown';
|
||||||
|
|
||||||
|
$info['PHP Timezone'] = date_default_timezone_get();
|
||||||
|
$info['Server Time'] = date('Y-m-d H:i:s');
|
||||||
|
$info['UTC Time'] = gmdate('Y-m-d H:i:s');
|
||||||
|
|
||||||
|
$info['Loaded PHP Extensions'] = implode(', ', get_loaded_extensions());
|
||||||
|
|
||||||
|
$infoText = '';
|
||||||
|
foreach ($info as $key => $value) {
|
||||||
|
$infoText .= $key . ': ' . $value . "\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
return new JsonResponse(['data' => $infoText]);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function formatBytes(int $bytes, int $precision = 2): string
|
||||||
|
{
|
||||||
|
$units = ['B', 'KB', 'MB', 'GB', 'TB'];
|
||||||
|
|
||||||
|
for ($i = 0; $bytes > 1024 && $i < count($units) - 1; $i++) {
|
||||||
|
$bytes /= 1024;
|
||||||
|
}
|
||||||
|
|
||||||
|
return round($bytes, $precision) . ' ' . $units[$i];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,6 +28,7 @@ return [
|
|||||||
'getTelegramCustomers' => [TelegramCustomersHandler::class, 'getCustomers'],
|
'getTelegramCustomers' => [TelegramCustomersHandler::class, 'getCustomers'],
|
||||||
'resetCache' => [SettingsHandler::class, 'resetCache'],
|
'resetCache' => [SettingsHandler::class, 'resetCache'],
|
||||||
'saveSettingsForm' => [SettingsHandler::class, 'saveSettingsForm'],
|
'saveSettingsForm' => [SettingsHandler::class, 'saveSettingsForm'],
|
||||||
|
'getSystemInfo' => [SettingsHandler::class, 'getSystemInfo'],
|
||||||
'sendMessageToCustomer' => [SendMessageHandler::class, 'sendMessage'],
|
'sendMessageToCustomer' => [SendMessageHandler::class, 'sendMessage'],
|
||||||
'testTgMessage' => [TelegramHandler::class, 'testTgMessage'],
|
'testTgMessage' => [TelegramHandler::class, 'testTgMessage'],
|
||||||
'tgGetMe' => [TelegramHandler::class, 'tgGetMe'],
|
'tgGetMe' => [TelegramHandler::class, 'tgGetMe'],
|
||||||
|
|||||||
Reference in New Issue
Block a user