前端: 按 Web Interface Guidelines 全面重做
组件: - Button: transition-all→明确属性列表, touch-action, aria-busy - Input: name/spellcheck/inputmode/aria-invalid/aria-describedby, focus-visible ring, label 关联, 暴露 focus() 供错误定位, required 标记 - Modal: Escape 关闭 + focus trap + 焦点归还, overscroll-behavior: contain, aria-labelledby, body 滚动锁, touch-action - 新增 Toast(aria-live polite) + pinia toast store 页面: - ConsoleLayout: skip link, <main> 语义标签, aside/nav aria-label, aria-current, 装饰 SVG aria-hidden, Intl 金额, translate=no 品牌/代码 - Dashboard: Intl.NumberFormat, 骨架屏 loading, aria-live 错误 - Keys: 字段级错误+焦点定位, toast 反馈(复制/吊销), name 属性 - Usage: select 加 label, 分页/筛选同步 URL(可深链), Intl 日期/金额, 表格 caption - Login/Register: 字段级校验+错误定位, spellcheck=false, inputmode, autocomplete - Landing: router-link 替换 href, aria-hidden, text-balance, scroll-mt - index.html: theme-color + color-scheme 验证: playwright 22 项断言全过, WCAG AA 对比度 9 组全过, 零控制台错误
This commit is contained in:
@@ -0,0 +1,27 @@
|
||||
// Toast 状态:轻量全局消息队列(操作反馈,aria-live 播报)
|
||||
import { defineStore } from 'pinia'
|
||||
|
||||
export interface Toast {
|
||||
id: number
|
||||
kind: 'success' | 'error' | 'info'
|
||||
message: string
|
||||
}
|
||||
|
||||
let seq = 0
|
||||
|
||||
export const useToastStore = defineStore('toast', {
|
||||
state: () => ({ items: [] as Toast[] }),
|
||||
actions: {
|
||||
push(kind: Toast['kind'], message: string) {
|
||||
const id = ++seq
|
||||
this.items.push({ id, kind, message })
|
||||
setTimeout(() => this.dismiss(id), 4000)
|
||||
},
|
||||
success(message: string) { this.push('success', message) },
|
||||
error(message: string) { this.push('error', message) },
|
||||
info(message: string) { this.push('info', message) },
|
||||
dismiss(id: number) {
|
||||
this.items = this.items.filter((t) => t.id !== id)
|
||||
},
|
||||
},
|
||||
})
|
||||
Reference in New Issue
Block a user