@tencent-rtc/trtc-agent-skills 0.1.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 (205) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +172 -0
  3. package/README.zh.md +173 -0
  4. package/bin/cli.js +434 -0
  5. package/knowledge-base/index.yaml +454 -0
  6. package/knowledge-base/platform-slice-template.md +233 -0
  7. package/knowledge-base/scenario-spec.md +350 -0
  8. package/knowledge-base/scenarios/conference/base/general-conference.md +365 -0
  9. package/knowledge-base/scenarios/conference/base/webinar-conference.md +130 -0
  10. package/knowledge-base/scenarios/conference/medical/1v1-video-consultation.md +145 -0
  11. package/knowledge-base/scenarios/conference/medical/medical-multidoctor-consultation.md +113 -0
  12. package/knowledge-base/scenarios/live/entertainment-live-room.md +118 -0
  13. package/knowledge-base/slice-spec.md +546 -0
  14. package/knowledge-base/slices/conference/web/ai-tools.md +225 -0
  15. package/knowledge-base/slices/conference/web/beauty-effects.md +188 -0
  16. package/knowledge-base/slices/conference/web/device-control.md +338 -0
  17. package/knowledge-base/slices/conference/web/login-auth.md +261 -0
  18. package/knowledge-base/slices/conference/web/network-quality.md +190 -0
  19. package/knowledge-base/slices/conference/web/official-roomkit-api.md +298 -0
  20. package/knowledge-base/slices/conference/web/official-roomkit-login-ui.md +246 -0
  21. package/knowledge-base/slices/conference/web/participant-list.md +238 -0
  22. package/knowledge-base/slices/conference/web/participant-management.md +718 -0
  23. package/knowledge-base/slices/conference/web/prejoin-check.md +293 -0
  24. package/knowledge-base/slices/conference/web/room-call.md +213 -0
  25. package/knowledge-base/slices/conference/web/room-chat.md +426 -0
  26. package/knowledge-base/slices/conference/web/room-lifecycle.md +534 -0
  27. package/knowledge-base/slices/conference/web/room-schedule.md +281 -0
  28. package/knowledge-base/slices/conference/web/screen-share.md +211 -0
  29. package/knowledge-base/slices/conference/web/video-layout.md +675 -0
  30. package/knowledge-base/slices/conference/web/virtual-background.md +197 -0
  31. package/knowledge-base/slices/conference/web/webinar-interaction.md +206 -0
  32. package/knowledge-base/slices/live/anchor-lifecycle.md +122 -0
  33. package/knowledge-base/slices/live/anchor-preview.md +90 -0
  34. package/knowledge-base/slices/live/anchor-room-config.md +104 -0
  35. package/knowledge-base/slices/live/audience-list.md +86 -0
  36. package/knowledge-base/slices/live/audience-manage.md +92 -0
  37. package/knowledge-base/slices/live/audience-watch.md +85 -0
  38. package/knowledge-base/slices/live/audio.md +116 -0
  39. package/knowledge-base/slices/live/barrage.md +88 -0
  40. package/knowledge-base/slices/live/beauty.md +99 -0
  41. package/knowledge-base/slices/live/coguest-apply.md +105 -0
  42. package/knowledge-base/slices/live/device-control.md +91 -0
  43. package/knowledge-base/slices/live/error-codes.md +167 -0
  44. package/knowledge-base/slices/live/gift.md +84 -0
  45. package/knowledge-base/slices/live/ios/.gitkeep +0 -0
  46. package/knowledge-base/slices/live/ios/anchor-lifecycle.md +313 -0
  47. package/knowledge-base/slices/live/ios/anchor-preview.md +228 -0
  48. package/knowledge-base/slices/live/ios/anchor-room-config.md +257 -0
  49. package/knowledge-base/slices/live/ios/audience-list.md +353 -0
  50. package/knowledge-base/slices/live/ios/audience-manage.md +381 -0
  51. package/knowledge-base/slices/live/ios/audience-watch.md +286 -0
  52. package/knowledge-base/slices/live/ios/audio.md +373 -0
  53. package/knowledge-base/slices/live/ios/barrage.md +285 -0
  54. package/knowledge-base/slices/live/ios/beauty.md +323 -0
  55. package/knowledge-base/slices/live/ios/coguest-apply.md +506 -0
  56. package/knowledge-base/slices/live/ios/device-control.md +286 -0
  57. package/knowledge-base/slices/live/ios/error-codes.md +270 -0
  58. package/knowledge-base/slices/live/ios/gift.md +315 -0
  59. package/knowledge-base/slices/live/ios/live-list.md +269 -0
  60. package/knowledge-base/slices/live/ios/login-auth.md +247 -0
  61. package/knowledge-base/slices/live/live-list.md +82 -0
  62. package/knowledge-base/slices/live/login-auth.md +78 -0
  63. package/package.json +34 -0
  64. package/skills/trtc/SKILL.md +326 -0
  65. package/skills/trtc/room-builder/SKILL.md +138 -0
  66. package/skills/trtc/room-builder/templates/scenarios/medical-consultation/README.md +108 -0
  67. package/skills/trtc/room-builder/templates/scenarios/medical-consultation/docs/backend-contract.zh-CN.md +162 -0
  68. package/skills/trtc/room-builder/templates/scenarios/medical-consultation/docs/integration.zh-CN.md +154 -0
  69. package/skills/trtc/room-builder/templates/scenarios/medical-consultation/docs/theme.zh-CN.md +78 -0
  70. package/skills/trtc/room-builder/templates/scenarios/medical-consultation/index.html +12 -0
  71. package/skills/trtc/room-builder/templates/scenarios/medical-consultation/package.json +28 -0
  72. package/skills/trtc/room-builder/templates/scenarios/medical-consultation/postcss.config.js +5 -0
  73. package/skills/trtc/room-builder/templates/scenarios/medical-consultation/src/App.vue +25 -0
  74. package/skills/trtc/room-builder/templates/scenarios/medical-consultation/src/components/ConsultationManagePanel.vue +838 -0
  75. package/skills/trtc/room-builder/templates/scenarios/medical-consultation/src/components/LanguageSwitch.vue +102 -0
  76. package/skills/trtc/room-builder/templates/scenarios/medical-consultation/src/components/LoadingSpinner.vue +6 -0
  77. package/skills/trtc/room-builder/templates/scenarios/medical-consultation/src/components/MedicalAlert.vue +34 -0
  78. package/skills/trtc/room-builder/templates/scenarios/medical-consultation/src/components/MedicalBusinessPanel.vue +148 -0
  79. package/skills/trtc/room-builder/templates/scenarios/medical-consultation/src/components/MedicalButton.vue +49 -0
  80. package/skills/trtc/room-builder/templates/scenarios/medical-consultation/src/components/MedicalConfirmDialog.vue +68 -0
  81. package/skills/trtc/room-builder/templates/scenarios/medical-consultation/src/components/MedicalDataPanel.vue +196 -0
  82. package/skills/trtc/room-builder/templates/scenarios/medical-consultation/src/components/MedicalRecordPanel.vue +270 -0
  83. package/skills/trtc/room-builder/templates/scenarios/medical-consultation/src/components/PrescriptionPanel.vue +363 -0
  84. package/skills/trtc/room-builder/templates/scenarios/medical-consultation/src/config/basic-info-config.ts +29 -0
  85. package/skills/trtc/room-builder/templates/scenarios/medical-consultation/src/config/lib-generate-test-usersig-es.min.d.ts +4 -0
  86. package/skills/trtc/room-builder/templates/scenarios/medical-consultation/src/config/lib-generate-test-usersig-es.min.js +2 -0
  87. package/skills/trtc/room-builder/templates/scenarios/medical-consultation/src/config/runtime-config.ts +12 -0
  88. package/skills/trtc/room-builder/templates/scenarios/medical-consultation/src/env.d.ts +32 -0
  89. package/skills/trtc/room-builder/templates/scenarios/medical-consultation/src/features/consultation/components/ConsultationChatPanel.vue +123 -0
  90. package/skills/trtc/room-builder/templates/scenarios/medical-consultation/src/features/consultation/components/ConsultationMembersPanel.vue +230 -0
  91. package/skills/trtc/room-builder/templates/scenarios/medical-consultation/src/features/consultation/components/ConsultationTranscriptionPanel.vue +135 -0
  92. package/skills/trtc/room-builder/templates/scenarios/medical-consultation/src/features/consultation/components/ConsultationVideoStage.vue +113 -0
  93. package/skills/trtc/room-builder/templates/scenarios/medical-consultation/src/features/consultation/components/InviteDoctorDialog.vue +132 -0
  94. package/skills/trtc/room-builder/templates/scenarios/medical-consultation/src/features/consultation/components/KickMemberConfirmDialog.vue +50 -0
  95. package/skills/trtc/room-builder/templates/scenarios/medical-consultation/src/features/consultation/types.ts +77 -0
  96. package/skills/trtc/room-builder/templates/scenarios/medical-consultation/src/features/consultation/useConsultationChat.ts +97 -0
  97. package/skills/trtc/room-builder/templates/scenarios/medical-consultation/src/features/consultation/useConsultationDevices.ts +48 -0
  98. package/skills/trtc/room-builder/templates/scenarios/medical-consultation/src/features/consultation/useConsultationParticipants.ts +121 -0
  99. package/skills/trtc/room-builder/templates/scenarios/medical-consultation/src/features/consultation/useConsultationPermissions.ts +25 -0
  100. package/skills/trtc/room-builder/templates/scenarios/medical-consultation/src/features/consultation/utils.ts +70 -0
  101. package/skills/trtc/room-builder/templates/scenarios/medical-consultation/src/i18n/en-US/index.ts +553 -0
  102. package/skills/trtc/room-builder/templates/scenarios/medical-consultation/src/i18n/index.ts +25 -0
  103. package/skills/trtc/room-builder/templates/scenarios/medical-consultation/src/i18n/medicalTranslate.ts +85 -0
  104. package/skills/trtc/room-builder/templates/scenarios/medical-consultation/src/i18n/state.ts +49 -0
  105. package/skills/trtc/room-builder/templates/scenarios/medical-consultation/src/i18n/zh-CN/index.ts +463 -0
  106. package/skills/trtc/room-builder/templates/scenarios/medical-consultation/src/main.ts +12 -0
  107. package/skills/trtc/room-builder/templates/scenarios/medical-consultation/src/mock/appointments.ts +96 -0
  108. package/skills/trtc/room-builder/templates/scenarios/medical-consultation/src/mock/users.ts +79 -0
  109. package/skills/trtc/room-builder/templates/scenarios/medical-consultation/src/router/index.ts +63 -0
  110. package/skills/trtc/room-builder/templates/scenarios/medical-consultation/src/services/adapters/index.ts +25 -0
  111. package/skills/trtc/room-builder/templates/scenarios/medical-consultation/src/services/adapters/integration/appointmentService.ts +77 -0
  112. package/skills/trtc/room-builder/templates/scenarios/medical-consultation/src/services/adapters/integration/authService.ts +38 -0
  113. package/skills/trtc/room-builder/templates/scenarios/medical-consultation/src/services/adapters/integration/launchContext.ts +31 -0
  114. package/skills/trtc/room-builder/templates/scenarios/medical-consultation/src/services/adapters/integration/userService.ts +35 -0
  115. package/skills/trtc/room-builder/templates/scenarios/medical-consultation/src/services/adapters/mock/appointmentService.ts +43 -0
  116. package/skills/trtc/room-builder/templates/scenarios/medical-consultation/src/services/adapters/mock/authService.ts +33 -0
  117. package/skills/trtc/room-builder/templates/scenarios/medical-consultation/src/services/adapters/mock/userService.ts +43 -0
  118. package/skills/trtc/room-builder/templates/scenarios/medical-consultation/src/services/adapters/types.ts +135 -0
  119. package/skills/trtc/room-builder/templates/scenarios/medical-consultation/src/shared/icons.ts +53 -0
  120. package/skills/trtc/room-builder/templates/scenarios/medical-consultation/src/styles/index.css +106 -0
  121. package/skills/trtc/room-builder/templates/scenarios/medical-consultation/src/styles/tailwind.css +3 -0
  122. package/skills/trtc/room-builder/templates/scenarios/medical-consultation/src/styles/theme.css +209 -0
  123. package/skills/trtc/room-builder/templates/scenarios/medical-consultation/src/utils/auth.ts +50 -0
  124. package/skills/trtc/room-builder/templates/scenarios/medical-consultation/src/utils/format.ts +24 -0
  125. package/skills/trtc/room-builder/templates/scenarios/medical-consultation/src/utils/navigation.ts +12 -0
  126. package/skills/trtc/room-builder/templates/scenarios/medical-consultation/src/utils/session.ts +28 -0
  127. package/skills/trtc/room-builder/templates/scenarios/medical-consultation/src/views/DoctorConsultationView.vue +777 -0
  128. package/skills/trtc/room-builder/templates/scenarios/medical-consultation/src/views/DoctorDashboardView.vue +678 -0
  129. package/skills/trtc/room-builder/templates/scenarios/medical-consultation/src/views/LoginView.vue +441 -0
  130. package/skills/trtc/room-builder/templates/scenarios/medical-consultation/src/views/PatientConsultationFinishedView.vue +185 -0
  131. package/skills/trtc/room-builder/templates/scenarios/medical-consultation/src/views/PatientConsultationView.vue +1003 -0
  132. package/skills/trtc/room-builder/templates/scenarios/medical-consultation/src/views/PatientSelectDoctorView.vue +317 -0
  133. package/skills/trtc/room-builder/templates/scenarios/medical-consultation/src/views/PatientWaitingView.vue +454 -0
  134. package/skills/trtc/room-builder/templates/scenarios/medical-consultation/tsconfig.json +21 -0
  135. package/skills/trtc/room-builder/templates/scenarios/medical-consultation/tsconfig.node.json +8 -0
  136. package/skills/trtc/room-builder/templates/scenarios/medical-consultation/vite.config.ts +17 -0
  137. package/skills/trtc/room-builder/templates/scenarios/medical-consultation//346/216/245/345/205/245/350/257/264/346/230/216.md +6 -0
  138. package/skills/trtc/room-builder/tools/render_ai_instructions.py +226 -0
  139. package/skills/trtc-apply/SKILL.md +97 -0
  140. package/skills/trtc-apply/guardrails/apply_lib/__init__.py +0 -0
  141. package/skills/trtc-apply/guardrails/apply_lib/__pycache__/__init__.cpython-313.pyc +0 -0
  142. package/skills/trtc-apply/guardrails/apply_lib/__pycache__/rule_parser.cpython-313.pyc +0 -0
  143. package/skills/trtc-apply/guardrails/apply_lib/rule_parser.py +268 -0
  144. package/skills/trtc-docs/SKILL.md +207 -0
  145. package/skills/trtc-onboarding/SKILL.md +839 -0
  146. package/skills/trtc-onboarding/reference/path-a1-demo.md +103 -0
  147. package/skills/trtc-onboarding/reference/path-a2-integrate.md +693 -0
  148. package/skills/trtc-onboarding/reference/path-b-troubleshoot.md +115 -0
  149. package/skills/trtc-onboarding/reference/path-c-expand.md +43 -0
  150. package/skills/trtc-onboarding/reference/reporting-protocol.md +174 -0
  151. package/skills/trtc-onboarding/reference/supported-matrix.md +100 -0
  152. package/skills/trtc-onboarding/reference/usersig-handling.md +140 -0
  153. package/skills/trtc-search/SKILL.md +221 -0
  154. package/skills/trtc-topic/SKILL.md +638 -0
  155. package/skills/trtc-topic/guardrails/__pycache__/gate_slice_read.cpython-313.pyc +0 -0
  156. package/skills/trtc-topic/guardrails/__pycache__/gate_slice_write.cpython-313.pyc +0 -0
  157. package/skills/trtc-topic/guardrails/__pycache__/stop_require_apply_evidence.cpython-313.pyc +0 -0
  158. package/skills/trtc-topic/guardrails/gate_slice_read.py +133 -0
  159. package/skills/trtc-topic/guardrails/gate_slice_write.py +169 -0
  160. package/skills/trtc-topic/guardrails/stop_require_apply_evidence.py +97 -0
  161. package/skills/trtc-topic/references/execution-units.yaml +58 -0
  162. package/skills/trtc-topic/runtime/README.md +50 -0
  163. package/skills/trtc-topic/runtime/RUNTIME.md +128 -0
  164. package/skills/trtc-topic/runtime/lib/__init__.py +0 -0
  165. package/skills/trtc-topic/runtime/lib/platforms.py +194 -0
  166. package/skills/trtc-topic/runtime/package-lock.json +1211 -0
  167. package/skills/trtc-topic/runtime/package.json +13 -0
  168. package/skills/trtc-topic/runtime/telemetry-bridge.mjs +339 -0
  169. package/skills/trtc-topic/runtime/telemetry_collector.py +293 -0
  170. package/skills/trtc-topic/scripts/STATE-MACHINE-GUIDE.md +186 -0
  171. package/skills/trtc-topic/scripts/__pycache__/apply.cpython-313.pyc +0 -0
  172. package/skills/trtc-topic/scripts/apply.py +581 -0
  173. package/skills/trtc-topic/scripts/finalize_session.py +113 -0
  174. package/skills/trtc-topic/scripts/init_slice_queue.py +96 -0
  175. package/skills/trtc-topic/scripts/lib/__pycache__/state_machine.cpython-313.pyc +0 -0
  176. package/skills/trtc-topic/scripts/lib/state_machine.py +328 -0
  177. package/skills/trtc-topic/scripts/next_slice.py +137 -0
  178. package/skills/trtc-topic/tests/README.md +70 -0
  179. package/skills/trtc-topic/tests/__pycache__/conftest.cpython-313-pytest-9.0.2.pyc +0 -0
  180. package/skills/trtc-topic/tests/__pycache__/conftest.cpython-313-pytest-9.0.3.pyc +0 -0
  181. package/skills/trtc-topic/tests/__pycache__/test_apply_cli.cpython-313-pytest-9.0.2.pyc +0 -0
  182. package/skills/trtc-topic/tests/__pycache__/test_apply_cli.cpython-313-pytest-9.0.3.pyc +0 -0
  183. package/skills/trtc-topic/tests/__pycache__/test_end_to_end.cpython-313-pytest-9.0.2.pyc +0 -0
  184. package/skills/trtc-topic/tests/__pycache__/test_end_to_end.cpython-313-pytest-9.0.3.pyc +0 -0
  185. package/skills/trtc-topic/tests/__pycache__/test_finalize_session.cpython-313-pytest-9.0.2.pyc +0 -0
  186. package/skills/trtc-topic/tests/__pycache__/test_finalize_session.cpython-313-pytest-9.0.3.pyc +0 -0
  187. package/skills/trtc-topic/tests/__pycache__/test_gates.cpython-313-pytest-9.0.2.pyc +0 -0
  188. package/skills/trtc-topic/tests/__pycache__/test_gates.cpython-313-pytest-9.0.3.pyc +0 -0
  189. package/skills/trtc-topic/tests/__pycache__/test_session_resolver.cpython-313-pytest-9.0.2.pyc +0 -0
  190. package/skills/trtc-topic/tests/__pycache__/test_session_resolver.cpython-313-pytest-9.0.3.pyc +0 -0
  191. package/skills/trtc-topic/tests/__pycache__/test_state_machine.cpython-313-pytest-9.0.2.pyc +0 -0
  192. package/skills/trtc-topic/tests/__pycache__/test_state_machine.cpython-313-pytest-9.0.3.pyc +0 -0
  193. package/skills/trtc-topic/tests/__pycache__/test_stop_require_apply.cpython-313-pytest-9.0.2.pyc +0 -0
  194. package/skills/trtc-topic/tests/__pycache__/test_stop_require_apply.cpython-313-pytest-9.0.3.pyc +0 -0
  195. package/skills/trtc-topic/tests/__pycache__/test_topic_skill_invariants.cpython-313-pytest-9.0.2.pyc +0 -0
  196. package/skills/trtc-topic/tests/__pycache__/test_topic_skill_invariants.cpython-313-pytest-9.0.3.pyc +0 -0
  197. package/skills/trtc-topic/tests/conftest.py +72 -0
  198. package/skills/trtc-topic/tests/test_apply_cli.py +480 -0
  199. package/skills/trtc-topic/tests/test_end_to_end.py +305 -0
  200. package/skills/trtc-topic/tests/test_finalize_session.py +51 -0
  201. package/skills/trtc-topic/tests/test_gates.py +316 -0
  202. package/skills/trtc-topic/tests/test_session_resolver.py +260 -0
  203. package/skills/trtc-topic/tests/test_state_machine.py +414 -0
  204. package/skills/trtc-topic/tests/test_stop_require_apply.py +99 -0
  205. package/skills/trtc-topic/tests/test_topic_skill_invariants.py +130 -0
