@opentiny/vue-docs 3.24.6 → 3.26.0

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 (249) hide show
  1. package/.stylelintrc.js +2 -2
  2. package/demos/apis/button.js +15 -0
  3. package/demos/apis/calendar-view.js +3 -2
  4. package/demos/apis/chart-demo.js +1 -1
  5. package/demos/apis/chart-docs.js +1 -1
  6. package/demos/apis/chart-events.js +1 -1
  7. package/demos/apis/chart-question.js +1 -1
  8. package/demos/apis/chart.js +1 -1
  9. package/demos/apis/form.js +3 -0
  10. package/demos/apis/grid.js +76 -16
  11. package/demos/apis/modal.js +1 -1
  12. package/demos/apis/numeric.js +3 -3
  13. package/demos/apis/search.js +28 -0
  14. package/demos/apis/slider-button.js +22 -0
  15. package/demos/apis/split.js +11 -0
  16. package/demos/apis/steps.js +3 -3
  17. package/demos/apis/tabs.js +12 -0
  18. package/demos/apis/time-line.js +20 -0
  19. package/demos/mobile-first/app/button/type.vue +1 -1
  20. package/demos/mobile-first/app/button/webdoc/button.js +2 -2
  21. package/demos/mobile-first/app/slider-button/basic-usage.vue +5 -5
  22. package/demos/mobile-first/app/slider-button/webdoc/slider-button.js +1 -1
  23. package/demos/mobile-first/app/steps/advanced-steps.vue +8 -1
  24. package/demos/mobile-first/menus.js +16 -9
  25. package/demos/pc/app/action-menu/basic-usage-composition-api.vue +1 -1
  26. package/demos/pc/app/action-menu/basic-usage.vue +1 -1
  27. package/demos/pc/app/action-menu/card-mode-composition-api.vue +1 -1
  28. package/demos/pc/app/action-menu/card-mode.vue +1 -1
  29. package/demos/pc/app/action-menu/disabled-composition-api.vue +2 -2
  30. package/demos/pc/app/action-menu/disabled.vue +2 -2
  31. package/demos/pc/app/action-menu/events-composition-api.vue +1 -1
  32. package/demos/pc/app/action-menu/events.vue +1 -1
  33. package/demos/pc/app/action-menu/icon-composition-api.vue +2 -2
  34. package/demos/pc/app/action-menu/icon.vue +2 -2
  35. package/demos/pc/app/action-menu/max-show-num-composition-api.vue +1 -1
  36. package/demos/pc/app/action-menu/max-show-num.vue +1 -1
  37. package/demos/pc/app/action-menu/more-text-composition-api.vue +1 -1
  38. package/demos/pc/app/action-menu/more-text.vue +1 -1
  39. package/demos/pc/app/action-menu/popper-class-composition-api.vue +1 -1
  40. package/demos/pc/app/action-menu/popper-class.vue +1 -1
  41. package/demos/pc/app/action-menu/slot-item-composition-api.vue +1 -1
  42. package/demos/pc/app/action-menu/slot-item.vue +1 -1
  43. package/demos/pc/app/action-menu/spacing-composition-api.vue +1 -1
  44. package/demos/pc/app/action-menu/spacing.vue +1 -1
  45. package/demos/pc/app/action-menu/text-field-composition-api.vue +1 -1
  46. package/demos/pc/app/action-menu/text-field.spec.ts +1 -1
  47. package/demos/pc/app/action-menu/text-field.vue +1 -1
  48. package/demos/pc/app/amount/custom-service.spec.js +4 -4
  49. package/demos/pc/app/base-select/slot-reference.spec.ts +1 -1
  50. package/demos/pc/app/button/icon-composition-api.vue +3 -1
  51. package/demos/pc/app/button/icon.vue +3 -1
  52. package/demos/pc/app/button/webdoc/button.js +3 -2
  53. package/demos/pc/app/calendar-view/calendar-mode-composition-api.vue +7 -1
  54. package/demos/pc/app/calendar-view/calendar-mode.spec.ts +3 -0
  55. package/demos/pc/app/calendar-view/calendar-mode.vue +7 -1
  56. package/demos/pc/app/carousel/webdoc/carousel.js +0 -18
  57. package/demos/pc/app/color-picker/alpha-composition-api.vue +1 -1
  58. package/demos/pc/app/color-picker/alpha.spec.ts +2 -2
  59. package/demos/pc/app/color-picker/alpha.vue +1 -1
  60. package/demos/pc/app/color-picker/base.spec.ts +2 -2
  61. package/demos/pc/app/color-picker/default-visible.spec.ts +1 -1
  62. package/demos/pc/app/color-picker/event-composition-api.vue +2 -2
  63. package/demos/pc/app/color-picker/event.spec.ts +4 -4
  64. package/demos/pc/app/color-picker/event.vue +1 -1
  65. package/demos/pc/app/color-picker/format.spec.ts +6 -6
  66. package/demos/pc/app/color-picker/history.spec.ts +1 -7
  67. package/demos/pc/app/color-picker/predefine.spec.ts +3 -10
  68. package/demos/pc/app/color-picker/size.spec.ts +4 -4
  69. package/demos/pc/app/color-select-panel/format.spec.ts +2 -8
  70. package/demos/pc/app/color-select-panel/history.spec.ts +0 -2
  71. package/demos/pc/app/color-select-panel/predefine.spec.ts +0 -3
  72. package/demos/pc/app/container/basic-usage-composition-api.vue +10 -10
  73. package/demos/pc/app/container/basic-usage.vue +10 -10
  74. package/demos/pc/app/container/custom-with-height-composition-api.vue +8 -8
  75. package/demos/pc/app/container/custom-with-height.vue +10 -10
  76. package/demos/pc/app/date-panel/custom-week.spec.ts +2 -2
  77. package/demos/pc/app/dialog-select/nest-grid-single.spec.ts +40 -0
  78. package/demos/pc/app/dialog-select/nest-tree-multi.spec.ts +53 -0
  79. package/demos/pc/app/dialog-select/nest-tree-single.spec.ts +25 -0
  80. package/demos/pc/app/dialog-select/set-selection.spec.ts +20 -0
  81. package/demos/pc/app/file-upload/before-upload-limit-composition-api.vue +1 -1
  82. package/demos/pc/app/file-upload/before-upload-limit.spec.ts +1 -1
  83. package/demos/pc/app/file-upload/before-upload-limit.vue +1 -1
  84. package/demos/pc/app/file-upload/custom-trigger-composition-api.vue +1 -1
  85. package/demos/pc/app/file-upload/custom-trigger.spec.ts +1 -1
  86. package/demos/pc/app/file-upload/custom-trigger.vue +1 -1
  87. package/demos/pc/app/file-upload/custom-upload-tip-composition-api.vue +1 -1
  88. package/demos/pc/app/file-upload/custom-upload-tip.vue +1 -1
  89. package/demos/pc/app/file-upload/form-validation-composition-api.vue +1 -1
  90. package/demos/pc/app/file-upload/form-validation.vue +1 -1
  91. package/demos/pc/app/file-upload/image-size-composition-api.vue +1 -1
  92. package/demos/pc/app/file-upload/image-size.spec.ts +1 -1
  93. package/demos/pc/app/file-upload/image-size.vue +1 -1
  94. package/demos/pc/app/file-upload/multiple-file-composition-api.vue +1 -1
  95. package/demos/pc/app/file-upload/multiple-file.spec.ts +1 -1
  96. package/demos/pc/app/file-upload/multiple-file.vue +1 -1
  97. package/demos/pc/app/file-upload/prevent-delete-file-composition-api.vue +1 -1
  98. package/demos/pc/app/file-upload/prevent-delete-file.vue +1 -1
  99. package/demos/pc/app/file-upload/upload-request-composition-api.vue +1 -1
  100. package/demos/pc/app/file-upload/upload-request.spec.ts +2 -2
  101. package/demos/pc/app/file-upload/upload-request.vue +1 -1
  102. package/demos/pc/app/grid/base/basic-usage-composition-api.vue +1 -17
  103. package/demos/pc/app/grid/custom/column-fixed.spec.js +2 -1
  104. package/demos/pc/app/grid/custom/page-size.spec.js +1 -1
  105. package/demos/pc/app/grid/data-source/auto-load.spec.js +0 -1
  106. package/demos/pc/app/grid/data-source/request-service.spec.js +1 -1
  107. package/demos/pc/app/grid/data-source/static-data.spec.js +1 -1
  108. package/demos/pc/app/grid/dynamically-columns/dynamically-columns.spec.js +2 -1
  109. package/demos/pc/app/grid/edit/scrollbar-not-blur-composition-api.vue +119 -0
  110. package/demos/pc/app/grid/edit/scrollbar-not-blur.spec.ts +28 -0
  111. package/demos/pc/app/grid/edit/scrollbar-not-blur.vue +129 -0
  112. package/demos/pc/app/grid/editor/custom-edit.spec.js +7 -2
  113. package/demos/pc/app/grid/empty/empty-data-iscenter.spec.js +1 -1
  114. package/demos/pc/app/grid/event/toolbar-button-click-event.spec.js +1 -1
  115. package/demos/pc/app/grid/expand/expand-trigger-slot-composition-api.vue +85 -0
  116. package/demos/pc/app/grid/expand/expand-trigger-slot.spec.ts +11 -0
  117. package/demos/pc/app/grid/expand/expand-trigger-slot.vue +95 -0
  118. package/demos/pc/app/grid/expand/set-row-expansion.spec.js +4 -0
  119. package/demos/pc/app/grid/filter/custom-filter.spec.js +3 -3
  120. package/demos/pc/app/grid/filter/default-filter-composition-api.vue +6 -0
  121. package/demos/pc/app/grid/filter/default-filter.vue +6 -0
  122. package/demos/pc/app/grid/filter/default-relation.spec.js +1 -1
  123. package/demos/pc/app/grid/filter/server-filter.spec.js +1 -1
  124. package/demos/pc/app/grid/filter/simple-filter.spec.ts +5 -4
  125. package/demos/pc/app/grid/fixed/right-fixed-composition-api.vue +4 -4
  126. package/demos/pc/app/grid/fixed/right-fixed.vue +4 -4
  127. package/demos/pc/app/grid/footer/footer-summation-empty.spec.js +0 -1
  128. package/demos/pc/app/grid/large-data/full-data-loading.spec.js +10 -3
  129. package/demos/pc/app/grid/large-data/virtual-rolling.spec.js +9 -2
  130. package/demos/pc/app/grid/mouse-keyboard/keyboard-navigation.spec.js +4 -1
  131. package/demos/pc/app/grid/renderer/inner-renderer-date-composition-api.vue +4 -3
  132. package/demos/pc/app/grid/renderer/inner-renderer-date.spec.js +2 -2
  133. package/demos/pc/app/grid/renderer/inner-renderer-date.vue +3 -3
  134. package/demos/pc/app/grid/renderer/inner-renderer.spec.js +4 -0
  135. package/demos/pc/app/grid/size/max-min-grid-height.spec.js +2 -2
  136. package/demos/pc/app/grid/slot/slot-conf-composition-api.vue +141 -0
  137. package/demos/pc/app/grid/slot/slot-conf.spec.js +12 -0
  138. package/demos/pc/app/grid/slot/slot-conf.vue +151 -0
  139. package/demos/pc/app/grid/sort/combinations-sort.spec.js +2 -2
  140. package/demos/pc/app/grid/webdoc/grid-edit.js +12 -0
  141. package/demos/pc/app/grid/webdoc/grid-empty.js +1 -1
  142. package/demos/pc/app/grid/webdoc/grid-expand.js +11 -0
  143. package/demos/pc/app/grid/webdoc/grid-slot.js +9 -0
  144. package/demos/pc/app/icon/iconGroups.js +8 -2
  145. package/demos/pc/app/input/basic-usage.spec.ts +1 -1
  146. package/demos/pc/app/loading/background.spec.ts +3 -1
  147. package/demos/pc/app/loading/custom-class.spec.ts +4 -2
  148. package/demos/pc/app/loading/fullscreen.spec.ts +6 -4
  149. package/demos/pc/app/loading/loading-tip-text.spec.ts +3 -1
  150. package/demos/pc/app/loading/size.spec.ts +5 -3
  151. package/demos/pc/app/locales/custom-service-composition-api.vue +3 -3
  152. package/demos/pc/app/locales/custom-service.spec.ts +1 -1
  153. package/demos/pc/app/locales/custom-service.vue +3 -3
  154. package/demos/pc/app/modal/basic-usage.spec.ts +2 -1
  155. package/demos/pc/app/modal/message-close.spec.ts +2 -2
  156. package/demos/pc/app/modal/message-id.spec.ts +2 -2
  157. package/demos/pc/app/modal/modal-fn-slots.spec.ts +5 -7
  158. package/demos/pc/app/modal/modal-header.spec.ts +2 -1
  159. package/demos/pc/app/numeric/input-event-composition-api.vue +26 -0
  160. package/demos/pc/app/numeric/input-event.spec.ts +15 -0
  161. package/demos/pc/app/numeric/input-event.vue +34 -0
  162. package/demos/pc/app/numeric/webdoc/numeric.js +12 -0
  163. package/demos/pc/app/pager/align-composition-api.vue +10 -13
  164. package/demos/pc/app/pager/align.spec.ts +8 -3
  165. package/demos/pc/app/pager/align.vue +11 -5
  166. package/demos/pc/app/pager/page-size-composition-api.vue +2 -2
  167. package/demos/pc/app/pager/page-size.spec.ts +1 -1
  168. package/demos/pc/app/pager/page-size.vue +2 -2
  169. package/demos/pc/app/pager/pager-in-grid-composition-api.vue +0 -1
  170. package/demos/pc/app/pager/pager-in-grid.vue +0 -1
  171. package/demos/pc/app/pager/popper-append-to-body-composition-api.vue +1 -7
  172. package/demos/pc/app/pager/popper-append-to-body.vue +1 -7
  173. package/demos/pc/app/pager/popper-class-composition-api.vue +1 -7
  174. package/demos/pc/app/pager/popper-class.vue +1 -7
  175. package/demos/pc/app/popeditor/conditions.spec.ts +1 -1
  176. package/demos/pc/app/popeditor/suggest.spec.ts +1 -1
  177. package/demos/pc/app/qr-code/icon-composition-api.vue +17 -3
  178. package/demos/pc/app/qr-code/icon.spec.ts +19 -0
  179. package/demos/pc/app/qr-code/icon.vue +25 -4
  180. package/demos/pc/app/qr-code/style-composition-api.vue +2 -9
  181. package/demos/pc/app/qr-code/style.spec.ts +18 -1
  182. package/demos/pc/app/qr-code/style.vue +11 -8
  183. package/demos/pc/app/query-builder/webdoc/query-builder.js +5 -3
  184. package/demos/pc/app/search/events.spec.ts +1 -1
  185. package/demos/pc/app/search/events.vue +9 -0
  186. package/demos/pc/app/search/slot-prefix-suffix.spec.ts +1 -1
  187. package/demos/pc/app/search/webdoc/search.js +12 -4
  188. package/demos/pc/app/select/nest-grid-remote.spec.ts +3 -3
  189. package/demos/pc/app/select/nest-grid.spec.ts +1 -1
  190. package/demos/pc/app/select/nest-radio-grid-much-data.spec.ts +5 -7
  191. package/demos/pc/app/tabs/basic-usage.spec.ts +2 -2
  192. package/demos/pc/app/tabs/header-only.vue +56 -0
  193. package/demos/pc/app/tabs/size.spec.ts +2 -2
  194. package/demos/pc/app/tabs/webdoc/tabs.js +12 -0
  195. package/demos/pc/app/time-line/slot-default-composition-api.vue +81 -0
  196. package/demos/pc/app/time-line/slot-default.spec.ts +13 -0
  197. package/demos/pc/app/time-line/slot-default.vue +95 -0
  198. package/demos/pc/app/time-line/webdoc/time-line.js +12 -0
  199. package/demos/pc/menus.js +20 -10
  200. package/demos/pc/webdoc/changelog-en.md +224 -197
  201. package/demos/pc/webdoc/changelog.md +167 -387
  202. package/demos/pc/webdoc/faq.md +14 -0
  203. package/demos/saas/menus.js +2 -14
  204. package/env/.env +3 -0
  205. package/package.json +25 -24
  206. package/playground/App.vue +2 -2
  207. package/postcss.config.cjs +1 -0
  208. package/src/App.vue +26 -59
  209. package/src/components/anchor.vue +5 -1
  210. package/src/components/demo.vue +18 -7
  211. package/src/components/design-token.vue +90 -0
  212. package/src/components/float-settings.vue +4 -23
  213. package/src/components/mcp-docs.vue +4 -26
  214. package/src/components/version-tip.vue +1 -1
  215. package/src/composable/useTinyRemoter.ts +176 -0
  216. package/src/composable/utils.ts +2 -166
  217. package/src/const.ts +6 -1
  218. package/src/i18n/en.json +2 -0
  219. package/src/i18n/es.json +47 -0
  220. package/src/i18n/index.js +24 -5
  221. package/src/i18n/pt.json +47 -0
  222. package/src/i18n/zh.json +2 -0
  223. package/src/main.js +17 -13
  224. package/src/{menus.jsx → menus.js} +0 -1
  225. package/src/router.js +3 -18
  226. package/src/tools/appData.js +6 -16
  227. package/src/tools/storage.js +5 -3
  228. package/src/tools/useApiMode.js +11 -3
  229. package/src/tools/useBulletin.jsx +9 -8
  230. package/src/tools/useStyleSettings.js +8 -0
  231. package/src/tools/useTemplateMode.js +5 -1
  232. package/src/tools/utils.js +32 -1
  233. package/src/views/components-doc/cmp-config.js +13 -1
  234. package/src/views/components-doc/common.vue +42 -15
  235. package/src/views/layout/layout.vue +5 -8
  236. package/src/views/overview.vue +1 -1
  237. package/tsconfig.node.json +2 -4
  238. package/src/components/MessageCard.vue +0 -117
  239. package/src/components/tiny-robot-chat.vue +0 -128
  240. package/src/composable/DifyModelProvider.ts +0 -65
  241. package/src/composable/useTinyRobot.ts +0 -167
  242. package/src/tools/useAllTaskFinish.ts +0 -0
  243. package/src/views/comprehensive/Demo.vue +0 -212
  244. package/src/views/comprehensive/index.vue +0 -380
  245. package/src/views/comprehensive/products.json +0 -98
  246. package/src/views/comprehensive/types/index.ts +0 -37
  247. package/src/views/remoter/index.vue +0 -63
  248. package/src/views/remoter/sound.vue +0 -349
  249. /package/demos/pc/app/grid/expand/{expand-config.spec.js → expand-config.spec.ts} +0 -0
