Compare commits
No commits in common. "8335b16bad4116d19083353f489f2c176c69d5af" and "d9befa634a89a528b893380112c269f052669315" have entirely different histories.
8335b16bad
...
d9befa634a
|
@ -1,58 +0,0 @@
|
||||||
<script setup>
|
|
||||||
|
|
||||||
defineProps({
|
|
||||||
drawingData: {
|
|
||||||
type: Array,
|
|
||||||
required: true
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
// Форматируем чертежи под TableItem
|
|
||||||
function formatDrawings(item) {
|
|
||||||
return item.drawings.reduce((acc, drawing) => {
|
|
||||||
acc[drawing.name] = drawing.path
|
|
||||||
return acc
|
|
||||||
}, {})
|
|
||||||
}
|
|
||||||
|
|
||||||
// Проверяем, есть ли спецификации
|
|
||||||
function hasSpecifications(item) {
|
|
||||||
return item.specifications && Array.isArray(item.specifications) && item.specifications.length > 0
|
|
||||||
}
|
|
||||||
|
|
||||||
// Форматируем спецификации под TableItem
|
|
||||||
function formatSpecifications(item) {
|
|
||||||
if (!hasSpecifications(item)) return {}
|
|
||||||
return item.specifications.reduce((acc, spec) => {
|
|
||||||
acc[spec.name] = spec.path
|
|
||||||
return acc
|
|
||||||
}, {})
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<template>
|
|
||||||
<div class="mt-6">
|
|
||||||
<h3 class="text-xl font-semibold mb-4">Результат: Чертежи и спецификации</h3>
|
|
||||||
|
|
||||||
<div v-for="item in drawingData" :key="item.document_name" class="mb-6 border p-4 rounded shadow-sm bg-white">
|
|
||||||
<h4 class="font-medium text-lg">{{ item.document_name }}</h4>
|
|
||||||
|
|
||||||
<!-- Чертежи -->
|
|
||||||
<TableItem
|
|
||||||
caption="Чертежи:"
|
|
||||||
:items="formatDrawings(item)"
|
|
||||||
label-key="Название"
|
|
||||||
label-value="Путь"
|
|
||||||
/>
|
|
||||||
|
|
||||||
<!-- Спецификации -->
|
|
||||||
<TableItem
|
|
||||||
v-if="hasSpecifications(item)"
|
|
||||||
caption="Спецификации:"
|
|
||||||
:items="formatSpecifications(item)"
|
|
||||||
label-key="Название"
|
|
||||||
label-value="Путь"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
|
@ -1,41 +0,0 @@
|
||||||
<template>
|
|
||||||
<div>
|
|
||||||
<h2 class="text-xl font-bold mb-4">Результаты сохранения в IGES</h2>
|
|
||||||
|
|
||||||
<table class="min-w-full border-collapse mt-4">
|
|
||||||
<thead class="bg-gray-100">
|
|
||||||
<tr>
|
|
||||||
<th class="border px-4 py-2 text-left">Документ</th>
|
|
||||||
<th class="border px-4 py-2 text-left">Файл</th>
|
|
||||||
<th class="border px-4 py-2 text-left">Успешно</th>
|
|
||||||
<th class="border px-4 py-2 text-left">Ошибка</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody>
|
|
||||||
<tr v-for="file in files" :key="file.timestamp" class="hover:bg-gray-50">
|
|
||||||
<td class="border px-4 py-2">{{ file.document_name }}</td>
|
|
||||||
<td class="border px-4 py-2">
|
|
||||||
<a :href="`file://${file.file}`" target="_blank">{{ file.file }}</a>
|
|
||||||
</td>
|
|
||||||
<td class="border px-4 py-2">
|
|
||||||
<span :class="file.success ? 'text-green-500' : 'text-red-500'">
|
|
||||||
{{ file.success ? '✅ Да' : '❌ Нет' }}
|
|
||||||
</span>
|
|
||||||
</td>
|
|
||||||
<td class="border px-4 py-2">
|
|
||||||
{{ file.error || '-' }}
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script setup>
|
|
||||||
defineProps({
|
|
||||||
files: {
|
|
||||||
type: Array,
|
|
||||||
required: true
|
|
||||||
}
|
|
||||||
})
|
|
||||||
</script>
|
|
|
@ -1,37 +0,0 @@
|
||||||
<script setup lang="ts">
|
|
||||||
defineProps({
|
|
||||||
caption: {
|
|
||||||
type: String,
|
|
||||||
default: ''
|
|
||||||
},
|
|
||||||
items: {
|
|
||||||
type: Object,
|
|
||||||
required: true
|
|
||||||
},
|
|
||||||
labelKey: {
|
|
||||||
type: String,
|
|
||||||
default: 'Ключ'
|
|
||||||
},
|
|
||||||
labelValue: {
|
|
||||||
type: String,
|
|
||||||
default: 'Значение'
|
|
||||||
}
|
|
||||||
})
|
|
||||||
</script>
|
|
||||||
<template>
|
|
||||||
<table class="min-w-full mt-4 border-collapse">
|
|
||||||
<caption v-if="caption" class="caption-top font-medium text-left">{{ caption }}</caption>
|
|
||||||
<thead class="bg-gray-100">
|
|
||||||
<tr>
|
|
||||||
<th class="border px-4 py-2 text-left">{{ labelKey }}</th>
|
|
||||||
<th class="border px-4 py-2 text-left">{{ labelValue }}</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody>
|
|
||||||
<tr v-for="(value, key) in items" :key="key">
|
|
||||||
<td class="border px-4 py-2">{{ key }}</td>
|
|
||||||
<td class="border px-4 py-2">{{ value }}</td>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</template>
|
|
|
@ -1,32 +0,0 @@
|
||||||
<template>
|
|
||||||
<div v-if="item">
|
|
||||||
<h3 class="text-xl font-bold mb-2">{{ item.name }}</h3>
|
|
||||||
<p>Количество элементов: {{ item.elements_count }}</p>
|
|
||||||
<p>Количество гибов: {{ item.bends_count }}</p>
|
|
||||||
|
|
||||||
<!-- Имя -->
|
|
||||||
<TableItem caption="По названию:" :items="item.statistics.Name" label-key="Название" label-value="Количество" />
|
|
||||||
|
|
||||||
<!-- Материал -->
|
|
||||||
<TableItem caption="По материалу:" :items="item.statistics.Material" label-key="Материал"
|
|
||||||
label-value="Количество" />
|
|
||||||
|
|
||||||
<!-- Площадь -->
|
|
||||||
<TableItem caption="Площадь материалов:" :items="item.statistics.Area" label-key="Материал"
|
|
||||||
label-value="Площадь (м²)" />
|
|
||||||
|
|
||||||
<!-- Сварки -->
|
|
||||||
<TableItem caption="Сварные швы:" :items="item.statistics.Welding" label-key="Имя сварки"
|
|
||||||
label-value="Длина (мм)" />
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script setup>
|
|
||||||
|
|
||||||
defineProps({
|
|
||||||
item: {
|
|
||||||
type: Object,
|
|
||||||
required: true
|
|
||||||
}
|
|
||||||
})
|
|
||||||
</script>
|
|
|
@ -4,33 +4,26 @@ const availableActions = ref<Record<string, { label: string; allowedTypes: numbe
|
||||||
|
|
||||||
export function useKompasActions() {
|
export function useKompasActions() {
|
||||||
const { sendCommandToPython, isReady } = usePythonBridge()
|
const { sendCommandToPython, isReady } = usePythonBridge()
|
||||||
|
const loading = ref(false)
|
||||||
const error = ref<string | null>(null)
|
const error = ref<string | null>(null)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Загружает список действий с бэкенда
|
* Загружает список действий с бэкенда
|
||||||
*/
|
*/
|
||||||
async function loadActions() {
|
async function loadActions() {
|
||||||
if (!isReady.value) {
|
loading.value = true
|
||||||
console.warn('Bridge не готов')
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
error.value = null
|
error.value = null
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Отправляем команду и ожидаем ответ в новом формате
|
const actions = await sendCommandToPython<{
|
||||||
const response = await sendCommandToPython<{
|
[key: string]: { label: string; allowed_types: number[] }
|
||||||
status: 'success' | 'error'
|
|
||||||
data: Record<string, { label: string; allowed_types: number[] }> | null
|
|
||||||
error: string | null
|
|
||||||
}>('get_available_actions')
|
}>('get_available_actions')
|
||||||
|
|
||||||
if (response.status === 'success' && response.data) {
|
if (actions) {
|
||||||
// Преобразуем данные
|
// Преобразуем все ключи `allowed_types` → `allowedTypes`
|
||||||
const convertedActions: Record<string, { label: string; allowedTypes: number[] }> = {}
|
const convertedActions: Record<string, { label: string; allowedTypes: number[] }> = {}
|
||||||
|
|
||||||
for (const key in response.data) {
|
for (const key in actions) {
|
||||||
const { label, allowed_types } = response.data[key]
|
const { label, allowed_types } = actions[key]
|
||||||
convertedActions[key] = {
|
convertedActions[key] = {
|
||||||
label,
|
label,
|
||||||
allowedTypes: allowed_types
|
allowedTypes: allowed_types
|
||||||
|
@ -38,18 +31,18 @@ export function useKompasActions() {
|
||||||
}
|
}
|
||||||
|
|
||||||
availableActions.value = convertedActions
|
availableActions.value = convertedActions
|
||||||
} else {
|
|
||||||
throw new Error(response.error || 'Неизвестная ошибка')
|
|
||||||
}
|
}
|
||||||
} catch (err: any) {
|
} catch (err: any) {
|
||||||
console.error('Ошибка при получении действий:', err)
|
console.error('Ошибка при получении действий:', err)
|
||||||
error.value = 'Не удалось загрузить список действий'
|
error.value = 'Не удалось загрузить список действий'
|
||||||
|
} finally {
|
||||||
|
loading.value = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
availableActions,
|
availableActions,
|
||||||
|
loading,
|
||||||
error,
|
error,
|
||||||
loadActions,
|
loadActions,
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
// composables/usePythonBridge.ts
|
import { ref, onMounted } from 'vue'
|
||||||
|
|
||||||
declare global {
|
declare global {
|
||||||
interface Window {
|
interface Window {
|
||||||
|
@ -12,25 +12,29 @@ declare global {
|
||||||
new(transport: any, ready: (channel: any) => void): void
|
new(transport: any, ready: (channel: any) => void): void
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
export function usePythonBridge() {
|
|
||||||
const pyjs = useState<any>('bridge_pyjs', () => null)
|
interface PythonEvent {
|
||||||
const isReady = useState<boolean>('bridge_ready', () => false)
|
type: string
|
||||||
const isAvailableOnPlatform = useState<boolean>('bridge_av', () => false)
|
data: any
|
||||||
const loading = useState<boolean>('bridge_loading', () => false)
|
}
|
||||||
|
|
||||||
|
const pyjs = ref<any>(null)
|
||||||
|
const isReady = ref<boolean>(false)
|
||||||
|
|
||||||
// Хранилище обработчиков событий
|
// Хранилище обработчиков событий
|
||||||
const pythonEventHandlers = new Map<string, Array<(data: any) => void>>()
|
const pythonEventHandlers = new Map<string, Array<(data: any) => void>>()
|
||||||
|
|
||||||
function receiveFromPython(eventType: string, data: any) {
|
function receiveFromPython(eventType: string, data: any) {
|
||||||
console.warn("🟢 Event from Python:", eventType, data)
|
console.warn("🟢 Event from Python:", eventType, data)
|
||||||
|
|
||||||
const handlers = pythonEventHandlers.get(eventType) || []
|
const handlers = pythonEventHandlers.get(eventType) || []
|
||||||
handlers.forEach(handler => handler(data))
|
handlers.forEach(handler => handler(data))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function usePythonBridge() {
|
||||||
function setupQWebChannel() {
|
function setupQWebChannel() {
|
||||||
if (window.QWebChannel && window.qt && window.qt.webChannelTransport) {
|
if (window.QWebChannel && window.qt && window.qt.webChannelTransport) {
|
||||||
new window.QWebChannel(window.qt.webChannelTransport, function (channel) {
|
new window.QWebChannel(window.qt.webChannelTransport, function (channel) {
|
||||||
isAvailableOnPlatform.value = true
|
|
||||||
isReady.value = true
|
isReady.value = true
|
||||||
pyjs.value = channel.objects.pyjs
|
pyjs.value = channel.objects.pyjs
|
||||||
|
|
||||||
|
@ -43,7 +47,6 @@ export function usePythonBridge() {
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
isAvailableOnPlatform.value = false
|
|
||||||
console.error('Qt WebChannel недоступен')
|
console.error('Qt WebChannel недоступен')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -52,34 +55,24 @@ export function usePythonBridge() {
|
||||||
command: string,
|
command: string,
|
||||||
data: Record<string, any> = {}
|
data: Record<string, any> = {}
|
||||||
): Promise<T> {
|
): Promise<T> {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
if (!isReady.value) {
|
if (!isReady.value) {
|
||||||
throw new Error('Мост еще не готов')
|
reject(new Error('Мост еще не готов'))
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!pyjs.value || !pyjs.value.callFromJS) {
|
if (!pyjs.value || !pyjs.value.callFromJS) {
|
||||||
throw new Error('Python недоступен')
|
reject(new Error('Python недоступен'))
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
loading.value = true
|
|
||||||
|
|
||||||
return new Promise<T>((resolve, reject) => {
|
|
||||||
setTimeout(() => {
|
|
||||||
try {
|
|
||||||
pyjs.value.callFromJS(command, JSON.stringify(data), (result: string) => {
|
pyjs.value.callFromJS(command, JSON.stringify(data), (result: string) => {
|
||||||
try {
|
try {
|
||||||
const parsed = JSON.parse(result)
|
resolve(JSON.parse(result))
|
||||||
resolve(parsed)
|
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
reject(e)
|
reject(e)
|
||||||
} finally {
|
|
||||||
loading.value = false
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
} catch (err) {
|
|
||||||
reject(err)
|
|
||||||
loading.value = false
|
|
||||||
}
|
|
||||||
}, 300)
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -103,7 +96,7 @@ export function usePythonBridge() {
|
||||||
}
|
}
|
||||||
|
|
||||||
const checkBridge = () => {
|
const checkBridge = () => {
|
||||||
if (import.meta.client && window.QWebChannel && window.qt?.webChannelTransport) {
|
if (window.QWebChannel && window.qt?.webChannelTransport) {
|
||||||
setupQWebChannel()
|
setupQWebChannel()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -114,16 +107,12 @@ export function usePythonBridge() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Вызываем один раз при первом монтировании
|
onMounted(() => {
|
||||||
if (!isReady.value) {
|
|
||||||
checkBridge()
|
checkBridge()
|
||||||
}
|
})
|
||||||
|
|
||||||
return {
|
return {
|
||||||
pyjs,
|
|
||||||
isReady,
|
isReady,
|
||||||
isAvailableOnPlatform,
|
|
||||||
loading,
|
|
||||||
sendCommandToPython,
|
sendCommandToPython,
|
||||||
onPythonEvent,
|
onPythonEvent,
|
||||||
offPythonEvent,
|
offPythonEvent,
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
|
|
||||||
const { sendCommandToPython, isReady, isAvailableOnPlatform, loading } = usePythonBridge()
|
const { sendCommandToPython, isReady } = usePythonBridge()
|
||||||
|
|
||||||
const {
|
const {
|
||||||
documents,
|
documents,
|
||||||
|
@ -21,85 +21,28 @@ watch(selectedAction, () => {
|
||||||
selectedTypes.value = availableActions.value[selectedAction.value].allowedTypes
|
selectedTypes.value = availableActions.value[selectedAction.value].allowedTypes
|
||||||
})
|
})
|
||||||
|
|
||||||
const statsData = ref(null)
|
|
||||||
const filesData = ref(null)
|
|
||||||
const drawingData = ref(null)
|
|
||||||
const resultData = ref(null)
|
|
||||||
|
|
||||||
// Синхронизация с КОМПАС
|
// Синхронизация с КОМПАС
|
||||||
async function syncKompas() {
|
async function syncKompas() {
|
||||||
try {
|
try {
|
||||||
// Получаем ответ в новом формате: { status, data, error }
|
const docs = await sendCommandToPython<KompasDocument[]>('open_kompas')
|
||||||
const response = await sendCommandToPython('open_kompas')
|
|
||||||
|
|
||||||
console.log('Полный ответ от Python:', response)
|
if (!docs || !Array.isArray(docs)) {
|
||||||
|
console.warn('Неожиданный ответ от Python:', docs)
|
||||||
// Проверяем структуру ответа
|
documents.value = []
|
||||||
if (!response || typeof response !== 'object') {
|
} else {
|
||||||
throw new Error('Некорректный формат ответа: пустой или не объект')
|
documents.value = docs
|
||||||
}
|
|
||||||
|
|
||||||
if (response.status === 'error') {
|
|
||||||
throw new Error(response.error || 'Неизвестная ошибка')
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!response.data || !Array.isArray(response.data)) {
|
|
||||||
throw new Error('Данные от сервера отсутствуют или имеют неверный формат')
|
|
||||||
}
|
|
||||||
|
|
||||||
// Успешно получили документы
|
|
||||||
documents.value = response.data
|
|
||||||
loadActions()
|
loadActions()
|
||||||
|
}
|
||||||
console.warn('Документы из КОМПАС:', documents.value)
|
console.warn('Документы из КОМПАС:', docs)
|
||||||
|
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error('Ошибка при синхронизации с КОМПАС:', err)
|
console.error('Ошибка при синхронизации с КОМПАС:', err)
|
||||||
alert(`Не удалось получить список документов из КОМПАС\n(${err})`)
|
alert('Не удалось получить список документов из КОМПАС')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const canRunAction = computed(() => {
|
const canRunAction = computed(() => {
|
||||||
return selectedAction.value && filteredDocuments.value.length > 0
|
return selectedAction.value && filteredDocuments.value.length > 0
|
||||||
})
|
})
|
||||||
|
|
||||||
function updateUIWithResult(data: any, action: any) {
|
|
||||||
// Обнуляем предыдущие данные
|
|
||||||
statsData.value = null
|
|
||||||
filesData.value = null
|
|
||||||
drawingData.value = null
|
|
||||||
resultData.value = null
|
|
||||||
|
|
||||||
// Сохраняем сырые данные на случай непредвиденного типа действия
|
|
||||||
resultData.value = data
|
|
||||||
|
|
||||||
if (!data || !data.result || !Array.isArray(data.result)) {
|
|
||||||
console.warn('Некорректный формат данных')
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
console.warn(action)
|
|
||||||
console.warn(JSON.stringify(data))
|
|
||||||
switch (action) {
|
|
||||||
case 'stats':
|
|
||||||
// Для статистики
|
|
||||||
statsData.value = data
|
|
||||||
break
|
|
||||||
|
|
||||||
case 'iges':
|
|
||||||
case 'export_raster':
|
|
||||||
filesData.value = data
|
|
||||||
break
|
|
||||||
|
|
||||||
case 'project_support':
|
|
||||||
drawingData.value = data
|
|
||||||
break
|
|
||||||
|
|
||||||
default:
|
|
||||||
console.warn(`Неизвестное действие: ${action}`)
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async function runSelectedAction() {
|
async function runSelectedAction() {
|
||||||
if (!selectedAction.value) {
|
if (!selectedAction.value) {
|
||||||
alert('Выберите действие')
|
alert('Выберите действие')
|
||||||
|
@ -108,40 +51,20 @@ async function runSelectedAction() {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Отправляем команду на бэкенд
|
// Отправляем команду на бэкенд
|
||||||
// Обнуляем предыдущие данные
|
|
||||||
statsData.value = null
|
|
||||||
filesData.value = null
|
|
||||||
drawingData.value = null
|
|
||||||
resultData.value = null
|
|
||||||
|
|
||||||
const result = await sendCommandToPython(selectedAction.value)
|
const result = await sendCommandToPython(selectedAction.value)
|
||||||
|
|
||||||
console.log('Полный ответ от сервера:', result)
|
console.log('Результат выполнения:', result)
|
||||||
|
|
||||||
// Проверяем, что результат — это объект и содержит поле status
|
if (result && result.status === 'success') {
|
||||||
if (typeof result !== 'object' || result === null) {
|
alert(`Действие "${selectedAction.value}" выполнено успешно!`)
|
||||||
// alert('Ошибка: получен некорректный формат данных от сервера')
|
} else if (result && result.status === 'error') {
|
||||||
console.error('Некорректный формат результата:', result)
|
alert(`Ошибка при выполнении: ${result.error || 'Неизвестная ошибка'}`)
|
||||||
return
|
} else {
|
||||||
}
|
alert('Не удалось получить результат от сервера')
|
||||||
|
|
||||||
// Теперь можно безопасно работать с result.status
|
|
||||||
if (result.status === 'success') {
|
|
||||||
// alert(`✅ Действие "${selectedAction.value}" выполнено успешно!`)
|
|
||||||
updateUIWithResult(result.data, selectedAction.value) // например, выводим данные в интерфейс
|
|
||||||
}
|
|
||||||
else if (result.status === 'error') {
|
|
||||||
const errorMessage = result.error || 'Неизвестная ошибка'
|
|
||||||
// alert(`❌ Ошибка при выполнении: ${errorMessage}`)
|
|
||||||
console.error('Ошибка от сервера:', errorMessage)
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
// alert('⚠️ Не удалось обработать результат от сервера')
|
|
||||||
console.warn('Неизвестный статус ответа:', result)
|
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error('🚨 Ошибка при выполнении действия:', err)
|
console.error('Ошибка при выполнении действия:', err)
|
||||||
alert('🔥 Произошла критическая ошибка при выполнении действия')
|
alert('Произошла ошибка при выполнении действия')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
@ -149,20 +72,16 @@ async function runSelectedAction() {
|
||||||
<template>
|
<template>
|
||||||
<div class="flex flex-col gap-4 p-4">
|
<div class="flex flex-col gap-4 p-4">
|
||||||
<h1>Компас — прослушка событий от Python</h1>
|
<h1>Компас — прослушка событий от Python</h1>
|
||||||
<div v-if="!isAvailableOnPlatform" class="mb-4 p-3 bg-red-100 text-red-800 rounded">
|
|
||||||
❌ <strong>Мост недоступен на этой платформе.</strong> Возможно, вы запускаете приложение не в Qt/PySide.
|
|
||||||
</div>
|
|
||||||
<!-- Статус -->
|
<!-- Статус -->
|
||||||
<div v-if="!isReady && isAvailableOnPlatform"
|
<div v-if="!isReady" class="mb-4 p-3 bg-yellow-100 text-yellow-800 rounded flex items-center">
|
||||||
class="mb-4 p-3 bg-yellow-100 text-yellow-800 rounded flex items-center">
|
|
||||||
⚠️ <strong class="ml-2">Ещё рано отправлять запросы. Идёт инициализация...</strong>
|
⚠️ <strong class="ml-2">Ещё рано отправлять запросы. Идёт инициализация...</strong>
|
||||||
</div>
|
</div>
|
||||||
<template v-if="isReady && isAvailableOnPlatform">
|
<template v-else>
|
||||||
<div>
|
<div>
|
||||||
<!-- Кнопка синхронизации -->
|
<!-- Кнопка синхронизации -->
|
||||||
<button @click="syncKompas"
|
<button @click="syncKompas"
|
||||||
class="bg-blue-500 hover:bg-blue-600 text-white px-4 py-2 rounded mb-4 transition"
|
class="bg-blue-500 hover:bg-blue-600 text-white px-4 py-2 rounded mb-4 transition">
|
||||||
:disabled="loading">
|
|
||||||
🔁 Синхронизировать КОМПАС
|
🔁 Синхронизировать КОМПАС
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
@ -172,15 +91,11 @@ async function runSelectedAction() {
|
||||||
Нет данных о документах. Нажмите "Синхронизировать КОМПАС".
|
Нет данных о документах. Нажмите "Синхронизировать КОМПАС".
|
||||||
</div>
|
</div>
|
||||||
<template v-else>
|
<template v-else>
|
||||||
<!-- Фильтры и действия в одной строке -->
|
|
||||||
<div class="grid grid-cols-2 gap-6">
|
|
||||||
|
|
||||||
<!-- Чекбоксы для фильтрации -->
|
<!-- Чекбоксы для фильтрации -->
|
||||||
<div class="mb-4 p-3 bg-gray-100 rounded shadow-sm">
|
<div class="mb-4 p-3 bg-gray-100 rounded shadow-sm">
|
||||||
<h3 class="font-medium mb-2">Фильтр по типам:</h3>
|
<h3 class="font-medium mb-2">Фильтр по типам:</h3>
|
||||||
<div class="flex flex-wrap gap-4">
|
<div class="flex flex-wrap gap-4">
|
||||||
<label v-for="(label, code) in documentTypeLabels" :key="code"
|
<label v-for="(label, code) in documentTypeLabels" :key="code" class="flex items-center gap-1">
|
||||||
class="flex items-center gap-1">
|
|
||||||
<input type="checkbox" :value="Number(code)" v-model="selectedTypes"
|
<input type="checkbox" :value="Number(code)" v-model="selectedTypes"
|
||||||
:disabled="documentCounts[Number(code)] === 0"
|
:disabled="documentCounts[Number(code)] === 0"
|
||||||
class="form-checkbox h-4 w-4 text-blue-600 disabled:opacity-50" />
|
class="form-checkbox h-4 w-4 text-blue-600 disabled:opacity-50" />
|
||||||
|
@ -202,13 +117,13 @@ async function runSelectedAction() {
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
<!-- Кнопка выполнения действия -->
|
<!-- Кнопка выполнения действия -->
|
||||||
<button type="button" @click="runSelectedAction" :disabled="!canRunAction || loading" class="mt-4 px-4 py-2 bg-blue-500 text-white rounded hover:bg-blue-600
|
<button type="button" @click="runSelectedAction" :disabled="!canRunAction" class="mt-4 px-4 py-2 bg-blue-500 text-white rounded hover:bg-blue-600
|
||||||
disabled:opacity-50 disabled:cursor-not-allowed disabled:pointer-events-none
|
disabled:opacity-50 disabled:cursor-not-allowed disabled:pointer-events-none
|
||||||
transition">
|
transition">
|
||||||
✅ Выполнить действие
|
✅ Выполнить действие
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Грид документов -->
|
<!-- Грид документов -->
|
||||||
<div v-if="filteredDocuments.length" class="mt-4 grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
|
<div v-if="filteredDocuments.length" class="mt-4 grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
|
||||||
|
@ -220,23 +135,18 @@ async function runSelectedAction() {
|
||||||
<strong>Тип:</strong> {{ getDocumentLabel(doc.type) }}
|
<strong>Тип:</strong> {{ getDocumentLabel(doc.type) }}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="mt-1">
|
||||||
|
<strong>Активен:</strong>
|
||||||
|
<span class="ml-2">
|
||||||
|
{{ doc.active ? '✅' : '❌' }}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="mt-2 text-xs text-gray-500 truncate">
|
<div class="mt-2 text-xs text-gray-500 truncate">
|
||||||
{{ doc.path }}
|
{{ doc.path }}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div>
|
|
||||||
<template v-if="filesData">
|
|
||||||
<TableFiles :files="(filesData as any).result" />
|
|
||||||
</template>
|
|
||||||
<template v-if="statsData">
|
|
||||||
<TableStats v-for="item in (statsData as any).result" :key="item.name" :item="item" />
|
|
||||||
</template>
|
|
||||||
<template v-if="drawingData">
|
|
||||||
<TableDrawing :drawingData="(drawingData as any).result" />
|
|
||||||
</template>
|
|
||||||
</div>
|
|
||||||
</template>
|
</template>
|
||||||
</template>
|
</template>
|
||||||
</div>
|
</div>
|
||||||
|
|
Loading…
Reference in New Issue