edit.vue 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685
  1. <template>
  2. <div class="system-edit-dic-container">
  3. <el-dialog :title="(ruleForm.id !== 0 ? '修改' : '添加') + '告警'" v-model="isShowDialog" width="50%">
  4. <el-form :model="ruleForm" ref="formRef" :rules="rules" size="default" label-width="110px">
  5. <el-form-item label="名称" prop="name">
  6. <el-input v-model="ruleForm.name" placeholder="请输入名称" />
  7. </el-form-item>
  8. <el-form-item label="告警级别" prop="level">
  9. <el-radio-group v-model="ruleForm.level">
  10. <el-radio :label="item.level" v-for="item in levelData" :key="item.level">{{ item.name }}</el-radio>
  11. </el-radio-group>
  12. </el-form-item>
  13. <el-form-item label="选择产品" prop="productKey">
  14. <el-select v-model="ruleForm.productKey" filterable placeholder="请选择产品" @change="setType()">
  15. <el-option v-for="item in productData" :key="item.key" :label="item.name" :value="item.key">
  16. <span style="float: left">{{ item.name }}</span>
  17. <span style="float: right; font-size: 13px">{{ item.key }}</span>
  18. </el-option>
  19. </el-select>
  20. </el-form-item>
  21. <el-form-item label="选择设备" prop="deviceKey">
  22. <el-select v-model="ruleForm.deviceKey" filterable placeholder="请选择设备">
  23. <el-option v-for="item in sourceData" :key="item.key" :label="item.name" :value="item.key">
  24. <span style="float: left">{{ item.name }}</span>
  25. <span style="float: right; font-size: 13px">{{ item.key }}</span>
  26. </el-option>
  27. </el-select>
  28. </el-form-item>
  29. <el-form-item label="触发方式" prop="triggerType" v-if="ruleForm.productKey">
  30. <el-radio-group v-model="ruleForm.triggerType" @change="getRadio()">
  31. <el-radio :label="item.type" v-for="item in typeData" :key="item.type">{{ item.title }}</el-radio>
  32. </el-radio-group>
  33. </el-form-item>
  34. <el-form-item label="选择事件" prop="eventKey" v-if="ruleForm.triggerType === 4">
  35. <el-select v-model="ruleForm.eventKey" filterable placeholder="请选择事件" @change="eventTypeChange">
  36. <el-option v-for="item in eventList" :key="item.key" :label="item.name" :value="item.key"></el-option>
  37. </el-select>
  38. </el-form-item>
  39. <div v-if="ruleForm.triggerType>2" >
  40. <el-divider content-position="left">触发条件</el-divider>
  41. <div class="box-content">
  42. <div v-for="(item, index) in requestParams" :key="index">
  43. <div style="text-align: center" v-if="index > 0">
  44. <el-icon>
  45. <Top />
  46. </el-icon>
  47. <div>
  48. <el-select v-model="item.andOr" placeholder="选择条件关系">
  49. <el-option label="无" :value="0" />
  50. <el-option label="并且" :value="1" />
  51. <el-option label="或" :value="2" />
  52. </el-select>
  53. </div>
  54. <el-icon>
  55. <Bottom />
  56. </el-icon>
  57. </div>
  58. <div style="
  59. padding: 10px;
  60. border: 1px solid var(--next-border-color-light);
  61. background-color: var(--next-border-color-light);
  62. margin-bottom: 10px;
  63. position: relative;
  64. ">
  65. <div class="conicon" style="width: 100%; text-align: right; position: absolute; right: -8px; top: -8px; color: red">
  66. <el-icon @click="delParams(index)">
  67. <CircleClose />
  68. </el-icon>
  69. </div>
  70. <div style="display: flex">
  71. <el-divider content-position="left">参数设置</el-divider>
  72. </div>
  73. <div v-for="(aaa, bbb) in item.filters" :key="bbb">
  74. <div style="text-align: center" v-if="bbb > 0">
  75. <el-icon>
  76. <Top />
  77. </el-icon>
  78. <div>
  79. <el-select v-model="aaa.andOr" placeholder="选择条件关系" style="width: 150px">
  80. <el-option label="无" :value="0" />
  81. <el-option label="并且" :value="1" />
  82. <el-option label="或" :value="2" />
  83. </el-select>
  84. </div>
  85. <el-icon>
  86. <Bottom />
  87. </el-icon>
  88. </div>
  89. <div class="content-f">
  90. <el-select v-model="aaa.key" :placeholder="ruleForm.triggerType === 4 && !ruleForm.eventKey ? '请先选择事件' : '选择参数'" style="width: 320px">
  91. <el-option v-for="a in triData" :key="a.paramKey" :label="a.title" :value="a.paramKey" />
  92. </el-select>
  93. <el-select v-model="aaa.operator" placeholder="选择操作符" style="width: 320px">
  94. <el-option v-for="b in operData" :key="b.type" :label="b.title" :value="b.type" />
  95. </el-select>
  96. <el-input v-model="aaa.value" placeholder="请输入条件值" style="width: 320px" />
  97. <div class="conicon">
  98. <el-icon @click="delParamss(index, bbb)">
  99. <Delete />
  100. </el-icon>
  101. </div>
  102. </div>
  103. </div>
  104. <el-button type="primary" class="addbutton" @click="addParams(index)">增加条件</el-button>
  105. </div>
  106. </div>
  107. </div>
  108. <el-button type="success" class="addbutton" @click="addParamss">增加分组</el-button>
  109. </div>
  110. <el-divider content-position="left">执行动作</el-divider>
  111. <div class="box-content">
  112. <div v-for="(item, index) in action" :key="index">
  113. <div style="
  114. padding: 10px;
  115. border: 1px solid var(--next-border-color-light);
  116. background-color: var(--next-border-color-light);
  117. margin-bottom: 10px;
  118. position: relative;
  119. ">
  120. <div class="conicon" style="width: 100%; text-align: right; position: absolute; right: -8px; top: -8px; color: red">
  121. <el-icon @click="delAction(index)">
  122. <CircleClose />
  123. </el-icon>
  124. </div>
  125. <div style="display: flex">
  126. <el-divider content-position="left">消息通知</el-divider>
  127. </div>
  128. <div class="content-f">
  129. <el-select v-model="item.sendGateway" placeholder="请选择通知方式" style="width: 320px" @change="getNode(item.sendGateway, index)">
  130. <el-option v-for="a in notice_send_gateway" :key="a.value" :label="a.label" :value="a.value" />
  131. </el-select>
  132. <el-select v-model="item.noticeConfig" placeholder="请选择通知配置" style="width: 320px" @change="getTem(item.noticeConfig, index)">
  133. <el-option v-for="b in sendGatewayData[index]" :key="b.id" :label="b.title" :value="b.id" />
  134. </el-select>
  135. <el-select v-model="item.noticeTemplate" placeholder="请选择通知模板" style="width: 320px">
  136. <el-option v-for="c in noticeConfigData[index]" :key="c.id" :label="c.title" :value="c.id" />
  137. </el-select>
  138. </div>
  139. <div>
  140. <div style="display: flex; margin-bottom: 10px" v-for="(ph, phindex) in item.addressee" :key="phindex">
  141. <el-input v-model="ph.phone" placeholder="请输入接收人信息" style="width: 320px" />
  142. <el-icon style="width: 32px; height: 32px; font-size: 24px" v-if="phindex == 0" @click="AddPhone(index)">
  143. <CirclePlus />
  144. </el-icon>
  145. <el-icon style="width: 32px; height: 32px; font-size: 24px" v-if="phindex > 0" @click="DelPhone(index, phindex)">
  146. <Remove />
  147. </el-icon>
  148. </div>
  149. </div>
  150. </div>
  151. </div>
  152. </div>
  153. <el-button type="success" class="addbutton" @click="addAction">增加执行</el-button>
  154. </el-form>
  155. <template #footer>
  156. <span class="dialog-footer">
  157. <el-button @click="onCancel" size="default">取 消</el-button>
  158. <el-button type="primary" @click="onSubmit" size="default">{{ ruleForm.id !== 0 ? '修 改' : '添 加' }}</el-button>
  159. </span>
  160. </template>
  161. </el-dialog>
  162. </div>
  163. </template>
  164. <script lang="ts">
  165. import { reactive, toRefs, defineComponent, ref, unref, getCurrentInstance, watch } from 'vue';
  166. import api from '/@/api/datahub';
  167. import iotapi from '/@/api/device';
  168. import alarm from '/@/api/alarm';
  169. import notice from '/@/api/notice';
  170. import { ElMessage } from 'element-plus';
  171. import { Delete, CircleClose, Top, Bottom, CirclePlus, Remove } from '@element-plus/icons-vue';
  172. interface RuleFormState {
  173. id: number;
  174. name: string;
  175. triggerType: number;
  176. level: string;
  177. eventKey: string;
  178. productKey: string;
  179. deviceKey: string;
  180. triggerCondition: any;
  181. action: any;
  182. }
  183. interface DicState {
  184. isShowDialog: boolean;
  185. ruleForm: RuleFormState;
  186. rules: any;
  187. sourceData: any;
  188. productData: any;
  189. typeData: any;
  190. triData: any;
  191. operData: any;
  192. levelData: any;
  193. requestParams: any;
  194. triggerCondition: any;
  195. action: any;
  196. tempData: any;
  197. sendGatewayData: any;
  198. noticeConfigData: any;
  199. eventList: any;
  200. }
  201. export default defineComponent({
  202. name: 'Edit',
  203. components: { Delete, CircleClose, Top, Bottom, CirclePlus, Remove },
  204. setup(prop, { emit }) {
  205. const myRef = ref<HTMLElement | null>(null);
  206. const formRef = ref<HTMLElement | null>(null);
  207. const { proxy } = getCurrentInstance() as any;
  208. const { notice_send_gateway } = proxy.useDict('notice_send_gateway');
  209. const state = reactive<DicState>({
  210. id: 0,
  211. isShowDialog: false,
  212. sourceData: [],
  213. tempData: [],
  214. productData: [],
  215. typeData: [],
  216. triData: [],
  217. operData: [],
  218. levelData: [],
  219. sendGatewayData: [],
  220. noticeConfigData: [],
  221. eventList: [],
  222. action: [
  223. {
  224. sendGateway: '',
  225. noticeConfig: '',
  226. noticeTemplate: '',
  227. addressee: [
  228. {
  229. phone: '',
  230. },
  231. ],
  232. },
  233. ],
  234. requestParams: [
  235. {
  236. andOr: '',
  237. filters: [
  238. {
  239. key: '',
  240. operator: '',
  241. value: '',
  242. andOr: 0,
  243. },
  244. ],
  245. },
  246. ],
  247. ruleForm: {
  248. id: 0,
  249. name: '',
  250. triggerType: 1,
  251. eventKey: '',
  252. level: '',
  253. productKey: '',
  254. deviceKey: '',
  255. action: [
  256. {
  257. sendGateway: '',
  258. noticeConfig: '',
  259. noticeTemplate: '',
  260. addressee: {},
  261. },
  262. ],
  263. triggerCondition: [
  264. {
  265. andOr: '',
  266. filters: [
  267. {
  268. key: '',
  269. operator: '',
  270. value: '',
  271. andOr: 0,
  272. },
  273. ],
  274. },
  275. ],
  276. },
  277. rules: {
  278. name: [{ required: true, message: '告警名称不能为空', trigger: 'blur' }],
  279. level: [{ required: true, message: '告警级别不能为空', trigger: 'blur' }],
  280. productKey: [{ required: true, message: '请选择产品', trigger: 'blur' }],
  281. deviceKey: [{ required: true, message: '请选择设备', trigger: 'blur' }],
  282. },
  283. });
  284. // 打开弹窗
  285. const openDialog = (row: RuleFormState | null) => {
  286. resetForm();
  287. getDevData();
  288. if (row) {
  289. setType(true);
  290. alarm.common.detail(row.id).then((res: any) => {
  291. state.requestParams = res.data.condition.triggerCondition;
  292. let product_key=res.data.productKey;
  293. res.data.performAction.action.forEach(function (value: { sendGateway: any; noticeConfig: number; }, index: string | number) {
  294. notice.config.getList({ sendGateway: value.sendGateway }).then((res: any) => {
  295. state.sendGatewayData[index] = res.Data;
  296. });
  297. if (value.noticeConfig) {
  298. notice.template.configIddetail(value.noticeConfig).then((res: any) => {
  299. state.noticeConfigData[index] = [res];
  300. });
  301. }
  302. });
  303. state.action = res.data.performAction.action;
  304. state.action.forEach(function (value: { addressee: any[]; }, index: string | number) {
  305. state.action[index].addressee = value.addressee.map((p: any) => {
  306. return { phone: p };
  307. });
  308. });
  309. iotapi.product.event({key:res.data.productKey}).then((ress: any) => {
  310. state.eventList = ress || []
  311. state.ruleForm.eventKey=row.eventKey
  312. })
  313. state.ruleForm = res.data;
  314. if(product_key){
  315. alarm.common.trigger_type(product_key).then((res: any) => {
  316. state.typeData = res.list || [];
  317. });
  318. }
  319. });
  320. }
  321. state.isShowDialog = true;
  322. };
  323. //获取设备列表
  324. const getDevData = () => {
  325. iotapi.product.getLists({ status: 1 }).then((res: any) => {
  326. state.productData = res.product || [];
  327. });
  328. alarm.common.levelall('').then((res: any) => {
  329. state.levelData = res.list || [];
  330. });
  331. alarm.common.operator('').then((res: any) => {
  332. state.operData = res.list || [];
  333. });
  334. };
  335. const resetForm = () => {
  336. state.requestParams = [
  337. {
  338. andOr: '',
  339. filters: [
  340. {
  341. key: '',
  342. operator: '',
  343. value: '',
  344. andOr: 0,
  345. },
  346. ],
  347. },
  348. ];
  349. state.action = [
  350. {
  351. sendGateway: '',
  352. noticeConfig: '',
  353. noticeTemplate: '',
  354. addressee: [
  355. {
  356. phone: '',
  357. },
  358. ],
  359. },
  360. ];
  361. state.ruleForm = {
  362. id: 0,
  363. name: '',
  364. triggerType: 1,
  365. level: '',
  366. productKey: '',
  367. deviceKey: '',
  368. action: [
  369. {
  370. sendGateway: '',
  371. noticeConfig: '',
  372. noticeTemplate: '',
  373. addressee: {},
  374. },
  375. ],
  376. triggerCondition: [
  377. {
  378. andOr: '',
  379. filters: [
  380. {
  381. key: '',
  382. operator: '',
  383. value: '',
  384. andOr: 0,
  385. },
  386. ],
  387. },
  388. ],
  389. };
  390. };
  391. // 关闭弹窗
  392. const closeDialog = () => {
  393. state.isShowDialog = false;
  394. };
  395. // 取消
  396. const onCancel = () => {
  397. closeDialog();
  398. };
  399. const eventTypeChange = () => {
  400. gettriData()
  401. };
  402. watch(() => state.ruleForm.productKey, (key) => {
  403. if (!key) return
  404. // 切换产品时候重新获取事件列表,清空之前选中的事件
  405. state.ruleForm.eventKey = ''
  406. iotapi.product.event({ key }).then((res: any) => {
  407. state.eventList = res || []
  408. })
  409. })
  410. // 新增
  411. const onSubmit = () => {
  412. const formWrap = unref(formRef) as any;
  413. if (!formWrap) return;
  414. formWrap.validate((valid: boolean) => {
  415. if (valid) {
  416. state.ruleForm.triggerCondition = state.requestParams;
  417. state.action.forEach(function (value: { addressee: any[]; }, index: string | number) {
  418. state.action[index].addressee = value.addressee.map((p: { phone: any; }) => {
  419. return p.phone;
  420. });
  421. });
  422. state.ruleForm.action = state.action;
  423. if (state.ruleForm.id !== 0) {
  424. //修改
  425. alarm.common.edit(state.ruleForm).then(() => {
  426. ElMessage.success('告警修改成功');
  427. closeDialog(); // 关闭弹窗
  428. emit('typeList');
  429. });
  430. } else {
  431. //添加
  432. alarm.common.add(state.ruleForm).then(() => {
  433. ElMessage.success('告警添加成功');
  434. closeDialog(); // 关闭弹窗
  435. emit('dataList');
  436. });
  437. }
  438. }
  439. });
  440. };
  441. const AddPhone = (index: string | number) => {
  442. state.action[index].addressee.push({
  443. phone: '',
  444. });
  445. };
  446. const DelPhone = (index: string | number, bbb: any) => {
  447. state.action[index].addressee.splice(bbb, 1);
  448. };
  449. const addAction = () => {
  450. state.action.push({
  451. sendGateway: '',
  452. noticeConfig: '',
  453. noticeTemplate: '',
  454. addressee: [
  455. {
  456. phone: '',
  457. },
  458. ],
  459. });
  460. };
  461. const delAction = (index: any) => {
  462. state.action.splice(index, 1);
  463. };
  464. const delParams = (index: any) => {
  465. state.requestParams.splice(index, 1);
  466. };
  467. const delParamss = (index: string | number, bbb: any) => {
  468. state.requestParams[index].filters.splice(bbb, 1);
  469. };
  470. const addParamss = () => {
  471. state.requestParams.push({
  472. andOr: '',
  473. filters: [
  474. {
  475. key: '',
  476. operator: '',
  477. value: '',
  478. andOr: '',
  479. },
  480. ],
  481. });
  482. };
  483. const addParams = (index: string | number) => {
  484. state.requestParams[index].filters.push({
  485. key: '',
  486. operator: '',
  487. value: '',
  488. andOr: '',
  489. });
  490. };
  491. const setType = (notResetDeviceKey: boolean) => {
  492. !notResetDeviceKey && (state.ruleForm.deviceKey = '')
  493. let product_id = 0;
  494. state.productData.forEach((item: { key: string; id: number; }) => {
  495. if (item.key == state.ruleForm.productKey) {
  496. product_id = item.id;
  497. }
  498. });
  499. api.common.getdevList({ productId: product_id }).then((res: any) => {
  500. state.sourceData = res.device;
  501. });
  502. alarm.common.trigger_type(state.ruleForm.productKey).then((res: any) => {
  503. state.typeData = res.list || [];
  504. });
  505. gettriData();
  506. };
  507. const getRadio = () => {
  508. gettriData();
  509. }
  510. const gettriData = () => {
  511. // 清空之前设置的参数设置
  512. state.requestParams = [{
  513. andOr: '',
  514. filters: [
  515. {
  516. key: '',
  517. operator: '',
  518. value: '',
  519. andOr: 0,
  520. },
  521. ],
  522. }]
  523. setTriData()
  524. }
  525. function setTriData() {
  526. // 重置参数列表
  527. state.triData = [];
  528. const triggerType = state.ruleForm.triggerType
  529. const form = {
  530. productKey: state.ruleForm.productKey,
  531. triggerType
  532. }
  533. // 如果是事件上报,需要传eventKey参数
  534. if (triggerType === 4) {
  535. form.eventKey = state.ruleForm.eventKey
  536. if (!form.eventKey) return
  537. }
  538. alarm.common.trigger_params(form).then((res: any) => {
  539. state.triData = res.list || [];
  540. });
  541. }
  542. const getNode = (event: any, index: string | number) => {
  543. state.action[index].noticeConfig = '';
  544. notice.config.getList({ sendGateway: event }).then((res: any) => {
  545. state.sendGatewayData[index] = res.Data;
  546. });
  547. };
  548. const getTem = (event: number, index: string | number) => {
  549. state.action[index].noticeTemplate = '';
  550. notice.template.configIddetail(event).then((res: any) => {
  551. state.noticeConfigData[index] = [res];
  552. });
  553. };
  554. return {
  555. getRadio,
  556. gettriData,
  557. getTem,
  558. getNode,
  559. delAction,
  560. addAction,
  561. eventTypeChange,
  562. AddPhone,
  563. DelPhone,
  564. setType,
  565. addParams,
  566. addParamss,
  567. delParamss,
  568. delParams,
  569. openDialog,
  570. closeDialog,
  571. getDevData,
  572. onCancel,
  573. onSubmit,
  574. formRef,
  575. notice_send_gateway,
  576. myRef,
  577. ...toRefs(state),
  578. };
  579. },
  580. });
  581. </script>
  582. <style>
  583. .inline {
  584. display: inline-flex;
  585. }
  586. .el-input__wrapper {
  587. width: 98%;
  588. }
  589. .box-content {
  590. border: 1px solid #e8e8e8;
  591. margin: 10px;
  592. padding: 10px;
  593. }
  594. .content-f {
  595. display: flex;
  596. margin-bottom: 10px;
  597. }
  598. .content-f .el-input__wrapper {
  599. margin-right: 5px;
  600. }
  601. .addbutton {
  602. width: 100%;
  603. margin-top: 10px;
  604. background: #fff;
  605. border: 1px solid #d1d1d1;
  606. color: #8d8b8b;
  607. }
  608. .conicon {
  609. width: 55px;
  610. height: 25px;
  611. font-size: 28px;
  612. line-height: 28px;
  613. cursor: pointer;
  614. }
  615. .jv-node {
  616. margin-left: 25px;
  617. }</style>