sctj-components 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.
Files changed (112) hide show
  1. package/PUBLISH_GUIDE.md +293 -0
  2. package/README.md +1112 -0
  3. package/lib/chunks/404-8b5347fb.js +4 -0
  4. package/lib/chunks/bug-29d5a8c8.js +4 -0
  5. package/lib/chunks/build-0e8711f7.js +4 -0
  6. package/lib/chunks/button-abec46ef.js +4 -0
  7. package/lib/chunks/cascader-328523ba.js +4 -0
  8. package/lib/chunks/chart-04ef8147.js +4 -0
  9. package/lib/chunks/checkbox-1238324c.js +4 -0
  10. package/lib/chunks/clipboard-625a991f.js +4 -0
  11. package/lib/chunks/code-2f6398b5.js +4 -0
  12. package/lib/chunks/color-13488c06.js +4 -0
  13. package/lib/chunks/component-495e49d4.js +4 -0
  14. package/lib/chunks/dashboard-3a81480c.js +4 -0
  15. package/lib/chunks/date-c2ef6759.js +4 -0
  16. package/lib/chunks/date-range-551e4fd6.js +4 -0
  17. package/lib/chunks/dict-5539087c.js +4 -0
  18. package/lib/chunks/documentation-8d81c185.js +4 -0
  19. package/lib/chunks/download-11fa6102.js +4 -0
  20. package/lib/chunks/drag-2fbf0e89.js +4 -0
  21. package/lib/chunks/druid-57209587.js +4 -0
  22. package/lib/chunks/edit-9e3738f0.js +4 -0
  23. package/lib/chunks/education-7fb0e453.js +4 -0
  24. package/lib/chunks/email-7477951a.js +4 -0
  25. package/lib/chunks/example-b8091a8b.js +4 -0
  26. package/lib/chunks/excel-9e8720a6.js +4 -0
  27. package/lib/chunks/exit-fullscreen-fe7ec08b.js +4 -0
  28. package/lib/chunks/eye-1a093b92.js +4 -0
  29. package/lib/chunks/eye-open-312c146f.js +4 -0
  30. package/lib/chunks/form-54837ed4.js +4 -0
  31. package/lib/chunks/fullscreen-552cc3b4.js +4 -0
  32. package/lib/chunks/github-0539cc3d.js +4 -0
  33. package/lib/chunks/guide-407e9748.js +4 -0
  34. package/lib/chunks/icon-83dfff61.js +4 -0
  35. package/lib/chunks/input-de62ab83.js +4 -0
  36. package/lib/chunks/international-7bb87f29.js +4 -0
  37. package/lib/chunks/job-e78e9a3d.js +4 -0
  38. package/lib/chunks/language-8b7629d9.js +4 -0
  39. package/lib/chunks/link-f264a825.js +4 -0
  40. package/lib/chunks/list-2e431778.js +4 -0
  41. package/lib/chunks/lock-5e8f10d7.js +4 -0
  42. package/lib/chunks/log-80bfb029.js +4 -0
  43. package/lib/chunks/logininfor-47a5f04e.js +4 -0
  44. package/lib/chunks/message-06f1d593.js +4 -0
  45. package/lib/chunks/money-14039a58.js +4 -0
  46. package/lib/chunks/monitor-b020306f.js +4 -0
  47. package/lib/chunks/nested-13647a6a.js +4 -0
  48. package/lib/chunks/number-290265fd.js +4 -0
  49. package/lib/chunks/online-64589b70.js +4 -0
  50. package/lib/chunks/password-1192ad67.js +4 -0
  51. package/lib/chunks/pdf-8176f032.js +4 -0
  52. package/lib/chunks/people-6e6b61b6.js +4 -0
  53. package/lib/chunks/peoples-35c96c5c.js +4 -0
  54. package/lib/chunks/phone-6bc01ca6.js +4 -0
  55. package/lib/chunks/post-0d01cf1a.js +4 -0
  56. package/lib/chunks/qq-df2843d2.js +4 -0
  57. package/lib/chunks/question-c1e9a4e7.js +4 -0
  58. package/lib/chunks/radio-5c66d676.js +4 -0
  59. package/lib/chunks/rate-eb858d5b.js +4 -0
  60. package/lib/chunks/redis-788c8d4f.js +4 -0
  61. package/lib/chunks/redis-list-6792700e.js +4 -0
  62. package/lib/chunks/row-d431ba9c.js +4 -0
  63. package/lib/chunks/search-990fe622.js +4 -0
  64. package/lib/chunks/select-1d794732.js +4 -0
  65. package/lib/chunks/server-b0c98c01.js +4 -0
  66. package/lib/chunks/shopping-2a187e37.js +4 -0
  67. package/lib/chunks/sip-0.13.6.min-53cd1379.js +5546 -0
  68. package/lib/chunks/size-e3f93f23.js +4 -0
  69. package/lib/chunks/skill-abe26c0c.js +4 -0
  70. package/lib/chunks/slider-cb3330ba.js +4 -0
  71. package/lib/chunks/star-5182766b.js +4 -0
  72. package/lib/chunks/swagger-266c9f25.js +4 -0
  73. package/lib/chunks/switch-74aa5d5b.js +4 -0
  74. package/lib/chunks/system-943da249.js +4 -0
  75. package/lib/chunks/tab-9202c247.js +4 -0
  76. package/lib/chunks/table-2d14e126.js +4 -0
  77. package/lib/chunks/textarea-4d9d0b2c.js +4 -0
  78. package/lib/chunks/theme-7bbe2d45.js +4 -0
  79. package/lib/chunks/time-f08907ac.js +4 -0
  80. package/lib/chunks/time-range-e7b40483.js +4 -0
  81. package/lib/chunks/tool-6f22c373.js +4 -0
  82. package/lib/chunks/tree-0118a113.js +4 -0
  83. package/lib/chunks/tree-table-54984188.js +4 -0
  84. package/lib/chunks/upload-e852b478.js +4 -0
  85. package/lib/chunks/user-82704b02.js +4 -0
  86. package/lib/chunks/validCode-ba29b5b3.js +4 -0
  87. package/lib/chunks/wechat-22f119d5.js +4 -0
  88. package/lib/chunks/zip-c3a63b61.js +4 -0
  89. package/lib/sctj-components.es.js +10491 -0
  90. package/lib/sctj-components.umd.js +1 -0
  91. package/lib/style.css +1 -0
  92. package/package.json +55 -0
  93. package/public/BimfaceSDKLoader@latest-release.js +643 -0
  94. package/public/hkPlayerPlugin/h5player.min.js +1 -0
  95. package/public/hkPlayerPlugin/playctrl1/DecodeWorker.js +705 -0
  96. package/public/hkPlayerPlugin/playctrl1/Decoder.js +171 -0
  97. package/public/hkPlayerPlugin/playctrl1simd/DecodeWorker.js +705 -0
  98. package/public/hkPlayerPlugin/playctrl1simd/Decoder.js +171 -0
  99. package/public/hkPlayerPlugin/playctrl2/Decoder.js +21 -0
  100. package/public/hkPlayerPlugin/playctrl2/Decoder.wasm +0 -0
  101. package/public/hkPlayerPlugin/playctrl2/Decoder.worker.js +1 -0
  102. package/public/hkPlayerPlugin/playctrl3/Decoder.js +21 -0
  103. package/public/hkPlayerPlugin/playctrl3/Decoder.wasm +0 -0
  104. package/public/hkPlayerPlugin/playctrl3/Decoder.worker.js +1 -0
  105. package/public/hkPlayerPlugin/talk/AudioInterCom.js +21 -0
  106. package/public/hkPlayerPlugin/talk/AudioInterCom.wasm +0 -0
  107. package/public/hkPlayerPlugin/talkW/AudioInterCom.js +21 -0
  108. package/public/hkPlayerPlugin/talkW/AudioInterCom.wasm +0 -0
  109. package/public/hkPlayerPlugin/talkW/AudioInterCom.worker.js +1 -0
  110. package/public/hkPlayerPlugin/transform/libSystemTransform.js +6589 -0
  111. package/public/hkPlayerPlugin/transform/libSystemTransform.wasm +0 -0
  112. package/public/hkPlayerPlugin/transform/systemTransform-worker.js +126 -0
