7.21 big change

This commit is contained in:
2026-07-21 17:57:04 +08:00
parent 4806ca6bc0
commit 6f6bde4a24
29 changed files with 2893 additions and 338 deletions
-18
View File
@@ -1,18 +0,0 @@
import { route } from "preact-router"
const Dashboard = () => {
return (
<div class="app-dashboard">
<div class="dashboard-sidebar">
<a href="/dashboard/datasets" onClick={(e) => { e.preventDefault(); route("/dashboard/datasets") }}></a>
<a href="/dashboard/testsets" onClick={(e) => { e.preventDefault(); route("/dashboard/testsets") }}></a>
<a href="/dashboard/logs" onClick={(e) => { e.preventDefault(); route("/dashboard/logs") }}></a>
</div>
<div class="dashboard-content">
{/* 子页面内容通过 Router 渲染到这里 */}
</div>
</div>
)
}
export default Dashboard
+9 -11
View File
@@ -1,11 +1,9 @@
export const Footer = () => {
return (
<footer class="app-footer">
<span>https://pytorch.org/</span>
<span>|</span>
<span>https://wails.io/</span>
<span>|</span>
<span>https://preactjs.com/</span>
</footer>
)
}
export const Footer = () => (
<footer class="app-footer">
<span>📩 xiadongliang88@163.com</span>
<span>|</span>
<span>📦 https://git.leonstack.com/owner</span>
<span>|</span>
<span>🌏 https://www.leonstack.com/</span>
</footer>
)
+64 -51
View File
@@ -1,82 +1,95 @@
import { useState, useEffect } from 'preact/hooks'
import { message } from '../utils/toast'
import Pagination from './Pagination'
const formatDate = (timestamp: number) => {
const date = new Date(timestamp * 1000)
return date.toLocaleString('zh-CN', {
year: 'numeric',
month: '2-digit',
day: '2-digit',
hour: '2-digit',
minute: '2-digit',
second: '2-digit',
})
}
const historyList = [
{
id: 1,
breeds: '英短&1212',
desc: 'The Maine Coon is a large, friendly cat breed known for its tufted ears.',
img: '../../',
date: 'Jan 15, 2024',
},
{
id: 2,
breeds: '英短&fdfd',
desc: 'The Maine Coon is a large, friendly cat breed known for its tufted ears.',
img: '../../',
date: 'Jan 15, 2024',
},
{
id: 3,
breeds: '英短&11111',
desc: 'The Maine Coon is a large, friendly cat breed known for its tufted ears.',
img: '../../',
date: 'Jan 15, 2024',
},
{
id: 4,
breeds: '英短&4545',
desc: 'The Maine Coon is a large, friendly cat breed known for its tufted ears.',
img: '../../',
date: 'Jan 15, 2024',
},
{
id: 5,
breeds: '英短&fff',
desc: 'The Maine Coon is a large, friendly cat breed known for its tufted ears.',
img: '../../',
date: 'Jan 15, 2024',
},
]
interface IHistoryItem {
id: number
img: string
breed: number
date: number
name: string
brief: string
}
const History = () => {
const [page, setPage] = useState<number>(1)
const pageSize = 5
const [total, setTotal] = useState<number>(50)
const [historyList, setHistoryList] = useState<IHistoryItem[]>([])
useEffect(() => {
if (!(window as any).go?.main?.App?.GetHistory) {
message.error('Wails runtime not ready')
return
}
fetchData(page)
}, [])
const handlePageChange = (page: number) => {
// setPage(page)
// loadTranscript(currentNav, currentOpt, page).then(res => {
// if (res && res.code === 0) {
// setData(res.data.data)
// setTotal(res.data.total)
// }
// }).catch(e => message.error(e.toString()))
const fetchData = async(page: number) => {
const result = await (window as any).go.main.App.GetHistory(page, pageSize)
if (result.code === 0) {
setHistoryList(result.data.list)
setTotal(result.data.total)
} else if (result.code === 1) {
message.error(result.message)
}
}
const handlePageChange = (page: number) => {
setPage(page)
fetchData(page)
}
const handleDelete = async(id: number) => {
const result = await (window as any).go.main.App.DeleteOneHistory(id)
if (result.code === 0) {
message.success('删除成功')
fetchData(page)
} else if (result.code === 1) {
message.error(result.message)
}
}
return (
<div class="app-history">
{historyList.map((item) =>
<div class="history-clear">
<a></a>
</div>
{historyList.map((item: IHistoryItem) =>
<div key={item.id} class="history-card">
<div class="card-left">
<img src="../assets/images/0012.jpg" />
</div>
<div class="card-right">
<div class="right-top">
<h3>{item.breeds}</h3>
<span>{item.date}</span>
<h3>{item.name}</h3>
<div class="card-actions">
<span>{formatDate(item.date)}</span>
<button onClick={() => handleDelete(item.id)} title="删除">
×
</button>
</div>
</div>
<div class="right-overview">
{item.desc}
{item.brief}
</div>
</div>
</div>)
}
<div class="history-pagination">
<Pagination page={page} pagesize={5} total={total} onChange={handlePageChange} />
<Pagination page={page} pagesize={pageSize} total={total} onChange={handlePageChange} />
</div>
</div>
)
+36 -48
View File
@@ -1,16 +1,22 @@
import { useState, useEffect, useRef } from 'preact/hooks'
import { useState, useRef } from 'preact/hooks'
import { message } from '../utils/toast'
interface IDetectResult {
id: number
code: string
name: number
brief: string
confidence_level: number
}
const Main = () => {
const fileInputRef = useRef<HTMLInputElement>(null)
const [fileName, setFileName] = useState<string>('')
const [fileSrc, setFileSrc] = useState<string>('')
const [step, setStep] = useState<number>(0)
const [detectResult, setDetectResult] = useState<IDetectResult | null>(null)
const [step, setStep] = useState(0)
const handleUploadClick = () => {
fileInputRef.current?.click()
}
const handleUploadClick = () => fileInputRef.current?.click()
const handleFileChange = (e: Event) => {
const target = e.target as HTMLInputElement
@@ -56,13 +62,20 @@ const Main = () => {
const handleDetect = () => {
setStep(2)
setTimeout(() => {
setStep(3)
setTimeout(async() => {
const result = await (window as any).go.main.App.Detect(fileName)
if (result.code === 0) {
setDetectResult(result.data)
setStep(3)
} else if (result.code === 1) {
message.error(result.message)
}
}, 1000)
}
const handleTryOther = () => {
setStep(0)
setDetectResult(null)
resetUpload()
}
@@ -74,9 +87,14 @@ const Main = () => {
<span></span><span></span>
</h1>
<p>
AI不仅认出它<span></span>
AI认出它<span></span>
</p>
<i></i>
<i>
<svg viewBox="0 0 24 24" fill="currentColor" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<polygon points="13 2 3 14 12 14 11 22 21 10 12 10 13 2"/>
</svg>
<span></span>
</i>
</div>
<div class={`upload${!(step == 0 || step == 1 || step == 2) ? ' hidden' : ''}`}>
<div
@@ -125,7 +143,7 @@ const Main = () => {
}
</div>
{fileSrc.length > 0 && step == 1 ?
<button id="detectBtn" onClick={handleDetect}>
<button onClick={handleDetect}>
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<path
stroke-linecap="round"
@@ -142,60 +160,30 @@ const Main = () => {
<svg viewBox="0 0 24 24" fill="currentColor">
<path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm-2 15l-5-5 1.41-1.41L10 14.17l7.59-7.59L19 8l-9 9z" />
</svg>
<h2></h2>
<h2></h2>
</div>
<div class="result-main">
<img />
<div class="result-word">
<div>
<h3></h3>
<h3>{detectResult?.name}</h3>
<div>
<div class="probability-bar">
<div />
</div>
<span> 78%</span>
<span> {detectResult ? detectResult.confidence_level * 100 + '%' : ''}</span>
</div>
</div>
<h4></h4>
<p> </p>
<p>{detectResult?.brief}</p>
</div>
</div>
<button onClick={handleTryOther}>
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<path stroke-linecap="round" stroke-linejoin="round" d="M16.023 9.348h4.992v-.001M2.985 19.644v-4.992m0 0h4.992m-4.993 0l3.181 3.183a8.25 8.25 0 0013.803-3.7M4.031 9.865a8.25 8.25 0 0113.803-3.7l3.181 3.182m0-4.991v4.99" />
</svg>
</button>
</div>
{/* <div id="featuresSection" class="grid grid-cols-1 md:grid-cols-3 gap-6 mt-16">
<div class="bg-white rounded-2xl border border-border p-6 text-center cursor-pointer hover:shadow-lg transition-shadow duration-200">
<div class="w-14 h-14 mx-auto mb-4 bg-primary/10 rounded-2xl flex items-center justify-center">
<svg class="w-7 h-7 text-primary" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<path stroke-linecap="round" stroke-linejoin="round" d="M3.75 13.5l10.5-11.25L12 10.5h8.25L9.75 21.75 12 13.5H3.75z" />
</svg>
</div>
<h3 class="font-heading font-semibold text-lg text-text mb-2">Lightning Fast</h3>
<p class="text-text/60 text-sm">Get results in under 3 seconds with our optimized AI model</p>
</div>
<div class="bg-white rounded-2xl border border-border p-6 text-center cursor-pointer hover:shadow-lg transition-shadow duration-200">
<div class="w-14 h-14 mx-auto mb-4 bg-cta/10 rounded-2xl flex items-center justify-center">
<svg class="w-7 h-7 text-cta" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<path stroke-linecap="round" stroke-linejoin="round" d="M9 6.75V15m6-6v8.25m.503 3.498l4.875-2.437c.381-.19.622-.58.622-1.006V4.82c0-.836-.88-1.38-1.628-1.006l-3.869 1.934c-.317.159-.69.159-1.006 0L9.503 3.252a1.125 1.125 0 00-1.006 0L3.622 5.689C3.24 5.88 3 6.27 3 6.695V19.18c0 .836.88 1.38 1.628 1.006l3.869-1.934c.317-.159.69-.159 1.006 0l4.994 2.497c.317.158.69.158 1.006 0z" />
</svg>
</div>
<h3 class="font-heading font-semibold text-lg text-text mb-2">98% Accuracy</h3>
<p class="text-text/60 text-sm">Trained on 50,000+ cat images across 60+ breeds</p>
</div>
<div class="bg-white rounded-2xl border border-border p-6 text-center cursor-pointer hover:shadow-lg transition-shadow duration-200">
<div class="w-14 h-14 mx-auto mb-4 bg-green-100 rounded-2xl flex items-center justify-center">
<svg class="w-7 h-7 text-green-600" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<path stroke-linecap="round" stroke-linejoin="round" d="M12 21a9.004 9.004 0 008.716-6.747M12 21a9.004 9.004 0 01-8.716-6.747M12 21c2.485 0 4.5-4.03 4.5-9S14.485 3 12 3m0 18c-2.485 0-4.5-4.03-4.5-9S9.515 3 12 3m0 0a8.997 8.997 0 017.843 4.582M12 3a8.997 8.997 0 00-7.843 4.582m15.686 0A11.953 11.953 0 0112 10.5c-2.998 0-5.74-1.1-7.843-2.918m15.686 0A8.959 8.959 0 0121 12c0 .778-.099 1.533-.284 2.253m0 0A17.919 17.919 0 0112 16.5c-3.162 0-6.133-.815-8.716-2.247m0 0A9.015 9.015 0 013 12c0-1.605.42-3.113 1.157-4.418" />
</svg>
</div>
<h3 class="font-heading font-semibold text-lg text-text mb-2">Always Free</h3>
<p class="text-text/60 text-sm">No hidden fees, no subscriptions. Detect away!</p>
</div>
</div> */}
</div>
</main>
)
+3 -4
View File
@@ -1,7 +1,7 @@
export const Navbar = () => {
const svgPath = "M12 10c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2zm-4.5 4c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2zm9 0c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2zm-9.5 3.5c-1.38 0-2.5 1.12-2.5 2.5s1.12 2.5 2.5 2.5 2.5-1.12 2.5-2.5-1.12-2.5-2.5-2.5zm11 0c-1.38 0-2.5 1.12-2.5 2.5s1.12 2.5 2.5 2.5 2.5-1.12 2.5-2.5-1.12-2.5-2.5-2.5zM12 18c-2.21 0-4 1.79-4 4h8c0-2.21-1.79-4-4-4z"
const handleClick = () => window.open('https://git.leonstack.com/Leon/Collage-Images', '_blank')
const handleClick = () => window.open('https://git.leonstack.com/owner/Collage-Images', '_blank')
return (
<nav class="app-navbar animate-fade-in">
@@ -10,13 +10,12 @@ export const Navbar = () => {
<svg class="icon" viewBox="0 0 24 24" fill="currentColor">
<path d={svgPath} />
</svg>
<span class="font-heading font-semibold text-xl text-text">miao</span>
<span class="font-heading font-semibold text-xl text-text"></span>
</div>
<div class="container-right">
<a href="/"></a>
<a href="/history"></a>
<a href="/dashboard"></a>
<button onClick={handleClick}></button>
<button onClick={handleClick}></button>
</div>
</div>
</nav>
+8 -5
View File
@@ -45,14 +45,17 @@ const Pagination = ({
const handleEnterPress = (e: KeyboardEvent) => {
if (e.key === 'Enter') {
if (parseInt(value) <= seqNums.length && parseInt(value) > 0) {
handleChangeNum(parseInt(value))
} else if (parseInt(value) >= seqNums.length) {
const target = e.target as HTMLInputElement
const page = parseInt(target.value)
if (page >= 1 && page <= seqNums.length) {
handleChangeNum(page)
onChange(page)
} else if (page > seqNums.length) {
handleChangeNum(seqNums.length)
} else if (parseInt(value) < seqNums.length) {
handleChangeNum(1)
onChange(seqNums.length)
} else {
handleChangeNum(1)
onChange(1)
}
}
}
@@ -1,7 +0,0 @@
const TestsetManagement = () => {
return (
<div></div>
)
}
export default TestsetManagement
@@ -1,7 +0,0 @@
const TrainsetManagement = () => {
return (
<div></div>
)
}
export default TrainsetManagement