物管理前端
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

420 lines
48 KiB

  1. const e="03b40c5b-f9f1-4356-8c85-133255cfc3d9",t="custom-switch-node",a="开关",n='<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1688346642186" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2492" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><path d="M764.928 251.392H259.072C116.224 251.392 0 367.616 0 510.464c0 142.848 116.224 259.072 259.072 259.072h505.856c142.848 0 259.072-116.224 259.072-259.072 0-142.848-116.224-259.072-259.072-259.072z m0 495.616c-130.56 0-236.544-105.984-236.544-236.544s105.984-236.544 236.544-236.544 236.544 105.984 236.544 236.544-105.984 236.544-236.544 236.544z" fill="#707070" p-id="2493"></path></svg>',l="svg",o="基础",i="常用",r=!1,u=!0,d="控制",s=`{"id":"u:270584784ce1","type":"page","name":"page1","asideResizor":false,"style":{"boxShadow":" 0px 0px 0px 0px transparent"},"pullRefresh":{"disabled":true},"body":[{"type":"tabs","name":"tab","tabs":[{"title":"样式","icon":"fa fa-th-large","body":[{"type":"form","title":"","name":"basicPropForm","body":[{"type":"input-text","label":"名称","name":"nodeAlias","id":"u:6b126f0520cb","size":"full","mode":"horizontal","inputControlClassName":"w-100","className":"m-b"},{"type":"input-text","label":"ID&nbsp;&nbsp;&nbsp;&nbsp;","name":"id","id":"u:6232710ac003","size":"full","mode":"horizontal","inputControlClassName":"w-100","className":"m-b"},{"type":"grid","id":"u:1954dc15dd5b","className":"m-b","columns":[{"body":[{"type":"input-number","label":"宽度","name":"width","keyboard":true,"id":"u:656efdb758ad","step":1,"suffix":"px","placeholder":"组件宽度","size":"full","mode":"horizontal","className":"m-b","value":100,"labelClassName":"w-8","labelAlign":"left","precision":2,"inputClassName":"w-full"}],"id":"u:4274c47a4ef5","md":6},{"body":[{"type":"input-number","label":"高度","name":"height","keyboard":true,"id":"u:1ed6dcd98c1a","step":1,"suffix":"px","placeholder":"组件高度","size":"full","mode":"horizontal","className":"m-b","value":100,"labelAlign":"left","labelClassName":"w-8","precision":2,"inputClassName":"w-full"}],"id":"u:3e9d1e71a69f","md":6}]},{"type":"grid","id":"u:c605398a724c","className":"m-b","columns":[{"body":[{"type":"input-number","label":"X 轴","name":"x","keyboard":true,"id":"u:dcc0c21d16f6","step":1,"suffix":"px","placeholder":"组件左边距","size":"full","mode":"horizontal","className":"m-b","value":200,"labelAlign":"left","precision":2,"inputClassName":"w-full","labelClassName":"w-8"}],"id":"u:14cc19d6ffb0","md":6},{"body":[{"type":"input-number","label":"Y 轴","name":"y","keyboard":true,"id":"u:cd6fdff9ca88","step":1,"suffix":"px","placeholder":"组件上边距","size":"full","mode":"horizontal","className":"m-b","value":200,"labelAlign":"left","precision":2,"inputClassName":"w-full","labelClassName":"w-8"}],"id":"u:4931801ca9b8","md":6}]},{"type":"grid","id":"u:a332a7bf83c1","className":"m-b","columns":[{"body":[{"type":"input-number","label":"旋转","name":"rotation","id":"u:f6a2dbb518f9","placeholder":"组件旋转角度","mode":"horizontal","size":"full","className":"","keyboard":true,"step":1,"suffix":"deg","value":0,"labelAlign":"left","inputClassName":"w-full"}],"id":"u:646cd98b7955","md":6},{"body":[{"type":"input-color","label":"前景色","name":"btnColor","id":"u:0d19ed3e2bdc","placeholder":"","mode":"horizontal","size":"full","className":"m-b","inputClassName":"w-full","format":"rgba"}],"id":"u:51ddf54ac749","md":6}],"gap":""},{"type":"grid","columns":[{"body":[{"type":"input-color","label":"填充","name":"fill","id":"u:0d19ed3e2bdc","placeholder":"","mode":"horizontal","size":"full","className":"m-b","format":"rgba","inputClassName":"w-full"}],"id":"u:facc5c90e990","md":6},{"body":[{"type":"input-color","label":"描边","name":"strokeColor","id":"u:89afff5fd00d","placeholder":"","mode":"horizontal","size":"full","className":"m-b","format":"rgba","inputClassName":"w-full"}],"id":"u:7c903d9d40ab","md":6}],"id":"u:457970dd35bf
  2. "nodes": [
  3. {
  4. "id": "11e5d77f-8601-4c60-8865-b0fce65ed5c7",
  5. "type": "custom-switch-node",
  6. "x": 200,
  7. "y": 200,
  8. "text": {
  9. "value": "",
  10. "x": 200,
  11. "y": 200
  12. },
  13. "properties": {
  14. "id": "11e5d77f-8601-4c60-8865-b0fce65ed5c7",
  15. "width": 60,
  16. "height": 34,
  17. "x": 200,
  18. "y": 200,
  19. "rotation": 0,
  20. "strokeWidth": 2,
  21. "showText": true,
  22. "fontSize": 15,
  23. "opacity": 1,
  24. "nodeAlias": "开关",
  25. "fontColor": "#ffffff",
  26. "strokeColor": "rgba(74, 144, 226, 1)",
  27. "btnColor": "rgba(255, 255, 255, 1)",
  28. "fill": "rgba(74, 144, 226, 1)",
  29. "fontStyle": "",
  30. "dynamic": {
  31. "normalData": {
  32. "dataPoint": "",
  33. "compareType": "",
  34. "conditionVariables": [],
  35. "defaultValue": "[false]",
  36. "unit": ""
  37. },
  38. "eventsData": {
  39. "eventCombo": [
  40. {
  41. "eventType": "change",
  42. "enable": false,
  43. "config": "{\\"globalInputParamsCalculated\\":[],\\"eventAction\\":\\"sendCommand\\",\\"dataPointParamsCalculate\\":\\"return [\\\\n {\\\\n key: \\\\\\"\\\\\\",\\\\n value: ''\\\\n }\\\\n]\\",\\"sendCommandMethod\\":\\"config\\",\\"inputParamsCalculate\\":\\"// console.log('deviceInfo', deviceInfo, 'command', command, 'event', event);\\\\n// 入参提示: deviceInfo -- 设备信息,command -- 指令信息, event -- 事件传参(当前部件所绑定的立即值,或当前部件经过计算后的自定义值), 入参计算。。。然后返回出参\\\\nconst condition = {\\\\n deviceName: deviceInfo.code,\\\\n attrCode: command.controlDeviceAttr,\\\\n value: event == 0 ? 1 : 0\\\\n}\\\\nreturn {\\\\n \\\\\\"condition\\\\\\": JSON.stringify(condition),\\\\n \\\\\\"controlId\\\\\\": command.id\\\\n}\\",\\"requestMethod\\":\\"post\\",\\"requestUrl\\":\\"/thing/device/control/control\\"}",
  44. "users": ""
  45. }
  46. ]
  47. },
  48. "uiData": {
  49. "dataPoint": "",
  50. "compareType": "",
  51. "conditionVariables": [
  52. {
  53. "type": "open",
  54. "label": "开启",
  55. "name": "",
  56. "value": ""
  57. },
  58. {
  59. "type": "close",
  60. "label": "关闭",
  61. "name": ""
  62. }
  63. ]
  64. },
  65. "animationData": {
  66. "animationCombo": [
  67. {
  68. "min": "",
  69. "max": "",
  70. "animationName": ""
  71. }
  72. ]
  73. },
  74. "hiddenData": {
  75. "hiddenCombo": [
  76. {
  77. "dataPoint": "",
  78. "min": "",
  79. "max": "",
  80. "showOrHiddenName": "隐藏"
  81. }
  82. ]
  83. }
  84. }
  85. }
  86. }
  87. ]
  88. }`,javascript:`
  89. const { createApp, createVNode, render } = Vue;
  90. const app = createApp({})
  91. const Switch = {
  92. template: \`<div :style="cssStyleBG" @click="click">
  93. <div :style="cssStyleBtn"></div>
  94. <div v-if="showText" :style="textStyle">{{state}}</div>
  95. </div>\`,
  96. props: {
  97. defaultValue: {
  98. type: String,
  99. default: '[]'
  100. },
  101. showText: {
  102. type: Boolean,
  103. default: false
  104. },
  105. fontColor: {
  106. type: String,
  107. default: '#ffffff'
  108. },
  109. fontSize: {
  110. type: Number,
  111. default: 14
  112. },
  113. fontFamily: {
  114. type: String,
  115. default: '宋体'
  116. },
  117. fontStyle: {
  118. type: String,
  119. default: 'normal'
  120. },
  121. width: {
  122. type: Number,
  123. default: 60
  124. },
  125. height: {
  126. type: Number,
  127. default: 34
  128. },
  129. lineHeight: {
  130. type: Number,
  131. default: 34,
  132. },
  133. strokeWidth: {
  134. type: Number,
  135. default: 2,
  136. },
  137. borderColor: {
  138. type: String,
  139. default: '#1890ff'
  140. },
  141. btnColor: {
  142. type: String,
  143. default: '#ffffff'
  144. },
  145. backgroundColor: {
  146. type: String,
  147. default: '#1890ff',
  148. },
  149. originFill: {
  150. type: String,
  151. default: '#1890ff',
  152. },
  153. openName: {
  154. type: String,
  155. default: '开'
  156. },
  157. closeName: {
  158. type: String,
  159. default: '关'
  160. },
  161. controledByData: {
  162. type: Boolean,
  163. default: false
  164. }
  165. },
  166. emits: ["change"],
  167. setup(props, { emit } ) {
  168. const {ref, toRefs, computed, watch} = Vue
  169. const { width, height, lineHeight, defaultValue, openName, closeName } = toRefs(props)
  170. const isOpen = ref(false);
  171. const state =ref('关');
  172. let realValue = ref(0);
  173. let finalFillColor = ref(props.backgroundColor);
  174. const click=(ev)=>{
  175. if (props.controledByData) {
  176. emit('change', Number(realValue.value));
  177. finalFillColor.value = props.backgroundColor;
  178. } else {
  179. isOpen.value = !isOpen.value
  180. state.value = isOpen.value? openName.value : closeName.value;
  181. finalFillColor.value = isOpen.value ? props.originFill : '#999999';
  182. emit('change', isOpen.value);
  183. }
  184. }
  185. const realWidth = parseInt(width.value);
  186. const realHeight = parseInt(height.value);
  187. watch(defaultValue, (val) => {
  188. if (val !== null && val !== undefined) {
  189. realValue.value = window.resolveScadaNewValue(val)
  190. isOpen.value = !!Number(realValue.value);
  191. state.value = isOpen.value? openName.value : closeName.value;
  192. }
  193. }, {
  194. immediate: true
  195. })
  196. const cssStyleBG=computed(()=>{
  197. const borderWidths = props.strokeWidth * 2;
  198. return \`
  199. position: relative;
  200. border-width: \${props.strokeWidth}px;
  201. border-style: solid;
  202. width: \${realWidth - borderWidths}px;
  203. height: \${realHeight}px;
  204. border-radius: \${realHeight}px;
  205. box-sizing: border-box;
  206. border-color:\${props.borderColor};
  207. background-color:\${finalFillColor.value}\`;
  208. })
  209. const cssStyleBtn=computed(()=>{
  210. const borderWidths = props.strokeWidth * 2;
  211. return \`
  212. position: absolute;
  213. width: \${realHeight - borderWidths}px;
  214. height: \${realHeight - borderWidths}px;
  215. border-radius: 50%;
  216. left: \${isOpen.value ? (realWidth - realHeight) : 0}px;
  217. background-color: \${props.btnColor};
  218. transition: left 0.15s ease-in-out\`;
  219. })
  220. const textTop = (realHeight - props.strokeWidth * 2 - props.fontSize) / 2;
  221. const textStyle = computed(()=>{
  222. const fontStyle = props.fontStyle;
  223. const style = {}
  224. if(fontStyle) {
  225. if (fontStyle.includes('bold')) {
  226. style.fontWeight = 'bolder';
  227. }
  228. if(fontStyle.includes('italic')) {
  229. style.fontStyle = 'italic'
  230. }
  231. if (fontStyle.includes('underline,line-through')) {
  232. style.textDecoration = 'underline line-through'
  233. } else if (fontStyle.includes('line-through,underline')) {
  234. style.textDecoration = 'line-through underline'
  235. } else if (fontStyle.includes('underline')) {
  236. style.textDecoration = 'underline'
  237. } else if (fontStyle.includes('line-through')) {
  238. style.textDecoration = 'line-through'
  239. }
  240. }
  241. return \`
  242. position: absolute;
  243. color: \${props.fontColor};
  244. font-size: \${props.fontSize}px;
  245. font-family: \${props.fontFamily};
  246. font-style: \${style.fontStyle};
  247. font-weight: \${style.fontWeight};
  248. text-decoration" \${style.textDecoration};
  249. border-radius: 50%;
  250. top: 0px;
  251. bottom: 0;
  252. left: \${isOpen.value ? 0 : realHeight - props.strokeWidth}px;
  253. width: \${realWidth - realHeight}px;
  254. display: flex;
  255. align-items: center;
  256. justify-content: center;
  257. \`;
  258. })
  259. return {
  260. state,
  261. click,
  262. cssStyleBG,
  263. cssStyleBtn,
  264. textStyle,
  265. }
  266. }
  267. }
  268. class CustomSwitchNode extends HtmlResize.view {
  269. clickTime = ''
  270. setHtml(rootEl) {
  271. const { graphModel } = this.props;
  272. const { properties, width, height, } = this.props.model;
  273. const { showText, fontColor, fontSize, fontFamily, fontStyle, strokeWidth, lineHeight, fill, strokeColor, btnColor } = properties;
  274. const { normalData, eventsData } = properties.dynamic || {};
  275. const { model } = this.props;
  276. const el = document.createElement('div');
  277. rootEl.innerHTML = '';
  278. let openName= '开';
  279. let closeName = '关';
  280. let fillColor = '';
  281. let controledByData = false;
  282. const findChange = eventsData?.eventCombo.find( i => i.eventType === 'change');
  283. const changeHandler = (e) => {
  284. if(controledByData) {
  285. const now = new Date().getTime();
  286. if (this.clickTime) {
  287. if (now - this.clickTime <= 10000) {
  288. messageFn('10秒之内不能重复触发')
  289. return;
  290. }
  291. }
  292. this.clickTime = now;
  293. }
  294. const cacheToken = sessionStorage.getItem('v1@CacheToken');
  295. if(!cacheToken) {
  296. return window.createLoginDialog();
  297. }
  298. const tokenParsed = JSON.parse(cacheToken || '{}');
  299. if (findChange.users && !findChange.users.includes(tokenParsed.userid)) {
  300. return messageFn('无用户权限')
  301. }
  302. graphModel.eventCenter.emit("node:change", {
  303. data: this.props.model,
  304. e,
  305. });
  306. }
  307. const { uiData } = properties.dynamic || {};
  308. if (uiData) {
  309. controledByData = !!uiData.dataPoint
  310. const realValue = window.resolveScadaNewValue(uiData.defaultValue)
  311. const flag = !!Number(realValue);
  312. fillColor = flag ? fill : '#999999';
  313. if (realValue !== '') {
  314. uiData.conditionVariables.forEach((item) => {
  315. if (item.type === 'rangeColor') {
  316. let from = item.from;
  317. let to = item.to;
  318. if (item.from >= item.to) {
  319. from = item.to;
  320. to = item.from;
  321. }
  322. if (item.color && Number(realValue) >= from && Number(realValue) <= to) {
  323. fillColor = item.color
  324. }
  325. } else if (item.type === 'open') {
  326. if (item.value === 'true' && (realValue === true || realValue === 'true')) {
  327. fillColor = item.color
  328. openName = item.valueLabel;
  329. } else {
  330. if(Number(realValue) === Number(item.value)) {
  331. fillColor = item.color
  332. openName = item.valueLabel;
  333. }
  334. }
  335. } else if (item.type === 'close') {
  336. if (item.value === 'false' && (realValue === false || realValue === 'false')) {
  337. fillColor = item.color
  338. openName = item.valueLabel;
  339. } else {
  340. if (Number(realValue) === Number(item.value)) {
  341. fillColor = item.color;
  342. closeName = item.valueLabel;
  343. }
  344. }
  345. }
  346. })
  347. }
  348. const instance = createVNode(Switch, {
  349. showText,
  350. fontColor,
  351. fontSize, fontFamily, fontStyle,width, height, lineHeight,
  352. originFill: fill,
  353. backgroundColor: fillColor,
  354. borderColor: fillColor,
  355. btnColor: btnColor,
  356. strokeWidth,
  357. defaultValue: uiData.defaultValue,
  358. openName,
  359. closeName,
  360. controledByData,
  361. onChange: changeHandler
  362. })
  363. instance.appContext = app._context
  364. render(instance, el)
  365. rootEl.appendChild(el);
  366. }
  367. }
  368. }
  369. class CustomSwitchModel extends HtmlResize.model {
  370. initNodeData(data) {
  371. // 自定义组件,需最开始重置一下text 。
  372. data.text = {
  373. value: "",
  374. x: data.x,
  375. y: data.y,
  376. };
  377. super.initNodeData(data);
  378. const { properties } = this;
  379. this.width = properties.width || 80;
  380. this.height = properties.height || 35;
  381. this.text.editable = false; // 不允许文本被编辑
  382. }
  383. setAttributes() {
  384. // 自定义组件需重置 text
  385. const { x, y, properties } = this;
  386. const { textHorizontalMove = 0, textVerticalMove = 0 } = properties;
  387. this.text = {
  388. ...this.text,
  389. x: x + textHorizontalMove,
  390. y: y + textVerticalMove,
  391. value: "",
  392. }
  393. }
  394. }
  395. lf.register({
  396. type: 'custom-switch-node',
  397. view: CustomSwitchNode,
  398. model: CustomSwitchModel,
  399. })
  400. `,css:"",fakeData:""},m={id:e,name:t,aliasName:a,image:n,imageType:l,groupName:o,groupType:i,isRemote:!1,isDefault:!0,sectionType:d,config:s,files:c};export{a as aliasName,s as config,m as default,c as files,o as groupName,i as groupType,e as id,n as image,l as imageType,u as isDefault,r as isRemote,t as name,d as sectionType};