@templmf/temp-solf-lmf 0.0.55 → 0.0.56

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (87) hide show
  1. package/package.json +1 -1
  2. package//345/242/236/351/207/217/351/234/200/346/261/202prompt +72 -0
  3. package/guanwang/README.md +0 -95
  4. package/guanwang/docs/changelog.md +0 -145
  5. package/guanwang/docs/doc-maintenance.md +0 -229
  6. package/guanwang/docs/product.md +0 -181
  7. package/guanwang/docs/test-cases.md +0 -395
  8. package/guanwang/docs/usage.md +0 -291
  9. package/guanwang/env.example +0 -27
  10. package/guanwang/index.html +0 -13
  11. package/guanwang/package-lock.json +0 -3825
  12. package/guanwang/package.json +0 -32
  13. package/guanwang/public/favicon.svg +0 -4
  14. package/guanwang/public/react-runtime/babel.min.js +0 -4
  15. package/guanwang/public/react-runtime/react-dom.min.js +0 -267
  16. package/guanwang/public/react-runtime/react.min.js +0 -31
  17. package/guanwang/public/vue-repl-assets/compiler-sfc.esm-browser.js +0 -50795
  18. package/guanwang/public/vue-repl-assets/runtime-dom.esm-browser.js +0 -12758
  19. package/guanwang/public/vue-repl-assets/server-renderer.esm-browser.js +0 -8600
  20. package/guanwang/public/vue-repl-assets/vue.esm-browser.js +0 -18672
  21. package/guanwang/src/App.vue +0 -61
  22. package/guanwang/src/chat-sdk/core/components/ChatBox.vue +0 -305
  23. package/guanwang/src/chat-sdk/core/components/ChatSidebar.vue +0 -84
  24. package/guanwang/src/chat-sdk/core/components/InputBar.vue +0 -354
  25. package/guanwang/src/chat-sdk/core/components/MessageBubble.vue +0 -703
  26. package/guanwang/src/chat-sdk/core/useTheme.js +0 -31
  27. package/guanwang/src/chat-sdk/features/artifact/ArtifactCard.vue +0 -172
  28. package/guanwang/src/chat-sdk/features/artifact/ArtifactPanel.vue +0 -963
  29. package/guanwang/src/chat-sdk/features/artifact/index.js +0 -13
  30. package/guanwang/src/chat-sdk/features/artifact/useArtifactStore.js +0 -275
  31. package/guanwang/src/chat-sdk/features/codepreview/CodePreview.vue +0 -523
  32. package/guanwang/src/chat-sdk/features/codepreview/index.js +0 -7
  33. package/guanwang/src/chat-sdk/features/markdown/index.js +0 -13
  34. package/guanwang/src/chat-sdk/features/markdown/useMarkdown.js +0 -724
  35. package/guanwang/src/chat-sdk/features/mermaid/MermaidZoom.vue +0 -254
  36. package/guanwang/src/chat-sdk/features/upload/FileAttachment.vue +0 -142
  37. package/guanwang/src/chat-sdk/features/upload/index.js +0 -17
  38. package/guanwang/src/chat-sdk/features/upload/useFileHandler.js +0 -336
  39. package/guanwang/src/chat-sdk/headless/api/adapters/openai.js +0 -76
  40. package/guanwang/src/chat-sdk/headless/api/chatApi.js +0 -126
  41. package/guanwang/src/chat-sdk/headless/buildSystemPrompt.js +0 -351
  42. package/guanwang/src/chat-sdk/headless/index.js +0 -15
  43. package/guanwang/src/chat-sdk/headless/useChat.js +0 -77
  44. package/guanwang/src/chat-sdk/headless/useChatDB.js +0 -147
  45. package/guanwang/src/chat-sdk/headless/useChatStore.js +0 -529
  46. package/guanwang/src/chat-sdk/index.js +0 -79
  47. package/guanwang/src/chat-sdk/modes/architect.js +0 -27
  48. package/guanwang/src/chat-sdk/modes/ask.js +0 -26
  49. package/guanwang/src/chat-sdk/modes/code.js +0 -25
  50. package/guanwang/src/chat-sdk/modes/index.js +0 -36
  51. package/guanwang/src/chat-sdk/modes/requirements.js +0 -175
  52. package/guanwang/src/chat-sdk/settings/SettingsPanel.vue +0 -170
  53. package/guanwang/src/chat-sdk/settings/index.js +0 -9
  54. package/guanwang/src/chat-sdk/settings/useSettings.js +0 -122
  55. package/guanwang/src/chat-sdk/tools/defaults.js +0 -89
  56. package/guanwang/src/chat-sdk/tools/index.js +0 -16
  57. package/guanwang/src/chat-sdk/tools/parser.js +0 -116
  58. package/guanwang/src/components/CustomCursor.vue +0 -69
  59. package/guanwang/src/components/Footer.vue +0 -24
  60. package/guanwang/src/components/LoginModal.vue +0 -109
  61. package/guanwang/src/components/Navbar.vue +0 -193
  62. package/guanwang/src/components/ThemeToggle.vue +0 -25
  63. package/guanwang/src/composables/useArtifactStore.js +0 -253
  64. package/guanwang/src/composables/useAuth.js +0 -88
  65. package/guanwang/src/composables/useChatDB.js +0 -147
  66. package/guanwang/src/composables/useCountUp.js +0 -24
  67. package/guanwang/src/composables/useFileHandler.js +0 -345
  68. package/guanwang/src/composables/useTheme.js +0 -31
  69. package/guanwang/src/config/api.js +0 -71
  70. package/guanwang/src/main.js +0 -23
  71. package/guanwang/src/router/index.js +0 -23
  72. package/guanwang/src/services/authApi.js +0 -27
  73. package/guanwang/src/services/chatApi.js +0 -66
  74. package/guanwang/src/styles/global.css +0 -478
  75. package/guanwang/src/tracker/analyze.js +0 -73
  76. package/guanwang/src/tracker/config.js +0 -82
  77. package/guanwang/src/tracker/index.js +0 -18
  78. package/guanwang/src/tracker/service.js +0 -102
  79. package/guanwang/src/tracker/useChatTracker.js +0 -179
  80. package/guanwang/src/tracker/useTracker.js +0 -45
  81. package/guanwang/src/views/ChatView.vue +0 -65
  82. package/guanwang/src/views/HomeView.vue +0 -156
  83. package/guanwang/src/views/MarketView.vue +0 -143
  84. package/guanwang/src/views/PracticesView.vue +0 -190
  85. package/guanwang/src/views/SkillsView.vue +0 -129
  86. package/guanwang/temp +0 -19
  87. package/guanwang/vite.config.js +0 -6
