Commit e43587ecf39066c8e4a74297c2a29deda9384cc0

Authored by ww
1 parent ef71e5bb

feat: implement video component bind videoUrl

@@ -32,6 +32,7 @@ @@ -32,6 +32,7 @@
32 32
33 <script src="./plugins/axios.min.js"></script> 33 <script src="./plugins/axios.min.js"></script>
34 34
  35 + <!-- video.js import -->
35 <link href="https://vjs.zencdn.net/7.10.2/video-js.min.css" rel="stylesheet"> 36 <link href="https://vjs.zencdn.net/7.10.2/video-js.min.css" rel="stylesheet">
36 <script src="https://vjs.zencdn.net/7.10.2/video.min.js"></script> 37 <script src="https://vjs.zencdn.net/7.10.2/video.min.js"></script>
37 38
@@ -5,7 +5,7 @@ class ConfigurationNodeApi { @@ -5,7 +5,7 @@ class ConfigurationNodeApi {
5 * @param {string} levelId - 组态资源ID 5 * @param {string} levelId - 组态资源ID
6 */ 6 */
7 static getConfigurationInfo(levelType, levelId) { 7 static getConfigurationInfo(levelType, levelId) {
8 - return defHttp.get(`/yt/configuration/node/${ levelType }/${ levelId }`) 8 + return defHttp.get(`/yt/configuration/node/${levelType}/${levelId}`)
9 } 9 }
10 10
11 /** 11 /**
@@ -22,7 +22,7 @@ class ConfigurationNodeApi { @@ -22,7 +22,7 @@ class ConfigurationNodeApi {
22 * @returns {Promise<*>} 22 * @returns {Promise<*>}
23 */ 23 */
24 static getDeviceAttr(tbDeviceId) { 24 static getDeviceAttr(tbDeviceId) {
25 - return defHttp.get(`/plugins/telemetry/DEVICE/${ tbDeviceId }/keys/timeseries`) 25 + return defHttp.get(`/plugins/telemetry/DEVICE/${tbDeviceId}/keys/timeseries`)
26 } 26 }
27 27
28 /** 28 /**
@@ -32,7 +32,7 @@ class ConfigurationNodeApi { @@ -32,7 +32,7 @@ class ConfigurationNodeApi {
32 * @returns {Promise<*>} 32 * @returns {Promise<*>}
33 */ 33 */
34 static getDeviceUnderTheOrg(deviceType, orgId) { 34 static getDeviceUnderTheOrg(deviceType, orgId) {
35 - return defHttp.get(`/yt/device/list/${ deviceType }?organizationId=${ orgId }`) 35 + return defHttp.get(`/yt/device/list/${deviceType}?organizationId=${orgId}`)
36 } 36 }
37 37
38 /** 38 /**
@@ -50,7 +50,7 @@ class ConfigurationNodeApi { @@ -50,7 +50,7 @@ class ConfigurationNodeApi {
50 * @returns {Promise<*>} 50 * @returns {Promise<*>}
51 */ 51 */
52 static getDeviceChildDevice(deviceId) { 52 static getDeviceChildDevice(deviceId) {
53 - return defHttp.get(`/yt/device/relation?page=1&pageSize=10&fromId=${ deviceId }`) 53 + return defHttp.get(`/yt/device/relation?page=1&pageSize=10&fromId=${deviceId}`)
54 } 54 }
55 55
56 /** 56 /**
@@ -59,7 +59,7 @@ class ConfigurationNodeApi { @@ -59,7 +59,7 @@ class ConfigurationNodeApi {
59 * @returns {Promise<*>} 59 * @returns {Promise<*>}
60 */ 60 */
61 static getMasterDevice(orgId) { 61 static getMasterDevice(orgId) {
62 - return defHttp.get(`/yt/device/list/master/${ orgId }`) 62 + return defHttp.get(`/yt/device/list/master/${orgId}`)
63 } 63 }
64 64
65 /** 65 /**
@@ -69,7 +69,7 @@ class ConfigurationNodeApi { @@ -69,7 +69,7 @@ class ConfigurationNodeApi {
69 * @returns {Promise<*>} 69 * @returns {Promise<*>}
70 */ 70 */
71 static getSlaveDevice(orgId, masterDeviceId) { 71 static getSlaveDevice(orgId, masterDeviceId) {
72 - return defHttp.get(`/yt/device/list/slave/${ orgId }?masterId=${ masterDeviceId }`) 72 + return defHttp.get(`/yt/device/list/slave/${orgId}?masterId=${masterDeviceId}`)
73 } 73 }
74 74
75 /** 75 /**
@@ -103,7 +103,7 @@ class ConfigurationNodeApi { @@ -103,7 +103,7 @@ class ConfigurationNodeApi {
103 * @param {object} data - 数据 103 * @param {object} data - 数据
104 */ 104 */
105 static sendInstructionOneWay(deviceId, data) { 105 static sendInstructionOneWay(deviceId, data) {
106 - return defHttp.post(`/rpc/oneway/${ deviceId }`, data) 106 + return defHttp.post(`/rpc/oneway/${deviceId}`, data)
107 } 107 }
108 108
109 /** 109 /**
@@ -112,7 +112,7 @@ class ConfigurationNodeApi { @@ -112,7 +112,7 @@ class ConfigurationNodeApi {
112 * @param {object} data - 数据 112 * @param {object} data - 数据
113 */ 113 */
114 static sendInstructionTwoWay(deviceId, data) { 114 static sendInstructionTwoWay(deviceId, data) {
115 - return defHttp.post(`/rpc/twoway/${ deviceId }`, data) 115 + return defHttp.post(`/rpc/twoway/${deviceId}`, data)
116 } 116 }
117 117
118 /** 118 /**
@@ -122,8 +122,8 @@ class ConfigurationNodeApi { @@ -122,8 +122,8 @@ class ConfigurationNodeApi {
122 * @param data 122 * @param data
123 * @return {*} 123 * @return {*}
124 */ 124 */
125 - static sendInstruction(way,deviceId, data) {  
126 - return defHttp.post(`/rpc/${way}/${ deviceId }`, data) 125 + static sendInstruction(way, deviceId, data) {
  126 + return defHttp.post(`/rpc/${way}/${deviceId}`, data)
127 } 127 }
128 128
129 /** 129 /**
@@ -131,7 +131,7 @@ class ConfigurationNodeApi { @@ -131,7 +131,7 @@ class ConfigurationNodeApi {
131 * @param deviceId 131 * @param deviceId
132 * @return {*} 132 * @return {*}
133 */ 133 */
134 - static deviceIsOnLine(deviceId){ 134 + static deviceIsOnLine(deviceId) {
135 return defHttp.get(`/plugins/telemetry/DEVICE/${deviceId}/values/attributes?keys=active`) 135 return defHttp.get(`/plugins/telemetry/DEVICE/${deviceId}/values/attributes?keys=active`)
136 } 136 }
137 137
@@ -140,7 +140,27 @@ class ConfigurationNodeApi { @@ -140,7 +140,27 @@ class ConfigurationNodeApi {
140 * @param data 140 * @param data
141 * @returns {*} 141 * @returns {*}
142 */ 142 */
143 - static uploadImg(data){ 143 + static uploadImg(data) {
144 return defHttp.post('/yt/oss/upload', data) 144 return defHttp.post('/yt/oss/upload', data)
145 } 145 }
  146 +
  147 + /**
  148 + * @description 获取流媒体
  149 + * @param {number} page
  150 + * @param {number} pageSize
  151 + * @returns
  152 + */
  153 + static getStreamingMediaList(organizationId, page = 1, pageSize = 10) {
  154 + return defHttp.get(`/yt/video`, { params: { organizationId, page, pageSize } })
  155 + }
  156 +
  157 +
  158 + /**
  159 + * @description 获取流媒体播放地址
  160 + * @param {string} id
  161 + * @returns
  162 + */
  163 + static getStreamingVideoPlayUrl(id) {
  164 + return defHttp.get(`/yt/video/url/${id}`)
  165 + }
146 } 166 }
@@ -227,7 +227,7 @@ @@ -227,7 +227,7 @@
227 * @description 柱状图类型 227 * @description 柱状图类型
228 */ 228 */
229 BAR_CHART: 'barChart', 229 BAR_CHART: 'barChart',
230 - 230 +
231 /** 231 /**
232 * @description 视频 232 * @description 视频
233 */ 233 */
@@ -273,7 +273,8 @@ @@ -273,7 +273,8 @@
273 BAR_CHART_EXPAND: 'barChartExpandDataSource', 273 BAR_CHART_EXPAND: 'barChartExpandDataSource',
274 INTERACTION: 'interaction', 274 INTERACTION: 'interaction',
275 DYNAMIC_EFFECT: 'dynamicEffect', 275 DYNAMIC_EFFECT: 'dynamicEffect',
276 - VAR_IMAGE: 'variableImage' 276 + VAR_IMAGE: 'variableImage',
  277 + VIDEO: 'video'
277 } 278 }
278 279
279 /** 280 /**
@@ -627,8 +628,8 @@ @@ -627,8 +628,8 @@
627 //更多图形,显示出来的的标题跟id,同时包括图片 628 //更多图形,显示出来的的标题跟id,同时包括图片
628 629
629 // TODO thingsKit 设置数据绑定展示面板 630 // TODO thingsKit 设置数据绑定展示面板
630 - const { LINE_CHART_EXPAND, BAR_CHART_EXPAND, DYNAMIC_EFFECT, DATA_SOURCE, VAR_IMAGE, INTERACTION } = this.enumPermissionPanel  
631 - const { LINE, LINE_CHART, REAL_TIME, TITLE, VARIABLE, DEFAULT, BAR_CHART } = this.enumComponentType 631 + const { LINE_CHART_EXPAND, BAR_CHART_EXPAND, DYNAMIC_EFFECT, DATA_SOURCE, VAR_IMAGE, INTERACTION, VIDEO: VIDEO_PANEL } = this.enumPermissionPanel
  632 + const { LINE, LINE_CHART, REAL_TIME, TITLE, VARIABLE, DEFAULT, BAR_CHART, VIDEO } = this.enumComponentType
632 this.setComponentPermission(LINE, [DYNAMIC_EFFECT]) 633 this.setComponentPermission(LINE, [DYNAMIC_EFFECT])
633 this.setComponentPermission(DEFAULT, [DYNAMIC_EFFECT]) 634 this.setComponentPermission(DEFAULT, [DYNAMIC_EFFECT])
634 this.setComponentPermission(REAL_TIME, [DYNAMIC_EFFECT]) 635 this.setComponentPermission(REAL_TIME, [DYNAMIC_EFFECT])
@@ -637,6 +638,7 @@ @@ -637,6 +638,7 @@
637 this.setComponentPermission(VARIABLE, [DATA_SOURCE, INTERACTION, DYNAMIC_EFFECT]) 638 this.setComponentPermission(VARIABLE, [DATA_SOURCE, INTERACTION, DYNAMIC_EFFECT])
638 this.setComponentPermission(BAR_CHART, [DATA_SOURCE, BAR_CHART_EXPAND]) 639 this.setComponentPermission(BAR_CHART, [DATA_SOURCE, BAR_CHART_EXPAND])
639 this.setComponentPermission(LINE_CHART, [DATA_SOURCE, LINE_CHART_EXPAND]) 640 this.setComponentPermission(LINE_CHART, [DATA_SOURCE, LINE_CHART_EXPAND])
  641 + this.setComponentPermission(VIDEO, [VIDEO_PANEL])
640 642
641 var thingskitEntries = [ 643 var thingskitEntries = [
642 { title: "风机", id: 'fan', image: IMAGE_PATH + '/thingskit/风机.png' }, 644 { title: "风机", id: 'fan', image: IMAGE_PATH + '/thingskit/风机.png' },
@@ -53,7 +53,7 @@ @@ -53,7 +53,7 @@
53 return this.createVertexTemplateFromCells([cell], cell.geometry.width, cell.geometry.height, '变量图片'); 53 return this.createVertexTemplateFromCells([cell], cell.geometry.width, cell.geometry.height, '变量图片');
54 })), 54 })),
55 this.addEntry(this.getTagsForStencil('mxgraph.basic', '视频', 'basic').join(' '), mxUtils.bind(this, function () { 55 this.addEntry(this.getTagsForStencil('mxgraph.basic', '视频', 'basic').join(' '), mxUtils.bind(this, function () {
56 - const template = createVideoTemplate() 56 + const template = createVideoTemplate(300, 150)
57 const cell = new mxCell(template, new mxGeometry(0, 0, 300, 150), 'text;html=1;strokeColor=none;fillColor=none;align=center;verticalAlign=middle;whiteSpace=wrap;overflow=hidden;'); 57 const cell = new mxCell(template, new mxGeometry(0, 0, 300, 150), 'text;html=1;strokeColor=none;fillColor=none;align=center;verticalAlign=middle;whiteSpace=wrap;overflow=hidden;');
58 cell.setVertex(true) 58 cell.setVertex(true)
59 this.setCellAttributes(cell, { [basicAttr.COMPONENT_TYPE]: componentType.VIDEO }) 59 this.setCellAttributes(cell, { [basicAttr.COMPONENT_TYPE]: componentType.VIDEO })
@@ -86,6 +86,7 @@ @@ -86,6 +86,7 @@
86 86
87 function createVideoTemplate(width = '100%', height = '100%') { 87 function createVideoTemplate(width = '100%', height = '100%') {
88 const m3u8 = 'http://d2zihajmogu5jn.cloudfront.net/bipbop-advanced/bipbop_16x9_variant.m3u8' 88 const m3u8 = 'http://d2zihajmogu5jn.cloudfront.net/bipbop-advanced/bipbop_16x9_variant.m3u8'
  89 + // const m3u8 = 'http://113.204.115.250:83/openUrl/iVnkGzK/live.m3u8'
89 const mp4 = 'http://vjs.zencdn.net/v/oceans.mp4' 90 const mp4 = 'http://vjs.zencdn.net/v/oceans.mp4'
90 const m3u8Type = 'application/x-mpegURL' 91 const m3u8Type = 'application/x-mpegURL'
91 const mp4Type = 'video/mp4' 92 const mp4Type = 'video/mp4'
@@ -93,7 +94,7 @@ @@ -93,7 +94,7 @@
93 94
94 // const cell = new mxCell('<video></video>', new mxGeometry(0, 0, 100, 95), 'image;image=images/thingskit/video.svg;imageAspect=0;'); 95 // const cell = new mxCell('<video></video>', new mxGeometry(0, 0, 100, 95), 'image;image=images/thingskit/video.svg;imageAspect=0;');
95 const template = `<video controls preload="auto" muted="muted" width="${width}" height="${height}" poster="${poster}" data-setup='{}'> 96 const template = `<video controls preload="auto" muted="muted" width="${width}" height="${height}" poster="${poster}" data-setup='{}'>
96 - <source src="${mp4}" type="${mp4Type}"> 97 + <source src="${m3u8}" type="${m3u8Type}">
97 <p class="vjs-no-js"> 98 <p class="vjs-no-js">
98 要查看此视频,请启用JavaScript,并考虑升级web浏览器. 99 要查看此视频,请启用JavaScript,并考虑升级web浏览器.
99 </p> 100 </p>
@@ -5123,12 +5123,12 @@ DataFormatPanel.prototype.addDataFont = function (container) { @@ -5123,12 +5123,12 @@ DataFormatPanel.prototype.addDataFont = function (container) {
5123 5123
5124 const renderMapping = { 5124 const renderMapping = {
5125 [permissionKey.DATA_SOURCE]: createDataSourcePanel, 5125 [permissionKey.DATA_SOURCE]: createDataSourcePanel,
5126 - // [permissionKey.DISPLAY_TYPE]: createChartBindPanel,  
5127 [permissionKey.LINE_CHART_EXPAND]: createLineChartPanel, 5126 [permissionKey.LINE_CHART_EXPAND]: createLineChartPanel,
5128 [permissionKey.BAR_CHART_EXPAND]: createBarChartPanel, 5127 [permissionKey.BAR_CHART_EXPAND]: createBarChartPanel,
5129 [permissionKey.INTERACTION]: createInteractionPanel, 5128 [permissionKey.INTERACTION]: createInteractionPanel,
5130 [permissionKey.DYNAMIC_EFFECT]: createDynamicEffectPanel, 5129 [permissionKey.DYNAMIC_EFFECT]: createDynamicEffectPanel,
5131 [permissionKey.VAR_IMAGE]: createVarImagePanel, 5130 [permissionKey.VAR_IMAGE]: createVarImagePanel,
  5131 + [permissionKey.VIDEO]: createVideoBindPanel
5132 } 5132 }
5133 5133
5134 5134
@@ -5255,6 +5255,128 @@ DataFormatPanel.prototype.addDataFont = function (container) { @@ -5255,6 +5255,128 @@ DataFormatPanel.prototype.addDataFont = function (container) {
5255 } 5255 }
5256 5256
5257 /** 5257 /**
  5258 + * @description 创建视频绑定面板
  5259 + */
  5260 + function createVideoBindPanel() {
  5261 +
  5262 + const enumConst = {
  5263 + ORG_ID: 'orgId',
  5264 + RECORD_ID: 'id',
  5265 + VIDEO_URL: 'videoUrl',
  5266 + ACCESSMODE: 'accessMode',
  5267 + VIDEO_FLAG: 'videoComponentFlag'
  5268 + }
  5269 +
  5270 + const enumActionEL = {
  5271 + VIDEO_FILTER: 'videoFilter',
  5272 + PANEL_EL: 'videoPanelControl',
  5273 + ORG_EL: 'orgTreeEl'
  5274 + }
  5275 +
  5276 + const fragment = document.createDocumentFragment()
  5277 + const title = createTitle('视频绑定')
  5278 + $(title).addClass('override__title--default')
  5279 +
  5280 + const defaultPanel = createPanel()
  5281 + $(defaultPanel).addClass('override__panel--default')
  5282 + $(defaultPanel).append(`<div id="${enumActionEL.ORG_EL}" class="video-panel-org__override"></div>`)
  5283 + $(defaultPanel).append(`<div class="layui-form-item" style="display: none;"><input name="${enumConst.ACCESSMODE}" /></div>`)
  5284 + $(defaultPanel).append(`<div class="layui-form-item" style="display: none;"><input name="${enumConst.VIDEO_FLAG}" value="true" /></div>`)
  5285 + $(defaultPanel).append(`<div class="layui-form-item" style="display: none;"><input name="${enumConst.VIDEO_URL}" /></div>`)
  5286 +
  5287 + const videoBindSelect = UseLayUi.createSelect({
  5288 + label: '视频流',
  5289 + layFilter: enumActionEL.VIDEO_FILTER,
  5290 + className: 'data-source__component-select',
  5291 + bindValueFiled: enumConst.RECORD_ID
  5292 + })
  5293 + $(defaultPanel).append(`<div id="${enumActionEL.PANEL_EL}">${videoBindSelect}</div>`)
  5294 +
  5295 + fragment.append(title)
  5296 + fragment.append(defaultPanel)
  5297 + $(container).append(fragment)
  5298 +
  5299 + function init() {
  5300 +
  5301 + let orgId = null;
  5302 +
  5303 + let recordOptions = []
  5304 +
  5305 + let treeList = []
  5306 +
  5307 + const refreshFN = echoRefreshFn
  5308 + echoRefreshFn = async function () {
  5309 + refreshFN.apply(this, arguments)
  5310 + await echoData()
  5311 + }
  5312 + async function echoData() {
  5313 + const { videoUrl, orgId: organizationId, accessMode, id } = currentNodeData?.dataSources?.[0]?.additional || {}
  5314 + orgId = organizationId
  5315 + await getStreamingMediaByOrgId()
  5316 + form.val(CONTAINER_FILTER, { videoUrl, accessMode, id })
  5317 + UseLayUi.nextTick(() => {
  5318 + const node = UseLayUi.findTreeObjectByField(treeList, organizationId)
  5319 + $(`#${enumActionEL.ORG_EL} input[name="${enumConst.ORG_ID}"]`).val(organizationId).parent().find('span').html(node?.name)
  5320 + })
  5321 + }
  5322 +
  5323 +
  5324 +
  5325 + /**
  5326 + * @description 创建组织树
  5327 + */
  5328 + async function createOrgTreeSelect() {
  5329 + const [err, res] = await to(ConfigurationNodeApi.getOrgTree())
  5330 + treeList = res
  5331 + if (err) return
  5332 + UseLayUi.createTreeSelect({
  5333 + elem: `#${enumActionEL.ORG_EL}`,
  5334 + layFilter: enumConst.ORG_ID,
  5335 + label: '组织',
  5336 + singleUsage: false,
  5337 + layVerify: 'required',
  5338 + layVerType: 'tips',
  5339 + treeProps: {
  5340 + data: res,
  5341 + onlyIconControl: true,
  5342 + click(node) {
  5343 + orgId = node.data.id
  5344 + getStreamingMediaByOrgId()
  5345 + form.val(CONTAINER_FILTER, {
  5346 + [enumConst.RECORD_ID]: null
  5347 + })
  5348 + },
  5349 + },
  5350 + })
  5351 + }
  5352 +
  5353 + async function getStreamingMediaByOrgId() {
  5354 + const [err, res] = await to(ConfigurationNodeApi.getStreamingMediaList(orgId))
  5355 + recordOptions = res.items
  5356 + const options = UseLayUi.generateOptionTemplate({ dataSource: res.items || [] })
  5357 + $(`#${enumActionEL.PANEL_EL} select[name="${enumConst.RECORD_ID}"]`).html(options)
  5358 + form.render()
  5359 + }
  5360 +
  5361 + function createLinsten() {
  5362 + form.on(`select(${enumActionEL.VIDEO_FILTER})`, event => {
  5363 + const { value } = event
  5364 + const item = recordOptions.find(item => item.id === value)
  5365 + form.val(CONTAINER_FILTER, {
  5366 + [enumConst.ACCESSMODE]: item[enumConst.ACCESSMODE],
  5367 + [enumConst.VIDEO_URL]: item[enumConst.VIDEO_URL],
  5368 + })
  5369 + })
  5370 + }
  5371 +
  5372 + createOrgTreeSelect()
  5373 + createLinsten()
  5374 + }
  5375 +
  5376 + init()
  5377 + }
  5378 +
  5379 + /**
5258 * @description 是否是折线图 5380 * @description 是否是折线图
5259 * @param {boolean} isLineChart 5381 * @param {boolean} isLineChart
5260 */ 5382 */
@@ -5688,10 +5810,43 @@ DataFormatPanel.prototype.addDataFont = function (container) { @@ -5688,10 +5810,43 @@ DataFormatPanel.prototype.addDataFont = function (container) {
5688 const panel = createPanel() 5810 const panel = createPanel()
5689 $(panel).addClass('data-source__submit-panel').append(`<button type="button" lay-submit lay-filter="formDataSource" class="layui-btn">保存</button>`) 5811 $(panel).addClass('data-source__submit-panel').append(`<button type="button" lay-submit lay-filter="formDataSource" class="layui-btn">保存</button>`)
5690 $(container).append(panel) 5812 $(container).append(panel)
5691 - const additionalKey = HandleDataSource.enumConst  
5692 form.on('submit(formDataSource)', async function (data) { 5813 form.on('submit(formDataSource)', async function (data) {
5693 - const ENABLED_FLAG = 'on'  
5694 const { field } = data 5814 const { field } = data
  5815 + const value = getValueOnSubmit(field)
  5816 + await to(autoSaveGraphInfo())
  5817 + const [err, res] = await to(ConfigurationNodeApi.updateNodeInfo(value))
  5818 + if (err) return
  5819 + UseLayUi.successMsg()
  5820 + await getNodeBindInfo()
  5821 + return false;
  5822 + });
  5823 + }
  5824 +
  5825 + function getValueOnSubmit(field) {
  5826 + const basicAttr = sidebarInstance.enumCellBasicAttribute
  5827 + const permissionKey = sidebarInstance.enumComponentType
  5828 +
  5829 +
  5830 + const renderMapping = {
  5831 + [permissionKey.VAR_IMAGE]: getSubmitValue,
  5832 + [permissionKey.CHARTS]: getSubmitValue,
  5833 + [permissionKey.TITLE]: getSubmitValue,
  5834 + [permissionKey.VARIABLE]: getSubmitValue,
  5835 + [permissionKey.LINE]: getSubmitValue,
  5836 + [permissionKey.REAL_TIME]: getSubmitValue,
  5837 + [permissionKey.LINE_CHART]: getSubmitValue,
  5838 + [permissionKey.DEFAULT]: getVideoSubmitValue,
  5839 + [permissionKey.VIDEO]: getVideoSubmitValue,
  5840 + }
  5841 +
  5842 + const cell = vertices[0]
  5843 + const permission = graph.getAttributeForCell(cell, basicAttr.COMPONENT_TYPE)
  5844 +
  5845 + return renderMapping[permission]?.() || {}
  5846 +
  5847 + function getSubmitValue() {
  5848 + const ENABLED_FLAG = 'on'
  5849 + const additionalKey = HandleDataSource.enumConst
5695 const value = { 5850 const value = {
5696 configurationId, 5851 configurationId,
5697 contentId: currentPageId.id, 5852 contentId: currentPageId.id,
@@ -5701,7 +5856,6 @@ DataFormatPanel.prototype.addDataFont = function (container) { @@ -5701,7 +5856,6 @@ DataFormatPanel.prototype.addDataFont = function (container) {
5701 [enumCategory.DATA_SOURCE]: { 5856 [enumCategory.DATA_SOURCE]: {
5702 [enumDataSourceConst.ORG_ID]: field[enumDataSourceConst.ORG_ID], 5857 [enumDataSourceConst.ORG_ID]: field[enumDataSourceConst.ORG_ID],
5703 [enumDataSourceConst.DEVICE_ID]: field[enumDataSourceConst.DEVICE_ID], 5858 [enumDataSourceConst.DEVICE_ID]: field[enumDataSourceConst.DEVICE_ID],
5704 - // ...(field[enumDataSourceConst.SLAVE_DEVICE_ID] && { [enumDataSourceConst.SLAVE_DEVICE_ID]: field[enumDataSourceConst.SLAVE_DEVICE_ID] }),  
5705 [enumDataSourceConst.SLAVE_DEVICE_ID]: field[enumDataSourceConst.SLAVE_DEVICE_ID] ? field[enumDataSourceConst.SLAVE_DEVICE_ID] : '', 5859 [enumDataSourceConst.SLAVE_DEVICE_ID]: field[enumDataSourceConst.SLAVE_DEVICE_ID] ? field[enumDataSourceConst.SLAVE_DEVICE_ID] : '',
5706 [enumDataSourceConst.ATTR]: field[enumDataSourceConst.ATTR], 5860 [enumDataSourceConst.ATTR]: field[enumDataSourceConst.ATTR],
5707 [enumDataSourceConst.ADDITIONAL]: field[additionalKey.DATA_TYPE] ? { 5861 [enumDataSourceConst.ADDITIONAL]: field[additionalKey.DATA_TYPE] ? {
@@ -5728,13 +5882,24 @@ DataFormatPanel.prototype.addDataFont = function (container) { @@ -5728,13 +5882,24 @@ DataFormatPanel.prototype.addDataFont = function (container) {
5728 }) 5882 })
5729 } 5883 }
5730 } 5884 }
5731 - await to(autoSaveGraphInfo())  
5732 - const [err, res] = await to(ConfigurationNodeApi.updateNodeInfo(value))  
5733 - if (err) return  
5734 - UseLayUi.successMsg()  
5735 - await getNodeBindInfo()  
5736 - return false;  
5737 - }); 5885 +
  5886 + return value
  5887 + }
  5888 +
  5889 + function getVideoSubmitValue() {
  5890 + const value = {
  5891 + configurationId,
  5892 + contentId: currentPageId.id,
  5893 + nodeId: graphId,
  5894 + [enumCategory.DATA_SOURCE]: {
  5895 + [enumDataSourceConst.ORG_ID]: 'b4dd6e2b-6e0f-413c-bf5a-70133bd571e8',
  5896 + [enumDataSourceConst.DEVICE_ID]: '6d9043f0-f1f7-11ec-98ad-a9680487d1e0',
  5897 + [enumDataSourceConst.ATTR]: 'attr',
  5898 + [enumDataSourceConst.ADDITIONAL]: field
  5899 + },
  5900 + }
  5901 + return value
  5902 + }
5738 } 5903 }
5739 5904
5740 /** 5905 /**
@@ -13260,6 +13425,11 @@ class HandleDynamicEffect { @@ -13260,6 +13425,11 @@ class HandleDynamicEffect {
13260 enableActList 13425 enableActList
13261 13426
13262 /** 13427 /**
  13428 + * @description 视频记录列表
  13429 + */
  13430 + videoRecordList
  13431 +
  13432 + /**
13263 * @description 动效节点映射 13433 * @description 动效节点映射
13264 * @type {Map<string, {display: boolean, value: Map<string, any>}>} 13434 * @type {Map<string, {display: boolean, value: Map<string, any>}>}
13265 */ 13435 */
@@ -13287,6 +13457,19 @@ class HandleDynamicEffect { @@ -13287,6 +13457,19 @@ class HandleDynamicEffect {
13287 HIDDEN: 'hidden', 13457 HIDDEN: 'hidden',
13288 } 13458 }
13289 13459
  13460 + static enumVideoConst = {
  13461 + ORG_ID: 'orgId',
  13462 + RECORD_ID: 'id',
  13463 + VIDEO_URL: 'videoUrl',
  13464 + ACCESSMODE: 'accessMode',
  13465 + VIDEO_FLAG: 'videoComponentFlag'
  13466 + }
  13467 +
  13468 + static enumVideoAccessMode = {
  13469 + MANUAL_ENTER: 0,
  13470 + STREAMING: 1
  13471 + }
  13472 +
13290 constructor(DispatchInstance) { 13473 constructor(DispatchInstance) {
13291 this.DispatchInstance = DispatchInstance 13474 this.DispatchInstance = DispatchInstance
13292 this.init() 13475 this.init()
@@ -13294,6 +13477,7 @@ class HandleDynamicEffect { @@ -13294,6 +13477,7 @@ class HandleDynamicEffect {
13294 13477
13295 init() { 13478 init() {
13296 this.getEnableActList() 13479 this.getEnableActList()
  13480 + this.getVideoRecord()
13297 this.generatorMappingRelation() 13481 this.generatorMappingRelation()
13298 } 13482 }
13299 13483
@@ -13326,6 +13510,15 @@ class HandleDynamicEffect { @@ -13326,6 +13510,15 @@ class HandleDynamicEffect {
13326 } 13510 }
13327 13511
13328 /** 13512 /**
  13513 + * @description 筛选出视频数据源
  13514 + */
  13515 + getVideoRecord() {
  13516 + const { dataSources = [] } = this.DispatchInstance.contentData
  13517 + const { VIDEO_FLAG } = HandleDynamicEffect.enumVideoConst
  13518 + this.videoRecordList = dataSources.filter(item => item?.additional?.[VIDEO_FLAG])
  13519 + }
  13520 +
  13521 + /**
13329 * @description 获取已开启的数据动效 13522 * @description 获取已开启的数据动效
13330 */ 13523 */
13331 getEnableActList() { 13524 getEnableActList() {
@@ -13465,13 +13658,6 @@ class HandleDynamicEffect { @@ -13465,13 +13658,6 @@ class HandleDynamicEffect {
13465 isShow = false 13658 isShow = false
13466 } 13659 }
13467 const updateFn = () => { 13660 const updateFn = () => {
13468 - // let style = node.getStyle()  
13469 - // const reg = /opacity=(-?)\w+(;?)/g  
13470 - // style = style.replace(reg, '')  
13471 - // style += `opacity=${isShow ? 100 : 0};`  
13472 - // console.log(style)  
13473 - // node.setStyle(style)  
13474 -  
13475 if (!isShow) { 13661 if (!isShow) {
13476 Object.keys(HandleDynamicEffect.enumActType).forEach(key => { 13662 Object.keys(HandleDynamicEffect.enumActType).forEach(key => {
13477 const delKey = node.id + key 13663 const delKey = node.id + key
@@ -13534,53 +13720,111 @@ class HandleDynamicEffect { @@ -13534,53 +13720,111 @@ class HandleDynamicEffect {
13534 } 13720 }
13535 } 13721 }
13536 13722
13537 - 13723 + /**
  13724 + * @description 播放视频
  13725 + */
13538 videoPlay() { 13726 videoPlay() {
13539 const basicAttr = Sidebar.prototype.enumCellBasicAttribute 13727 const basicAttr = Sidebar.prototype.enumCellBasicAttribute
13540 - const videoCell = this.DispatchInstance.contentAllCell.filter(cell => cell.getAttribute(basicAttr.COMPONENT_TYPE) === 'video')  
13541 - // const options = {  
13542 - // hls: {  
13543 - // withCredentials: true  
13544 - // }  
13545 - // }  
13546 - // var player = videojs('my-player', options, function onPlayerReady() {  
13547 - // videojs.log('Your player is ready!');  
13548 -  
13549 - // // In this context, `this` is the player that was created by Video.js.  
13550 - // this.play();  
13551 -  
13552 - // // How about an event listener?  
13553 - // this.on('ended', function () {  
13554 - // videojs.log('Awww...over so soon?!');  
13555 - // });  
13556 - // });  
13557 -  
13558 - // console.log(player)  
13559 - // for (const cell of videoCell) {  
13560 - // this.graph.getModel().beginUpdate()  
13561 - // try {  
13562 - // const options = {  
13563 - // hls: {  
13564 - // withCredentials: true  
13565 - // }  
13566 - // }  
13567 - // var player = videojs('my-player', options, function onPlayerReady() {  
13568 - // videojs.log('Your player is ready!');  
13569 -  
13570 - // // In this context, `this` is the player that was created by Video.js.  
13571 - // this.play();  
13572 -  
13573 - // // How about an event listener?  
13574 - // this.on('ended', function () {  
13575 - // videojs.log('Awww...over so soon?!');  
13576 - // });  
13577 - // });  
13578 - // this.graph.refresh(cell);  
13579 - // } finally {  
13580 - // this.graph.getModel().endUpdate()  
13581 - // }  
13582 - // } 13728 + const enumAccessMode = HandleDynamicEffect.enumVideoAccessMode
  13729 +
  13730 + const videoPlayConfig = {
  13731 + controls: true,
  13732 + bigPlayButton: true,
  13733 + textTrackDisplay: false,
  13734 + posterImage: false,
  13735 + errorDisplay: false,
  13736 + }
  13737 + for (const record of this.videoRecordList) {
  13738 + const { additional = {}, nodeId } = record
  13739 + const { accessMode, videoUrl, id } = additional
  13740 + const cell = this.getCellByCellId(nodeId)
  13741 + if (!cell) continue
  13742 + const { geometry = {} } = cell
  13743 + const { width, height } = geometry
  13744 + const idEl = getIdEl()
  13745 + if (Number(accessMode) === enumAccessMode.MANUAL_ENTER) {
  13746 + this.graph.getModel().beginUpdate()
  13747 + try {
  13748 + const template = this.createVideoTemplate(idEl, width, height, videoUrl)
  13749 + cell.setAttribute('label', template)
  13750 + this.graph.refresh(cell);
  13751 + } finally {
  13752 + this.graph.getModel().endUpdate()
  13753 + console.log(idEl)
  13754 + videojs(idEl,
  13755 + {
  13756 + ...videoPlayConfig
  13757 + },
  13758 + function () {
  13759 + const el = document.getElementById(idEl)
  13760 + const videoEl = el.getElementsByTagName('video')?.[0]
  13761 + videoEl.style.width = `${width}px`
  13762 + videoEl.style.height = `${height}px`
  13763 + this.play()
  13764 + })
  13765 + }
  13766 + } else {
  13767 + getStreamingVideoPlayUrl.call(this, id, nodeId)
  13768 + }
  13769 + }
  13770 +
  13771 + async function getStreamingVideoPlayUrl(id, nodeId) {
  13772 + const [err, res = {}] = await to(ConfigurationNodeApi.getStreamingVideoPlayUrl(id))
  13773 + const { url } = res?.data || {}
  13774 + if (!url) return
  13775 + const cell = this.getCellByCellId(nodeId)
  13776 + if (!cell) return
  13777 + const { geometry = {} } = cell
  13778 + const { width, height } = geometry
  13779 + const idEl = getIdEl()
  13780 + this.graph.getModel().beginUpdate()
  13781 + try {
  13782 + const template = this.createVideoTemplate(idEl, width, height, url, 'application/x-mpegURL')
  13783 + cell.setAttribute('label', template)
  13784 + this.graph.refresh(cell);
  13785 + } finally {
  13786 + this.graph.getModel().endUpdate()
  13787 + videojs(idEl,
  13788 + {
  13789 + ...videoPlayConfig,
  13790 + hls: {
  13791 + withCredentials: true
  13792 + }
  13793 + },
  13794 + function () {
  13795 + const el = document.getElementById(idEl)
  13796 + const videoEl = el.getElementsByTagName('video')?.[0]
  13797 + videoEl.style.width = `${width}px`
  13798 + videoEl.style.height = `${height}px`
  13799 + this.play()
  13800 + })
  13801 + }
  13802 + }
  13803 +
  13804 + function getIdEl() {
  13805 + return `video-play__${Date.now()}`
  13806 + }
  13807 + }
  13808 +
  13809 +
  13810 + createVideoTemplate(idEl, width, height, videoUrl, videoType = 'video/mp4') {
  13811 + const poster = `/thingskit-drawio/images/youtube.png`
  13812 + const template = `<video id="${idEl}" controls preload="auto" muted="muted" width="${width}" height="${height}" poster="${poster}" data-setup='{}'>
  13813 + <source src="${videoUrl}" type="${videoType}">
  13814 + <p class="vjs-no-js">
  13815 + 要查看此视频,请启用JavaScript,并考虑升级web浏览器.
  13816 + </p>
  13817 + </video>`
  13818 + return template
13583 } 13819 }
  13820 + /**
  13821 + * @description 获取cell 通过cell id
  13822 + */
  13823 + getCellByCellId(id) {
  13824 + const allCell = this.DispatchInstance.contentAllCell || []
  13825 + return allCell.find(item => item.id === id)
  13826 + }
  13827 +
13584 13828
13585 /** 13829 /**
13586 * @description 验证是否满足条件列表中的任意一条 13830 * @description 验证是否满足条件列表中的任意一条
@@ -480,3 +480,15 @@ @@ -480,3 +480,15 @@
480 .chart-panel__style .layui-input-block { 480 .chart-panel__style .layui-input-block {
481 margin-left: 0px !important; 481 margin-left: 0px !important;
482 } 482 }
  483 +
  484 +.video-panel-org__override .layui-form-item {
  485 + display: flex;
  486 +}
  487 +.video-panel-org__override .layui-form-item label{
  488 + width: 60px;
  489 + box-sizing: border-box;
  490 +}
  491 +.video-panel-org__override .layui-form-item .layui-input-block {
  492 + flex: auto;
  493 + margin-left: 0;
  494 +}