package/README.md ADDED
@@ -0,0 +1,1112 @@
1
+ # SCTJ Components 组件库
2
+
3
+ 这是一个基于 Vue 3 + Element Plus 的组件库,包含了后台管理系统中常用的各种组件。
4
+
5
+ ## 📦 安装
6
+
7
+ ```bash
8
+ npm install sctj-components
9
+ # 或
10
+ yarn add sctj-components
11
+ # 或
12
+ pnpm add sctj-components
13
+ ```
14
+
15
+ ## 🚀 快速开始
16
+
17
+ ### 第一步:安装必需依赖
18
+
19
+ 组件库使用 `peerDependencies` 管理依赖,需要手动安装以下依赖:
20
+
21
+ ```bash
22
+ # 基础必需依赖
23
+ npm install vue@^3.2.0 element-plus@^2.2.0 @element-plus/icons-vue@^2.0.0
24
+
25
+ # 根据使用的组件选择性安装
26
+ # 使用图表组件时
27
+ npm install echarts@^5.0.0
28
+
29
+ # 使用 3D/BIM 组件时
30
+ npm install three@^0.150.0
31
+
32
+ # 使用地图组件时
33
+ npm install @amap/amap-jsapi-loader@^1.0.0
34
+
35
+ # 使用 SCTJYsyPlayer 萤石云播放器组件时
36
+ npm install ezuikit-js@^8.1.0
37
+ ```
38
+
39
+ ### 第二步:引入组件库
40
+
41
+ #### 完整引入
42
+
43
+ 在 main.js 中引入组件库:
44
+
45
+ ```javascript
46
+ import { createApp } from 'vue'
47
+ import ElementPlus from 'element-plus'
48
+ import 'element-plus/dist/index.css'
49
+ import SctjComponents from 'sctj-components'
50
+ // 引入组件库样式(如果构建后生成了 style.css)
51
+ import 'sctj-components/lib/style.css'
52
+
53
+ const app = createApp(App)
54
+ app.use(ElementPlus)
55
+ app.use(SctjComponents)
56
+ app.mount('#app')
57
+ ```
58
+
59
+ #### 按需引入
60
+
61
+ 组件名称均带前缀 `SCTJ`:
62
+ ```javascript
63
+ import { SCTJDictTag, SCTJTable, SCTJSearch } from 'sctj-components'
64
+ ```
65
+
66
+ 模板中使用时可用 PascalCase 或 kebab-case:
67
+ ```vue
68
+ <template>
69
+ <SCTJDictTag :options="dictOptions" :value="status" />
70
+ <sctj-table :data="tableData" />
71
+ <sctj-search :visible="visible" />
72
+ </template>
73
+ ```
74
+
75
+ ## 📚 组件列表
76
+
77
+ ### 基础组件
78
+ - `SCTJDictTag` - 字典标签
79
+ - `SCTJTreeSelect` - 树形选择器
80
+ - `SCTJSvgIcon` - SVG 图标组件
81
+
82
+ ### 表单组件
83
+ - `SCTJFileUpload` - 文件上传
84
+ - `SCTJImageUpload` - 图片上传
85
+ - `SCTJImagePreview` - 图片预览
86
+ - `SCTJIconSelect` - 图标选择器
87
+ - `SCTJSearch` - 搜索组件
88
+ - `SCTJDateRangePicker` - 日期范围选择器
89
+
90
+ ### 表格组件
91
+ - `SCTJTable` - 表格组件
92
+ - `SCTJTableContainer` - 表格容器(布局组件)
93
+ - `SCTJTablePageContainer` - 表格页面容器
94
+ - `SCTJTableTopActionContainer` - 表格顶部操作容器
95
+ - `SCTJRightToolbar` - 右侧工具栏
96
+
97
+ ### 布局组件
98
+ - `SCTJBtnContainer` - 按钮容器
99
+
100
+ ### 图表组件
101
+ - `SCTJBaseChart` - 基础图表
102
+ - `SCTJCommonChart` - 通用图表
103
+ - `SCTJPieChart` - 饼图
104
+
105
+ ### 播放器组件
106
+ - `SCTJFlvPlayer` - FLV 播放器
107
+ - `SCTJH5hkPlayer` - H5 海康播放器
108
+ - `SCTJHelmetPlayer` - 头盔播放器
109
+ - `SCTJYsyPlayer` - 萤石云播放器
110
+
111
+ ### 其他组件
112
+ - `SCTJIframe` - iframe 组件
113
+ - `SCTJImportDialog` - 导入对话框
114
+ - `SCTJDialogTable` - 对话框表格
115
+
116
+ ### 地图组件
117
+ - `SCTJMapViewer` - 地图查看器
118
+ - `SCTJMapDrawingDialog` - 地图绘制对话框
119
+ - `SCTJBusinessMapDrawingDialog` - 业务地图绘制对话框
120
+
121
+ ### Bim组件
122
+ - `SCTJBimViewer` - Bim 查看器
123
+ - `SCTJDwgViewer` - DWG 查看器
124
+
125
+ ## 📝 使用示例
126
+
127
+ ### SCTJDictTag 字典标签
128
+
129
+ ```vue
130
+ <template>
131
+ <SCTJDictTag :options="dictOptions" :value="status" />
132
+ </template>
133
+
134
+ <script setup>
135
+ import { SCTJDictTag } from 'sctj-components'
136
+
137
+ const dictOptions = [
138
+ { label: '启用', value: '1', elTagType: 'success' },
139
+ { label: '禁用', value: '0', elTagType: 'danger' }
140
+ ]
141
+ const status = '1'
142
+ </script>
143
+ ```
144
+
145
+ ### SCTJTreeSelect 树形选择器
146
+
147
+ ```vue
148
+ <template>
149
+ <SCTJTreeSelect
150
+ v-model="selectedValue"
151
+ :options="treeData"
152
+ :obj-map="{ value: 'id', label: 'label', children: 'children' }"
153
+ placeholder="请选择"
154
+ />
155
+ </template>
156
+
157
+ <script setup>
158
+ import { ref } from 'vue'
159
+ import { SCTJTreeSelect } from 'sctj-components'
160
+
161
+ const selectedValue = ref('')
162
+ const treeData = [
163
+ {
164
+ id: '1',
165
+ label: '一级',
166
+ children: [
167
+ { id: '1-1', label: '二级' }
168
+ ]
169
+ }
170
+ ]
171
+ </script>
172
+ ```
173
+
174
+ ### SCTJTable 表格组件
175
+
176
+ ```vue
177
+ <template>
178
+ <SCTJTable
179
+ :request="fetchTableData"
180
+ :request-params="queryParams"
181
+ row-key="id"
182
+ :show-select="true"
183
+ :show-index="true"
184
+ @selection-change="handleSelectionChange"
185
+ >
186
+ <el-table-column prop="name" label="姓名" />
187
+ <el-table-column prop="age" label="年龄" />
188
+ <el-table-column prop="email" label="邮箱" />
189
+ </SCTJTable>
190
+ </template>
191
+
192
+ <script setup>
193
+ import { ref } from 'vue'
194
+ import { SCTJTable } from 'sctj-components'
195
+
196
+ const queryParams = ref({ keyword: '' })
197
+
198
+ // request 函数需要返回 Promise,格式: { total: number, rows: Array }
199
+ const fetchTableData = async (params) => {
200
+ const response = await fetch('/api/users', {
201
+ method: 'POST',
202
+ body: JSON.stringify({
203
+ pageNum: params.pageNum,
204
+ pageSize: params.pageSize,
205
+ ...queryParams.value
206
+ })
207
+ })
208
+ return await response.json()
209
+ }
210
+
211
+ const handleSelectionChange = (selection) => {
212
+ console.log('选中的行:', selection)
213
+ }
214
+ </script>
215
+ ```
216
+
217
+ ### SCTJSearch 搜索组件
218
+
219
+ ```vue
220
+ <template>
221
+ <SCTJSearch v-model:visible="showSearch">
222
+ <el-form :model="queryParams" :inline="true">
223
+ <el-form-item label="姓名">
224
+ <el-input v-model="queryParams.name" placeholder="请输入姓名" />
225
+ </el-form-item>
226
+ <el-form-item label="状态">
227
+ <el-select v-model="queryParams.status" placeholder="请选择">
228
+ <el-option label="启用" value="1" />
229
+ <el-option label="禁用" value="0" />
230
+ </el-select>
231
+ </el-form-item>
232
+ </el-form>
233
+ </SCTJSearch>
234
+ </template>
235
+
236
+ <script setup>
237
+ import { ref } from 'vue'
238
+ import { SCTJSearch } from 'sctj-components'
239
+
240
+ const showSearch = ref(true)
241
+ const queryParams = ref({
242
+ name: '',
243
+ status: ''
244
+ })
245
+ </script>
246
+ ```
247
+
248
+ ### SCTJDateRangePicker 日期范围选择器
249
+
250
+ ```vue
251
+ <template>
252
+ <SCTJDateRangePicker
253
+ v-model="dateRange"
254
+ value-format="YYYY-MM-DD"
255
+ @change="handleDateChange"
256
+ />
257
+ </template>
258
+
259
+ <script setup>
260
+ import { ref } from 'vue'
261
+ import { SCTJDateRangePicker } from 'sctj-components'
262
+
263
+ const dateRange = ref([])
264
+
265
+ const handleDateChange = (val) => {
266
+ console.log('选择的日期范围:', val)
267
+ }
268
+ </script>
269
+ ```
270
+
271
+ ### SCTJH5hkPlayer 海康播放器
272
+
273
+ > ⚠️ **前置准备**:使用此组件前,需要拷贝静态资源:
274
+ > 1. 从 `node_modules/sctj-components/public/hkPlayerPlugin/` 目录(及其所有文件)拷贝到宿主项目的 `public/` 根目录
275
+ > 2. 在宿主 `index.html` 中添加:`<script src="/hkPlayerPlugin/h5player.min.js" type="application/javascript"></script>`
276
+
277
+ ```vue
278
+ <template>
279
+ <SCTJH5hkPlayer
280
+ :device-serial="deviceSerial"
281
+ :channel-no="channelNo"
282
+ :device-name="deviceName"
283
+ :channel-name="channelName"
284
+ :get-live-address="getLiveAddress"
285
+ :get-replay-address="getReplayAddress"
286
+ :download-certificate="downloadCertificate"
287
+ />
288
+ </template>
289
+
290
+ <script setup>
291
+ import { ref } from 'vue'
292
+ import { SCTJH5hkPlayer } from 'sctj-components'
293
+
294
+ const deviceSerial = ref('your-device-serial')
295
+ const channelNo = ref('1')
296
+ const deviceName = ref('摄像头名称')
297
+ const channelName = ref('通道名称')
298
+
299
+ // 获取实时播放地址的函数,需要返回 Promise<{ code: number, data: { url: string }, msg?: string }>
300
+ const getLiveAddress = async (params) => {
301
+ const response = await fetch('/api/camera/live', {
302
+ method: 'POST',
303
+ body: JSON.stringify(params)
304
+ })
305
+ return await response.json()
306
+ }
307
+
308
+ // 获取回放地址的函数,需要返回 Promise<{ code: number, data: { url: string }, msg?: string }>
309
+ const getReplayAddress = async (params) => {
310
+ const response = await fetch('/api/camera/replay', {
311
+ method: 'POST',
312
+ body: JSON.stringify(params)
313
+ })
314
+ return await response.json()
315
+ }
316
+
317
+ // 下载证书的函数,需要返回 Promise
318
+ const downloadCertificate = async (deviceSerial) => {
319
+ const response = await fetch(`/api/camera/certificate/${deviceSerial}`, {
320
+ method: 'GET'
321
+ })
322
+ return await response.blob()
323
+ }
324
+ </script>
325
+ ```
326
+
327
+ ### SCTJHelmetPlayer 头盔播放器
328
+
329
+ ```vue
330
+ <template>
331
+ <SCTJHelmetPlayer
332
+ :device-id="deviceId"
333
+ :call-api="callApi"
334
+ :handle-streaming-api="handleStreamingApi"
335
+ :query-admin-sip-info-api="queryAdminSipInfoApi"
336
+ />
337
+ </template>
338
+
339
+ <script setup>
340
+ import { ref } from 'vue'
341
+ import { SCTJHelmetPlayer } from 'sctj-components'
342
+
343
+ const deviceId = ref('your-device-id')
344
+
345
+ // 发起通话的 API 函数,需要返回 Promise<{ status: boolean, sip_id?: string, msg?: string }>
346
+ // 参数: { deviceId: string, v_type: number }
347
+ const callApi = async (params) => {
348
+ const response = await fetch('/api/helmet/call', {
349
+ method: 'POST',
350
+ body: JSON.stringify(params)
351
+ })
352
+ return await response.json()
353
+ }
354
+
355
+ // 处理流媒体的 API 函数,需要返回 Promise<any>
356
+ // 参数: { deviceId: string, isPush: number } (isPush: 1-开启, 0-停止)
357
+ const handleStreamingApi = async (params) => {
358
+ const response = await fetch('/api/helmet/streaming', {
359
+ method: 'POST',
360
+ body: JSON.stringify(params)
361
+ })
362
+ return await response.json()
363
+ }
364
+
365
+ // 获取管理员 SIP 信息的 API 函数,需要返回 Promise<{ status: boolean, admin_info: { sip_info: any }, msg?: string }>
366
+ const queryAdminSipInfoApi = async () => {
367
+ const response = await fetch('/api/helmet/sip-info')
368
+ return await response.json()
369
+ }
370
+ </script>
371
+ ```
372
+
373
+ ### SCTJYsyPlayer 萤石云播放器
374
+
375
+ > ⚠️ **前置准备**:使用此组件前,需要安装依赖:
376
+ > ```bash
377
+ > npm install ezuikit-js@^8.1.0
378
+ > ```
379
+
380
+ ```vue
381
+ <template>
382
+ <SCTJYsyPlayer
383
+ :device-serial="deviceSerial"
384
+ :channel-no="channelNo"
385
+ :play-type="playType"
386
+ :start-time="startTime"
387
+ :end-time="endTime"
388
+ :get-ys-token="getYsToken"
389
+ />
390
+ </template>
391
+
392
+ <script setup>
393
+ import { ref } from 'vue'
394
+ import { SCTJYsyPlayer } from 'sctj-components'
395
+
396
+ const deviceSerial = ref('your-device-serial')
397
+ const channelNo = ref(1)
398
+ const playType = ref(0) // 0-直播, 1-回放
399
+ const startTime = ref('2023-01-01 12:00:00')
400
+ const endTime = ref('2023-01-01 13:00:00')
401
+
402
+ // 获取 Token 的函数,需要返回 Promise<{ code: number, data: { accessToken: string, expireTime: number }, msg?: string }>
403
+ const getYsToken = async () => {
404
+ const response = await fetch('/api/threeController/getYsToken', {
405
+ method: 'GET'
406
+ })
407
+ return await response.json()
408
+ }
409
+ </script>
410
+ ```
411
+
412
+ ### SCTJFileUpload 文件上传
413
+
414
+ ```vue
415
+ <template>
416
+ <SCTJFileUpload
417
+ v-model="fileList"
418
+ :upload-file-url="'/api/upload'"
419
+ :limit="5"
420
+ :file-size="10"
421
+ :file-type="['docx', 'xlsx', 'pdf', 'png', 'jpg']"
422
+ :base-url="baseUrl"
423
+ :http-request="customUpload"
424
+ :response-config="{
425
+ code: 'code',
426
+ fileName: 'fileName',
427
+ fileUrl: 'url',
428
+ msg: 'msg'
429
+ }"
430
+ @success="handleUploadSuccess"
431
+ />
432
+ </template>
433
+
434
+ <script setup>
435
+ import { ref } from 'vue'
436
+ import { SCTJFileUpload } from 'sctj-components'
437
+
438
+ const fileList = ref('')
439
+ const baseUrl = import.meta.env.VITE_APP_BASE_API // 可选,用于处理相对路径
440
+
441
+ // 可选:自定义上传函数,如果不传则使用 el-upload 默认的 XHR 行为
442
+ const customUpload = async (options) => {
443
+ const formData = new FormData()
444
+ formData.append('file', options.file)
445
+ const response = await fetch('/api/upload', {
446
+ method: 'POST',
447
+ body: formData
448
+ })
449
+ return await response.json()
450
+ }
451
+
452
+ const handleUploadSuccess = (response) => {
453
+ console.log('上传成功:', response)
454
+ }
455
+ </script>
456
+ ```
457
+
458
+ ### SCTJImageUpload 图片上传
459
+
460
+ ```vue
461
+ <template>
462
+ <SCTJImageUpload
463
+ v-model="imageList"
464
+ :upload-img-url="'/api/upload/image'"
465
+ :limit="3"
466
+ :file-size="5"
467
+ :file-type="['png', 'jpg', 'jpeg']"
468
+ :base-url="baseUrl"
469
+ :http-request="customUpload"
470
+ />
471
+ </template>
472
+
473
+ <script setup>
474
+ import { ref } from 'vue'
475
+ import { SCTJImageUpload } from 'sctj-components'
476
+
477
+ const imageList = ref([])
478
+ const baseUrl = import.meta.env.VITE_APP_BASE_API
479
+
480
+ // 可选:自定义上传函数
481
+ const customUpload = async (options) => {
482
+ // 自定义上传逻辑
483
+ }
484
+ </script>
485
+ ```
486
+
487
+ ### SCTJImagePreview 图片预览
488
+
489
+ ```vue
490
+ <template>
491
+ <SCTJImagePreview
492
+ :value="imageUrl"
493
+ :width="100"
494
+ :height="100"
495
+ :base-url="baseUrl"
496
+ :enable-delete="true"
497
+ />
498
+ </template>
499
+
500
+ <script setup>
501
+ import { SCTJImagePreview } from 'sctj-components'
502
+
503
+ const imageUrl = 'image1.jpg,image2.jpg,image3.jpg' // 多张图片用逗号分隔
504
+ const baseUrl = import.meta.env.VITE_APP_BASE_API
505
+ </script>
506
+ ```
507
+
508
+ ### SCTJIconSelect 图标选择器
509
+
510
+ ```vue
511
+ <template>
512
+ <el-dialog v-model="dialogVisible" title="选择图标">
513
+ <SCTJIconSelect @selected="handleIconSelected" />
514
+ </el-dialog>
515
+ </template>
516
+
517
+ <script setup>
518
+ import { ref } from 'vue'
519
+ import { SCTJIconSelect } from 'sctj-components'
520
+
521
+ const dialogVisible = ref(false)
522
+ const selectedIcon = ref('')
523
+
524
+ const handleIconSelected = (iconName) => {
525
+ selectedIcon.value = iconName
526
+ dialogVisible.value = false
527
+ console.log('选中的图标:', iconName)
528
+ }
529
+ </script>
530
+ ```
531
+
532
+ ### SCTJSvgIcon SVG 图标
533
+
534
+ ```vue
535
+ <template>
536
+ <SCTJSvgIcon icon-class="user" :color="'#409EFF'" />
537
+ </template>
538
+
539
+ <script setup>
540
+ import { SCTJSvgIcon } from 'sctj-components'
541
+ </script>
542
+ ```
543
+
544
+ ### SCTJTableContainer 表格容器
545
+
546
+ ```vue
547
+ <template>
548
+ <SCTJTableContainer>
549
+ <SCTJTableTopActionContainer
550
+ v-model:show-search="showSearch"
551
+ :show-refresh="true"
552
+ @refresh="handleRefresh"
553
+ >
554
+ <template #left>
555
+ <el-button type="primary" @click="handleAdd">新增</el-button>
556
+ </template>
557
+ </SCTJTableTopActionContainer>
558
+
559
+ <SCTJSearch v-model:visible="showSearch">
560
+ <!-- 搜索表单内容 -->
561
+ </SCTJSearch>
562
+
563
+ <SCTJTable :request="fetchData" />
564
+ </SCTJTableContainer>
565
+ </template>
566
+
567
+ <script setup>
568
+ import { ref } from 'vue'
569
+ import {
570
+ SCTJTableContainer,
571
+ SCTJTableTopActionContainer,
572
+ SCTJSearch,
573
+ SCTJTable
574
+ } from 'sctj-components'
575
+
576
+ const showSearch = ref(true)
577
+
578
+ const handleRefresh = () => {
579
+ // 刷新表格数据
580
+ }
581
+
582
+ const handleAdd = () => {
583
+ // 新增逻辑
584
+ }
585
+
586
+ const fetchData = async (params) => {
587
+ // 获取表格数据
588
+ }
589
+ </script>
590
+ ```
591
+
592
+ ### SCTJRightToolbar 右侧工具栏
593
+
594
+ ```vue
595
+ <template>
596
+ <SCTJRightToolbar
597
+ v-model:show-search="showSearch"
598
+ :columns="columns"
599
+ :show-refresh="true"
600
+ @query-table="handleQuery"
601
+ />
602
+ </template>
603
+
604
+ <script setup>
605
+ import { ref } from 'vue'
606
+ import { SCTJRightToolbar } from 'sctj-components'
607
+
608
+ const showSearch = ref(true)
609
+ const columns = ref([
610
+ { key: 0, label: '姓名', visible: true },
611
+ { key: 1, label: '年龄', visible: true },
612
+ { key: 2, label: '邮箱', visible: false }
613
+ ])
614
+
615
+ const handleQuery = () => {
616
+ // 查询表格数据
617
+ }
618
+ </script>
619
+ ```
620
+
621
+ ### SCTJBtnContainer 按钮容器
622
+
623
+ ```vue
624
+ <template>
625
+ <SCTJBtnContainer>
626
+ <el-button type="primary">按钮1</el-button>
627
+ <el-button type="success">按钮2</el-button>
628
+ <el-button type="warning">按钮3</el-button>
629
+ </SCTJBtnContainer>
630
+ </template>
631
+
632
+ <script setup>
633
+ import { SCTJBtnContainer } from 'sctj-components'
634
+ </script>
635
+ ```
636
+
637
+ ### SCTJBaseChart 基础图表
638
+
639
+ ```vue
640
+ <template>
641
+ <SCTJBaseChart
642
+ :option="chartOption"
643
+ width="100%"
644
+ height="400px"
645
+ @chart-click="handleChartClick"
646
+ />
647
+ </template>
648
+
649
+ <script setup>
650
+ import { ref } from 'vue'
651
+ import { SCTJBaseChart } from 'sctj-components'
652
+
653
+ const chartOption = ref({
654
+ title: { text: '示例图表' },
655
+ xAxis: { type: 'category', data: ['Mon', 'Tue', 'Wed'] },
656
+ yAxis: { type: 'value' },
657
+ series: [{ data: [120, 200, 150], type: 'bar' }]
658
+ })
659
+
660
+ const handleChartClick = (params) => {
661
+ console.log('图表点击:', params)
662
+ }
663
+ </script>
664
+ ```
665
+
666
+ ### SCTJCommonChart 通用图表
667
+
668
+ ```vue
669
+ <template>
670
+ <SCTJCommonChart
671
+ :data="chartData"
672
+ :series-config="seriesConfig"
673
+ category-name="name"
674
+ title="销售统计"
675
+ :height="'400px'"
676
+ :loading="loading"
677
+ />
678
+ </template>
679
+
680
+ <script setup>
681
+ import { ref } from 'vue'
682
+ import { SCTJCommonChart } from 'sctj-components'
683
+
684
+ const loading = ref(false)
685
+ const chartData = ref([
686
+ { name: '一月', value: 100 },
687
+ { name: '二月', value: 200 },
688
+ { name: '三月', value: 150 }
689
+ ])
690
+
691
+ const seriesConfig = ref([
692
+ {
693
+ name: '销售额',
694
+ type: 'bar',
695
+ dataKey: 'value'
696
+ }
697
+ ])
698
+ </script>
699
+ ```
700
+
701
+ ### SCTJPieChart 饼图
702
+
703
+ ```vue
704
+ <template>
705
+ <SCTJPieChart
706
+ title="数据分布"
707
+ :data="pieData"
708
+ type="pie"
709
+ :center="['50%', '50%']"
710
+ :radius="['0%', '70%']"
711
+ :show-center-text="true"
712
+ :height="'400px'"
713
+ />
714
+ </template>
715
+
716
+ <script setup>
717
+ import { ref } from 'vue'
718
+ import { SCTJPieChart } from 'sctj-components'
719
+
720
+ const pieData = ref([
721
+ { name: '类型A', value: 335 },
722
+ { name: '类型B', value: 310 },
723
+ { name: '类型C', value: 234 }
724
+ ])
725
+ </script>
726
+ ```
727
+
728
+ ### SCTJFlvPlayer FLV 播放器
729
+
730
+ ```vue
731
+ <template>
732
+ <SCTJFlvPlayer
733
+ :src="flvUrl"
734
+ :player-id="'flv-player-1'"
735
+ :autoplay="true"
736
+ :controls="true"
737
+ :is-live="true"
738
+ :max-retries="3"
739
+ />
740
+ </template>
741
+
742
+ <script setup>
743
+ import { ref } from 'vue'
744
+ import { SCTJFlvPlayer } from 'sctj-components'
745
+
746
+ const flvUrl = ref('https://example.com/video.flv')
747
+ </script>
748
+ ```
749
+
750
+ ### SCTJBimViewer Bim 查看器
751
+
752
+ > ⚠️ **前置准备**:使用此组件前,需要拷贝静态资源:
753
+ > 1. 从 `node_modules/sctj-components/public/BimfaceSDKLoader@latest-release.js` 文件拷贝到宿主项目的 `public/` 根目录
754
+ > 2. 在宿主 `index.html` 中添加:`<script src="/BimfaceSDKLoader@latest-release.js" type="application/javascript" charset="utf-8"></script>`
755
+
756
+ ```vue
757
+ <template>
758
+ <SCTJBimViewer
759
+ :view-token="viewToken"
760
+ :extra-context-menu="contextMenu"
761
+ @context-menu-click="handleContextMenuClick"
762
+ />
763
+ </template>
764
+
765
+ <script setup>
766
+ import { ref } from 'vue'
767
+ import { SCTJBimViewer } from 'sctj-components'
768
+
769
+ const viewToken = ref('your-view-token')
770
+ const contextMenu = ref([
771
+ {
772
+ label: '其他',
773
+ key: 'extraOther',
774
+ children: [
775
+ { label: '添加养护', key: 'addMaintain' },
776
+ { label: '养护记录', key: 'maintainRecord' }
777
+ ]
778
+ }
779
+ ])
780
+
781
+ const handleContextMenuClick = (key) => {
782
+ console.log('点击了菜单项:', key)
783
+ }
784
+ </script>
785
+ ```
786
+
787
+ ### SCTJDwgViewer DWG 查看器
788
+
789
+ ```vue
790
+ <template>
791
+ <SCTJDwgViewer
792
+ :view-token="viewToken"
793
+ :extra-context-menu="contextMenu"
794
+ @context-menu-click="handleContextMenuClick"
795
+ />
796
+ </template>
797
+
798
+ <script setup>
799
+ import { ref } from 'vue'
800
+ import { SCTJDwgViewer } from 'sctj-components'
801
+
802
+ const viewToken = ref('your-view-token')
803
+ const contextMenu = ref([
804
+ {
805
+ label: '其他',
806
+ key: 'extraOther',
807
+ children: [
808
+ { label: '添加养护', key: 'addMaintain' },
809
+ { label: '养护记录', key: 'maintainRecord' }
810
+ ]
811
+ }
812
+ ])
813
+
814
+ const handleContextMenuClick = (key) => {
815
+ console.log('点击了菜单项:', key)
816
+ }
817
+ </script>
818
+ ```
819
+
820
+ ### SCTJIframe iframe 组件
821
+
822
+ ```vue
823
+ <template>
824
+ <SCTJIframe :src="iframeUrl" />
825
+ </template>
826
+
827
+ <script setup>
828
+ import { ref } from 'vue'
829
+ import { SCTJIframe } from 'sctj-components'
830
+
831
+ const iframeUrl = ref('https://example.com')
832
+ </script>
833
+ ```
834
+
835
+ ### SCTJImportDialog 导入对话框
836
+
837
+ ```vue
838
+ <template>
839
+ <el-button @click="dialogVisible = true">导入数据</el-button>
840
+ <SCTJImportDialog
841
+ v-model:open="dialogVisible"
842
+ title="用户"
843
+ :upload-url="'/api/import/users'"
844
+ :template-title="'用户导入模板'"
845
+ :template-url="'/api/import/template/users'"
846
+ :show-check-box="true"
847
+ @success="handleImportSuccess"
848
+ />
849
+ </template>
850
+
851
+ <script setup>
852
+ import { ref } from 'vue'
853
+ import { SCTJImportDialog } from 'sctj-components'
854
+
855
+ const dialogVisible = ref(false)
856
+
857
+ const handleImportSuccess = (response) => {
858
+ console.log('导入成功:', response)
859
+ dialogVisible.value = false
860
+ }
861
+ </script>
862
+ ```
863
+
864
+ ### SCTJDialogTable 对话框表格
865
+
866
+ ```vue
867
+ <template>
868
+ <el-button @click="dialogVisible = true">选择数据</el-button>
869
+ <SCTJDialogTable
870
+ v-model:open="dialogVisible"
871
+ title="选择用户"
872
+ :columns="columns"
873
+ :request="fetchUsers"
874
+ :select-options="{
875
+ show: true,
876
+ multiple: true,
877
+ valueKey: 'id',
878
+ reserveSelection: true
879
+ }"
880
+ :query-columns="queryColumns"
881
+ @confirm="handleConfirm"
882
+ />
883
+ </template>
884
+
885
+ <script setup>
886
+ import { ref } from 'vue'
887
+ import { SCTJDialogTable } from 'sctj-components'
888
+
889
+ const dialogVisible = ref(false)
890
+
891
+ const columns = ref([
892
+ { prop: 'name', label: '姓名' },
893
+ { prop: 'age', label: '年龄' },
894
+ { prop: 'email', label: '邮箱' }
895
+ ])
896
+
897
+ const queryColumns = ref([
898
+ {
899
+ prop: 'name',
900
+ label: '姓名',
901
+ query: {
902
+ type: 'input',
903
+ queryKey: 'name',
904
+ placeholder: '请输入姓名'
905
+ }
906
+ }
907
+ ])
908
+
909
+ const fetchUsers = async (params) => {
910
+ const response = await fetch('/api/users', {
911
+ method: 'POST',
912
+ body: JSON.stringify(params)
913
+ })
914
+ return await response.json()
915
+ }
916
+
917
+ const handleConfirm = (selectedRows) => {
918
+ console.log('选中的行:', selectedRows)
919
+ dialogVisible.value = false
920
+ }
921
+ </script>
922
+ ```
923
+
924
+ ### SCTJMapViewer 地图查看器
925
+
926
+ ```vue
927
+ <template>
928
+ <SCTJMapViewer
929
+ :height="'600px'"
930
+ :width="'100%'"
931
+ :center="[116.397428, 39.90923]"
932
+ :static-markers="staticMarkers"
933
+ :dynamic-markers="dynamicMarkers"
934
+ :polylines="polylines"
935
+ :polygons="polygons"
936
+ :legend-config="legendConfig"
937
+ :change-map-type="true"
938
+ @marker-click="handleMarkerClick"
939
+ />
940
+ </template>
941
+
942
+ <script setup>
943
+ import { ref } from 'vue'
944
+ import { SCTJMapViewer } from 'sctj-components'
945
+
946
+ const staticMarkers = ref([
947
+ {
948
+ position: [116.397428, 39.90923],
949
+ title: '标记点1',
950
+ icon: 'https://webapi.amap.com/theme/v1.3/markers/n/mark_b.png'
951
+ }
952
+ ])
953
+
954
+ const dynamicMarkers = ref([
955
+ {
956
+ id: '1',
957
+ position: [116.407428, 39.91923],
958
+ title: '动态标记点',
959
+ icon: 'https://webapi.amap.com/theme/v1.3/markers/n/mark_r.png'
960
+ }
961
+ ])
962
+
963
+ const polylines = ref([
964
+ {
965
+ path: [
966
+ [116.397428, 39.90923],
967
+ [116.407428, 39.91923]
968
+ ],
969
+ strokeColor: '#3366FF',
970
+ strokeWeight: 3
971
+ }
972
+ ])
973
+
974
+ const polygons = ref([
975
+ {
976
+ path: [
977
+ [116.397428, 39.90923],
978
+ [116.407428, 39.91923],
979
+ [116.417428, 39.92923]
980
+ ],
981
+ fillColor: '#FF0000',
982
+ strokeColor: '#0000FF',
983
+ strokeWeight: 2
984
+ }
985
+ ])
986
+
987
+ const legendConfig = ref([
988
+ { label: '类型A', value: 'typeA' },
989
+ { label: '类型B', value: 'typeB' }
990
+ ])
991
+
992
+ const handleMarkerClick = (marker) => {
993
+ console.log('点击了标记点:', marker)
994
+ }
995
+ </script>
996
+ ```
997
+
998
+ ### SCTJMapDrawingDialog 地图绘制对话框
999
+
1000
+ ```vue
1001
+ <template>
1002
+ <el-button @click="dialogVisible = true">绘制地图</el-button>
1003
+ <SCTJMapDrawingDialog
1004
+ v-model:open="dialogVisible"
1005
+ title="绘制区域"
1006
+ @confirm="handleConfirm"
1007
+ />
1008
+ </template>
1009
+
1010
+ <script setup>
1011
+ import { ref } from 'vue'
1012
+ import { SCTJMapDrawingDialog } from 'sctj-components'
1013
+
1014
+ const dialogVisible = ref(false)
1015
+
1016
+ const handleConfirm = (drawingData) => {
1017
+ console.log('绘制的数据:', drawingData)
1018
+ dialogVisible.value = false
1019
+ }
1020
+ </script>
1021
+ ```
1022
+
1023
+ ### SCTJBusinessMapDrawingDialog 业务地图绘制对话框
1024
+
1025
+ ```vue
1026
+ <template>
1027
+ <el-button @click="dialogVisible = true">业务绘制</el-button>
1028
+ <SCTJBusinessMapDrawingDialog
1029
+ v-model:open="dialogVisible"
1030
+ title="业务区域绘制"
1031
+ @confirm="handleConfirm"
1032
+ />
1033
+ </template>
1034
+
1035
+ <script setup>
1036
+ import { ref } from 'vue'
1037
+ import { SCTJBusinessMapDrawingDialog } from 'sctj-components'
1038
+
1039
+ const dialogVisible = ref(false)
1040
+
1041
+ const handleConfirm = (drawingData) => {
1042
+ console.log('业务绘制数据:', drawingData)
1043
+ dialogVisible.value = false
1044
+ }
1045
+ </script>
1046
+ ```
1047
+
1048
+ ## ⚠️ 注意事项
1049
+
1050
+ ### 1. 组件特殊依赖说明
1051
+
1052
+ 部分组件需要通过 props 传入业务 API 函数:
1053
+
1054
+ - **SCTJH5hkPlayer**:需要传入 `getLiveAddress`、`getReplayAddress`、`downloadCertificate` 函数
1055
+ - **SCTJHelmetPlayer**:需要传入 `callApi`、`handleStreamingApi`、`queryAdminSipInfoApi` 函数
1056
+ - **SCTJYsyPlayer**:需要传入 `getYsToken` 函数
1057
+ - **SCTJFileUpload、SCTJImageUpload、SCTJImagePreview**:可选传入 `baseUrl` prop 处理相对路径
1058
+
1059
+ ### 2. 样式
1060
+
1061
+ 需要引入 Element Plus 的样式文件:
1062
+ ```javascript
1063
+ import 'element-plus/dist/index.css'
1064
+ ```
1065
+
1066
+ ### 3. 按需引入
1067
+
1068
+ 推荐使用按需引入以减少打包体积。
1069
+
1070
+ ### 4. TypeScript
1071
+
1072
+ 如果需要 TypeScript 支持,需要额外配置类型声明文件。
1073
+
1074
+ ## 🔧 常见问题
1075
+
1076
+ ### 1. 组件无法正常工作
1077
+
1078
+ **原因**:缺少必要的依赖或配置
1079
+
1080
+ **解决**:
1081
+ - 检查组件依赖的工具函数
1082
+ - 确保使用者安装了所有 peerDependencies
1083
+ - 查看组件的使用文档
1084
+
1085
+ ### 2. 播放器组件报错
1086
+
1087
+ **原因**:未提供必需的 API 函数
1088
+
1089
+ **解决**:
1090
+ - 确保通过 props 传入了所有必需的 API 函数
1091
+ - 检查 API 函数的返回格式是否正确
1092
+
1093
+ ### 3. 静态资源加载失败
1094
+
1095
+ **原因**:未正确拷贝静态资源文件
1096
+
1097
+ **解决**:
1098
+ - 确保已将 `public/` 目录下的文件拷贝到宿主项目
1099
+ - 检查 `index.html` 中的 script 标签路径是否正确
1100
+
1101
+ ## 📚 更多信息
1102
+
1103
+ - 详细发布指南:查看 `PUBLISH_GUIDE.md`(仅限组件库维护者)
1104
+
1105
+ ## 📄 许可证
1106
+
1107
+ MIT
1108
+
1109
+ ## 👥 作者
1110
+
1111
+ 铁建
1112
+