@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,102 +0,0 @@
1
- /**
2
- * tracker/service.js
3
- *
4
- * Ackee 上报服务,管理 ackee-tracker 实例和上报队列。
5
- * 所有事件通过 track() 统一入口,TRACK_ENABLED=false 时静默丢弃。
6
- */
7
- import { ACKEE_URL, ACKEE_DOMAIN, TRACK_ENABLED, EVENTS } from './config.js'
8
-
9
- // ── Ackee tracker 实例(懒加载)──────────────────────────────────
10
- let _instance = null
11
- let _loading = false
12
-
13
- async function getInstance() {
14
- if (_instance) return _instance
15
- if (!TRACK_ENABLED) return null
16
- if (_loading) {
17
- // 等待加载完成
18
- return new Promise(resolve => {
19
- const timer = setInterval(() => {
20
- if (!_loading) { clearInterval(timer); resolve(_instance) }
21
- }, 50)
22
- })
23
- }
24
-
25
- _loading = true
26
- try {
27
- const { default: ackeeTracker } = await import('ackee-tracker')
28
- _instance = ackeeTracker.create(ACKEE_URL, {
29
- detailed: false, // 不收集详细浏览器信息,保护隐私
30
- ignoreLocalhost: false, // 内网环境需要设为 false
31
- ignoreOwnVisits: false,
32
- })
33
- // 上报一次 page view(domain 维度)
34
- _instance.record(ACKEE_DOMAIN)
35
- } catch (e) {
36
- console.warn('[tracker] ackee-tracker 加载失败', e)
37
- }
38
- _loading = false
39
- return _instance
40
- }
41
-
42
- // ── 上报队列(页面加载初期 Ackee 未就绪时缓存事件)────────────────
43
- const _queue = []
44
- let _flushing = false
45
-
46
- async function flush() {
47
- if (_flushing || _queue.length === 0) return
48
- _flushing = true
49
-
50
- const instance = await getInstance()
51
- if (!instance) {
52
- _queue.length = 0 // 无实例时清空队列(disabled 状态)
53
- _flushing = false
54
- return
55
- }
56
-
57
- while (_queue.length > 0) {
58
- const { eventId, key, value } = _queue.shift()
59
- try {
60
- instance.action(eventId, { key: String(key), value: Number(value) || 1 })
61
- } catch (e) {
62
- console.warn('[tracker] action 上报失败', eventId, e)
63
- }
64
- }
65
- _flushing = false
66
- }
67
-
68
- // ── 核心上报函数 ─────────────────────────────────────────────────
69
-
70
- /**
71
- * 上报一个 Ackee action
72
- * @param {string} eventId EVENTS 里的 UUID
73
- * @param {string} key 分组维度
74
- * @param {number} value 数值,默认 1
75
- */
76
- export function track(eventId, key, value = 1) {
77
- if (!TRACK_ENABLED) return
78
- if (!eventId || !key) return
79
-
80
- _queue.push({ eventId, key: String(key), value })
81
- flush()
82
- }
83
-
84
- /**
85
- * 批量上报多个 action(同一事件触发多条记录时使用)
86
- * @param {Array<{eventId, key, value?}>} actions
87
- */
88
- export function trackBatch(actions) {
89
- if (!TRACK_ENABLED) return
90
- actions.forEach(({ eventId, key, value = 1 }) => {
91
- if (eventId && key) _queue.push({ eventId, key: String(key), value })
92
- })
93
- flush()
94
- }
95
-
96
- // 页面加载后预热实例
97
- if (TRACK_ENABLED) {
98
- getInstance()
99
- }
100
-
101
- // 导出 EVENTS 方便外部引用,避免重复 import config
102
- export { EVENTS }
@@ -1,179 +0,0 @@
1
- /**
2
- * tracker/useChatTracker.js
3
- *
4
- * AI 对话框埋点 composable,覆盖:
5
- * - 对话行为(发消息、回复、中止、报错、模式/模型切换)
6
- * - 采纳行为(复制、下载)
7
- * - 提问内容分析(方向、意图、复杂度、附件,无用户关联)
8
- * - 工具调用
9
- *
10
- * 用法:在 useChatStore 或 ChatBox 里引入
11
- * import { useChatTracker } from '@/tracker/useChatTracker.js'
12
- * const chatTracker = useChatTracker({ getUserName: () => user.value?.name })
13
- */
14
- import { track, trackBatch, EVENTS } from './service.js'
15
- import { getDirection, getIntent, getComplexity, getAttachmentType } from './analyze.js'
16
-
17
- /**
18
- * @param {object} opts
19
- * @param {() => string} opts.getUserName 获取当前用户名的函数,未登录返回空字符串
20
- */
21
- export function useChatTracker({ getUserName = () => '' } = {}) {
22
-
23
- // ── 对话行为 ───────────────────────────────────────────────────
24
-
25
- /**
26
- * 用户发送消息
27
- * 同时触发:模式分布、模型分布、用户用量、提问分析(4个方向)
28
- *
29
- * @param {object} opts
30
- * @param {string} opts.mode 当前模式
31
- * @param {string} opts.modelName 模型显示名
32
- * @param {string} opts.text 提问文本(本地分析后不上报原文)
33
- * @param {Array} opts.attachments 附件列表
34
- */
35
- function messageSent({ mode, modelName, text = '', attachments = [] }) {
36
- const userName = getUserName()
37
-
38
- // 对话行为:模式、模型、用户
39
- const actions = [
40
- { eventId: EVENTS.MSG_MODE, key: mode || 'unknown' },
41
- { eventId: EVENTS.MSG_MODEL, key: modelName || 'unknown' },
42
- ]
43
- if (userName) {
44
- actions.push({ eventId: EVENTS.MSG_USER, key: userName })
45
- }
46
- trackBatch(actions)
47
-
48
- // 提问内容分析(无用户关联,单独上报)
49
- _trackQuestionAnalysis(text, mode, attachments)
50
- }
51
-
52
- /**
53
- * AI 回复开始(记录开始时间,和 responseDone 配合计算耗时)
54
- * @returns {number} startTime 用于传入 responseDone
55
- */
56
- function responseStart() {
57
- return Date.now()
58
- }
59
-
60
- /**
61
- * AI 回复完成
62
- * @param {object} opts
63
- * @param {number} opts.startTime responseStart() 返回的时间戳
64
- * @param {number} opts.ttfbMs 首字节延迟(ms)
65
- * @param {string} opts.modelName 模型显示名
66
- * @param {boolean} opts.hasError 是否报错
67
- * @param {string} opts.errorType 报错类型,hasError=true 时有值
68
- * @param {string[]} opts.toolNames 触发的工具名列表
69
- */
70
- function responseDone({ startTime, ttfbMs, modelName, hasError, errorType, toolNames = [] }) {
71
- const duration = startTime ? Date.now() - startTime : 0
72
- const name = modelName || 'unknown'
73
-
74
- if (hasError) {
75
- track(EVENTS.RESP_ERROR, errorType || 'unknown')
76
- return
77
- }
78
-
79
- const actions = [
80
- { eventId: EVENTS.RESP_DURATION, key: name, value: duration },
81
- ]
82
- if (ttfbMs > 0) {
83
- actions.push({ eventId: EVENTS.RESP_TTFB, key: name, value: ttfbMs })
84
- }
85
- trackBatch(actions)
86
-
87
- // 工具调用
88
- toolNames.forEach(toolName => {
89
- track(EVENTS.TOOL_EXECUTED, toolName)
90
- })
91
- }
92
-
93
- /**
94
- * 用户中止回复
95
- * @param {string} userName
96
- */
97
- function responseAbort(userName) {
98
- track(EVENTS.RESP_ABORT, userName || getUserName() || 'anonymous')
99
- }
100
-
101
- /**
102
- * 模式切换
103
- * @param {string} fromMode
104
- * @param {string} toMode
105
- * @param {'manual'|'ai_tool'} trigger 触发来源
106
- */
107
- function modeSwitch(fromMode, toMode, trigger = 'manual') {
108
- track(EVENTS.MODE_SWITCH, `${fromMode}→${toMode}:${trigger}`)
109
- }
110
-
111
- // ── 采纳行为 ───────────────────────────────────────────────────
112
-
113
- /**
114
- * 内容复制
115
- * @param {object} opts
116
- * @param {'code_block'|'artifact_panel'|'bubble_text'|'bubble_btn'} opts.source
117
- * @param {string} opts.lang 代码语言,非代码时传空字符串
118
- */
119
- function contentCopy({ source, lang }) {
120
- const userName = getUserName()
121
- const actions = [
122
- { eventId: EVENTS.COPY_SOURCE, key: source || 'unknown' },
123
- ]
124
- if (userName) {
125
- actions.push({ eventId: EVENTS.COPY_USER, key: userName })
126
- }
127
- if (lang) {
128
- actions.push({ eventId: EVENTS.COPY_LANG, key: lang })
129
- }
130
- trackBatch(actions)
131
- }
132
-
133
- /**
134
- * 文件下载
135
- * @param {object} opts
136
- * @param {string} opts.lang 文件语言
137
- */
138
- function fileDownload({ lang }) {
139
- const userName = getUserName()
140
- const actions = [
141
- { eventId: EVENTS.DOWNLOAD_LANG, key: lang || 'unknown' },
142
- ]
143
- if (userName) {
144
- actions.push({ eventId: EVENTS.DOWNLOAD_USER, key: userName })
145
- }
146
- trackBatch(actions)
147
- }
148
-
149
- // ── 提问内容分析(内部,无用户关联)──────────────────────────
150
- function _trackQuestionAnalysis(text, mode, attachments) {
151
- const direction = getDirection(mode)
152
- const intent = getIntent(text, mode)
153
- const complexity = getComplexity(text)
154
- const attachmentType = getAttachmentType(attachments)
155
-
156
- const actions = [
157
- { eventId: EVENTS.Q_DIRECTION, key: direction },
158
- { eventId: EVENTS.Q_COMPLEXITY, key: complexity },
159
- { eventId: EVENTS.Q_ATTACHMENT, key: attachmentType },
160
- ]
161
-
162
- // 意图只在代码方向触发
163
- if (intent) {
164
- actions.push({ eventId: EVENTS.Q_INTENT, key: intent })
165
- }
166
-
167
- trackBatch(actions)
168
- }
169
-
170
- return {
171
- messageSent,
172
- responseStart,
173
- responseDone,
174
- responseAbort,
175
- modeSwitch,
176
- contentCopy,
177
- fileDownload,
178
- }
179
- }
@@ -1,45 +0,0 @@
1
- /**
2
- * tracker/useTracker.js
3
- *
4
- * 官网页面行为埋点 composable。
5
- * 在 App.vue 或各页面组件里引入使用。
6
- *
7
- * 用法:
8
- * import { useTracker } from '@/tracker/useTracker.js'
9
- * const tracker = useTracker()
10
- * tracker.pageView('/chat')
11
- * tracker.btnClick('hero_cta', '立即体验')
12
- */
13
- import { track, EVENTS } from './service.js'
14
-
15
- export function useTracker() {
16
-
17
- /**
18
- * 页面访问
19
- * 在路由 afterEach 里调用
20
- * @param {string} path 路由路径,如 '/chat'
21
- */
22
- function pageView(path) {
23
- track(EVENTS.PAGE_VIEW, path)
24
- }
25
-
26
- /**
27
- * 按钮点击
28
- * @param {string} btnId 按钮唯一标识,如 'hero_cta' / 'nav_chat'
29
- * @param {string} [label] 按钮文案,可选,用于拼接 key 更易读
30
- */
31
- function btnClick(btnId, label) {
32
- const key = label ? `${btnId}:${label}` : btnId
33
- track(EVENTS.BTN_CLICK, key)
34
- }
35
-
36
- /**
37
- * 登录成功
38
- * @param {string} userName
39
- */
40
- function loginSuccess(userName) {
41
- track(EVENTS.LOGIN_SUCCESS, userName || 'unknown')
42
- }
43
-
44
- return { pageView, btnClick, loginSuccess }
45
- }
@@ -1,65 +0,0 @@
1
- <template>
2
- <div class="chat-page">
3
- <ChatBox
4
- :config="sdkConfig"
5
- :chat-store="chatStore"
6
- :user="user"
7
- />
8
- </div>
9
- </template>
10
-
11
- <script setup>
12
- import { computed } from 'vue'
13
- import { useAuth } from '../composables/useAuth.js'
14
- import ChatBox from '../chat-sdk/core/components/ChatBox.vue'
15
-
16
- const props = defineProps({
17
- chatStore: { type: Object, required: true },
18
- })
19
-
20
- const { user } = useAuth()
21
-
22
- const sdkConfig = computed(() => ({
23
- title: 'Frontend AI 助手',
24
- placeholder: '向 AI 发消息... (Enter 发送,Shift+Enter 换行)',
25
-
26
- // 注入用户信息,供埋点使用
27
- getUser: () => user.value,
28
-
29
- models: [
30
- {
31
- id: import.meta.env.VITE_MODEL || 'gpt-4o',
32
- name: import.meta.env.VITE_MODEL || 'gpt-4o',
33
- baseURL: import.meta.env.VITE_API_BASE_URL || 'https://api.openai.com',
34
- apiKey: import.meta.env.VITE_API_KEY || '',
35
- vision: false,
36
- },
37
- ],
38
- defaultModel: import.meta.env.VITE_MODEL || 'gpt-4o',
39
- autoVision: true,
40
-
41
- modes: ['code', 'ask', 'architect', 'requirements'],
42
- defaultMode: 'code',
43
-
44
- features: {
45
- artifact: true,
46
- markdown: true,
47
- upload: true,
48
- codepreview: true,
49
- modelSelector: true
50
- },
51
-
52
- userControls: {
53
- modelSelector: true,
54
- artifact: true,
55
- upload: true,
56
- },
57
- }))
58
- </script>
59
-
60
- <style scoped>
61
- .chat-page {
62
- height: calc(100vh - 64px);
63
- overflow: hidden;
64
- }
65
- </style>
@@ -1,156 +0,0 @@
1
- <template>
2
- <div class="dot-grid" style="position: relative;">
3
- <div class="glow-orb" style="width: 400px; height: 400px; background: rgba(26,111,196,0.2); top: 0; left: 25%;" />
4
- <div class="glow-orb" style="width: 260px; height: 260px; background: rgba(96,165,250,0.1); top: 140px; right: 25%;" />
5
-
6
- <!-- Hero -->
7
- <section style="position: relative; max-width: 860px; margin: 0 auto; padding: 80px 24px 96px; display: flex; flex-direction: column; align-items: center; text-align: center;">
8
- <div class="animate-fade-up" style="display: inline-flex; align-items: center; gap: 8px; padding: 6px 16px; border-radius: 999px; border: 1px solid var(--tag-border); background: var(--tag-bg); margin-bottom: 28px;">
9
- <span class="animate-pulse-slow" style="width: 7px; height: 7px; border-radius: 50%; background: #4ade80; display: inline-block;" />
10
- <span class="font-mono" style="font-size: 12px; color: var(--brand-400);">v1.0 现已上线 · 对话即服务</span>
11
- </div>
12
-
13
- <h1 class="font-display animate-fade-up stagger-1" style="font-weight: 800; line-height: 1.1; margin-bottom: 16px; font-size: clamp(2.4rem, 5.5vw, 3.8rem);">
14
- <span class="gradient-text">Citic Frontend</span><br />
15
- </h1>
16
-
17
- <p class="animate-fade-up stagger-2" style="color: var(--text-secondary); margin-bottom: 36px; max-width: 480px; font-size: 1rem; line-height: 1.7; font-family: Inter, 'Helvetica Neue', Helvetica, 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei', '微软雅黑', Arial, sans-serif;">
18
- 前端开发全流程智能伙伴
19
- </p>
20
-
21
- <div class="glass animate-fade-up stagger-3" style="width: 100%; max-width: 600px; border-radius: 16px; padding: 18px 18px 14px; box-shadow: 0 0 60px rgba(26,111,196,0.08), 0 20px 40px rgba(0,0,0,0.12);">
22
- <div style="display: flex; flex-wrap: wrap; gap: 6px; margin-bottom: 12px;">
23
- <button
24
- v-for="s in QUICK"
25
- :key="s"
26
- class="quick-btn"
27
- style="font-size: 12px; padding: 5px 10px; border-radius: 999px; border: 1px solid var(--border-subtle); background: var(--bg-secondary); color: var(--text-secondary); cursor: pointer; font-family: Inter, 'Helvetica Neue', Helvetica, 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei', '微软雅黑', Arial, sans-serif; transition: all 0.15s;"
28
- @click="handleSend(s)"
29
- >{{ s }}</button>
30
- </div>
31
- <InputBar
32
- :is-loading="false"
33
- placeholder="描述您的需求,回车即进入 AI 对话..."
34
- :available-models="props.chatStore.availableModels.filter(m => !m.vision)"
35
- :selected-model-id="props.chatStore.selectedModel.value?.id || ''"
36
- :show-model-selector="true"
37
- @send="handleSend"
38
- @select-model="props.chatStore.selectModel"
39
- />
40
- <p class="font-mono" style="font-size: 11px; color: var(--text-muted); text-align: center; margin-top: 10px;">
41
- 发送后自动跳转到 AI 对话页面
42
- </p>
43
- </div>
44
- </section>
45
-
46
- <!-- Features -->
47
- <section style="max-width: 960px; margin: 0 auto; padding: 0 24px 96px;">
48
- <h2 class="section-title" style="text-align: center; margin-bottom: 10px;">核心能力</h2>
49
- <p style="color: var(--text-secondary); text-align: center; margin-bottom: 40px; font-family: Inter, 'Helvetica Neue', Helvetica, 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei', '微软雅黑', Arial, sans-serif;">四大场景,全部通过对话驱动</p>
50
- <div style="display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: 16px;">
51
- <div v-for="f in FEATURES" :key="f.title" class="card">
52
- <div style="width: 44px; height: 44px; border-radius: 12px; background: var(--tag-bg); border: 1px solid var(--tag-border); display: flex; align-items: center; justify-content: center; margin-bottom: 14px;">
53
- <component :is="f.Icon" :size="22" color="var(--brand-400)" :stroke-width="1.75" />
54
- </div>
55
- <h3 class="font-display" style="font-weight: 600; color: var(--text-primary); font-size: 15px; margin-bottom: 8px;">{{ f.title }}</h3>
56
- <p style="color: var(--text-secondary); font-size: 13px; line-height: 1.6; font-family: Inter, 'Helvetica Neue', Helvetica, 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei', '微软雅黑', Arial, sans-serif;">{{ f.desc }}</p>
57
- <div style="margin-top: 16px; padding-top: 12px; border-top: 1px solid var(--border-subtle);">
58
- <span class="font-mono" style="font-size: 12px; color: var(--brand-400);">{{ f.example }}</span>
59
- </div>
60
- </div>
61
- </div>
62
- </section>
63
-
64
- <!-- Stats -->
65
- <section ref="statsRef" style="max-width: 960px; margin: 0 auto; padding: 0 24px 96px;">
66
- <div class="glass" style="border-radius: 16px; padding: 32px; display: grid; grid-template-columns: repeat(auto-fit, minmax(160px, 1fr)); gap: 32px; text-align: center;">
67
- <div v-for="(stat, i) in RAW_STATS" :key="stat.label" style="display: flex; flex-direction: column; align-items: center; gap: 4px;">
68
- <div class="font-display" style="font-weight: 700; color: var(--text-primary); font-size: 2rem;">
69
- {{ counters[i].current.value.toLocaleString() }}<span style="color: var(--brand-400);">{{ stat.suffix }}</span>
70
- </div>
71
- <div style="color: var(--text-muted); font-size: 14px; font-family: Inter, 'Helvetica Neue', Helvetica, 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei', '微软雅黑', Arial, sans-serif;">{{ stat.label }}</div>
72
- </div>
73
- </div>
74
- </section>
75
-
76
- <!-- CTA -->
77
- <section style="max-width: 960px; margin: 0 auto; padding: 0 24px 112px; text-align: center;">
78
- <div class="glass" style="border-radius: 16px; padding: 48px 32px; position: relative; overflow: hidden;">
79
- <div class="glow-orb" style="width: 256px; height: 256px; background: rgba(26,111,196,0.15); top: -40px; left: 50%; transform: translateX(-50%);" />
80
- <h2 class="section-title" style="margin-bottom: 14px; position: relative; z-index: 1;">立即体验对话式开发</h2>
81
- <p style="color: var(--text-secondary); margin-bottom: 28px; font-family: Inter, 'Helvetica Neue', Helvetica, 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei', '微软雅黑', Arial, sans-serif; position: relative; z-index: 1;">无需配置,直接对话,从第一个消息开始提速</p>
82
- <div style="display: flex; gap: 12px; justify-content: center; flex-wrap: wrap; position: relative; z-index: 1;">
83
- <button class="btn-primary" style="padding: 12px 32px; font-size: 15px;" @click="router.push('/chat')">
84
- <MessageSquare :size="16" /> 开始 AI 对话
85
- </button>
86
- <button class="btn-ghost" style="padding: 12px 32px; font-size: 15px; border: 1px solid var(--border-default); border-radius: 8px;" @click="router.push('/market')">
87
- <Layers :size="16" /> 浏览组件市场
88
- </button>
89
- </div>
90
- </div>
91
- </section>
92
- </div>
93
- </template>
94
-
95
- <script setup>
96
- import { ref, onMounted, onUnmounted } from 'vue'
97
- import { useRouter } from 'vue-router'
98
- import { Rocket, Package, BarChart2, Wrench, MessageSquare, Layers } from 'lucide-vue-next'
99
- import InputBar from '../chat-sdk/core/components/InputBar.vue'
100
- import { useCountUp } from '../composables/useCountUp.js'
101
-
102
- const props = defineProps({
103
- chatStore: { type: Object, required: true },
104
- })
105
-
106
- const router = useRouter()
107
-
108
- const FEATURES = [
109
- { Icon: Rocket, title: '脚手架生成', desc: '描述项目类型和技术栈,AI 即时生成可运行的工程模板', example: '「生成 Vue 3 + TS + Pinia 项目」' },
110
- { Icon: Package, title: '组件搜索', desc: '用自然语言找到最合适的组件,直接获取安装命令', example: '「找一个企业级 Table 组件」' },
111
- { Icon: BarChart2, title: '流水线监控', desc: '对话查询 CI/CD 状态,异常时自动推送修复建议', example: '「查看 main 分支构建状态」' },
112
- { Icon: Wrench, title: '异常修复', desc: '粘贴报错信息,获取精准定位分析与可执行修复方案', example: '「分析这个 TypeScript 报错」' },
113
- ]
114
-
115
- const RAW_STATS = [
116
- { label: '接入开发者', target: 12000, suffix: '+' },
117
- { label: '组件总数', target: 380, suffix: '+' },
118
- { label: 'Skills 数量', target: 95, suffix: '+' },
119
- { label: 'GitHub Stars', target: 2100, suffix: '★' },
120
- ]
121
-
122
- const QUICK = ['生成 Vue 3 + TS 脚手架', '查找 Table 组件', '查看流水线状态', '分析构建失败原因']
123
-
124
- const counters = RAW_STATS.map(s => useCountUp(s.target))
125
- const statsRef = ref(null)
126
- let observer = null
127
-
128
- function handleSend(val) {
129
- const sid = props.chatStore.newSession(val)
130
- router.push('/chat')
131
- setTimeout(() => props.chatStore.sendMessage(val, sid), 80)
132
- }
133
-
134
- onMounted(() => {
135
- observer = new IntersectionObserver(
136
- ([entry]) => {
137
- if (entry.isIntersecting) {
138
- counters.forEach(c => c.start())
139
- observer.disconnect()
140
- }
141
- },
142
- { threshold: 0.3 }
143
- )
144
- if (statsRef.value) observer.observe(statsRef.value)
145
- })
146
-
147
- onUnmounted(() => observer?.disconnect())
148
- </script>
149
-
150
- <style scoped>
151
- .quick-btn:hover {
152
- border-color: rgba(26,111,196,0.4) !important;
153
- color: var(--brand-400) !important;
154
- background: var(--tag-bg) !important;
155
- }
156
- </style>