@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,61 +0,0 @@
1
- <template>
2
- <div style="display: flex; flex-direction: column; min-height: 100vh;">
3
- <!-- 非移动端 且 非 /chat 页才启用自定义鼠标 -->
4
- <CustomCursor v-if="showCursor" />
5
- <Navbar />
6
- <main style="flex: 1; padding-top: 64px;">
7
- <router-view :chat-store="chatStore" />
8
- </main>
9
- <Footer v-if="!isChat" />
10
- </div>
11
- </template>
12
-
13
- <script setup>
14
- import { computed } from 'vue'
15
- import { useRoute, useRouter } from 'vue-router'
16
- import { provideTheme } from './composables/useTheme.js'
17
- import { provideAuth } from './composables/useAuth.js'
18
- import { useChatStore } from './chat-sdk/headless/useChatStore.js'
19
- import { useTracker } from './tracker/index.js'
20
- import Navbar from './components/Navbar.vue'
21
- import Footer from './components/Footer.vue'
22
- import CustomCursor from './components/CustomCursor.vue'
23
-
24
- provideTheme()
25
-
26
- const { user } = provideAuth()
27
- const chatStore = useChatStore({
28
- models: [
29
- {
30
- id: import.meta.env.VITE_MODEL || 'gpt-4o',
31
- name: import.meta.env.VITE_MODEL || 'gpt-4o',
32
- baseURL: import.meta.env.VITE_API_BASE_URL || 'https://api.openai.com',
33
- apiKey: import.meta.env.VITE_API_KEY || '',
34
- vision: false,
35
- },
36
- {
37
- id: import.meta.env.VITE_VL_MODEL || 'gpt-4o',
38
- name: import.meta.env.VITE_VL_MODEL || 'gpt-4o',
39
- baseURL: import.meta.env.VITE_VL_API_BASE_URL || 'https://api.openai.com',
40
- apiKey: import.meta.env.VITE_VL_API_KEY || '',
41
- vision: true,
42
- },
43
- ],
44
- defaultModel: import.meta.env.VITE_MODEL || 'gpt-4o',
45
- autoVision: true,
46
- modes: ['code', 'ask', 'architect', 'requirements'],
47
- defaultMode: 'code',
48
- getUser: () => user.value,
49
- })
50
- const route = useRoute()
51
- const router = useRouter()
52
- const isMobile = window.innerWidth < 768
53
- const isChat = computed(() => route.path === '/chat')
54
- const showCursor = computed(() => !isMobile && !isChat.value)
55
-
56
- // ── 路由页面访问埋点 ───────────────────────────────────────────────
57
- const tracker = useTracker()
58
- router.afterEach((to) => {
59
- tracker.pageView(to.path)
60
- })
61
- </script>
@@ -1,305 +0,0 @@
1
- <template>
2
- <div class="chat-root">
3
-
4
- <!-- 侧边栏 -->
5
- <aside v-if="!isMobile" class="chat-sidebar-bg" style="width:256px;flex-shrink:0;">
6
- <ChatSidebar :store="chatStore" :user="user" />
7
- </aside>
8
-
9
- <!-- Mobile 侧边栏 -->
10
- <template v-if="isMobile && mobileSidebar">
11
- <div style="position:fixed;inset:0;z-index:40;display:flex;" @click="mobileSidebar=false">
12
- <aside class="chat-sidebar-bg" style="width:256px;height:100%;z-index:41;" @click.stop>
13
- <ChatSidebar :store="chatStore" :user="user" @close="mobileSidebar=false" />
14
- </aside>
15
- <div style="flex:1;background:rgba(0,0,0,0.4);" />
16
- </div>
17
- </template>
18
-
19
- <!-- 主区 -->
20
- <div class="chat-main">
21
-
22
- <!-- Header -->
23
- <div class="chat-header">
24
- <el-button v-if="isMobile" text circle @click="mobileSidebar=true">
25
- <Menu :size="18" color="var(--text-secondary)" />
26
- </el-button>
27
- <div class="chat-header__avatar">
28
- <Bot :size="18" color="white" :stroke-width="1.75" />
29
- </div>
30
- <div style="flex:1;">
31
- <p class="font-display" style="font-weight:600;color:var(--text-primary);font-size:14px;margin:0;">
32
- {{ config.title || 'AI 助手' }}
33
- </p>
34
- </div>
35
- <!-- 模式切换 -->
36
- <el-select
37
- v-if="availableModes.length > 1"
38
- :model-value="chatStore.currentMode?.value"
39
- size="small"
40
- class="mode-select"
41
- @change="chatStore.switchMode"
42
- >
43
- <el-option
44
- v-for="m in availableModes"
45
- :key="m.id"
46
- :label="m.label"
47
- :value="m.id"
48
- />
49
- </el-select>
50
- <el-button v-if="chatStore.isLoading.value" size="small"
51
- style="color:#f87171;border-color:rgba(248,113,113,0.3);"
52
- @click="chatStore.abortStream()">
53
- <StopCircle :size="13" style="margin-right:5px;" color="#f87171" /> 停止
54
- </el-button>
55
- <el-button v-else size="small" text @click="chatStore.clearSession(chatStore.activeId.value)">
56
- <Trash2 :size="13" style="margin-right:5px;" /> 清空
57
- </el-button>
58
- </div>
59
-
60
- <!-- 消息列表 -->
61
- <el-scrollbar ref="scrollbarRef" style="flex:1;" @scroll="onScroll">
62
- <div class="msg-list" ref="msgListRef">
63
- <MessageBubble
64
- v-for="msg in chatStore.activeSession.value.messages"
65
- :key="msg.id"
66
- :msg="msg"
67
- :user="user"
68
- v-memo="[msg.id, msg.streaming, msg.error]"
69
- />
70
- <div ref="bottomAnchorRef" style="height:1px;" />
71
- </div>
72
- </el-scrollbar>
73
-
74
- <!-- 新消息提示 -->
75
- <transition name="fade">
76
- <button v-if="showNewMsgTip" class="new-msg-tip" @click="scrollToBottom(true)">
77
- ↓ 新消息
78
- </button>
79
- </transition>
80
-
81
- <!-- 输入区 -->
82
- <div class="chat-input-wrap">
83
- <div style="max-width:760px;margin:0 auto;">
84
- <InputBar
85
- :is-loading="chatStore.isLoading.value"
86
- :placeholder="config.placeholder || '发送消息... (Enter 发送,Shift+Enter 换行)'"
87
- :auto-focus="true"
88
- :available-models="textModels"
89
- :selected-model-id="chatStore.selectedModel.value?.id || ''"
90
- :show-model-selector="featuresEnabled.modelSelector !== false && textModels.length > 1"
91
- @send="onSend"
92
- @select-model="chatStore.selectModel"
93
- />
94
- <p class="font-mono" style="font-size:11px;color:var(--text-muted);text-align:center;margin-top:8px;">
95
- AI 可能会出错,重要决策请自行核实
96
- </p>
97
- </div>
98
- </div>
99
- </div>
100
-
101
- <!-- Artifact 面板 -->
102
- <ArtifactPanel v-if="featuresEnabled.artifact" />
103
- </div>
104
- </template>
105
-
106
- <script setup>
107
- import { ref, computed, watch, nextTick, onMounted, onUnmounted, defineAsyncComponent } from 'vue'
108
- import { Menu, Bot, StopCircle, Trash2 } from 'lucide-vue-next'
109
- import MessageBubble from './MessageBubble.vue'
110
- import ChatSidebar from './ChatSidebar.vue'
111
- import InputBar from './InputBar.vue'
112
- import { provideArtifactStore } from '../../features/artifact/useArtifactStore.js'
113
-
114
- // ArtifactPanel 按需加载
115
- const ArtifactPanel = defineAsyncComponent(() =>
116
- import('../../features/artifact/ArtifactPanel.vue')
117
- )
118
-
119
- const props = defineProps({
120
- // SDK config,由 createAIChat() 传入
121
- config: { type: Object, required: true },
122
- // chatStore 实例,由 createAIChat() 通过 useChat() 创建后传入
123
- chatStore: { type: Object, required: true },
124
- // 用户信息(可选,不传则为游客模式)
125
- user: { type: Object, default: null },
126
- })
127
-
128
- // features 开关
129
- const featuresEnabled = computed(() => props.config.features || {})
130
-
131
- // 只把非视觉模型暴露给用户选择
132
- const textModels = computed(() =>
133
- props.chatStore.availableModels.filter(m => !m.vision)
134
- )
135
-
136
- // 可用模式列表(从 modeConfigs 中提取,供 header select 使用)
137
- const MODE_LABELS = { code: 'Code 模式', ask: 'Ask 模式', architect: 'Architect 模式', requirements: '需求模式' }
138
- const availableModes = computed(() => {
139
- const configs = props.chatStore.modeConfigs?.value || {}
140
- return Object.keys(configs).map(id => ({
141
- id,
142
- label: MODE_LABELS[id] || id,
143
- }))
144
- })
145
-
146
- // Artifact Store provide
147
- const artifactStore = provideArtifactStore()
148
-
149
- const isMobile = window.innerWidth < 768
150
- const mobileSidebar = ref(false)
151
- const scrollbarRef = ref(null)
152
- const bottomAnchorRef = ref(null)
153
- const isAtBottom = ref(true)
154
- const showNewMsgTip = ref(false)
155
- let anchorObserver = null
156
-
157
- onMounted(() => {
158
- anchorObserver = new IntersectionObserver(
159
- ([entry]) => {
160
- isAtBottom.value = entry.isIntersecting
161
- if (entry.isIntersecting) showNewMsgTip.value = false
162
- },
163
- { root: scrollbarRef.value?.wrapRef, threshold: 0.1 }
164
- )
165
- nextTick(() => {
166
- if (bottomAnchorRef.value) anchorObserver.observe(bottomAnchorRef.value)
167
- })
168
- })
169
-
170
- onUnmounted(() => {
171
- anchorObserver?.disconnect()
172
- if (scrollRafId) cancelAnimationFrame(scrollRafId)
173
- })
174
-
175
- // ── 滚动节流 ─────────────────────────────────────────────────────
176
- // 流式期间每次 content 变化都会触发 scrollToBottom,
177
- // 用 rAF 确保同一帧内多次调用只执行一次,避免反复读写 scrollHeight 导致强制回流
178
- let scrollRafId = null
179
-
180
- function scrollToBottom(force = false) {
181
- const wrap = scrollbarRef.value?.wrapRef
182
- if (!wrap) return
183
- if (!force && !isAtBottom.value) {
184
- showNewMsgTip.value = true
185
- return
186
- }
187
- if (scrollRafId) return // 本帧已排队,跳过
188
- scrollRafId = requestAnimationFrame(() => {
189
- scrollRafId = null
190
- const w = scrollbarRef.value?.wrapRef
191
- if (!w) return
192
- w.scrollTop = w.scrollHeight
193
- showNewMsgTip.value = false
194
- })
195
- }
196
-
197
- function onScroll() {
198
- if (isAtBottom.value) showNewMsgTip.value = false
199
- }
200
-
201
- function onSend(payload) {
202
- // 有附件时强制走 vision 模型,用户无法通过模型选择器改变此行为
203
- const hasAttachments = payload.attachments?.length > 0
204
- if (hasAttachments) {
205
- const visionModel = props.chatStore.availableModels.find(m => m.vision)
206
- if (visionModel) payload = { ...payload, modelOverride: visionModel.id }
207
- }
208
- props.chatStore.sendMessage(payload, props.chatStore.activeId.value, payload.modelOverride)
209
- }
210
-
211
- watch(
212
- () => props.chatStore.activeSession.value.messages.length,
213
- () => nextTick(() => scrollToBottom())
214
- )
215
- watch(
216
- () => {
217
- const msgs = props.chatStore.activeSession.value.messages
218
- const last = msgs[msgs.length - 1]
219
- return last?.streaming ? last.content?.length : 0
220
- },
221
- () => { if (isAtBottom.value) scrollToBottom() }
222
- )
223
- watch(() => props.chatStore.activeId.value, () => {
224
- artifactStore.clearSession()
225
- })
226
- </script>
227
-
228
- <style scoped>
229
- .chat-root {
230
- display: flex;
231
- height: 100%;
232
- overflow: hidden;
233
- }
234
- .chat-main {
235
- flex: 1;
236
- display: flex;
237
- flex-direction: column;
238
- overflow: hidden;
239
- background: var(--bg-primary);
240
- transition: background 0.3s;
241
- min-width: 320px;
242
- }
243
- .chat-header {
244
- padding: 10px 20px;
245
- border-bottom: 1px solid var(--border-subtle);
246
- display: flex; align-items: center; gap: 10px;
247
- background: var(--bg-secondary); transition: background 0.3s;
248
- flex-shrink: 0;
249
- }
250
- .chat-header__avatar {
251
- width: 34px; height: 34px; border-radius: 50%;
252
- background: var(--brand-500);
253
- display: flex; align-items: center; justify-content: center; flex-shrink: 0;
254
- }
255
- .msg-list {
256
- padding: 24px 20px;
257
- display: flex; flex-direction: column; gap: 16px;
258
- min-height: 100%;
259
- }
260
- .chat-input-wrap {
261
- padding: 14px 20px;
262
- border-top: 1px solid var(--border-subtle);
263
- background: var(--bg-secondary); transition: background 0.3s;
264
- flex-shrink: 0;
265
- }
266
- .new-msg-tip {
267
- position: absolute; bottom: 90px; left: 50%; transform: translateX(-50%);
268
- padding: 6px 16px; border-radius: 20px;
269
- background: var(--brand-500); color: white;
270
- font-size: 13px; border: none; cursor: pointer;
271
- box-shadow: 0 4px 16px rgba(26,111,196,0.4);
272
- transition: all 0.15s; z-index: 10;
273
- }
274
- .new-msg-tip:hover { background: var(--brand-600); }
275
- .fade-enter-active, .fade-leave-active { transition: opacity 0.2s; }
276
- .fade-enter-from, .fade-leave-to { opacity: 0; }
277
- :deep(.el-scrollbar__wrap) { overflow-x: hidden; }
278
-
279
- /* 模式切换 select */
280
- .mode-select { width: 110px; }
281
- :deep(.mode-select .el-input__wrapper) {
282
- background: var(--tag-bg) !important;
283
- box-shadow: none !important;
284
- border: 1px solid var(--border-default) !important;
285
- border-radius: 6px !important;
286
- padding: 0 8px !important;
287
- height: 28px !important;
288
- transition: border-color 0.15s !important;
289
- }
290
- :deep(.mode-select .el-input__wrapper:hover),
291
- :deep(.mode-select .el-input__wrapper.is-focus) {
292
- border-color: var(--brand-500) !important;
293
- }
294
- :deep(.mode-select .el-input__inner) {
295
- font-size: 12px !important;
296
- font-family: Inter, 'Helvetica Neue', Helvetica, 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei', '微软雅黑', Arial, sans-serif !important;
297
- color: var(--text-secondary) !important;
298
- height: 26px !important;
299
- line-height: 26px !important;
300
- }
301
- :deep(.mode-select .el-select__caret) {
302
- color: var(--text-muted) !important;
303
- font-size: 11px !important;
304
- }
305
- </style>
@@ -1,84 +0,0 @@
1
- <template>
2
- <div style="display: flex; flex-direction: column; height: 100%; padding: 14px 10px;">
3
- <el-button
4
- type="primary"
5
- style="width: 100%; margin-bottom: 16px; font-size: 13px; border-radius: 10px;"
6
- @click="store.newSession(); $emit('close')"
7
- >
8
- <Plus :size="14" style="margin-right: 6px;" /> 新建对话
9
- </el-button>
10
-
11
- <p class="font-mono" style="font-size: 10px; color: var(--text-muted); padding: 2px 6px; margin-bottom: 6px; text-transform: uppercase; letter-spacing: 0.08em;">历史记录</p>
12
-
13
- <el-scrollbar style="flex: 1;">
14
- <div style="display: flex; flex-direction: column; gap: 1px; padding-right: 2px;">
15
- <div
16
- v-for="s in store.sessions.value"
17
- :key="s.id"
18
- style="position: relative; display: flex; align-items: center;"
19
- >
20
- <div
21
- class="chat-history-item"
22
- :class="{ active: s.id === store.activeId.value }"
23
- style="flex: 1; padding-right: 28px;"
24
- @click="store.setActiveId(s.id); $emit('close')"
25
- >{{ s.title }}</div>
26
- <el-tooltip content="删除对话" placement="right" :show-after="400">
27
- <el-button
28
- text
29
- size="small"
30
- circle
31
- style="position: absolute; right: 2px; color: var(--text-muted); opacity: 0.5; transition: opacity 0.15s;"
32
- class="delete-btn"
33
- @click.stop="store.deleteSession(s.id)"
34
- >
35
- <Trash2 :size="12" />
36
- </el-button>
37
- </el-tooltip>
38
- </div>
39
- </div>
40
- </el-scrollbar>
41
-
42
- <!-- Bottom user info -->
43
- <div style="padding-top: 10px; border-top: 1px solid var(--border-subtle); margin-top: 8px;">
44
- <div v-if="user" style="display: flex; align-items: center; gap: 8px;">
45
- <div
46
- :style="{
47
- width: '24px', height: '24px', borderRadius: '50%',
48
- background: avatarBg, display: 'flex', alignItems: 'center', justifyContent: 'center',
49
- color: 'white', fontFamily: 'Syne, sans-serif', fontWeight: 700, fontSize: '10px', flexShrink: 0,
50
- }"
51
- >{{ userInitial }}</div>
52
- <div>
53
- <p style="font-size: 12px; color: var(--text-primary); font-family: Inter, 'Helvetica Neue', Helvetica, 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei', '微软雅黑', Arial, sans-serif; margin: 0;">{{ user.name }}</p>
54
- <p class="font-mono" style="font-size: 10px; color: var(--text-muted); margin: 0;">{{ user.role }}</p>
55
- </div>
56
- </div>
57
- <div v-else style="display: flex; align-items: center; gap: 6px;">
58
- <span class="animate-pulse-slow" style="width: 6px; height: 6px; border-radius: 50%; background: #4ade80; display: inline-block;" />
59
- <span class="font-mono" style="font-size: 11px; color: var(--text-muted);">游客模式</span>
60
- </div>
61
- </div>
62
- </div>
63
- </template>
64
-
65
- <script setup>
66
- import { computed } from 'vue'
67
- import { Plus, Trash2 } from 'lucide-vue-next'
68
-
69
- const props = defineProps({
70
- store: { type: Object, required: true },
71
- user: { type: Object, default: null },
72
- })
73
-
74
- defineEmits(['close'])
75
-
76
- const AVATAR_COLORS = ['#1A6FC4', '#0891b2', '#059669', '#7c3aed', '#b45309']
77
- const userInitial = computed(() => (props.user?.name || props.user?.username || '?')[0].toUpperCase())
78
- const avatarBg = computed(() => AVATAR_COLORS[(props.user?.id || 0) % AVATAR_COLORS.length])
79
- </script>
80
-
81
- <style scoped>
82
- .delete-btn:hover { opacity: 1 !important; }
83
- :deep(.el-scrollbar__wrap) { overflow-x: hidden; }
84
- </style>