Actions.vue 37 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166
  1. <template>
  2. <div class="props">
  3. <div v-for="(a, index) in data.actions" class="mb-12">
  4. <div class="flex middle between" style="position:relative;">
  5. <div class="flex middle">
  6. {{$t(' 动作')}}{{ index + 1 }}
  7. <t-tooltip :content="$t('单位ms,默认不延迟执行')">
  8. <t-input-number class="input-none" style="position:absolute;left:76px" v-model="a.timeout" theme="normal" :min="1" :placeholder="$t('延迟')"></t-input-number>
  9. </t-tooltip>
  10. </div>
  11. <close-icon class="hover" @click="data.actions.splice(index, 1)"></close-icon>
  12. </div>
  13. <div class="py-4">
  14. <div class="form-item mt-4">
  15. <label>{{$t('动作类型')}}</label>
  16. <t-select v-model="a.action" @change="onChangeAction(a)" :placeholder="$t('请选择')">
  17. <t-option v-for="option in actionOptions" :key="option.value" :value="option.value" :label="option.label"></t-option>
  18. </t-select>
  19. </div>
  20. <template v-if="a.action == 0">
  21. <div class="form-item mt-8">
  22. <label>{{$t('链接地址')}}</label>
  23. <t-input v-model="a.value" placeholder="URL"></t-input>
  24. </div>
  25. <div class="form-item mt-8">
  26. <label>{{$t('打开方式')}}</label>
  27. <t-radio-group v-model="a.params">
  28. <t-radio value="_blank">{{$t('新页面')}}</t-radio>
  29. <t-radio value="_self">{{$t('当前页面')}}</t-radio>
  30. </t-radio-group>
  31. </div>
  32. </template>
  33. <template v-else-if="a.action == 13">
  34. <div class="form-item mt-8">
  35. <label>{{$t('视图')}}</label>
  36. <t-input v-model="a.value" placeholder="ID"></t-input>
  37. </div>
  38. </template>
  39. <template v-else-if="a.action == 2 || a.action == 3 || a.action == 4">
  40. <div class="form-item mt-8">
  41. <label>{{$t('对象类型')}}</label>
  42. <t-radio-group v-model="a.targetType" @change="a.value = ''">
  43. <t-radio value="id">{{$t('图元')}}</t-radio>
  44. <t-radio value="tag">{{$t('组')}}</t-radio>
  45. </t-radio-group>
  46. </div>
  47. <div class="form-item mt-8">
  48. <label>{{$t('播放对象')}}</label>
  49. <t-tree-select v-if="a.targetType === 'id'" v-model="a.value" :data="penTree" filterable @change="getAnimations(a.value)" :placeholder="$t('默认自己')"></t-tree-select>
  50. <t-select v-else v-model="a.value" :options="groups" @change="getAnimations(a.value)" :placeholder="$t('组')"></t-select>
  51. </div>
  52. <div class="form-item mt-8">
  53. <label>{{$t('动画名称')}}</label>
  54. <t-select-input
  55. v-model:inputValue="a.params"
  56. :value="a.params"
  57. v-model:popupVisible="a.popupVisible"
  58. allow-input
  59. clearable
  60. @clear="a.params = undefined"
  61. @focus="a.popupVisible = true"
  62. @blur="a.popupVisible = false"
  63. :placeholder="$t('缺省第一个动画')"
  64. >
  65. <template #panel>
  66. <ul style="padding: 8px 12px">
  67. <li v-for="item in animations" :key="item" @click="a.params = item;a.popupVisible = false;">
  68. {{ item }}
  69. </li>
  70. </ul>
  71. </template>
  72. </t-select-input>
  73. </div>
  74. </template>
  75. <template v-else-if="a.action == 1">
  76. <div class="form-item mt-8">
  77. <label>{{$t('对象类型')}}</label>
  78. <t-radio-group v-model="a.targetType" @change="a.params = ''">
  79. <t-radio value="id">{{$t('图元')}}</t-radio>
  80. <t-radio value="tag">{{$t('组')}}</t-radio>
  81. </t-radio-group>
  82. </div>
  83. <div class="form-item mt-8">
  84. <label>{{$t( '更改对象' )}}</label>
  85. <t-tree-select
  86. v-if="a.targetType === 'id'"
  87. v-model="a.params"
  88. :data="penTree"
  89. filterable
  90. placeholder="默认自己"
  91. @change="getProps(a)"
  92. />
  93. <t-select
  94. v-else
  95. v-model="a.params"
  96. :options="groups"
  97. placeholder="组"
  98. />
  99. </div>
  100. <div class="form-item mt-8">
  101. <label>{{$t('属性数据')}}</label>
  102. <div class="w-full">
  103. <div class="prop-grid head">
  104. <div>{{$t('属性名')}}</div>
  105. <div>{{$t('属性值')}}</div>
  106. <div class="right">
  107. <t-dropdown
  108. :min-column-width="160"
  109. @click="onAddValue(a, $event)"
  110. >
  111. <add-circle-icon class="hover"/>
  112. <!-- <t-icon name="add-circle" class="hover" /> -->
  113. <t-dropdown-menu>
  114. <t-dropdown-item
  115. key="custom"
  116. value="custom"
  117. disabled="true"
  118. divider="true"
  119. class="input"
  120. >
  121. <t-input
  122. v-model="a.input"
  123. style="pointer-events: auto;"
  124. :placeholder="$t('自定义')"
  125. @enter="
  126. onAddValue(a, { key: a.input });
  127. a.input = '';
  128. "
  129. />
  130. </t-dropdown-item>
  131. <t-dropdown-item
  132. v-for="prop in cprops"
  133. :key="prop.value"
  134. :value="prop.value"
  135. >
  136. {{ prop.label }}
  137. </t-dropdown-item>
  138. </t-dropdown-menu>
  139. </t-dropdown>
  140. </div>
  141. </div>
  142. <template
  143. v-if="Object.keys(a.value).length"
  144. class="center gray mt-8"
  145. >
  146. <div class="prop-grid mt-8" v-for="(value, key) in a.value">
  147. <div class="ml-8 value-label">
  148. <t-tooltip :content="key">
  149. {{ getPropDesc(a, key) }}
  150. </t-tooltip>
  151. </div>
  152. <div class="value-input">
  153. <t-input
  154. :title="a.value[key]"
  155. v-model="a.value[key]"
  156. @change="valueChange($event,a.value,key)"
  157. :placeholder="$t('值')"
  158. />
  159. </div>
  160. <div class="right px-8" style="line-height: 20px">
  161. <!-- <t-icon
  162. name="delete"
  163. class="hover"
  164. @click="delete a.value[key]"
  165. /> -->
  166. <delete-icon class="hover"
  167. @click="delete a.value[key]"/>
  168. </div>
  169. </div>
  170. </template>
  171. <div v-else class="center gray mt-8">{{$t('暂无数据')}}</div>
  172. </div>
  173. </div>
  174. </template>
  175. <template v-else-if="a.action == 14">
  176. <div class="form-item mt-8">
  177. <label>{{$t('窗口标题')}}</label>
  178. <t-input v-model="a.value" :placeholder="$t('弹框标题')"></t-input>
  179. </div>
  180. <div class="form-item mt-8">
  181. <label>{{$t('画面')}}URL</label>
  182. <t-input v-model="a.params" :placeholder="$t('窗口画面URL')"></t-input>
  183. </div>
  184. <div class="form-item mt-8">
  185. <label>{{$t('弹框位置')}}</label>
  186. <t-input class="ml-4" label="X" placeholder="X" v-model.number="a.extend.x" style="width: 80px" :format="decimalPlaces"></t-input>
  187. <t-input class="ml-4" label="Y" placeholder="Y" v-model.number="a.extend.y" style="width: 80px" :format="decimalPlaces"></t-input>
  188. </div>
  189. <div class="form-item mt-8">
  190. <label>{{$t('弹框大小')}}</label>
  191. <t-input class="ml-4" label="W" v-model.number="a.extend.width" min="1" style="width: 80px" :format="decimalPlaces" :placeholder="$t('宽')"></t-input>
  192. <t-input class="ml-4" label="H" v-model.number="a.extend.height" min="1" style="width: 80px" :format="decimalPlaces" :placeholder="$t('高')"></t-input>
  193. </div>
  194. </template>
  195. <template v-else-if="a.action == 7">
  196. <div class="form-item mt-8">
  197. <label>{{$t('消息名称')}}</label>
  198. <t-input v-model="a.value" :placeholder="$t('名称')"></t-input>
  199. </div>
  200. <div class="form-item mt-8">
  201. <label>{{$t('消息参数')}}</label>
  202. <t-input v-model="a.params" :placeholder="$t('参数')"></t-input>
  203. </div>
  204. </template>
  205. <template v-else-if="a.action == 15">
  206. <Network v-model="a.network" mode="1" />
  207. <div class="flex middle mt-16">
  208. <t-tooltip content="json格式">
  209. <div class="flex middle mr-8" style="font-size:12px;color:var(--color)">数据</div>
  210. </t-tooltip>
  211. <add-circle-icon @click="addSendData(a)" class="hover"/>
  212. </div>
  213. <template v-for="(d,idx) in a.data">
  214. <div class="flex middle actions-data mt-16" style="position:relative" >
  215. <t-tooltip :content="d.prop?(d._label+'('+d.prop+')'):''">
  216. <!-- <t-input class="actions-prop" style="width: 70px;" v-model="d.prop" /> -->
  217. <div class="actions-prop"> {{ d.label||'请编辑' }}</div>
  218. </t-tooltip>
  219. <Edit1Icon style="position:absolute;left:56px;height: 32px;" class="hover" @click="selectDeviceProps(d)"/>
  220. <!-- <t-input style="width: 100px;" v-model="item.value" /> -->
  221. <t-tree-select
  222. placeholder="固定值"
  223. style="width: 90px;"
  224. v-model="d.id"
  225. :data="propTree"
  226. filterable
  227. @change="getAProps(d)"
  228. />
  229. <t-select-input
  230. v-if="d.id&&d.id!=='固定值'"
  231. placeholder="可自定义输入"
  232. v-model:inputValue="d.key"
  233. :value="d.keyLabel"
  234. v-model:popupVisible="d.keyPopupVisible"
  235. allow-input
  236. clearable
  237. @clear="d.keyLabel = undefined"
  238. @focus="d.keyPopupVisible = true"
  239. @blur="d.keyPopupVisible = false"
  240. @input-change="onKeyInput(d)"
  241. class="shrink-0 actions-key"
  242. style="width: 82px"
  243. >
  244. <template #panel>
  245. <ul style="padding: 8px 12px">
  246. <li
  247. v-for="item in dprops"
  248. :key="item.value"
  249. @click="
  250. d.key = item.value;
  251. d.keyLabel = item.label;
  252. d.keyPopupVisible = false;
  253. "
  254. >
  255. {{ item.label }}
  256. </li>
  257. <t-divider style="border-top: 1px solid var(--color-border-input);"/>
  258. <li @click="getKeyMore(d)">
  259. 更多
  260. </li>
  261. </ul>
  262. </template>
  263. </t-select-input>
  264. <template v-else>
  265. <t-switch
  266. size="small"
  267. class="actions-value"
  268. v-if="['switch','bool','boolean'].includes(d.type)"
  269. v-model="d.value"
  270. />
  271. <t-input-number
  272. class="actions-value"
  273. v-else-if="['integer','number','int','enum','double'].includes(d.type)"
  274. v-model.number="d.value"
  275. theme="column"
  276. />
  277. <t-button
  278. class="actions-value"
  279. v-else-if="['code','struct','array','object'].includes(d.type)"
  280. shape="square"
  281. variant="outline"
  282. style="width: 24px"
  283. @click="showCode(d)"
  284. >
  285. <ellipsis-icon slot="icon" />
  286. </t-button>
  287. <t-input v-else class="actions-value" placeholder="输入值" style="width: 82px;" v-model="d.value" @change="valueDChange($event,d)" />
  288. </template>
  289. <close-icon style="position:absolute;right:2px" class="hover" @click="delSendData(a.data,idx)"/>
  290. </div>
  291. </template>
  292. <template v-for="(item,idx) in a.list">
  293. <div class="flex middle between mt-16">
  294. <div class="flex middle" style="font-size:12px">{{$t('数据')}}{{ idx+1 }}</div>
  295. <close-icon class="hover" @click="a.list.splice(index, 1)"></close-icon>
  296. </div>
  297. <div class="form-item mt-8">
  298. <label>{{$t('数据对象')}}</label>
  299. <t-tree-select v-model="item.params" :data="penTree" filterable @change="getProps(item)" :placeholder="$t('默认自己')"></t-tree-select>
  300. </div>
  301. <div class="form-item mt-8">
  302. <label>{{$t('属性数据')}}</label>
  303. <div class="w-full">
  304. <div class="prop-grid head">
  305. <div>{{$t('属性名')}}</div>
  306. <div>{{$t('属性值')}}</div>
  307. <div class="right">
  308. <t-dropdown :min-column-width="160" @click="onAddValue(item, $event)">
  309. <add-circle-icon class="hover"></add-circle-icon>
  310. <!-- <t-icon name="add-circle" class="hover" /> -->
  311. <t-dropdown-menu>
  312. <t-dropdown-item key="custom" value="custom" disabled="true" divider="true" class="input">
  313. <t-input v-model="item.input" style="pointer-events: auto;" @enter="
  314. onAddValue(item, { key: item.input });
  315. item.input = '';
  316. " :placeholder="$t('自定义')"></t-input>
  317. </t-dropdown-item>
  318. <t-dropdown-item v-for="prop in cprops" :key="prop.value" :value="prop.value">
  319. {{ prop.label }}
  320. </t-dropdown-item>
  321. </t-dropdown-menu>
  322. </t-dropdown>
  323. </div>
  324. </div>
  325. <template
  326. v-if="Object.keys(item.value).length"
  327. class="center gray mt-8"
  328. >
  329. <div class="prop-grid mt-8" v-for="(value, key) in item.value">
  330. <div class="ml-8">
  331. <t-tooltip :content="key">
  332. {{ getPropDesc(item, key) }}
  333. </t-tooltip>
  334. </div>
  335. <div class="value-input">
  336. <t-input v-model="item.value[key]" @change="valueChange($event,item.value,key)" :placeholder="$t('值')"></t-input>
  337. </div>
  338. <div class="right px-8" style="line-height: 20px">
  339. <delete-icon class="hover" @click="delete item.value[key]"></delete-icon>
  340. <!-- <t-icon
  341. name="delete"
  342. class="hover"
  343. @click="delete a.value[key]"
  344. /> -->
  345. </div>
  346. </div>
  347. </template>
  348. <div v-else class="center gray mt-8">{{$t('暂无数据')}}</div>
  349. </div>
  350. </div>
  351. </template>
  352. <!-- <div class="form-item mt-8">
  353. <label></label>
  354. <t-button style="width:150px" @click="addData(a)">
  355. {{$t('添加数据')}}
  356. </t-button>
  357. </div> -->
  358. <div class="form-item mt-8" v-if="a.network&&a.network.protocol==='http'">
  359. <label>{{$t('回调')}}</label>
  360. <CodeEditor v-model="a.callback" class="mt-4" style="height: 50px"></CodeEditor>
  361. </div>
  362. <div class="form-item mt-8 desc" v-if="a.network&&a.network.protocol==='http'">
  363. <label></label>
  364. <div>
  365. {{$t('可获取')}}pen、data{{$t('和')}}context{{$t('参数')}},{{$t('参考')}}:<a target="_blank" href="https://doc.le5le.com/document/22">{{$t('发送指令')}}</a>
  366. </div>
  367. </div>
  368. </template>
  369. <template v-else-if="a.action == 8 || a.action == 9 || a.action == 10">
  370. <div class="form-item mt-8">
  371. <label>{{$t('对象类型')}}</label>
  372. <t-radio-group v-model="a.targetType" @change="a.value = ''">
  373. <t-radio value="id">{{$t('图元')}}</t-radio>
  374. <t-radio value="tag">{{$t('组')}}</t-radio>
  375. </t-radio-group>
  376. </div>
  377. <div class="form-item mt-8">
  378. <label>{{$t('播放对象')}}</label>
  379. <t-tree-select v-if="a.targetType === 'id'" v-model="a.value" :data="penTree" filterable :placeholder="$t('默认自己')"></t-tree-select>
  380. <t-select v-else v-model="a.value" :options="groups" :placeholder="$t('组')"></t-select>
  381. </div>
  382. </template>
  383. <template v-else-if="a.action == 5">
  384. <div class="form-item mt-8">
  385. <!-- <label>函数</label> -->
  386. <div class="w-full">
  387. <div>function javascriptFn(pen) {</div>
  388. <CodeEditor v-model="a.value" class="mt-4" @change="codeChange($event,a)" style="height: 200px"></CodeEditor>
  389. <div class="mt-4">}</div>
  390. </div>
  391. </div>
  392. </template>
  393. <template v-else-if="a.action == 6">
  394. <div class="form-item mt-8">
  395. <label>{{$t('函数名称')}}</label>
  396. <t-input v-model="a.value" :placeholder="$t('函数名称')"></t-input>
  397. </div>
  398. <div class="form-item mt-8">
  399. <label>{{$t('函数参数')}}</label>
  400. <t-input v-model="a.params" :placeholder="$t('函数参数')"></t-input>
  401. </div>
  402. </template>
  403. <template v-else-if="a.action == 16">
  404. <div class="form-item mt-8">
  405. <label>{{$t('场景对象')}}</label>
  406. <!-- <t-input v-model="a.params" placeholder="画笔id/tag" /> -->
  407. <t-tree-select v-model="a.params" :data="iframeTree" filterable :placeholder="$t('必填')"></t-tree-select>
  408. </div>
  409. <div class="form-item mt-8">
  410. <label>{{$t('消息名')}}</label>
  411. <t-input v-model="a.value" :placeholder="$t('消息名')"></t-input>
  412. </div>
  413. <template v-for="(item,idx) in a.list">
  414. <div class="flex middle between mt-16">
  415. <div class="flex middle" style="font-size:12px">{{$t('消息数据')}}{{ idx+1 }}</div>
  416. <close-icon class="hover" @click="a.list.splice(index, 1)"></close-icon>
  417. </div>
  418. <div class="form-item mt-8">
  419. <label>{{$t('消息对象')}}</label>
  420. <t-tree-select v-model="item.params" :data="penTree" filterable @change="getProps(item)" :placeholder="$t('默认自己')"></t-tree-select>
  421. </div>
  422. <div class="form-item mt-8">
  423. <label>{{$t('消息数据')}}</label>
  424. <div class="w-full">
  425. <div class="prop-grid head">
  426. <div>{{$t('属性名')}}</div>
  427. <div>{{$t('属性值')}}</div>
  428. <div class="right">
  429. <t-dropdown :min-column-width="160" @click="onAddValue(item, $event)">
  430. <add-circle-icon class="hover"></add-circle-icon>
  431. <t-dropdown-menu>
  432. <t-dropdown-item
  433. key="custom"
  434. value="custom"
  435. disabled="true"
  436. divider="true"
  437. class="input"
  438. >
  439. <t-input
  440. v-model="item.input"
  441. style="pointer-events: auto;"
  442. :placeholder="$t('自定义')"
  443. @enter="
  444. onAddValue(item, { key: item.input });
  445. item.input = '';
  446. "
  447. />
  448. </t-dropdown-item>
  449. <t-dropdown-item
  450. v-for="prop in cprops"
  451. :key="prop.value"
  452. :value="prop.value"
  453. >
  454. {{ prop.label }}
  455. </t-dropdown-item>
  456. </t-dropdown-menu>
  457. </t-dropdown>
  458. </div>
  459. </div>
  460. <template
  461. v-if="Object.keys(item.value).length"
  462. class="center gray mt-8"
  463. >
  464. <div class="prop-grid mt-8" v-for="(value, key) in item.value">
  465. <div class="ml-8">
  466. <t-tooltip :content="key">
  467. {{ getPropDesc(item, key) }}
  468. </t-tooltip>
  469. </div>
  470. <div class="value-input">
  471. <t-input v-model="item.value[key]" @change="valueChange($event,item.value,key)" :placeholder="$t('值')"></t-input>
  472. </div>
  473. <div class="right px-8" style="line-height: 20px">
  474. <delete-icon class="hover"
  475. @click="delete item.value[key]"/>
  476. </div>
  477. </div>
  478. </template>
  479. <div v-else class="center gray mt-8">{{$t('暂无数据')}}</div>
  480. </div>
  481. </div>
  482. </template>
  483. <div class="form-item mt-8">
  484. <label></label>
  485. <t-button style="width:150px" @click="addData(a)">
  486. {{$t('添加消息数据')}}
  487. </t-button>
  488. </div>
  489. </template>
  490. <template v-else-if="a.action == 17">
  491. <div class="form-item mt-8">
  492. <label>{{$t('消息名')}}</label>
  493. <t-input v-model="a.value" :placeholder="$t('消息名')"></t-input>
  494. </div>
  495. <template v-for="(item,idx) in a.list">
  496. <div class="flex middle between mt-16">
  497. <div class="flex middle" style="font-size:12px">{{$t('消息数据')}}{{ idx+1 }}</div>
  498. <close-icon class="hover" @click="a.list.splice(index, 1)"></close-icon>
  499. </div>
  500. <div class="form-item mt-8">
  501. <label>{{$t('消息对象')}}</label>
  502. <t-tree-select v-model="item.params" :data="penTree" filterable @change="getProps(item)" :placeholder="$t('默认自己')"></t-tree-select>
  503. </div>
  504. <div class="form-item mt-8">
  505. <label>{{$t('消息数据')}}</label>
  506. <div class="w-full">
  507. <div class="prop-grid head">
  508. <div>{{$t('属性名')}}</div>
  509. <div>{{$t('属性值')}}</div>
  510. <div class="right">
  511. <t-dropdown :min-column-width="160" @click="onAddValue(item, $event)">
  512. <add-circle-icon class="hover"></add-circle-icon>
  513. <t-dropdown-menu>
  514. <t-dropdown-item
  515. key="custom"
  516. value="custom"
  517. disabled="true"
  518. divider="true"
  519. class="input"
  520. >
  521. <t-input
  522. v-model="item.input"
  523. style="pointer-events: auto;"
  524. :placeholder="$t('自定义')"
  525. @enter="
  526. onAddValue(item, { key: item.input });
  527. item.input = '';
  528. "
  529. />
  530. </t-dropdown-item>
  531. <t-dropdown-item
  532. v-for="prop in cprops"
  533. :key="prop.value"
  534. :value="prop.value"
  535. >
  536. {{ prop.label }}
  537. </t-dropdown-item>
  538. </t-dropdown-menu>
  539. </t-dropdown>
  540. </div>
  541. </div>
  542. <template
  543. v-if="Object.keys(item.value).length"
  544. class="center gray mt-8"
  545. >
  546. <div class="prop-grid mt-8" v-for="(value, key) in item.value">
  547. <div class="ml-8">
  548. <t-tooltip :content="key">
  549. {{ getPropDesc(item, key) }}
  550. </t-tooltip>
  551. </div>
  552. <div class="value-input">
  553. <t-input v-model="item.value[key]" @change="valueChange($event,item.value,key)" :placeholder="$t('值')"></t-input>
  554. </div>
  555. <div class="right px-8" style="line-height: 20px">
  556. <delete-icon class="hover"
  557. @click="delete item.value[key]"/>
  558. </div>
  559. </div>
  560. </template>
  561. <div v-else class="center gray mt-8">{{$t('暂无数据')}}</div>
  562. </div>
  563. </div>
  564. </template>
  565. <div class="form-item mt-8">
  566. <label></label>
  567. <t-button style="width:150px" @click="addData(a)">
  568. {{$t('添加消息数据')}}
  569. </t-button>
  570. </div>
  571. </template>
  572. <template v-else-if="a.action == 18">
  573. <div class="form-item mt-8">
  574. <label>消息类型</label>
  575. <t-select
  576. v-model="a.params"
  577. placeholder="请选择"
  578. >
  579. <t-option
  580. v-for="option in themeOptions"
  581. :key="option.value"
  582. :value="option.value"
  583. :label="option.label"
  584. />
  585. </t-select>
  586. </div>
  587. <div class="form-item mt-8">
  588. <label>消息内容</label>
  589. <t-input v-model="a.value" placeholder="消息内容" />
  590. </div>
  591. </template>
  592. </div>
  593. </div>
  594. <div class="mt-8">
  595. <a @click="data.actions.push({})"> + {{$t('添加动作')}} </a>
  596. </div>
  597. </div>
  598. <PropModal v-model:visible="propModal.visible" @change="getProp" />
  599. <MoreModal v-model:visible="more.visible" @change="getMProp" />
  600. <t-dialog
  601. v-if="codeDialog.show"
  602. :visible="true"
  603. header="下发数据"
  604. @confirm="codeDialog.show = false"
  605. @close="codeDialog.show = false"
  606. :width="800"
  607. >
  608. <CodeEditor v-model="codeDialog.data.value" style="height: 300px" />
  609. </t-dialog>
  610. </template>
  611. <script lang="ts" setup>
  612. import { onBeforeMount, ref, reactive, getCurrentInstance } from 'vue';
  613. import PropModal from '@/views/components/common/PropModal.vue';
  614. import MoreModal from '@/views/components/common/MoreModal.vue';
  615. import CodeEditor from '@/views/components/common/CodeEditor.vue';
  616. import Network from './Network.vue';
  617. import { CloseIcon, AddCircleIcon, DeleteIcon, CheckIcon, Edit1Icon, LinkIcon, EllipsisIcon} from 'tdesign-icons-vue-next';
  618. import { getPenAnimations, getPenTree ,changeType, getIframeTree} from '@/services/common';
  619. import { deepClone } from '@meta2d/core';
  620. const { proxy } = getCurrentInstance();
  621. const $t = proxy.$t
  622. const { data } = defineProps<{
  623. data: any;
  624. }>();
  625. const actionOptions = [
  626. {
  627. label: $t('打开链接'),
  628. value: 0,
  629. },
  630. {
  631. label: $t('打开视图'),
  632. value: 13,
  633. },
  634. {
  635. label: $t('播放动画'),
  636. value: 2,
  637. },
  638. {
  639. label: $t('暂停动画'),
  640. value: 3,
  641. },
  642. {
  643. label: $t('停止动画'),
  644. value: 4,
  645. },
  646. {
  647. label: $t('更改属性'),
  648. value: 1,
  649. },
  650. {
  651. label: $t('打开弹框'),
  652. value: 14,
  653. },
  654. {
  655. label: $t('发送消息'),
  656. value: 7,
  657. },
  658. {
  659. label: $t('发送数据'),
  660. value: 15,
  661. },
  662. {
  663. label: $t('播放视频'),
  664. value: 8,
  665. },
  666. {
  667. label: $t('暂停视频'),
  668. value: 9,
  669. },
  670. {
  671. label: $t('停止视频'),
  672. value: 10,
  673. },
  674. {
  675. label: $t('自定义函数'),
  676. value: 5,
  677. },
  678. {
  679. label: $t('全局函数'),
  680. value: 6,
  681. },
  682. {
  683. label: $t('向场景发送消息'),
  684. value: 16,
  685. },
  686. {
  687. label: $t('向父窗口发送消息'),
  688. value: 17,
  689. },
  690. {
  691. label: '全局消息',
  692. value: 18,
  693. },
  694. ];
  695. const penTree: any = ref([]);
  696. const groups: any = ref([]);
  697. const animations: any = ref([]);
  698. const iframeTree:any = ref([]);
  699. onBeforeMount(() => {
  700. if (!data.actions) {
  701. data.actions = [];
  702. }
  703. data.actions.forEach((action: any) => {
  704. if(action.action === 14){
  705. if(!action.extend){
  706. action.extend = {};
  707. }
  708. }
  709. });
  710. penTree.value = getPenTree();
  711. propTree.value = deepClone(penTree.value);
  712. propTree.value.unshift({
  713. label:"固定值",
  714. value:"固定值"
  715. })
  716. iframeTree.value = getIframeTree();
  717. groups.value = [];
  718. const d = meta2d.store.data as any;
  719. if (d.groups) {
  720. for (const item of d.groups) {
  721. groups.value.push({ label: item, value: item });
  722. }
  723. }
  724. animations.value = getPenAnimations();
  725. });
  726. const getAnimations = (idOrTag: string) => {
  727. animations.value = getPenAnimations(idOrTag);
  728. };
  729. const onChangeAction = (action: any) => {
  730. switch (action.action) {
  731. case 0:
  732. action.value = '';
  733. action.params = '_blank';
  734. break;
  735. case 1:
  736. action.params = '';
  737. action.value = {};
  738. action.targetType = 'id';
  739. getProps(action);
  740. break;
  741. case 2:
  742. case 3:
  743. case 4:
  744. action.value = '';
  745. action.targetType = 'id';
  746. break;
  747. case 14:
  748. if(!action.extend){
  749. action.extend = {};
  750. }
  751. break;
  752. case 15:
  753. action.network = {}// {type: 'publish',protocol: 'mqtt', options: {}};
  754. // action.params = '';
  755. // action.value = {};
  756. action.targetType = 'id';
  757. // action.list = [
  758. // {params:undefined,value:{}}
  759. // ];
  760. getProps(action);
  761. break;
  762. default:
  763. action.value = '';
  764. action.params = '';
  765. break;
  766. }
  767. };
  768. let cprops = [
  769. {
  770. value: 'x',
  771. label: 'X',
  772. },
  773. {
  774. value: 'y',
  775. label: 'Y',
  776. },
  777. {
  778. value: 'width',
  779. label: $t('宽'),
  780. },
  781. {
  782. value: 'height',
  783. label: $t('高'),
  784. },
  785. {
  786. value: 'visible',
  787. label: $t('显示'),
  788. },
  789. {
  790. value: 'text',
  791. label: $t('文字'),
  792. },
  793. {
  794. value: 'color',
  795. label: $t('颜色'),
  796. },
  797. {
  798. value: 'background',
  799. label: $t('背景颜色'),
  800. },
  801. {
  802. value: 'progress',
  803. label: $t('进度'),
  804. },
  805. {
  806. value: 'progressColor',
  807. label: $t('进度颜色'),
  808. },
  809. {
  810. value: 'showChild',
  811. label: $t('状态'),
  812. },
  813. {
  814. value: 'checked',
  815. label: $t('选中'),
  816. },
  817. {
  818. value: 'rotate',
  819. label: $t('旋转'),
  820. },
  821. {
  822. value: 'disabled',
  823. label: $t('禁用'),
  824. },
  825. {
  826. value: 'selectedKey',
  827. label: $t('单选选中值'),
  828. },
  829. {
  830. value: 'iframe',
  831. label: $t('网页地址'),
  832. },
  833. {
  834. value: 'animateReverse',
  835. label: $t('连线动画反向'),
  836. }
  837. ];
  838. const getProps = (c: any) => {
  839. // c.props = [
  840. // {
  841. // value: 'x',
  842. // label: 'X',
  843. // },
  844. // {
  845. // value: 'y',
  846. // label: 'Y',
  847. // },
  848. // {
  849. // value: 'width',
  850. // label: $t('宽'),
  851. // },
  852. // {
  853. // value: 'height',
  854. // label: $t('高'),
  855. // },
  856. // {
  857. // value: 'visible',
  858. // label: $t('显示'),
  859. // },
  860. // {
  861. // value: 'text',
  862. // label: $t('文字'),
  863. // },
  864. // {
  865. // value: 'progress',
  866. // label: $t('进度'),
  867. // },
  868. // {
  869. // value: 'showChild',
  870. // label: $t('状态'),
  871. // },
  872. // {
  873. // value: 'rotate',
  874. // label: $t('旋转'),
  875. // },
  876. // ];
  877. let target: any;
  878. if (c.params) {
  879. target = meta2d.findOne(c.params);
  880. } else if (meta2d.store.active) {
  881. target = meta2d.store.active[0];
  882. }
  883. if (target?.realTimes) {
  884. for (const item of target.realTimes) {
  885. const found = cprops.findIndex((elem: any) => elem.value === item.key);
  886. if (found < 0) {
  887. cprops.push({
  888. value: item.key,
  889. label: item.label,
  890. });
  891. }
  892. }
  893. }
  894. };
  895. const getPropDesc = (a: any, key: any) => {
  896. const found = cprops.find((elem: any) => elem.value === key);
  897. if (found) {
  898. return found.label;
  899. }
  900. return key;
  901. };
  902. const onAddValue = (action: any, data: any) => {
  903. if (!action.value[data.key]) {
  904. action.value[data.key] = "";
  905. }
  906. };
  907. const valueChange = (e,aValue:any,key:any)=>{
  908. aValue[key] = changeType(e)??"";
  909. }
  910. const codeChange = (e:any,a:any)=>{
  911. a.fn = null;
  912. }
  913. const decimalPlaces = (val: number) => {
  914. if (!val) {
  915. return undefined;
  916. }
  917. return Math.round(+val * 100) / 100;
  918. };
  919. const addData = (a:any)=>{
  920. if(!a.list){
  921. a.list = [];
  922. }
  923. a.list.push({params:undefined,value:{}})
  924. }
  925. const addSendData = (a:any)=>{
  926. if(!a.data){
  927. a.data = [];
  928. }
  929. a.data.push({
  930. key:'',
  931. value:''
  932. });
  933. }
  934. const delSendData = (data:any[] ,i:number)=>{
  935. data.splice(i,1);
  936. }
  937. let dprops = ref<any>([{
  938. value: 'text',
  939. label: '文字',
  940. },
  941. {
  942. value: 'visible',
  943. label: '显示',
  944. },
  945. {
  946. value: 'progress',
  947. label: '进度',
  948. },
  949. {
  950. value: 'showChild',
  951. label: '状态',
  952. },
  953. {
  954. value: 'checked',
  955. label: '选中',
  956. },
  957. {
  958. value: 'selectedKey',
  959. label: '单选选中值',
  960. }]);
  961. const propTree = ref([]);
  962. const getAProps = (a)=>{
  963. let props = [{
  964. value: 'text',
  965. label: '文字',
  966. },
  967. {
  968. value: 'visible',
  969. label: '显示',
  970. },
  971. {
  972. value: 'progress',
  973. label: '进度',
  974. },
  975. {
  976. value: 'showChild',
  977. label: '状态',
  978. },
  979. {
  980. value: 'checked',
  981. label: '选中',
  982. },
  983. {
  984. value: 'selectedKey',
  985. label: '单选选中值',
  986. },]
  987. let target: any;
  988. if (a.id && a.id!=='固定值') {
  989. target = meta2d.findOne(a.id);
  990. } else {
  991. return;
  992. }
  993. if (target?.realTimes) {
  994. for (const item of target.realTimes) {
  995. const found = props.findIndex((elem: any) => elem.value === item.key);
  996. if (found < 0) {
  997. props.push({
  998. value: item.key,
  999. label: item.label,
  1000. });
  1001. }
  1002. }
  1003. }
  1004. dprops.value = props;
  1005. }
  1006. const propModal = reactive({
  1007. visible:false,
  1008. data:null
  1009. })
  1010. const selectDeviceProps = (i)=>{
  1011. propModal.visible = true;
  1012. propModal.data = i;
  1013. }
  1014. const getProp = (e)=>{
  1015. propModal.data.prop = e.value;
  1016. propModal.data.label = e.label;
  1017. propModal.data._label = e._label
  1018. propModal.data.type = e.type;
  1019. propModal.data.class = e.class;
  1020. propModal.data.token = e.token;
  1021. propModal.visible = false;
  1022. }
  1023. const codeDialog = reactive({
  1024. show:false,
  1025. data:null
  1026. });
  1027. const showCode = (d)=>{
  1028. codeDialog.data = d;
  1029. codeDialog.show = true;
  1030. }
  1031. const more = ref({
  1032. visible:false,
  1033. data:null,
  1034. });
  1035. const getKeyMore = (d)=>{
  1036. more.value.data = d;
  1037. more.value.visible = true;
  1038. }
  1039. const getMProp = (e)=>{
  1040. let d = deepClone(e);
  1041. more.value.data.key = d.value;
  1042. more.value.data.keyLabel = d.label;
  1043. more.value.data.keyPopupVisible = false;
  1044. more.value.visible = false;
  1045. }
  1046. const valueDChange = (e,c:any)=>{
  1047. c.value= changeType(e);
  1048. }
  1049. const onKeyInput = (item: any) => {
  1050. item.keyLabel = item.key;
  1051. };
  1052. const themeOptions = [
  1053. {
  1054. label: '普通消息',
  1055. value: 'info',
  1056. },
  1057. {
  1058. label: '成功',
  1059. value: 'success',
  1060. },
  1061. {
  1062. label: '警告',
  1063. value: 'warning',
  1064. },
  1065. {
  1066. label: '错误',
  1067. value: 'error',
  1068. },
  1069. {
  1070. label:'问题',
  1071. value:'question'
  1072. }
  1073. ];
  1074. </script>
  1075. <style lang="postcss" scoped>
  1076. .props {
  1077. .prop-grid {
  1078. display: grid;
  1079. grid-template-columns: 2fr 3fr 32px;
  1080. line-height: 30px;
  1081. &.head {
  1082. background: var(--color-background-input);
  1083. padding: 0 8px;
  1084. }
  1085. }
  1086. .input-none{
  1087. :deep(.t-input){
  1088. border: none;
  1089. }
  1090. }
  1091. .actions-data{
  1092. :deep(.t-input){
  1093. border-color:transparent;
  1094. &:hover {
  1095. border-color: var(--color-primary);
  1096. }
  1097. }
  1098. .actions-prop{
  1099. /* :deep(.t-input){
  1100. width: 70px;
  1101. } */
  1102. width: 70px;
  1103. min-width: 70px;
  1104. white-space:nowrap;
  1105. overflow:hidden;
  1106. text-overflow:ellipsis;
  1107. }
  1108. .actions-key{
  1109. :deep(.t-input){
  1110. width: 82px;
  1111. }
  1112. }
  1113. .actions-value{
  1114. :deep(.t-input){
  1115. width: 82px;
  1116. }
  1117. }
  1118. .t-input-number.t-is-controls-right{
  1119. width: 82px;
  1120. }
  1121. }
  1122. }
  1123. </style>