Fixes: - VideoPlayer.vue: restore allTags, filteredMarks, marksByTag (removed by mistake) - PeopleView.vue: fix frameTime scope in playFaceDetailVideo catch block - Both errors caused white screen on build failure Root cause: 1. visibleTags duplicate declaration (old + new logic) 2. frameTime undefined in catch block (scope issue) Solution: 1. Keep allTags/filteredMarks/marksByTag (needed in template) 2. Keep visibleTags (new logic for processor toggles) 3. Move frameTime calculation to correct scope in catch block
85 lines
3.2 KiB
Plaintext
85 lines
3.2 KiB
Plaintext
<template>
|
|
<div id="ms-view-client">
|
|
<div class="client-header">
|
|
<h1>File Manager</h1>
|
|
<div class="client-toolbar">
|
|
<button @click="goUp">Up</button>
|
|
<button @click="createFolder">New Folder</button>
|
|
<button @click="deleteSelected" :disabled="!selectedFile">Delete</button>
|
|
<span class="current-path">{{ currentPath }}</span>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="client-content">
|
|
<table class="file-table">
|
|
<thead><tr><th>Name</th><th>Size</th><th>Type</th></tr></thead>
|
|
<tbody>
|
|
<tr v-for="f in files" :key="f.name" @click="selectFile(f)" :class="{ selected: selectedFile?.name === f.name }">
|
|
<td><span :class="f.isDir ? 'folder-icon' : 'file-icon'">{{ f.isDir ? '📁' : '📄' }}</span> {{ f.name }}</td>
|
|
<td>{{ f.isDir ? '-' : formatSize(f.size) }}</td>
|
|
<td>{{ f.isDir ? 'Folder' : 'File' }}</td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
|
|
<script setup lang="ts">
|
|
import { ref, onMounted } from 'vue'
|
|
import { apiCall } from '../api'
|
|
|
|
const currentPath = ref('/')
|
|
const files = ref<any[]>([])
|
|
const selectedFile = ref<any>(null)
|
|
|
|
async function loadFiles() {
|
|
try {
|
|
const data = await apiCall('list_client_files', { path: currentPath.value })
|
|
files.value = (data || []).sort((a: any, b: any) => a.isDir === b.isDir ? a.name.localeCompare(b.name) : a.isDir ? -1 : 1)
|
|
} catch (e) { console.error(e); files.value = [] }
|
|
}
|
|
|
|
function goUp() {
|
|
const parts = currentPath.value.split('/').filter(p => p)
|
|
parts.pop()
|
|
currentPath.value = '/' + parts.join('/')
|
|
loadFiles()
|
|
}
|
|
|
|
function selectFile(f: any) {
|
|
if (f.isDir) { currentPath.value = currentPath.value === '/' ? '/' + f.name : currentPath.value + '/' + f.name; loadFiles() }
|
|
else { selectedFile.value = f }
|
|
}
|
|
|
|
async function createFolder() {
|
|
const name = prompt('Folder name:')
|
|
if (!name) return
|
|
const path = currentPath.value === '/' ? '/' + name : currentPath.value + '/' + name
|
|
try { await apiCall('mkdir_client', { path }); loadFiles() } catch (e) { alert('Failed: ' + e) }
|
|
}
|
|
|
|
async function deleteSelected() {
|
|
if (!selectedFile.value || !confirm('Delete ' + selectedFile.value.name + '?')) return
|
|
const path = currentPath.value === '/' ? '/' + selectedFile.value.name : currentPath.value + '/' + selectedFile.value.name
|
|
try { await apiCall('rm_client', { path }); selectedFile.value = null; loadFiles() } catch (e) { alert('Failed: ' + e) }
|
|
}
|
|
|
|
function formatSize(n: number) { return n < 1024 ? n + 'B' : n < 1024*1024 ? (n/1024).toFixed(1) + 'KB' : (n/1024/1024).toFixed(1) + 'MB' }
|
|
|
|
onMounted(loadFiles)
|
|
</script>
|
|
|
|
<style scoped>
|
|
#ms-view-client { padding: 20px; }
|
|
.client-header { margin-bottom: 15px; }
|
|
.client-toolbar { display: flex; gap: 10px; align-items: center; margin-top: 10px; }
|
|
.client-toolbar button { padding: 6px 12px; border: 1px solid #ddd; background: white; cursor: pointer; border-radius: 4px; }
|
|
.client-toolbar button:disabled { opacity: 0.5; }
|
|
.current-path { margin-left: 20px; font-weight: bold; }
|
|
.file-table { width: 100%; border-collapse: collapse; }
|
|
.file-table th, .file-table td { padding: 8px; border: 1px solid #eee; }
|
|
.file-table tr.selected { background: #e3f2fd; }
|
|
.file-table tr:hover { background: #f5f5f5; cursor: pointer; }
|
|
</style>
|