index.vue 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741
  1. <template>
  2. <div ref="mod">
  3. <a-modal
  4. :get-container="() => $refs.mod"
  5. :open="props.open"
  6. :title="modelTitle"
  7. :mask-closable="false"
  8. width="600px"
  9. @cancel="cancel"
  10. :footer="null"
  11. >
  12. <a-form
  13. ref="formRef"
  14. :model="formState"
  15. :label-col="{ style: { width: '80px' } }"
  16. hideRequiredMark
  17. >
  18. <a-form-item
  19. label="计划名称"
  20. name="planName"
  21. :rules="[{ required: true, message: '请输入计划名称' }]"
  22. >
  23. <a-input
  24. v-model:value.trim="formState.planName"
  25. placeholder="请输入计划名称"
  26. :maxlength="20"
  27. show-count
  28. allow-clear
  29. />
  30. </a-form-item>
  31. <a-form-item
  32. label="计划备注"
  33. name="planName"
  34. :rules="[{ required: true, message: '请输入计划备注' }]"
  35. >
  36. <a-input
  37. v-model:value.trim="formState.remark"
  38. placeholder="请输入备注"
  39. :maxlength="200"
  40. show-count
  41. allow-clear
  42. />
  43. </a-form-item>
  44. <a-form-item
  45. label="触发阈值"
  46. name="thresholdTime"
  47. :rules="[{ required: true, message: '请输入触发阈值' }]"
  48. >
  49. <a-input-number
  50. v-model:value.trim="formState.thresholdTime"
  51. placeholder="请输入(默认300,需要大于0)"
  52. min="0"
  53. show-count
  54. allow-clear
  55. style="width: 100%"
  56. >
  57. <template #addonAfter>
  58. <a-select v-model:value="thresholdTimeFormat" style="width: 80px">
  59. <a-select-option value="s">秒</a-select-option>
  60. <a-select-option value="min">分钟</a-select-option>
  61. <a-select-option value="hour">小时</a-select-option>
  62. <a-select-option value="day">天</a-select-option>
  63. </a-select>
  64. </template>
  65. </a-input-number>
  66. </a-form-item>
  67. <a-form-item
  68. label="归并时间"
  69. name="mergeTime"
  70. :rules="[{ required: true, message: '请输入归并时间' }]"
  71. >
  72. <a-input-number
  73. v-model:value.trim="formState.mergeTime"
  74. placeholder="请输入(默认30,需要大于0)"
  75. min="0"
  76. show-count
  77. allow-clear
  78. style="width: 100%"
  79. />
  80. </a-form-item>
  81. <a-form-item
  82. label="事件类型"
  83. name="eventType"
  84. :rules="[{ required: true, message: '请选择事件类型' }]"
  85. >
  86. <a-select
  87. v-model:value="formState.eventType"
  88. :options="eventTypeList"
  89. placeholder="请选择事件类型"
  90. />
  91. <a-form-item-rest v-if="formState.eventType && ![1, 2, 3].includes(formState.eventType)">
  92. <div class="eventTypeBox">
  93. <div v-if="[4, 5, 6, 7, 8].includes(formState.eventType)" class="eventTypeBox-item">
  94. <span class="eventTypeBox-item-label">统计时间:</span>
  95. <a-form-item
  96. name="statisticsTime"
  97. :rules="[{ required: true, message: '请选择统计时间' }]"
  98. >
  99. <a-time-range-picker
  100. v-model:value="formState.statisticsTime"
  101. valueFormat="HH:mm"
  102. format="HH:mm"
  103. style="width: 100%"
  104. />
  105. </a-form-item>
  106. </div>
  107. <div v-if="[6, 7].includes(formState.eventType)" class="eventTypeBox-item">
  108. <span class="eventTypeBox-item-label">异常阈值:</span>
  109. <a-form-item name="count" :rules="[{ required: true, message: '请输入异常阈值' }]">
  110. <a-input-number
  111. v-model:value.trim="formState.count"
  112. placeholder="请输入(默认3,需要大于0)"
  113. min="0"
  114. show-count
  115. allow-clear
  116. style="width: 100%"
  117. />
  118. </a-form-item>
  119. </div>
  120. <div v-if="formState.eventType === 9" class="eventTypeBox-item">
  121. <span class="eventTypeBox-item-labelend">异常消失时间阈值:</span>
  122. <a-form-item
  123. name="timeThreshold"
  124. :rules="[{ required: true, message: '请输入异常消失时间阈值' }]"
  125. >
  126. <a-input-number
  127. v-model:value.trim="formState.timeThreshold"
  128. placeholder="请输入(默认300,需要大于0)"
  129. min="0"
  130. show-count
  131. allow-clear
  132. style="width: 100%"
  133. >
  134. <template #addonAfter>
  135. <a-select v-model:value="timeThresholdFormat" style="width: 80px">
  136. <a-select-option value="s">秒</a-select-option>
  137. <a-select-option value="min">分钟</a-select-option>
  138. <a-select-option value="hour">小时</a-select-option>
  139. <a-select-option value="day">天</a-select-option>
  140. </a-select>
  141. </template>
  142. </a-input-number>
  143. </a-form-item>
  144. </div>
  145. </div>
  146. </a-form-item-rest>
  147. </a-form-item>
  148. <a-form-item
  149. label="计划时间"
  150. name="planTime"
  151. :rules="[{ type: 'array' as const, required: true, message: '请选择计划时间' }]"
  152. >
  153. <a-range-picker
  154. v-model:value="formState.planTime"
  155. style="width: 100%"
  156. :show-time="false"
  157. valueFormat="YYYY-MM-DD"
  158. />
  159. </a-form-item>
  160. <a-form-item label="生效时段">
  161. <div style="display: flex; align-items: center; gap: 8px">
  162. <a-time-range-picker
  163. v-model:value="formState.effectTimeFrame"
  164. valueFormat="HH:mm"
  165. format="HH:mm"
  166. style="width: 100%"
  167. />
  168. <a-button size="small" type="link" @click="addEffectTime">添加</a-button>
  169. </div>
  170. <div style="margin-top: 12px">
  171. <span
  172. v-if="formState.effectTimeFrames && !formState.effectTimeFrames.length"
  173. style="color: #aaa; font-size: 14px"
  174. >⚠️暂无生效时段</span
  175. >
  176. <a-space wrap v-else>
  177. <a-tag
  178. v-for="(item, index) in formState.effectTimeFrames"
  179. :key="index"
  180. closable
  181. style="font-size: 14px; padding: 4px 10px"
  182. @close="deleteEffectTimeItem($event, index)"
  183. >{{ item.startTime }} - {{ item.endTime }}</a-tag
  184. >
  185. </a-space>
  186. </div>
  187. </a-form-item>
  188. <a-form-item label="生效方式">
  189. <a-form-item-rest>
  190. <a-radio-group
  191. v-model:value="formState.effectType"
  192. name="radioGroup"
  193. @change="effectTypeChange"
  194. >
  195. <a-radio value="week">按周</a-radio>
  196. <a-radio value="month">按月</a-radio>
  197. </a-radio-group>
  198. <a-checkbox
  199. v-model:checked="checkState.checkAll"
  200. :indeterminate="checkState.indeterminate"
  201. @change="onCheckAllChange"
  202. >
  203. 全选
  204. </a-checkbox>
  205. <a-checkbox-group v-model:value="formState.effectTimeRanges" :options="plainOptions" />
  206. </a-form-item-rest>
  207. </a-form-item>
  208. <a-form-item label="检测区域" name="region">
  209. 检测区域选择组件 {{ formState.region }}
  210. </a-form-item>
  211. <a-form-item label="是否启用">
  212. <a-switch v-model:checked="formState.enable" />
  213. </a-form-item>
  214. </a-form>
  215. <div class="footer">
  216. <a-space>
  217. <a-button @click="cancel">取消</a-button>
  218. <a-button type="primary" :loading="submitLoading" @click="submit">保存</a-button>
  219. </a-space>
  220. </div>
  221. </a-modal>
  222. </div>
  223. </template>
  224. <script setup lang="ts">
  225. import { ref, reactive, watch, computed } from 'vue'
  226. import { message, type FormInstance } from 'ant-design-vue'
  227. import * as alarmApi from '@/api/alarm'
  228. defineOptions({
  229. name: 'AlarmPlanModal',
  230. })
  231. const formRef = ref<FormInstance>()
  232. type AlarmPlan = {
  233. id: number
  234. uuid: ID
  235. name: string
  236. clientId: string
  237. enable: SwitchType
  238. region: string
  239. eventVal: number
  240. alarmTimePlanId: ID
  241. thresholdTime: ID
  242. mergeTime: ID
  243. param: string
  244. createTime: string
  245. updateTime: string
  246. remark: string | null
  247. alarmTimePlan: {
  248. createId: ID
  249. updateId: ID
  250. createTime: ID
  251. updateTime: ID
  252. isDeleted: SwitchType | null
  253. remark: ID
  254. id: ID
  255. startDate: string
  256. stopDate: string
  257. timeRange: string
  258. monthDays: string
  259. weekdays: string
  260. }
  261. }
  262. type Props = {
  263. open: boolean
  264. title?: string
  265. clientId: string // 设备ID
  266. alarmPlanId?: number | null // 告警计划ID 编辑时传入
  267. data?: AlarmPlan // 编辑数据
  268. }
  269. const emit = defineEmits<{
  270. (e: 'update:open', value: boolean): void
  271. (e: 'success', value: void): void
  272. }>()
  273. const props = withDefaults(defineProps<Props>(), {
  274. open: false,
  275. title: '告警计划',
  276. clientId: '',
  277. alarmPlanId: null,
  278. data: undefined,
  279. })
  280. const modelTitle = computed(() => {
  281. return props.alarmPlanId ? '编辑告警计划' : '新增告警计划'
  282. })
  283. const weekOptions = ['周一', '周二', '周三', '周四', '周五', '周六', '周日']
  284. const monthOptions = [
  285. 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27,
  286. 28, 29, 30, 31,
  287. ]
  288. type FormState = {
  289. planName: string // 计划名称
  290. region: number[] // 检测区域 [left, top, width, height]
  291. eventType: number | null // 事件类型
  292. thresholdTime: number | null // 触发阈值
  293. mergeTime: number | null // 归并时间
  294. planTime: string[] // 计划时间
  295. effectType: 'week' | 'month' // 生效方式 周week、月month
  296. effectTimeRanges: (number | string)[] // 生效范围 周 1-7、月 1-31
  297. effectTimeFrame: string[] // 生效时段 单条 00:00:00 - 23:59:59
  298. effectTimeFrames: { startTime: string; endTime: string }[] // 生效时段 多条
  299. enable: boolean // 是否启用
  300. statisticsTime: string[] // 统计时间
  301. count?: number | null // 异常阈值
  302. timeThreshold?: number | null // 异常消失时间阈值(单位:秒)
  303. remark?: string // 备注
  304. }
  305. const formState = reactive<FormState>({
  306. planName: '',
  307. region: [-200, 200, 400, 400],
  308. eventType: null,
  309. thresholdTime: 300,
  310. mergeTime: 30,
  311. planTime: [],
  312. effectType: 'week',
  313. effectTimeRanges: weekOptions,
  314. effectTimeFrame: [],
  315. effectTimeFrames: [],
  316. enable: true,
  317. statisticsTime: [],
  318. count: 3,
  319. timeThreshold: 300,
  320. })
  321. const thresholdTimeFormat = ref<'s' | 'min' | 'hour' | 'day'>('s') // 触发阈值 额外选择器
  322. const timeThresholdFormat = ref<'s' | 'min' | 'hour' | 'day'>('s') // 异常消失时间阈值 额外选择器
  323. const plainOptions = ref<(number | string)[]>(weekOptions)
  324. const checkState = reactive({
  325. indeterminate: true,
  326. checkAll: false,
  327. })
  328. const onCheckAllChange = (e: Event) => {
  329. const checked = (e.target as HTMLInputElement).checked
  330. checkState.checkAll = checked
  331. console.log('onCheckAllChange', e, checked)
  332. formState.effectTimeRanges = checked ? [...plainOptions.value] : []
  333. }
  334. // 星期映射数字
  335. const weekToNumMap: Record<string, number> = {
  336. 周一: 1,
  337. 周二: 2,
  338. 周三: 3,
  339. 周四: 4,
  340. 周五: 5,
  341. 周六: 6,
  342. 周日: 7,
  343. }
  344. // 数字映射星期
  345. const numToWeekMap: Record<number, string> = {
  346. 1: '周一',
  347. 2: '周二',
  348. 3: '周三',
  349. 4: '周四',
  350. 5: '周五',
  351. 6: '周六',
  352. 7: '周日',
  353. }
  354. watch(
  355. () => formState.effectTimeRanges,
  356. (val) => {
  357. checkState.indeterminate = !!val.length && val.length < plainOptions.value.length //设置全选按钮的半选状态
  358. checkState.checkAll = val.length === plainOptions.value.length // 设置全选按钮的选中状态
  359. },
  360. {
  361. immediate: true,
  362. }
  363. )
  364. const safeParse = <T,>(str: string | undefined | null, fallback: T): T => {
  365. try {
  366. return JSON.parse(str ?? JSON.stringify(fallback)) as T
  367. } catch {
  368. return fallback
  369. }
  370. }
  371. interface ParamType {
  372. start_time?: string
  373. end_time?: string
  374. count?: number
  375. time_threshold?: number
  376. }
  377. interface TimeFrame {
  378. start_time?: string
  379. end_time?: string
  380. }
  381. interface AlarmTimePlan {
  382. startDate?: string
  383. stopDate?: string
  384. weekdays?: string
  385. monthDays?: string
  386. timeRange?: string
  387. }
  388. interface SourceData {
  389. name?: string
  390. remark?: string
  391. thresholdTime?: number
  392. mergeTime?: number
  393. eventVal?: number | null
  394. param?: string
  395. alarmTimePlan?: AlarmTimePlan
  396. region?: string
  397. enable?: number
  398. }
  399. const echoFormState = (val: SourceData) => {
  400. const paramObj = safeParse<ParamType>(val.param, {})
  401. const weekdays = safeParse<string[]>(val.alarmTimePlan?.weekdays, [])
  402. const monthDays = safeParse<string[]>(val.alarmTimePlan?.monthDays, [])
  403. const timeFrames = safeParse<TimeFrame[]>(val.alarmTimePlan?.timeRange, [])
  404. plainOptions.value = weekdays.length === 0 ? monthOptions : weekOptions
  405. return {
  406. planName: val.name ?? '',
  407. remark: val.remark ?? '',
  408. thresholdTime: typeof val.thresholdTime === 'number' ? val.thresholdTime : null,
  409. mergeTime: typeof val.mergeTime === 'number' ? val.mergeTime : null,
  410. eventType: val.eventVal ?? null,
  411. statisticsTime: [paramObj.start_time ?? null, paramObj.end_time ?? null] as string[],
  412. count: paramObj.count ?? null,
  413. timeThreshold: paramObj.time_threshold ?? null,
  414. planTime: [val.alarmTimePlan?.startDate ?? '', val.alarmTimePlan?.stopDate ?? ''],
  415. effectType: (weekdays.length === 0 ? 'month' : 'week') as 'week' | 'month',
  416. effectTimeRanges:
  417. weekdays.length === 0
  418. ? monthDays
  419. : weekdays.map((item: string) => numToWeekMap[Number(item)]),
  420. effectTimeFrames: Array.isArray(timeFrames)
  421. ? timeFrames.map((item) => ({
  422. startTime: item?.start_time ?? '',
  423. endTime: item?.end_time ?? '',
  424. }))
  425. : [],
  426. region: JSON.parse(val.region ?? '[]'),
  427. enable: val?.enable === 1,
  428. }
  429. }
  430. watch(
  431. () => props.open,
  432. (value) => {
  433. const val = props.data as SourceData
  434. console.log('🌸🌸 监听data用于编辑回显数据 🌸🌸', value, val)
  435. if (value && val) {
  436. formState.planName = echoFormState(val).planName
  437. formState.remark = echoFormState(val).remark
  438. formState.thresholdTime = echoFormState(val).thresholdTime
  439. formState.mergeTime = echoFormState(val).mergeTime
  440. formState.eventType = echoFormState(val).eventType
  441. formState.statisticsTime = echoFormState(val).statisticsTime
  442. formState.count = echoFormState(val).count
  443. formState.timeThreshold = echoFormState(val).timeThreshold
  444. formState.planTime = echoFormState(val).planTime
  445. formState.effectType = echoFormState(val).effectType
  446. formState.effectTimeRanges = echoFormState(val).effectTimeRanges
  447. formState.effectTimeFrames = echoFormState(val).effectTimeFrames
  448. }
  449. },
  450. { immediate: true }
  451. )
  452. // 生效方式变化 周week、月month
  453. const effectTypeChange = (e: Event) => {
  454. const value = (e.target as HTMLInputElement).value
  455. console.log('effectTypeChange', e, value)
  456. if (value === 'week') {
  457. plainOptions.value = weekOptions
  458. formState.effectTimeRanges = weekOptions
  459. } else if (value === 'month') {
  460. plainOptions.value = monthOptions
  461. formState.effectTimeRanges = monthOptions
  462. }
  463. /* 置全选按钮的状态 */
  464. checkState.indeterminate =
  465. !!formState.effectTimeRanges.length &&
  466. formState.effectTimeRanges.length < plainOptions.value.length // 设置全选按钮的半选状态
  467. checkState.checkAll = formState.effectTimeRanges.length === plainOptions.value.length // 设置全选按钮的选中状态
  468. }
  469. // 添加时间段
  470. const addEffectTime = () => {
  471. console.log('addEffectTime', formState.effectTimeFrame)
  472. if (!formState.effectTimeFrame || !formState.effectTimeFrame.length) {
  473. message.warn('请选择时间段')
  474. return
  475. }
  476. formState.effectTimeFrames.push({
  477. startTime: formState.effectTimeFrame[0],
  478. endTime: formState.effectTimeFrame[1],
  479. })
  480. // formState.effectTimeFrame = [] // 清空选择的时间段
  481. }
  482. // 删除已添加的时间段
  483. const deleteEffectTimeItem = (e: Event, index: number) => {
  484. console.log('deleteEffectTimeItem', e, index)
  485. formState.effectTimeFrames.splice(index, 1)
  486. }
  487. // 关闭弹窗
  488. const cancel = () => {
  489. formRef?.value?.resetFields()
  490. emit('update:open', false)
  491. // 重置表单
  492. formState.planName = ''
  493. formState.region = []
  494. formState.eventType = null
  495. formState.thresholdTime = 300
  496. formState.mergeTime = 30
  497. formState.planTime = []
  498. formState.effectType = 'week'
  499. plainOptions.value = weekOptions
  500. formState.effectTimeRanges = weekOptions
  501. formState.effectTimeFrame = []
  502. formState.effectTimeFrames = []
  503. formState.enable = true
  504. formState.statisticsTime = []
  505. formState.count = 3
  506. formState.timeThreshold = 300
  507. formState.remark = ''
  508. }
  509. const eventTypeList = ref<{ label: string; value: string }[]>([])
  510. // 获取事件类型下拉列表
  511. const fetchEventTypeList = async () => {
  512. try {
  513. const res = await alarmApi.getAlarmEventTypeList()
  514. console.log('获取事件类型下拉列表成功✅', res)
  515. const data = res.data
  516. eventTypeList.value =
  517. (Array.isArray(data) &&
  518. data.map((item) => ({
  519. label: item.eventDesc,
  520. value: item.eventVal,
  521. }))) ||
  522. []
  523. } catch (err) {
  524. console.log('获取事件类型下拉列表失败❌', err)
  525. }
  526. }
  527. fetchEventTypeList()
  528. function thresholdTimeFormatValue() {
  529. if (thresholdTimeFormat.value === 's') {
  530. return Number(formState.thresholdTime) // 触发阈值
  531. } else if (thresholdTimeFormat.value === 'min') {
  532. return Number(formState.thresholdTime) * 60 // 触发阈值
  533. } else if (thresholdTimeFormat.value === 'hour') {
  534. return Number(formState.thresholdTime) * 60 * 60 // 触发阈值
  535. } else if (thresholdTimeFormat.value === 'day') {
  536. return Number(formState.thresholdTime) * 24 * 60 * 60 // 触发阈值
  537. }
  538. }
  539. function timeThresholdFormatValue() {
  540. if (timeThresholdFormat.value === 's') {
  541. return Number(formState.timeThreshold) // 触发阈值
  542. } else if (timeThresholdFormat.value === 'min') {
  543. return Number(formState.timeThreshold) * 60 // 触发阈值
  544. } else if (timeThresholdFormat.value === 'hour') {
  545. return Number(formState.timeThreshold) * 60 * 60 // 触发阈值
  546. } else if (timeThresholdFormat.value === 'day') {
  547. return Number(formState.timeThreshold) * 24 * 60 * 60 // 触发阈值
  548. }
  549. }
  550. const submitLoading = ref(false)
  551. // 确定
  552. const submit = () => {
  553. formRef?.value
  554. ?.validate()
  555. .then(() => {
  556. console.log('校验通过', formState)
  557. let paramData = {}
  558. if ([1, 2, 3].includes(formState.eventType as number)) {
  559. paramData = {}
  560. console.log('🔥paramData🔥', paramData)
  561. } else if ([4, 5, 8].includes(formState.eventType as number)) {
  562. paramData = {
  563. start_time: formState.statisticsTime[0],
  564. end_time: formState.statisticsTime[1],
  565. }
  566. console.log('🔥paramData🔥', paramData)
  567. } else if ([6, 7].includes(formState.eventType as number)) {
  568. paramData = {
  569. start_time: formState.statisticsTime[0],
  570. end_time: formState.statisticsTime[1],
  571. count: isNaN(Number(formState.count)) ? 0 : Number(formState.count),
  572. }
  573. console.log('🔥paramData🔥', paramData)
  574. } else if ([9].includes(formState.eventType as number)) {
  575. paramData = {
  576. time_threshold: isNaN(Number(formState.timeThreshold)) ? 0 : timeThresholdFormatValue(),
  577. }
  578. console.log('🔥paramData🔥', paramData)
  579. }
  580. const params = {
  581. alarmPlanId: props.alarmPlanId || undefined, // 告警计划ID 编辑时传入
  582. clientId: props.clientId, // 设备ID
  583. name: formState.planName, // 计划名称
  584. remark: formState.remark || '', // 备注
  585. thresholdTime: thresholdTimeFormatValue(), // 触发阈值
  586. mergeTime: Number(formState.mergeTime) || 30, // 归并时间
  587. eventVal: formState.eventType as number, // 事件类型 与 param 有联动关系
  588. param: JSON.stringify(paramData), // 事件参数 与 eventVal 有联动关系
  589. region: JSON.stringify(formState.region), // 检测区域
  590. enable: Number(formState.enable) as 0 | 1, // 是否启用 0否 1是
  591. // 生效方式
  592. alarmTimePlan: {
  593. startDate: formState.planTime[0], // 计划开始时间
  594. stopDate: formState.planTime[1], // 计划结束时间
  595. // 生效时段
  596. timeRange: JSON.stringify(
  597. formState.effectTimeFrames.map((item) => ({
  598. start_time: item.startTime,
  599. end_time: item.endTime,
  600. }))
  601. ),
  602. monthDays: JSON.stringify(
  603. formState.effectType === 'month' ? formState.effectTimeRanges : []
  604. ),
  605. weekdays: JSON.stringify(
  606. formState.effectType === 'week'
  607. ? formState.effectTimeRanges.map((item) => weekToNumMap[item])
  608. : []
  609. ),
  610. },
  611. }
  612. console.log('🚀🚀🚀提交参数', params)
  613. if (formState.effectTimeFrames.length === 0) {
  614. message.warn('请添加生效时段')
  615. return
  616. }
  617. if (formState.effectTimeRanges.length === 0) {
  618. message.warn('请选择生效方式的范围')
  619. return
  620. }
  621. // if (formState.region.length !== 4) {
  622. // message.warn('请选择检测区域')
  623. // return
  624. // }
  625. submitLoading.value = true
  626. alarmApi
  627. .saveAlarmPlan(params)
  628. .then((res) => {
  629. console.log('添加成功', res)
  630. submitLoading.value = false
  631. message.success('添加成功')
  632. emit('success')
  633. cancel()
  634. })
  635. .catch(() => {
  636. submitLoading.value = false
  637. })
  638. })
  639. .catch((err) => {
  640. console.log('校验失败', err)
  641. })
  642. }
  643. </script>
  644. <style scoped lang="less">
  645. :deep(.ant-modal) {
  646. .footer {
  647. text-align: right;
  648. }
  649. .ant-modal-body {
  650. padding: 12px 0;
  651. }
  652. }
  653. :deep(.ant-checkbox-group) {
  654. .ant-checkbox + span {
  655. min-width: 32px;
  656. }
  657. }
  658. :deep(.ant-tag) {
  659. margin-inline-end: 0 !important;
  660. }
  661. .eventTypeBox {
  662. margin-top: 12px;
  663. color: #555;
  664. font-size: 14px;
  665. padding: 20px 12px;
  666. background: #fafafa;
  667. border-radius: 8px;
  668. box-shadow: 0 1px 3px rgba(0, 0, 0, 0.15);
  669. &-item {
  670. margin-bottom: 12px;
  671. display: flex;
  672. align-items: center;
  673. gap: 8px;
  674. &-label {
  675. width: 100px;
  676. }
  677. &-labelend {
  678. width: 140px;
  679. }
  680. &:last-child {
  681. margin-bottom: 0;
  682. }
  683. :deep(.ant-form-item) {
  684. flex: 1;
  685. margin-bottom: 0;
  686. }
  687. }
  688. }
  689. </style>