Init Repo

This commit is contained in:
2026-02-28 03:22:04 +08:00
commit de59b57ee7
883 changed files with 156857 additions and 0 deletions
+363
View File
@@ -0,0 +1,363 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Shot Table View Test</title>
<style>
body {
font-family: Arial, sans-serif;
max-width: 1200px;
margin: 20px auto;
padding: 20px;
}
.test-section {
margin-bottom: 30px;
padding: 20px;
border: 1px solid #ddd;
border-radius: 8px;
}
.test-section h2 {
margin-top: 0;
color: #333;
}
.success {
color: green;
font-weight: bold;
}
.error {
color: red;
font-weight: bold;
}
.info {
color: blue;
}
pre {
background: #f5f5f5;
padding: 10px;
border-radius: 4px;
overflow-x: auto;
}
button {
background: #007bff;
color: white;
border: none;
padding: 10px 20px;
border-radius: 4px;
cursor: pointer;
margin-right: 10px;
}
button:hover {
background: #0056b3;
}
.result {
margin-top: 10px;
padding: 10px;
background: #f9f9f9;
border-left: 4px solid #007bff;
}
</style>
</head>
<body>
<h1>Shot Table View - Implementation Test</h1>
<p class="info">This page tests the shot table view implementation with task status display.</p>
<div class="test-section">
<h2>Test 1: Backend API - Get Shots with Task Status</h2>
<button onclick="testGetShots()">Run Test</button>
<div id="test1-result" class="result" style="display:none;"></div>
</div>
<div class="test-section">
<h2>Test 2: Backend API - Filter by Task Status</h2>
<button onclick="testFilterByTaskStatus()">Run Test</button>
<div id="test2-result" class="result" style="display:none;"></div>
</div>
<div class="test-section">
<h2>Test 3: Backend API - Sort by Task Status</h2>
<button onclick="testSortByTaskStatus()">Run Test</button>
<div id="test3-result" class="result" style="display:none;"></div>
</div>
<div class="test-section">
<h2>Test 4: Backend API - Sort by Name</h2>
<button onclick="testSortByName()">Run Test</button>
<div id="test4-result" class="result" style="display:none;"></div>
</div>
<div class="test-section">
<h2>Test 5: Custom Task Types Support</h2>
<button onclick="testCustomTaskTypes()">Run Test</button>
<div id="test5-result" class="result" style="display:none;"></div>
</div>
<script>
const API_BASE = 'http://localhost:8000';
let authToken = null;
// Login first
async function login() {
if (authToken) return authToken;
try {
const response = await fetch(`${API_BASE}/auth/login`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
email: 'admin@vfx.com',
password: 'admin123'
})
});
if (!response.ok) {
throw new Error('Login failed');
}
const data = await response.json();
authToken = data.access_token;
return authToken;
} catch (error) {
console.error('Login error:', error);
throw error;
}
}
async function testGetShots() {
const resultDiv = document.getElementById('test1-result');
resultDiv.style.display = 'block';
resultDiv.innerHTML = '<p>Running test...</p>';
try {
const token = await login();
const response = await fetch(`${API_BASE}/shots/`, {
headers: {
'Authorization': `Bearer ${token}`
}
});
if (!response.ok) {
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
}
const shots = await response.json();
let html = `<p class="success">✓ Test Passed</p>`;
html += `<p>Found ${shots.length} shots</p>`;
if (shots.length > 0) {
const shot = shots[0];
html += `<p><strong>First Shot:</strong></p>`;
html += `<pre>${JSON.stringify({
id: shot.id,
name: shot.name,
episode_id: shot.episode_id,
frame_range: `${shot.frame_start}-${shot.frame_end}`,
task_count: shot.task_count,
task_status: shot.task_status,
task_details_count: shot.task_details?.length || 0
}, null, 2)}</pre>`;
if (shot.task_status) {
html += `<p class="success">✓ Task status included</p>`;
} else {
html += `<p class="error">✗ Task status missing</p>`;
}
if (shot.task_details && shot.task_details.length > 0) {
html += `<p class="success">✓ Task details included (${shot.task_details.length} tasks)</p>`;
} else {
html += `<p class="error">✗ Task details missing</p>`;
}
}
resultDiv.innerHTML = html;
} catch (error) {
resultDiv.innerHTML = `<p class="error">✗ Test Failed: ${error.message}</p>`;
}
}
async function testFilterByTaskStatus() {
const resultDiv = document.getElementById('test2-result');
resultDiv.style.display = 'block';
resultDiv.innerHTML = '<p>Running test...</p>';
try {
const token = await login();
const response = await fetch(`${API_BASE}/shots/?task_status_filter=layout:not_started`, {
headers: {
'Authorization': `Bearer ${token}`
}
});
if (!response.ok) {
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
}
const shots = await response.json();
let html = `<p class="success">✓ Test Passed</p>`;
html += `<p>Found ${shots.length} shots with layout task not started</p>`;
if (shots.length > 0) {
const allMatch = shots.every(shot =>
shot.task_status && shot.task_status.layout === 'not_started'
);
if (allMatch) {
html += `<p class="success">✓ All shots match filter criteria</p>`;
} else {
html += `<p class="error">✗ Some shots don't match filter</p>`;
}
}
resultDiv.innerHTML = html;
} catch (error) {
resultDiv.innerHTML = `<p class="error">✗ Test Failed: ${error.message}</p>`;
}
}
async function testSortByTaskStatus() {
const resultDiv = document.getElementById('test3-result');
resultDiv.style.display = 'block';
resultDiv.innerHTML = '<p>Running test...</p>';
try {
const token = await login();
const response = await fetch(`${API_BASE}/shots/?sort_by=layout_status&sort_direction=asc`, {
headers: {
'Authorization': `Bearer ${token}`
}
});
if (!response.ok) {
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
}
const shots = await response.json();
let html = `<p class="success">✓ Test Passed</p>`;
html += `<p>Sorted ${shots.length} shots by layout task status</p>`;
if (shots.length > 0) {
html += `<p><strong>First 5 shots (sorted by layout status):</strong></p>`;
html += '<ul>';
shots.slice(0, 5).forEach(shot => {
html += `<li>${shot.name}: ${shot.task_status?.layout || 'N/A'}</li>`;
});
html += '</ul>';
}
resultDiv.innerHTML = html;
} catch (error) {
resultDiv.innerHTML = `<p class="error">✗ Test Failed: ${error.message}</p>`;
}
}
async function testSortByName() {
const resultDiv = document.getElementById('test4-result');
resultDiv.style.display = 'block';
resultDiv.innerHTML = '<p>Running test...</p>';
try {
const token = await login();
const response = await fetch(`${API_BASE}/shots/?sort_by=name&sort_direction=asc`, {
headers: {
'Authorization': `Bearer ${token}`
}
});
if (!response.ok) {
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
}
const shots = await response.json();
let html = `<p class="success">✓ Test Passed</p>`;
html += `<p>Sorted ${shots.length} shots by name</p>`;
if (shots.length > 0) {
html += `<p><strong>First 5 shots (sorted by name):</strong></p>`;
html += '<ul>';
shots.slice(0, 5).forEach(shot => {
html += `<li>${shot.name}</li>`;
});
html += '</ul>';
// Check if sorted
const names = shots.map(s => s.name);
const sortedNames = [...names].sort();
const isSorted = JSON.stringify(names) === JSON.stringify(sortedNames);
if (isSorted) {
html += `<p class="success">✓ Shots are correctly sorted</p>`;
} else {
html += `<p class="error">✗ Shots are not correctly sorted</p>`;
}
}
resultDiv.innerHTML = html;
} catch (error) {
resultDiv.innerHTML = `<p class="error">✗ Test Failed: ${error.message}</p>`;
}
}
async function testCustomTaskTypes() {
const resultDiv = document.getElementById('test5-result');
resultDiv.style.display = 'block';
resultDiv.innerHTML = '<p>Running test...</p>';
try {
const token = await login();
const response = await fetch(`${API_BASE}/shots/`, {
headers: {
'Authorization': `Bearer ${token}`
}
});
if (!response.ok) {
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
}
const shots = await response.json();
let html = `<p class="success">✓ Test Passed</p>`;
if (shots.length > 0) {
const shot = shots[0];
const taskTypes = Object.keys(shot.task_status || {});
html += `<p>Found ${taskTypes.length} task types in shot data</p>`;
html += `<p><strong>Task Types:</strong></p>`;
html += '<ul>';
taskTypes.forEach(type => {
html += `<li>${type}</li>`;
});
html += '</ul>';
// Check for custom task types (non-standard)
const standardTypes = ['layout', 'animation', 'simulation', 'lighting', 'compositing'];
const customTypes = taskTypes.filter(t => !standardTypes.includes(t));
if (customTypes.length > 0) {
html += `<p class="success">✓ Custom task types found: ${customTypes.join(', ')}</p>`;
} else {
html += `<p class="info"> No custom task types in this project (only standard types)</p>`;
}
}
resultDiv.innerHTML = html;
} catch (error) {
resultDiv.innerHTML = `<p class="error">✗ Test Failed: ${error.message}</p>`;
}
}
// Auto-run first test on page load
window.addEventListener('load', () => {
console.log('Page loaded. Ready to run tests.');
});
</script>
</body>
</html>