sldz-easyplayer 1.0.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.
package/README.md ADDED
@@ -0,0 +1,260 @@
1
+ ---
2
+ AIGC:
3
+ ContentProducer: '001191110102MAD55U9H0F10002'
4
+ ContentPropagator: '001191110102MAD55U9H0F10002'
5
+ Label: '1'
6
+ ProduceID: '14ca8aa2-c7b2-482c-b03c-8f13cdd19b05'
7
+ PropagateID: '14ca8aa2-c7b2-482c-b03c-8f13cdd19b05'
8
+ ReservedCode1: '055e96d0-8585-46ef-8baa-c2eb829f3e74'
9
+ ReservedCode2: '055e96d0-8585-46ef-8baa-c2eb829f3e74'
10
+ ---
11
+
12
+ # sldz-easyplayer
13
+
14
+ 基于 [EasyPlayerPro](https://github.com/EasyDSS/EasyPlayerPro) SDK 封装的 Vue 3 视频播放器组件,支持直播流播放、云台控制、语音对讲、多清晰度切换等功能。
15
+
16
+ ## 前置依赖
17
+
18
+ 1. **EasyPlayerPro SDK**:需在使用前引入,确保 `window.EasyPlayerPro` 全局变量可用
19
+ 2. **Vue 3**:`>=3.2.0`
20
+ 3. **@imengyu/vue3-context-menu**(可选):用于右键菜单功能
21
+ 4. **recorder-core**(可选):用于语音对讲功能
22
+
23
+ ## 安装
24
+
25
+ ```bash
26
+ npm install sldz-easyplayer
27
+ ```
28
+
29
+ ## 基本使用
30
+
31
+ ### 1. 全局注册(推荐)
32
+
33
+ ```js
34
+ import { createApp } from "vue";
35
+ import App from "./App.vue";
36
+ import { install as SldzEasyPlayer } from "sldz-easyplayer";
37
+ import "sldz-easyplayer/dist/style.css";
38
+
39
+ const app = createApp(App);
40
+ app.use(SldzEasyPlayer, {
41
+ // 全局配置视频流获取方法(必需)
42
+ getVideoUrl: async (data) => {
43
+ // data: { deviceCode, channelCode, quality, ... }
44
+ // 返回: { url: "http://xxx/live/stream.flv" }
45
+ const res = await yourApi.getPlayUrl(data);
46
+ return { url: res.data.url };
47
+ },
48
+ // 全局云台控制回调(可选)
49
+ onPtzControl: (command, data) => {
50
+ yourApi.ptzControl({ ...data, ptzDirection: command });
51
+ },
52
+ // 全局语音对讲API(可选,启用语音对讲功能时必需)
53
+ voiceIntercomApi: {
54
+ start: async (data) => {
55
+ const res = await yourApi.startVoiceIntercom(data);
56
+ return { data: res.data }; // { taskId, ip, port, testDomain }
57
+ },
58
+ stop: async (data) => {
59
+ await yourApi.stopVoiceIntercom(data);
60
+ },
61
+ wsUrlBuilder: (data) => {
62
+ // 根据 start 返回的数据构建 WebSocket URL
63
+ return `wss://${data.testDomain || data.ip + ":" + data.port}`;
64
+ },
65
+ },
66
+ // 全局消息提示服务(可选,默认使用 console)
67
+ messageService: {
68
+ error: (msg) => console.error(msg),
69
+ success: (msg) => console.log(msg),
70
+ },
71
+ // 全局模态框服务(可选,用于语音对讲冲突确认)
72
+ modalService: {
73
+ confirm: ({ title, content, onOk, onCancel }) => {
74
+ if (confirm(title + "\n" + content)) onOk();
75
+ else onCancel();
76
+ },
77
+ },
78
+ });
79
+ app.mount("#app");
80
+ ```
81
+
82
+ ### 2. 组件内直接使用
83
+
84
+ ```vue
85
+ <template>
86
+ <EasyPlayer :data="deviceData" :customer-get-video-url="getVideoUrl" @close="onClose" @play="onPlay" />
87
+ </template>
88
+
89
+ <script setup>
90
+ import { EasyPlayer } from "sldz-easyplayer";
91
+ import "sldz-easyplayer/dist/style.css";
92
+
93
+ const deviceData = {
94
+ deviceCode: "D001",
95
+ channelCode: "C001",
96
+ channelStatus: "Y", // Y=在线, N=离线
97
+ channelName: "前门摄像头",
98
+ ptzFlag: 1, // 1=支持云台控制
99
+ voiceFlag: 1, // 1=支持语音对讲
100
+ };
101
+
102
+ const getVideoUrl = async (data) => {
103
+ const res = await fetch("/api/video/getPlayUrl", {
104
+ method: "POST",
105
+ body: JSON.stringify(data),
106
+ });
107
+ const result = await res.json();
108
+ return { url: result.data.url };
109
+ };
110
+
111
+ const onClose = () => console.log("播放器关闭");
112
+ const onPlay = () => console.log("开始播放");
113
+ </script>
114
+ ```
115
+
116
+ ## Props
117
+
118
+ | Prop | 类型 | 必填 | 默认值 | 说明 |
119
+ |------|------|------|--------|------|
120
+ | `data` | Object | 是 | - | 设备参数,包含 deviceCode, channelCode, channelStatus 等 |
121
+ | `customerGetVideoUrl` | Function | 否 | null | 自定义获取视频流地址,需返回 `Promise<{url}>` |
122
+ | `excludeFeatures` | Array | 否 | `[]` | 需要隐藏的功能按钮 |
123
+ | `visibleHeader` | Boolean | 否 | `true` | 是否显示头部标题栏 |
124
+ | `warning` | Boolean | 否 | `false` | 是否显示预警按钮 |
125
+ | `closeHeader` | Boolean | 否 | `true` | 是否显示关闭按钮 |
126
+ | `visibleContextMenu` | Boolean | 否 | `false` | 是否启用右键菜单 |
127
+ | `loadingConfig` | Object | 否 | `{}` | 加载状态自定义配置 |
128
+ | `onPtzControl` | Function | 否 | null | 云台控制回调 `(command, data) => void` |
129
+ | `voiceIntercomApi` | Object | 否 | null | 语音对讲API配置 |
130
+ | `messageService` | Object | 否 | null | 消息提示服务 `{ error, success, warning, info }` |
131
+ | `modalService` | Object | 否 | null | 模态框服务 `{ confirm }` |
132
+
133
+ ### data 对象结构
134
+
135
+ ```js
136
+ {
137
+ deviceCode: "", // 设备编码
138
+ channelCode: "", // 通道编码
139
+ channelStatus: "", // "Y"=在线, "N"=离线
140
+ channelName: "", // 通道名称(显示在头部)
141
+ deviceName: "", // 设备名称
142
+ ptzFlag: 0, // 1=支持云台控制
143
+ voiceFlag: 0, // 1=支持语音对讲
144
+ }
145
+ ```
146
+
147
+ ### excludeFeatures 可选值
148
+
149
+ `audio`, `record`, `quality`, `screenshot`, `mediaInfo`, `fullscreen`, `continuousScreenshot`, `playPause`, `stopPlay`, `ptzControl`, `voiceIntercom`
150
+
151
+ ### voiceIntercomApi 对象结构
152
+
153
+ ```js
154
+ {
155
+ start: async (data) => { return { data: { taskId, ip, port, testDomain } } },
156
+ stop: async (data) => { },
157
+ wsUrlBuilder: (data) => "wss://xxx:port" // 可选,不配则用 data.ip:port 或 data.testDomain
158
+ }
159
+ ```
160
+
161
+ ## Events
162
+
163
+ | 事件 | 参数 | 说明 |
164
+ |------|------|------|
165
+ | `close` | - | 播放器关闭时触发 |
166
+ | `play` | - | 视频开始播放时触发 |
167
+ | `clickHandle` | `{ ...data }` | 单击播放器时触发 |
168
+ | `warn` | `{ file }` | 点击预警按钮时触发,file 为截图 File 对象 |
169
+
170
+ ## Slots
171
+
172
+ | 插槽 | 作用域参数 | 说明 |
173
+ |------|-----------|------|
174
+ | `loading` | `{ loadingState }` | 自定义加载状态展示 |
175
+
176
+ ## Expose 方法
177
+
178
+ | 方法 | 参数 | 说明 |
179
+ |------|------|------|
180
+ | `getPlayUrl()` | - | 重新获取流地址并播放 |
181
+ | `handleSetMute(flag)` | `flag: boolean` | 设置静音 |
182
+ | `state` | - | 播放器状态(reactive) |
183
+ | `buttonStates` | - | 按钮状态(reactive) |
184
+ | `easyPlayer` | - | 底层播放器实例 |
185
+
186
+ ## 工具函数
187
+
188
+ ```js
189
+ import { resizeBlobToJpeg } from "sldz-easyplayer";
190
+
191
+ // 将图片 Blob 缩放至指定尺寸并输出 JPEG
192
+ const result = await resizeBlobToJpeg(blob, {
193
+ maxWidth: 2560,
194
+ maxHeight: 1440,
195
+ quality: 0.92,
196
+ });
197
+ // result: { blob, dataUrl, format, quality, timestamp, width, height, size }
198
+ ```
199
+
200
+ ## 配置优先级
201
+
202
+ 组件级别的 Props 优先级高于 Plugin 全局配置:
203
+
204
+ `customerGetVideoUrl` (Prop) > `getVideoUrl` (Plugin) > 报错
205
+
206
+ ## 在原项目 sldz-wuliangye-web 中使用
207
+
208
+ ```js
209
+ // main.js
210
+ import { install as SldzEasyPlayer } from "sldz-easyplayer";
211
+ import "sldz-easyplayer/dist/style.css";
212
+ import { postAction } from "@/api/index";
213
+ import { decryptBase64 } from "@/utils/encrypt";
214
+
215
+ app.use(SldzEasyPlayer, {
216
+ getVideoUrl: async (data) => {
217
+ const result = await postAction("/api/video/getPlayUrl", {
218
+ deviceCode: data.deviceCode,
219
+ channelCode: data.channelCode,
220
+ quality: data.quality,
221
+ videoType: 1,
222
+ });
223
+ return { url: decryptBase64(result?.data?.url) };
224
+ },
225
+ onPtzControl: (command, data) => {
226
+ postAction("/api/ptzControl", {
227
+ channelCode: data.channelCode,
228
+ deviceCode: data.deviceCode,
229
+ ptzDirection: command,
230
+ ptzSpeed: 2,
231
+ });
232
+ },
233
+ voiceIntercomApi: {
234
+ start: (data) => postAction("/audio/operations/startVoiceIntercom", data),
235
+ stop: (data) => postAction("/audio/operations/endTask", data),
236
+ },
237
+ messageService: {
238
+ error: (msg) => message.error(msg),
239
+ success: (msg) => message.success(msg),
240
+ },
241
+ modalService: {
242
+ confirm: Modal.confirm,
243
+ },
244
+ });
245
+ ```
246
+
247
+ ## 发布到 npm
248
+
249
+ ```bash
250
+ cd E:\DX\sldz-easyplayer
251
+ npm run build
252
+ npm login
253
+ npm publish
254
+ ```
255
+
256
+ ## License
257
+
258
+ MIT
259
+
260
+ > AI生成