@@ -1,349 +0,0 @@
1
- <template>
2
- <div class="sound-container">
3
- <div class="messages-container" ref="messagesContainer">
4
- <template v-if="messages && messages.length > 0">
5
- <message-card
6
- v-for="(msg, index) in messages"
7
- :key="index"
8
- :role="msg.role === 'system' ? 'assistant' : msg.role"
9
- :message="msg.content"
10
- :timestamp="messageTimestamps[index]"
11
- />
12
- </template>
13
- <div v-else class="empty-message">
14
- <p>暂无对话记录</p>
15
- </div>
16
- </div>
17
- <div class="sound-box">
18
- <div class="recording-status" v-show="isTalk">
19
- <div class="wave-animation"></div>
20
- <span>{{ recordingTime }}s</span>
21
- </div>
22
- <tiny-button
23
- @touchstart.prevent="handleStart"
24
- @touchend.prevent="handleEnd"
25
- @touchcancel.prevent="handleEnd"
26
- :type="isTalk ? 'danger' : 'info'"
27
- class="talk-button"
28
- size="large"
29
- :reset-time="0"
30
- :disabled="!isSupported"
31
- >
32
- {{ buttonText }}
33
- </tiny-button>
34
- </div>
35
- </div>
36
- </template>
37
-
38
- <script setup lang="ts">
39
- import { ref, computed, onUnmounted, watch, nextTick } from 'vue'
40
- import { TinyButton, TinyNotify } from '@opentiny/vue'
41
- import { useTinyRobot } from '../../composable/useTinyRobot'
42
- import MessageCard from '../../components/MessageCard.vue'
43
-
44
- // 类型定义
45
- interface SpeechRecognitionResult {
46
- [index: number]: {
47
- transcript: string
48
- confidence: number
49
- }
50
- isFinal?: boolean
51
- length: number
52
- }
53
-
54
- interface SpeechRecognitionResultList {
55
- [index: number]: SpeechRecognitionResult
56
- length: number
57
- }
58
-
59
- interface SpeechRecognitionEvent extends Event {
60
- results: SpeechRecognitionResultList
61
- }
62
-
63
- interface SpeechRecognitionErrorEvent extends Event {
64
- error: string
65
- message: string
66
- }
67
-
68
- // 获取SpeechRecognition构造函数
69
- const getSpeechRecognition = () => {
70
- const SpeechRecognition =
71
- (window as any).SpeechRecognition ||
72
- (window as any).webkitSpeechRecognition ||
73
- (window as any).mozSpeechRecognition ||
74
- (window as any).msSpeechRecognition
75
- return SpeechRecognition
76
- }
77
-
78
- // 状态管理
79
- const isTalk = ref(false)
80
- const isSupported = ref(false)
81
- const recordingTime = ref(0)
82
- const maxRecordingTime = 60
83
- let recognition: any = null
84
- let recordingTimer: number | null = null
85
- const messagesContainer = ref<HTMLElement | null>(null)
86
- const messageTimestamps = ref<number[]>([])
87
- const { sendMessage, messages } = useTinyRobot()
88
- const isSafari = /^((?!chrome|android).)*safari/i.test(navigator.userAgent)
89
-
90
- // 计算属性
91
- const buttonText = computed(() => {
92
- if (!isSupported.value) return '当前浏览器不支持语音识别'
93
- if (isTalk.value) return `录音中 ${recordingTime.value}s`
94
- return '长按说话'
95
- })
96
-
97
- // 监听消息变化,更新时间戳和自动滚动
98
- watch(
99
- () => messages.value,
100
- async (newMessages) => {
101
- if (!newMessages) return
102
-
103
- // 更新时间戳
104
- if (messageTimestamps.value.length < newMessages.length) {
105
- const timestamp = Date.now()
106
- messageTimestamps.value = newMessages.map((_, index) => messageTimestamps.value[index] || timestamp)
107
- }
108
-
109
- // 自动滚动到底部
110
- await nextTick()
111
- if (messagesContainer.value) {
112
- messagesContainer.value.scrollTop = messagesContainer.value.scrollHeight
113
- }
114
- },
115
- { deep: true }
116
- )
117
-
118
- // 初始化语音识别
119
- const initSpeechRecognition = () => {
120
- const SpeechRecognition = getSpeechRecognition()
121
-
122
- if (SpeechRecognition) {
123
- isSupported.value = true
124
- recognition = new SpeechRecognition()
125
- recognition.lang = 'zh-CN'
126
- recognition.continuous = false
127
- recognition.interimResults = false
128
- recognition.maxAlternatives = 1
129
-
130
- // Safari 需要特殊处理
131
- if (isSafari) {
132
- recognition.interimResults = true
133
- }
134
-
135
- let finalTranscript = ''
136
-
137
- recognition.addEventListener('result', (event: SpeechRecognitionEvent) => {
138
- const transcript = event.results[0][0].transcript
139
- if (transcript.trim()) {
140
- finalTranscript = transcript
141
- }
142
- })
143
-
144
- recognition.addEventListener('end', () => {
145
- stopRecording()
146
- // 确保在录音结束时发送消息
147
- if (finalTranscript.trim()) {
148
- sendMessage(finalTranscript)
149
- finalTranscript = ''
150
- }
151
- })
152
-
153
- recognition.addEventListener('error', (event: SpeechRecognitionErrorEvent) => {
154
- handleRecognitionError(event)
155
- finalTranscript = ''
156
- })
157
- } else {
158
- isSupported.value = false
159
- TinyNotify({
160
- type: 'error',
161
- title: '提示',
162
- message: '您的浏览器不支持语音识别,请使用Chrome、Safari或Edge浏览器',
163
- position: 'top-right',
164
- duration: 5000
165
- })
166
- }
167
- }
168
-
169
- // 错误处理
170
- const handleRecognitionError = (event: SpeechRecognitionErrorEvent) => {
171
- stopRecording()
172
- let errorMessage = '语音识别出错'
173
-
174
- switch (event.error) {
175
- case 'not-allowed':
176
- errorMessage = '请允许浏览器使用麦克风'
177
- break
178
- case 'no-speech':
179
- errorMessage = '未检测到语音,请重试'
180
- break
181
- case 'network':
182
- errorMessage = '网络连接出错,请检查网络后重试'
183
- break
184
- case 'aborted':
185
- return // 用户主动取消,不显示错误
186
- default:
187
- errorMessage = `语音识别失败: ${event.message || '未知错误'}`
188
- }
189
-
190
- TinyNotify({
191
- type: 'error',
192
- title: '语音识别出错',
193
- message: errorMessage,
194
- position: 'top-right',
195
- duration: 3000
196
- })
197
- }
198
-
199
- // 开始录音
200
- const handleStart = async (event: TouchEvent) => {
201
- event.preventDefault()
202
- event.stopPropagation()
203
-
204
- if (!isSupported.value) {
205
- TinyNotify({
206
- type: 'error',
207
- title: '提示',
208
- message: '当前浏览器不支持语音识别',
209
- position: 'top-right',
210
- duration: 3000
211
- })
212
- return
213
- }
214
-
215
- if (isTalk.value) return
216
-
217
- try {
218
- recognition.start()
219
- isTalk.value = true
220
- recordingTime.value = 0
221
- startRecordingTimer()
222
- } catch (error) {
223
- handleRecognitionError({
224
- error: 'start_error',
225
- message: '启动语音识别失败,请重试'
226
- } as SpeechRecognitionErrorEvent)
227
- }
228
- }
229
-
230
- // 结束录音
231
- const handleEnd = () => {
232
- if (!isTalk.value) return
233
- try {
234
- recognition.stop()
235
- } catch (error) {
236
- console.error('停止录音失败:', error)
237
- }
238
- stopRecording()
239
- }
240
-
241
- // 开始计时
242
- const startRecordingTimer = () => {
243
- recordingTimer = window.setInterval(() => {
244
- recordingTime.value++
245
- if (recordingTime.value >= maxRecordingTime) {
246
- handleEnd()
247
- TinyNotify({
248
- type: 'warning',
249
- title: '提示',
250
- message: '已达到最大录音时长',
251
- position: 'top-right',
252
- duration: 3000
253
- })
254
- }
255
- }, 1000)
256
- }
257
-
258
- // 停止录音
259
- const stopRecording = () => {
260
- isTalk.value = false
261
- if (recordingTimer) {
262
- clearInterval(recordingTimer)
263
- recordingTimer = null
264
- }
265
- }
266
-
267
- // 初始化
268
- initSpeechRecognition()
269
-
270
- // 组件卸载时清理
271
- onUnmounted(() => {
272
- if (recordingTimer) {
273
- clearInterval(recordingTimer)
274
- }
275
- if (recognition) {
276
- try {
277
- recognition.abort()
278
- } catch (error) {
279
- console.error('清理语音识别失败:', error)
280
- }
281
- }
282
- })
283
- </script>
284
-
285
- <style scoped lang="less">
286
- .sound-container {
287
- display: flex;
288
- flex-direction: column;
289
- height: 100vh;
290
- position: relative;
291
-
292
- .messages-container {
293
- flex: 1;
294
- overflow-y: auto;
295
- padding: 16px;
296
- margin-bottom: 120px;
297
-
298
- .empty-message {
299
- text-align: center;
300
- color: #999;
301
- padding: 20px;
302
- }
303
- }
304
-
305
- .sound-box {
306
- position: fixed;
307
- bottom: 0;
308
- left: 0;
309
- right: 0;
310
- margin: 10px;
311
- background: white;
312
- padding: 10px;
313
- box-shadow: 0 -2px 10px rgba(0, 0, 0, 0.1);
314
-
315
- .recording-status {
316
- text-align: center;
317
- margin-bottom: 10px;
318
-
319
- .wave-animation {
320
- width: 100px;
321
- height: 20px;
322
- margin: 0 auto 5px;
323
- background: linear-gradient(90deg, #ff4d4f 25%, #ff7875 50%, #ff4d4f 75%);
324
- background-size: 200% 100%;
325
- animation: wave 2s linear infinite;
326
- }
327
- }
328
-
329
- .talk-button {
330
- width: 100%;
331
- margin: 20px 0;
332
- transition: all 0.3s;
333
-
334
- &:active {
335
- transform: scale(0.98);
336
- }
337
- }
338
- }
339
- }
340
-
341
- @keyframes wave {
342
- 0% {
343
- background-position: 100% 50%;
344
- }
345
- 100% {
346
- background-position: 0% 50%;
347
- }
348
- }
349
- </style>