@@ -0,0 +1,454 @@
1
+ <script setup lang="ts">
2
+ import { computed, onBeforeUnmount, onMounted, ref } from 'vue';
3
+ import { useRoute, useRouter } from 'vue-router';
4
+ import { useUIKit } from '@tencentcloud/uikit-base-component-vue3';
5
+ import {
6
+ Activity,
7
+ CheckCircle2,
8
+ FileText,
9
+ Phone,
10
+ Shield,
11
+ Stethoscope,
12
+ Video,
13
+ X,
14
+ } from '@/shared/icons';
15
+ import { RoomEvent, useRoomState } from 'tuikit-atomicx-vue3';
16
+ import { services } from '@/services/adapters';
17
+ import { formatTimeRange } from '@/utils/format';
18
+ import { getSessionUser } from '@/utils/session';
19
+ import LoadingSpinner from '@/components/LoadingSpinner.vue';
20
+ import MedicalButton from '@/components/MedicalButton.vue';
21
+ import LanguageSwitch from '@/components/LanguageSwitch.vue';
22
+
23
+ const route = useRoute();
24
+ const router = useRouter();
25
+ const roomState = useRoomState();
26
+ const { t } = useUIKit();
27
+
28
+ const joining = ref(false);
29
+ const rejecting = ref(false);
30
+ const returning = ref(false);
31
+ const incomingCall = ref(false);
32
+ const callMessage = ref(t('Medical.PatientWaiting.InitialCallMessage'));
33
+
34
+ const appointment = computed(() =>
35
+ services.appointment.getAppointmentById(String(route.params.appointmentId))
36
+ );
37
+ const doctor = computed(() =>
38
+ appointment.value
39
+ ? services.user.getDoctorById(appointment.value.doctorId)
40
+ : null
41
+ );
42
+ const appointmentTime = computed(() => {
43
+ if (!appointment.value) {
44
+ return '-';
45
+ }
46
+ return formatTimeRange(
47
+ appointment.value.scheduleStartTime,
48
+ appointment.value.scheduleEndTime
49
+ );
50
+ });
51
+
52
+ async function acceptIncomingCall() {
53
+ if (!appointment.value || joining.value || rejecting.value) {
54
+ return;
55
+ }
56
+ joining.value = true;
57
+ try {
58
+ if (incomingCall.value) {
59
+ try {
60
+ await roomState.acceptCall({ roomId: appointment.value.roomId });
61
+ } catch {
62
+ await roomState.joinRoom({ roomId: appointment.value.roomId });
63
+ }
64
+ } else {
65
+ await roomState.joinRoom({ roomId: appointment.value.roomId });
66
+ }
67
+ router.push(`/patient/consultation/${appointment.value.id}`);
68
+ callMessage.value = '';
69
+ } catch (error) {
70
+ callMessage.value =
71
+ error instanceof Error ? error.message : t('Medical.PatientWaiting.JoinFailed');
72
+ } finally {
73
+ joining.value = false;
74
+ }
75
+ }
76
+
77
+ async function rejectIncomingCall() {
78
+ if (!appointment.value || joining.value || rejecting.value) {
79
+ return;
80
+ }
81
+ rejecting.value = true;
82
+ try {
83
+ await roomState
84
+ .rejectCall({ roomId: appointment.value.roomId })
85
+ .catch(() => undefined);
86
+ incomingCall.value = false;
87
+ callMessage.value = t('Medical.PatientWaiting.RejectedMessage');
88
+ } finally {
89
+ rejecting.value = false;
90
+ }
91
+ }
92
+
93
+ async function returnToDoctorList() {
94
+ if (returning.value) {
95
+ return;
96
+ }
97
+ returning.value = true;
98
+ try {
99
+ await router.replace('/patient/select-doctor');
100
+ } finally {
101
+ returning.value = false;
102
+ }
103
+ }
104
+
105
+ function handleCallReceived(eventInfo: any) {
106
+ if (eventInfo.roomInfo?.roomId !== appointment.value?.roomId) {
107
+ return;
108
+ }
109
+ incomingCall.value = true;
110
+ callMessage.value =
111
+ eventInfo.extensionInfo || t('Medical.PatientWaiting.CallingMessage', { doctor: doctor.value?.userName });
112
+ }
113
+
114
+ function handleCallCancelled(eventInfo: any) {
115
+ if (eventInfo.roomInfo?.roomId !== appointment.value?.roomId) {
116
+ return;
117
+ }
118
+ incomingCall.value = false;
119
+ callMessage.value = t('Medical.PatientWaiting.CancelledMessage');
120
+ }
121
+
122
+ function handleCallTimeout(eventInfo: any) {
123
+ if (eventInfo.roomInfo?.roomId !== appointment.value?.roomId) {
124
+ return;
125
+ }
126
+ incomingCall.value = false;
127
+ callMessage.value = t('Medical.PatientWaiting.TimeoutMessage');
128
+ }
129
+
130
+ onMounted(async () => {
131
+ const currentUser = getSessionUser();
132
+ if (!currentUser || currentUser.role !== 'patient' || !appointment.value) {
133
+ router.replace('/login');
134
+ return;
135
+ }
136
+
137
+ await roomState.getScheduledRoomList({ cursor: '' }).catch(() => undefined);
138
+ roomState.subscribeEvent(RoomEvent.onCallReceived, handleCallReceived);
139
+ roomState.subscribeEvent(RoomEvent.onCallCancelled, handleCallCancelled);
140
+ roomState.subscribeEvent(RoomEvent.onCallTimeout, handleCallTimeout);
141
+ });
142
+
143
+ onBeforeUnmount(() => {
144
+ roomState.unsubscribeEvent(RoomEvent.onCallReceived, handleCallReceived);
145
+ roomState.unsubscribeEvent(RoomEvent.onCallCancelled, handleCallCancelled);
146
+ roomState.unsubscribeEvent(RoomEvent.onCallTimeout, handleCallTimeout);
147
+ });
148
+ </script>
149
+
150
+ <template>
151
+ <Teleport to="body">
152
+ <div
153
+ v-if="incomingCall && appointment && doctor"
154
+ class="fixed inset-0 z-[100] flex h-[100dvh] w-screen items-center justify-center bg-black/50 p-4 backdrop-blur-sm"
155
+ >
156
+ <div
157
+ class="w-full max-w-sm border-none shadow-2xl rounded-3xl overflow-hidden bg-white animate-in fade-in zoom-in duration-300 relative"
158
+ >
159
+ <button
160
+ @click="rejectIncomingCall"
161
+ :disabled="rejecting || joining"
162
+ class="absolute top-4 right-4 z-10 w-8 h-8 rounded-full bg-white/20 backdrop-blur-sm hover:bg-white/30 transition-colors flex items-center justify-center disabled:opacity-60 disabled:cursor-not-allowed"
163
+ >
164
+ <LoadingSpinner v-if="rejecting" class="text-white" />
165
+ <X v-else class="w-5 h-5 text-white" />
166
+ </button>
167
+
168
+ <div
169
+ class="bg-gradient-to-r from-[#10B981] to-[#0D9488] p-6 text-center"
170
+ >
171
+ <div class="relative inline-block mb-4">
172
+ <div
173
+ class="w-24 h-24 rounded-full bg-white/20 backdrop-blur-sm flex items-center justify-center mx-auto"
174
+ >
175
+ <Phone class="w-12 h-12 text-white" />
176
+ </div>
177
+ <div
178
+ class="absolute inset-0 rounded-full border-4 border-white/50 animate-ping"
179
+ ></div>
180
+ <div
181
+ class="absolute inset-0 rounded-full border-4 border-white/30"
182
+ ></div>
183
+ </div>
184
+ <h3 class="text-2xl font-semibold text-white mb-2">{{ t('Medical.PatientWaiting.DoctorCalling') }}</h3>
185
+ <p class="text-white/90 text-sm">
186
+ {{ t('Medical.PatientWaiting.InviteToConsultation', { doctor: doctor.userName }) }}
187
+ </p>
188
+ </div>
189
+ <div class="p-6 bg-white">
190
+ <div class="flex items-center gap-3 mb-6 p-4 bg-gray-50 rounded-xl">
191
+ <div
192
+ class="w-12 h-12 rounded-full bg-gradient-to-br from-[#0D9488] to-[#0F766E] text-white flex items-center justify-center text-lg font-semibold"
193
+ >
194
+ {{ doctor.userName.slice(0, 1) }}
195
+ </div>
196
+ <div>
197
+ <p class="font-semibold text-gray-900">{{ doctor.userName }}</p>
198
+ <p class="text-sm text-gray-500">
199
+ {{ doctor.department }} · {{ doctor.title }}
200
+ </p>
201
+ </div>
202
+ </div>
203
+ <div class="flex gap-3">
204
+ <MedicalButton
205
+ @click="rejectIncomingCall"
206
+ :disabled="rejecting || joining"
207
+ :loading="rejecting"
208
+ variant="outline"
209
+ size="lg"
210
+ class="flex-1"
211
+ >
212
+ {{ rejecting ? t('Medical.Common.Processing') : t('Medical.PatientWaiting.JoinLater') }}
213
+ </MedicalButton>
214
+ <MedicalButton
215
+ @click="acceptIncomingCall"
216
+ :loading="joining"
217
+ size="lg"
218
+ class="flex-1 bg-gradient-to-r from-medical-success to-primary hover:from-primary hover:to-primary-hover shadow-lg shadow-emerald-500/30"
219
+ >
220
+ <Video v-if="!joining" class="w-5 h-5" />
221
+ {{ joining ? t('Medical.PatientWaiting.Joining') : t('Medical.PatientWaiting.JoinNow') }}
222
+ </MedicalButton>
223
+ </div>
224
+ </div>
225
+ </div>
226
+ </div>
227
+ </Teleport>
228
+
229
+ <div
230
+ v-if="appointment && doctor"
231
+ class="min-h-screen bg-gradient-to-b from-[#F8FAFB] to-[#E0F2F1]"
232
+ >
233
+ <div class="bg-gradient-to-r from-[#0D9488] to-[#0F766E] pt-safe">
234
+ <div class="px-4 py-4 text-white">
235
+ <div class="flex items-start justify-between gap-3 mb-2">
236
+ <div class="flex items-center gap-3 min-w-0">
237
+ <div class="bg-white/20 backdrop-blur-sm p-2 rounded-xl">
238
+ <Stethoscope class="w-5 h-5" />
239
+ </div>
240
+ <div class="min-w-0">
241
+ <h1 class="font-semibold text-2xl leading-none">{{ t('Medical.Common.PlatformName') }}</h1>
242
+ <p class="text-xs text-white/80 mt-1">{{ t('Medical.PatientWaiting.Subtitle') }}</p>
243
+ </div>
244
+ </div>
245
+ <LanguageSwitch />
246
+ </div>
247
+ </div>
248
+ </div>
249
+
250
+ <div class="px-4 py-4 space-y-4 pb-safe">
251
+ <div
252
+ class="border-none shadow-[0_4px_20px_rgba(0,0,0,0.08)] rounded-3xl bg-white overflow-hidden"
253
+ >
254
+ <div class="p-6 text-center">
255
+ <div class="relative inline-block mb-6">
256
+ <div class="absolute inset-0 flex items-center justify-center">
257
+ <div
258
+ class="w-40 h-40 rounded-full bg-[#0D9488]/5 animate-pulse"
259
+ ></div>
260
+ </div>
261
+ <div
262
+ class="absolute inset-0 flex items-center justify-center animate-spin"
263
+ style="animation-duration: 4s"
264
+ >
265
+ <svg class="w-36 h-36" viewBox="0 0 100 100">
266
+ <circle
267
+ cx="50"
268
+ cy="50"
269
+ r="45"
270
+ fill="none"
271
+ stroke="url(#waiting-ring-gradient)"
272
+ stroke-width="3"
273
+ stroke-linecap="round"
274
+ stroke-dasharray="70 200"
275
+ />
276
+ <defs>
277
+ <linearGradient
278
+ id="waiting-ring-gradient"
279
+ x1="0%"
280
+ y1="0%"
281
+ x2="100%"
282
+ y2="100%"
283
+ >
284
+ <stop offset="0%" stop-color="#0D9488" stop-opacity="0.8" />
285
+ <stop
286
+ offset="100%"
287
+ stop-color="#10B981"
288
+ stop-opacity="0.3"
289
+ />
290
+ </linearGradient>
291
+ </defs>
292
+ </svg>
293
+ </div>
294
+ <div
295
+ class="relative w-28 h-28 rounded-full bg-gradient-to-br from-[#0D9488] to-[#0F766E] flex items-center justify-center mx-auto shadow-xl shadow-teal-500/20"
296
+ >
297
+ <Stethoscope class="w-14 h-14 text-white animate-pulse" />
298
+ </div>
299
+ </div>
300
+
301
+ <h2 class="text-2xl font-semibold text-gray-900 mb-2">{{ t('Medical.PatientWaiting.Title') }}</h2>
302
+ <p class="text-gray-600 mb-6 text-base leading-7">
303
+ {{ t('Medical.PatientWaiting.Description') }}
304
+ </p>
305
+
306
+ <div
307
+ class="inline-flex items-center gap-4 bg-gradient-to-r from-[#F0FDFA] to-white px-6 py-4 rounded-2xl shadow-sm border border-[#0D9488]/10"
308
+ >
309
+ <div
310
+ class="w-12 h-12 rounded-full ring-2 ring-[#0D9488]/20 bg-gradient-to-br from-[#0D9488] to-[#0F766E] text-white flex items-center justify-center text-lg font-semibold"
311
+ >
312
+ {{ doctor.userName.slice(0, 1) }}
313
+ </div>
314
+ <div class="text-left">
315
+ <p class="font-semibold text-gray-900">{{ doctor.userName }}</p>
316
+ <p class="text-sm text-gray-500">
317
+ {{ doctor.department }} · {{ doctor.title }}
318
+ </p>
319
+ </div>
320
+ <span
321
+ class="bg-emerald-500/10 text-emerald-700 shrink-0 ml-2 px-2.5 py-1 rounded-full text-xs font-medium"
322
+ >
323
+ {{ t('Medical.Common.Online') }}
324
+ </span>
325
+ </div>
326
+ <p class="text-xs text-gray-500 mt-4">{{ callMessage }}</p>
327
+ </div>
328
+
329
+ <div class="h-px bg-gray-100"></div>
330
+
331
+ <div class="p-6 bg-gray-50">
332
+ <h3 class="font-medium text-gray-900 mb-4 text-sm">{{ t('Medical.PatientWaiting.Flow') }}</h3>
333
+ <div class="space-y-4">
334
+ <div class="flex items-start gap-3">
335
+ <div
336
+ class="w-8 h-8 rounded-full bg-emerald-500 flex items-center justify-center shrink-0 shadow-md"
337
+ >
338
+ <CheckCircle2 class="w-5 h-5 text-white" />
339
+ </div>
340
+ <div class="flex-1 pt-1">
341
+ <p class="font-medium text-gray-900 text-sm">{{ t('Medical.PatientWaiting.StepAppointment') }}</p>
342
+ <p class="text-xs text-gray-500 mt-0.5">{{ t('Medical.PatientWaiting.StepAppointmentDesc') }}</p>
343
+ </div>
344
+ </div>
345
+
346
+ <div class="flex items-start gap-3">
347
+ <div
348
+ class="w-8 h-8 rounded-full bg-[#0D9488] flex items-center justify-center shrink-0 shadow-md"
349
+ >
350
+ <Activity class="w-5 h-5 text-white animate-pulse" />
351
+ </div>
352
+ <div class="flex-1 pt-1">
353
+ <p class="font-medium text-[#0D9488] text-sm">
354
+ {{ t('Medical.PatientWaiting.StepWaiting') }}
355
+ </p>
356
+ <p class="text-xs text-gray-500 mt-0.5">{{ t('Medical.PatientWaiting.StepWaitingDesc') }}</p>
357
+ </div>
358
+ </div>
359
+
360
+ <div class="flex items-start gap-3">
361
+ <div
362
+ class="w-8 h-8 rounded-full bg-gray-200 flex items-center justify-center shrink-0"
363
+ >
364
+ <Video class="w-5 h-5 text-gray-400" />
365
+ </div>
366
+ <div class="flex-1 pt-1">
367
+ <p class="text-sm text-gray-400">{{ t('Medical.PatientWaiting.StepVideo') }}</p>
368
+ <p class="text-xs text-gray-400 mt-0.5">{{ t('Medical.PatientWaiting.StepVideoDesc') }}</p>
369
+ </div>
370
+ </div>
371
+
372
+ <div class="flex items-start gap-3">
373
+ <div
374
+ class="w-8 h-8 rounded-full bg-gray-200 flex items-center justify-center shrink-0"
375
+ >
376
+ <FileText class="w-5 h-5 text-gray-400" />
377
+ </div>
378
+ <div class="flex-1 pt-1">
379
+ <p class="text-sm text-gray-400">{{ t('Medical.PatientWaiting.StepPrescription') }}</p>
380
+ <p class="text-xs text-gray-400 mt-0.5">{{ t('Medical.PatientWaiting.StepPrescriptionDesc') }}</p>
381
+ </div>
382
+ </div>
383
+ </div>
384
+ </div>
385
+ </div>
386
+
387
+ <div
388
+ class="border-none shadow-[0_2px_12px_rgba(0,0,0,0.06)] rounded-2xl bg-white"
389
+ >
390
+ <div class="p-5">
391
+ <h3 class="font-semibold text-gray-900 mb-4 flex items-center gap-2">
392
+ <FileText class="w-4 h-4 text-[#0D9488]" />
393
+ {{ t('Medical.PatientWaiting.AppointmentDetails') }}
394
+ </h3>
395
+ <div class="space-y-3">
396
+ <div class="flex items-center justify-between py-2">
397
+ <span class="text-sm text-gray-500">{{ t('Medical.PatientWaiting.AppointmentTime') }}</span>
398
+ <span class="text-sm font-medium text-gray-900">{{
399
+ appointmentTime
400
+ }}</span>
401
+ </div>
402
+ <div class="h-px bg-gray-100"></div>
403
+ <div class="flex items-center justify-between py-2">
404
+ <span class="text-sm text-gray-500">{{ t('Medical.PatientWaiting.AppointmentId') }}</span>
405
+ <span class="text-sm font-mono font-medium text-gray-900">{{
406
+ appointment.id
407
+ }}</span>
408
+ </div>
409
+ <div class="h-px bg-gray-100"></div>
410
+ <div class="py-2">
411
+ <span class="text-sm text-gray-500 block mb-2">{{ t('Medical.PatientWaiting.ChiefComplaint') }}</span>
412
+ <p class="text-sm text-gray-900 bg-gray-50 p-3 rounded-xl">
413
+ {{ appointment.chiefComplaint }}
414
+ </p>
415
+ </div>
416
+ </div>
417
+ </div>
418
+ </div>
419
+
420
+ <div
421
+ class="border-none shadow-[0_2px_12px_rgba(0,0,0,0.06)] rounded-2xl bg-gradient-to-r from-blue-50 to-white border-l-4 border-l-blue-500"
422
+ >
423
+ <div class="p-5">
424
+ <div class="flex items-start gap-3">
425
+ <div
426
+ class="w-8 h-8 rounded-lg bg-blue-100 flex items-center justify-center shrink-0"
427
+ >
428
+ <Shield class="w-4 h-4 text-blue-600" />
429
+ </div>
430
+ <div>
431
+ <h4 class="font-semibold text-gray-900 mb-2 text-sm">{{ t('Medical.Login.Tips') }}</h4>
432
+ <ul class="text-xs text-gray-600 space-y-1.5 leading-relaxed">
433
+ <li>{{ t('Medical.PatientWaiting.Tip1') }}</li>
434
+ <li>{{ t('Medical.PatientWaiting.Tip2') }}</li>
435
+ <li>{{ t('Medical.PatientWaiting.Tip3') }}</li>
436
+ </ul>
437
+ </div>
438
+ </div>
439
+ </div>
440
+ </div>
441
+
442
+ <MedicalButton
443
+ v-if="!incomingCall"
444
+ @click="returnToDoctorList"
445
+ :loading="returning"
446
+ variant="outline"
447
+ size="lg"
448
+ block
449
+ >
450
+ {{ returning ? t('Medical.PatientWaiting.Returning') : t('Medical.PatientWaiting.BackToDoctors') }}
451
+ </MedicalButton>
452
+ </div>
453
+ </div>
454
+ </template>
@@ -0,0 +1,21 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "esnext",
4
+ "useDefineForClassFields": true,
5
+ "module": "esnext",
6
+ "moduleResolution": "bundler",
7
+ "strict": false,
8
+ "jsx": "preserve",
9
+ "jsxImportSource": "vue",
10
+ "sourceMap": true,
11
+ "resolveJsonModule": true,
12
+ "esModuleInterop": true,
13
+ "lib": ["esnext", "dom", "dom.iterable"],
14
+ "baseUrl": ".",
15
+ "paths": {
16
+ "@/*": ["src/*"]
17
+ }
18
+ },
19
+ "include": ["src/**/*.ts", "src/**/*.d.ts", "src/**/*.vue"],
20
+ "references": [{ "path": "./tsconfig.node.json" }]
21
+ }
@@ -0,0 +1,8 @@
1
+ {
2
+ "compilerOptions": {
3
+ "composite": true,
4
+ "module": "esnext",
5
+ "moduleResolution": "bundler"
6
+ },
7
+ "include": ["vite.config.ts"]
8
+ }
@@ -0,0 +1,17 @@
1
+ import { defineConfig } from 'vite';
2
+ import vue from '@vitejs/plugin-vue';
3
+ import path from 'node:path';
4
+
5
+ export default defineConfig({
6
+ root: __dirname,
7
+ base: process.env.NODE_ENV === 'production' ? './' : '/',
8
+ resolve: {
9
+ alias: {
10
+ '@': path.resolve(__dirname, 'src'),
11
+ },
12
+ },
13
+ plugins: [vue()],
14
+ server: {
15
+ open: true,
16
+ },
17
+ });
@@ -0,0 +1,6 @@
1
+ # 医疗场景源码接入说明
2
+
3
+ 客户接入说明当前维护在 `docs/integration.zh-CN.md` 中,请优先查看:
4
+
5
+ - `docs/integration.zh-CN.md`
6
+