@@ -1,253 +0,0 @@
1
- /**
2
- * useArtifactStore.js v2
3
- *
4
- * 对标 Claude Artifacts 体验:
5
- * - 每个代码块 = 一个 Artifact(有文件名、语言、内容)
6
- * - 右侧面板顶部 tab 栏展示当前会话所有 artifact,可切换
7
- * - 聊天气泡里只显示轻量文件卡片
8
- * - 流式生成时实时更新右侧面板内容
9
- */
10
- import { ref, computed, provide, inject, shallowRef } from 'vue'
11
-
12
- const STORE_KEY = Symbol('artifact-store')
13
-
14
- // ── 常量 ─────────────────────────────────────────────────────────
15
- export const ARTIFACT_MIN_LINES = 6
16
-
17
- export const ARTIFACT_LANGS = new Set([
18
- 'vue','html','jsx','tsx','mermaid','svg',
19
- ])
20
-
21
- export const LANG_LABEL = {
22
- vue:'Vue SFC', html:'HTML', jsx:'React JSX', tsx:'React TSX',
23
- javascript:'JavaScript', js:'JavaScript', typescript:'TypeScript', ts:'TypeScript',
24
- python:'Python', go:'Go', rust:'Rust', java:'Java', kotlin:'Kotlin', swift:'Swift',
25
- css:'CSS', scss:'SCSS', sass:'SASS', less:'LESS',
26
- sql:'SQL', graphql:'GraphQL',
27
- bash:'Shell', sh:'Shell', shell:'Shell',
28
- json:'JSON', yaml:'YAML', yml:'YAML', toml:'TOML', xml:'XML',
29
- markdown:'Markdown', md:'Markdown',
30
- mermaid:'Mermaid 图', svg:'SVG', math:'Math', latex:'LaTeX',
31
- }
32
-
33
- export const LANG_EXT = {
34
- vue:'vue', html:'html', jsx:'jsx', tsx:'tsx',
35
- javascript:'js', js:'js', typescript:'ts', ts:'ts',
36
- python:'py', go:'go', rust:'rs', java:'java', kotlin:'kt', swift:'swift',
37
- css:'css', scss:'scss', sass:'sass', less:'less',
38
- sql:'sql', graphql:'graphql', bash:'sh', sh:'sh', shell:'sh',
39
- json:'json', yaml:'yaml', yml:'yaml', toml:'toml', xml:'xml',
40
- markdown:'md', md:'md', mermaid:'mmd', svg:'svg', math:'tex', latex:'tex',
41
- }
42
-
43
- // ── 判断是否应成为 Artifact(兜底规则,优先级低于 AI 的 [artifact] 显式标记)──
44
- // 仅当代码行数 >= 50 且语言有意义时自动路由到面板
45
- export function shouldBeArtifact(lang, code) {
46
- if (!code?.trim()) return false
47
- if (!lang) return false
48
- return code.split('\n').length >= 50
49
- }
50
-
51
- // ── 推断文件名 ────────────────────────────────────────────────────
52
- export function inferFileName(lang, code, index) {
53
- const ext = LANG_EXT[lang] || 'txt'
54
-
55
- if (lang === 'vue') {
56
- const m = code.match(/(?:name|defineOptions\(\{[^}]*name):\s*['"]([^'"]+)['"]/)
57
- || code.match(/\/\/\s*([A-Z][a-zA-Z0-9]+)\.vue/)
58
- if (m?.[1]) return `${m[1]}.vue`
59
- return `Component${index > 1 ? index : ''}.vue`
60
- }
61
- if (lang === 'html') {
62
- const m = code.match(/<title>([^<]{1,40})<\/title>/)
63
- if (m?.[1]) return `${m[1].trim().replace(/\s+/g,'-').toLowerCase()}.html`
64
- return `index.html`
65
- }
66
- if (lang === 'jsx' || lang === 'tsx') {
67
- const m = code.match(/(?:function|const|class)\s+([A-Z][a-zA-Z0-9]+)/)
68
- if (m?.[1]) return `${m[1]}.${ext}`
69
- return `App.${ext}`
70
- }
71
- if (lang === 'mermaid') {
72
- const first = code.trim().split('\n')[0]?.trim().replace(/\s+.*/,'').toLowerCase()
73
- return first ? `${first}.mmd` : `diagram.mmd`
74
- }
75
- if (lang === 'python') {
76
- const m = code.match(/^#\s*(.+)/m) || code.match(/def\s+(\w+)/)
77
- if (m?.[1]) return `${m[1].trim().replace(/\s+/g,'_').toLowerCase()}.py`
78
- return `script.py`
79
- }
80
- if (lang === 'json') {
81
- try {
82
- const obj = JSON.parse(code)
83
- if (obj.name) return `${obj.name}.json`
84
- } catch {}
85
- return `data.json`
86
- }
87
-
88
- return `${lang === 'javascript' || lang === 'js' ? 'script' : 'code'}-${index}.${ext}`
89
- }
90
-
91
- // ── Store 工厂 ───────────────────────────────────────────────────
92
- export function createArtifactStore() {
93
- // 当前激活 artifact 的 code 独立 ref,专门用于外部精确订阅
94
- // 因为 artifactsMap 是 shallowRef,item 对象内部属性变化无法被 computed/watch 自动追踪
95
- const activeCode = ref('')
96
-
97
- // 正在 streaming 的 artifact id 集合,用 ref 包装保证 ArtifactCard 能响应式追踪
98
- const streamingIds = ref(new Set())
99
-
100
- // 同步 activeCode 到当前激活 artifact 的 code
101
- function syncActiveCode() {
102
- const art = artifactsMap.value.get(activeId.value)
103
- || [...artifactsMap.value.values()].at(-1)
104
- || null
105
- activeCode.value = art?.code ?? ''
106
- }
107
-
108
- // 所有 artifact,shallowRef 避免深层响应式
109
- const artifactsMap = shallowRef(new Map())
110
-
111
- // 当前激活的 artifact id
112
- const activeId = ref(null)
113
-
114
- // 面板是否可见(有任何 artifact 就显示)
115
- const panelVisible = computed(() => artifactsMap.value.size > 0)
116
-
117
- // 所有 artifact 列表(按注册顺序,用于 tab 栏)
118
- const allArtifacts = computed(() => {
119
- return [...artifactsMap.value.values()].sort((a, b) => a._seq - b._seq)
120
- })
121
-
122
- // 当前激活的 artifact
123
- const activeArtifact = computed(() =>
124
- artifactsMap.value.get(activeId.value) || allArtifacts.value[allArtifacts.value.length - 1] || null
125
- )
126
-
127
- // 按 messageId 分组(MessageBubble 用)
128
- const byMessage = computed(() => {
129
- const map = new Map()
130
- for (const art of allArtifacts.value) {
131
- const list = map.get(art.messageId) || []
132
- list.push(art)
133
- map.set(art.messageId, list)
134
- }
135
- return map
136
- })
137
-
138
- let _seq = 0
139
-
140
- function preRegister({ messageId, lang, index }) {
141
- const id = `art-${messageId}-${index}`
142
- if (artifactsMap.value.has(id)) return id
143
- const label = LANG_LABEL[lang] || lang?.toUpperCase() || 'Code'
144
- const ext = LANG_EXT[lang] || 'txt'
145
- const fileName = `generating.${ext}`
146
- const item = {
147
- id, messageId, lang, code: '', fileName, label, lines: 0,
148
- _seq: ++_seq, streaming: true,
149
- }
150
- const next = new Map(artifactsMap.value)
151
- next.set(id, item)
152
- artifactsMap.value = next
153
- activeId.value = id
154
- syncActiveCode()
155
- return id
156
- }
157
-
158
- function register({ messageId, lang, code, index }) {
159
- const id = `art-${messageId}-${index}`
160
- const label = LANG_LABEL[lang] || lang?.toUpperCase() || 'Code'
161
- const lines = code.split('\n').length
162
- const inferred = inferFileName(lang, code, index)
163
- const fileName = (inferred && !inferred.startsWith('generating')) ? inferred : `code-${index}.${LANG_EXT[lang] || 'txt'}`
164
-
165
- const existing = artifactsMap.value.get(id)
166
- const next = new Map(artifactsMap.value)
167
- // 始终替换为新对象,确保引用变化
168
- next.set(id, existing
169
- ? { ...existing, code, lines, fileName: (inferred && !inferred.startsWith('generating')) ? inferred : existing.fileName }
170
- : { id, messageId, lang, code, fileName, label, lines, _seq: ++_seq, streaming: false }
171
- )
172
- artifactsMap.value = next
173
- activeId.value = id
174
- syncActiveCode()
175
- return id
176
- }
177
-
178
- function updateCode(artifactId, code) {
179
- const item = artifactsMap.value.get(artifactId)
180
- if (!item) return
181
- const inferred = inferFileName(item.lang, code, item._seq)
182
- const next = new Map(artifactsMap.value)
183
- // 替换为新对象,确保引用变化能触发 ArtifactCard 重渲染
184
- next.set(artifactId, {
185
- ...item,
186
- code,
187
- lines: code.split('\n').length,
188
- streaming: true,
189
- fileName: (inferred && !inferred.startsWith('generating')) ? inferred : item.fileName,
190
- })
191
- artifactsMap.value = next
192
- syncActiveCode()
193
- }
194
-
195
- function markDone(artifactId) {
196
- const item = artifactsMap.value.get(artifactId)
197
- console.log('[markDone] item found:', !!item, 'current streaming:', item?.streaming)
198
- if (!item) return
199
- const next = new Map(artifactsMap.value)
200
- const newItem = { ...item, streaming: false }
201
- next.set(artifactId, newItem)
202
- artifactsMap.value = next
203
- console.log('[markDone] done, newItem.streaming:', newItem.streaming)
204
- syncActiveCode()
205
- }
206
-
207
- function open(id) {
208
- activeId.value = id
209
- syncActiveCode()
210
- }
211
-
212
- function close() {
213
- // 不关闭面板,只清空 activeId(面板由 panelVisible 控制,有 artifact 就显示)
214
- activeId.value = null
215
- }
216
-
217
- function clearSession() {
218
- artifactsMap.value = new Map()
219
- activeId.value = null
220
- }
221
-
222
- function clearByMessage(messageId) {
223
- const next = new Map(artifactsMap.value)
224
- for (const [id, art] of next) {
225
- if (art.messageId === messageId) next.delete(id)
226
- }
227
- if (activeId.value && !next.has(activeId.value)) {
228
- activeId.value = next.size > 0 ? [...next.values()].at(-1).id : null
229
- }
230
- artifactsMap.value = next
231
- }
232
-
233
- return {
234
- artifactsMap, activeId, activeArtifact, activeCode,
235
- allArtifacts, panelVisible, byMessage,
236
- preRegister, register, updateCode, markDone,
237
- open, close, clearSession, clearByMessage,
238
- LANG_LABEL, LANG_EXT,
239
- shouldBeArtifact,
240
- }
241
- }
242
-
243
- export function provideArtifactStore() {
244
- const store = createArtifactStore()
245
- provide(STORE_KEY, store)
246
- return store
247
- }
248
-
249
- export function useArtifactStore() {
250
- const store = inject(STORE_KEY)
251
- if (!store) throw new Error('useArtifactStore: missing provideArtifactStore()')
252
- return store
253
- }
@@ -1,88 +0,0 @@
1
- /**
2
- * useAuth.js
3
- * 全局用户认证状态管理(provide/inject 模式)
4
- * 登录态持久化到 localStorage,页面刷新后自动恢复
5
- */
6
- import { ref, computed, provide, inject } from 'vue'
7
- import { login, logout } from '../services/authApi.js'
8
-
9
- const AUTH_KEY = Symbol('auth')
10
- const LS_USER_KEY = 'citic_auth_user'
11
- const LS_TOKEN_KEY = 'citic_auth_token'
12
-
13
- // ── localStorage 工具 ─────────────────────────────────────────────
14
- function lsSave(user, token) {
15
- try {
16
- localStorage.setItem(LS_USER_KEY, JSON.stringify(user))
17
- localStorage.setItem(LS_TOKEN_KEY, token)
18
- } catch { /* 隐私模式下 localStorage 可能不可用,静默忽略 */ }
19
- }
20
-
21
- function lsClear() {
22
- try {
23
- localStorage.removeItem(LS_USER_KEY)
24
- localStorage.removeItem(LS_TOKEN_KEY)
25
- } catch {}
26
- }
27
-
28
- function lsRestore() {
29
- try {
30
- const rawUser = localStorage.getItem(LS_USER_KEY)
31
- const rawToken = localStorage.getItem(LS_TOKEN_KEY)
32
- if (rawUser && rawToken) {
33
- return { user: JSON.parse(rawUser), token: rawToken }
34
- }
35
- } catch {}
36
- return null
37
- }
38
-
39
- export function createAuth() {
40
- // 初始化时从 localStorage 恢复登录态
41
- const saved = lsRestore()
42
-
43
- const user = ref(saved?.user || null)
44
- const token = ref(saved?.token || null)
45
- const isLoading = ref(false)
46
- const error = ref('')
47
-
48
- const isLoggedIn = computed(() => !!user.value)
49
-
50
- async function doLogin(username, password) {
51
- isLoading.value = true
52
- error.value = ''
53
- try {
54
- const result = await login(username, password)
55
- user.value = result.user
56
- token.value = result.token
57
- lsSave(result.user, result.token) // 持久化
58
- return true
59
- } catch (err) {
60
- error.value = err.message || '登录失败,请重试'
61
- return false
62
- } finally {
63
- isLoading.value = false
64
- }
65
- }
66
-
67
- async function doLogout() {
68
- await logout()
69
- user.value = null
70
- token.value = null
71
- error.value = ''
72
- lsClear() // 清除持久化
73
- }
74
-
75
- return { user, token, isLoggedIn, isLoading, error, doLogin, doLogout }
76
- }
77
-
78
- export function provideAuth() {
79
- const auth = createAuth()
80
- provide(AUTH_KEY, auth)
81
- return auth
82
- }
83
-
84
- export function useAuth() {
85
- const auth = inject(AUTH_KEY)
86
- if (!auth) throw new Error('useAuth must be used inside a component with provideAuth()')
87
- return auth
88
- }
@@ -1,147 +0,0 @@
1
- /**
2
- * useChatDB.js
3
- * IndexedDB 持久化层,负责聊天 sessions 的存取
4
- *
5
- * 存储策略:
6
- * - 仅存 displayText(msg.content)和 attachments 元信息(不存 base64 图片数据)
7
- * - apiContent 含 image_url base64,体积大且无需持久化,不写入 DB
8
- * - 每次写入整个 sessions 数组(简化实现,sessions 数量通常不超过几十条)
9
- *
10
- * DB 结构:
11
- * db: citic_chat version: 1
12
- * store: sessions keyPath: id
13
- */
14
-
15
- const DB_NAME = 'citic_chat'
16
- const DB_VERSION = 1
17
- const STORE_NAME = 'sessions'
18
-
19
- let _db = null
20
-
21
- // ── 打开 / 初始化 DB ──────────────────────────────────────────────
22
- function openDB() {
23
- if (_db) return Promise.resolve(_db)
24
-
25
- return new Promise((resolve, reject) => {
26
- const req = indexedDB.open(DB_NAME, DB_VERSION)
27
-
28
- req.onupgradeneeded = (e) => {
29
- const db = e.target.result
30
- if (!db.objectStoreNames.contains(STORE_NAME)) {
31
- db.createObjectStore(STORE_NAME, { keyPath: 'id' })
32
- }
33
- }
34
-
35
- req.onsuccess = (e) => {
36
- _db = e.target.result
37
- resolve(_db)
38
- }
39
-
40
- req.onerror = () => reject(req.error)
41
- })
42
- }
43
-
44
- // ── 序列化:去除不需要持久化的大体积字段 ─────────────────────────
45
- function serializeSession(session) {
46
- return {
47
- id: session.id,
48
- title: session.title,
49
- messages: session.messages.map(msg => {
50
- const base = {
51
- id: msg.id,
52
- role: msg.role,
53
- content: msg.content, // displayText,安全
54
- error: msg.error || false,
55
- streaming: false, // 持久化时流式已结束
56
- }
57
- // attachments 只保留元信息(无 base64 preview)
58
- if (msg.attachments && msg.attachments.length > 0) {
59
- base.attachments = msg.attachments.map(att => ({
60
- id: att.id,
61
- fileName: att.fileName,
62
- type: att.type,
63
- ext: att.ext,
64
- // preview(图片 dataURL)体积大,不持久化
65
- }))
66
- }
67
- // apiContent 完全不持久化(含 base64 / 文件原文)
68
- return base
69
- }),
70
- }
71
- }
72
-
73
- // ── 保存所有 sessions ─────────────────────────────────────────────
74
- export async function saveSessions(sessions) {
75
- try {
76
- const db = await openDB()
77
- const tx = db.transaction(STORE_NAME, 'readwrite')
78
- const store = tx.objectStore(STORE_NAME)
79
-
80
- // 先清空旧数据,再写入当前全量(保持顺序)
81
- store.clear()
82
- for (const session of sessions) {
83
- store.put(serializeSession(session))
84
- }
85
-
86
- return new Promise((resolve, reject) => {
87
- tx.oncomplete = () => resolve()
88
- tx.onerror = () => reject(tx.error)
89
- })
90
- } catch (err) {
91
- // DB 操作失败静默处理,不影响主流程
92
- console.warn('[ChatDB] saveSessions failed:', err)
93
- }
94
- }
95
-
96
- // ── 读取所有 sessions ─────────────────────────────────────────────
97
- export async function loadSessions() {
98
- try {
99
- const db = await openDB()
100
- const tx = db.transaction(STORE_NAME, 'readonly')
101
- const store = tx.objectStore(STORE_NAME)
102
-
103
- return new Promise((resolve, reject) => {
104
- const req = store.getAll()
105
- req.onsuccess = () => {
106
- const rows = req.result || []
107
- // IndexedDB getAll 不保证顺序,按 id(时间戳)降序排列(新会话在前)
108
- rows.sort((a, b) => b.id - a.id)
109
- resolve(rows)
110
- }
111
- req.onerror = () => reject(req.error)
112
- })
113
- } catch (err) {
114
- console.warn('[ChatDB] loadSessions failed:', err)
115
- return []
116
- }
117
- }
118
-
119
- // ── 删除单条 session ──────────────────────────────────────────────
120
- export async function deleteSession(id) {
121
- try {
122
- const db = await openDB()
123
- const tx = db.transaction(STORE_NAME, 'readwrite')
124
- tx.objectStore(STORE_NAME).delete(id)
125
- return new Promise((resolve, reject) => {
126
- tx.oncomplete = () => resolve()
127
- tx.onerror = () => reject(tx.error)
128
- })
129
- } catch (err) {
130
- console.warn('[ChatDB] deleteSession failed:', err)
131
- }
132
- }
133
-
134
- // ── 清空所有 sessions ─────────────────────────────────────────────
135
- export async function clearAllSessions() {
136
- try {
137
- const db = await openDB()
138
- const tx = db.transaction(STORE_NAME, 'readwrite')
139
- tx.objectStore(STORE_NAME).clear()
140
- return new Promise((resolve, reject) => {
141
- tx.oncomplete = () => resolve()
142
- tx.onerror = () => reject(tx.error)
143
- })
144
- } catch (err) {
145
- console.warn('[ChatDB] clearAllSessions failed:', err)
146
- }
147
- }
@@ -1,24 +0,0 @@
1
- /**
2
- * useCountUp.js
3
- * 数字滚动动画
4
- */
5
- import { ref } from 'vue'
6
-
7
- export function useCountUp(target, duration = 1800) {
8
- const current = ref(0)
9
- let started = false
10
-
11
- function start() {
12
- if (started) return
13
- started = true
14
- const t0 = performance.now()
15
- const tick = (now) => {
16
- const p = Math.min((now - t0) / duration, 1)
17
- current.value = Math.round((1 - Math.pow(1 - p, 3)) * target)
18
- if (p < 1) requestAnimationFrame(tick)
19
- }
20
- requestAnimationFrame(tick)
21
- }
22
-
23
- return { current, start }
24
- }