form.vue 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552
  1. <template>
  2. <xn-form-container
  3. :title="formData.id ? '编辑点位' : '新增点位'"
  4. :width="'800px'"
  5. :visible="visible"
  6. :destroy-on-close="true"
  7. @close="onClose"
  8. >
  9. <a-form
  10. ref="formRef"
  11. :model="formData"
  12. :rules="formRules"
  13. layout="inline"
  14. :label-col="{ style: { width: '110px', justifyContent: 'end' } }"
  15. >
  16. <a-row :gutter="10">
  17. <!-- 选择点位 -->
  18. <div class="dict">
  19. <span>点位标签:</span>
  20. <a-radio-group
  21. v-model:value="pointName"
  22. :options="pointOptions"
  23. option-type="button"
  24. @change="pointNameChange(pointName)"
  25. >
  26. </a-radio-group>
  27. </div>
  28. <a-col :xs="24" :sm="24" :md="12" :lg="12" :xl="12">
  29. <a-form-item label="监测对象" name="monitorTargetId">
  30. <a-select
  31. ref="select"
  32. v-model:value="formData.monitorTargetId"
  33. :options="monitorTargetOptions"
  34. placeholder="请选择监测对象"
  35. :field-names="{ label: 'name', value: 'id' }"
  36. disabled
  37. />
  38. </a-form-item>
  39. </a-col>
  40. <a-col :xs="24" :sm="24" :md="12" :lg="12" :xl="12">
  41. <a-form-item label="点位名称" name="name">
  42. <a-input :value="formData.name" placeholder="请输入点位名称" allow-clear @input="nameInput" :max="20" />
  43. </a-form-item>
  44. </a-col>
  45. <a-col :xs="24" :sm="24" :md="12" :lg="12" :xl="12">
  46. <a-form-item label="传感器类型" name="sensorType">
  47. <a-select
  48. ref="select"
  49. v-model:value="formData.sensorType"
  50. :options="sensorOptions"
  51. placeholder="请选择传感器类型"
  52. @change="sensorTypeChange"
  53. />
  54. </a-form-item>
  55. </a-col>
  56. <a-col :xs="24" :sm="24" :md="12" :lg="12" :xl="12">
  57. <a-form-item label="监测设备" name="monitorDeviceId">
  58. <a-select
  59. ref="select"
  60. v-model:value="formData.monitorDeviceId"
  61. :options="memListOptions"
  62. placeholder="请选择监测设备"
  63. :field-names="{ label: 'deviceName', value: 'id' }"
  64. @change="monitorDeviceIdChange"
  65. />
  66. </a-form-item>
  67. </a-col>
  68. <a-col :xs="24" :sm="24" :md="12" :lg="12" :xl="12" v-if="formData.monitorDeviceId">
  69. <a-form-item label="传感器编号" name="sensorCode">
  70. <a-input v-model:value="formData.sensorCode" disabled placeholder="请输入传感器编号" allow-clear />
  71. </a-form-item>
  72. </a-col>
  73. <a-col :xs="24" :sm="24" :md="12" :lg="12" :xl="12" v-if="formData.monitorDeviceId">
  74. <a-form-item label="传感器路数" name="sensorRoute">
  75. <a-radio-group v-model:value="formData.sensorRoute">
  76. <a-radio-button v-for="i in sensorRouteMax" :key="i" :value="i" :disabled="isRouteDisabled(i)">
  77. {{ i }}路
  78. </a-radio-button>
  79. </a-radio-group>
  80. </a-form-item>
  81. </a-col>
  82. <!-- 报警接收人 -->
  83. <a-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24">
  84. <a-form-item label="报警接收人" name="alarmUsers">
  85. <a-checkbox-group v-model:value="formData.alarmUsers" name="checkboxgroup">
  86. <a-checkbox
  87. v-for="option in alarmUsersOptions"
  88. :key="option.openId"
  89. :value="option.openId"
  90. :label="option.nickName"
  91. >
  92. {{ option.nickName }}
  93. </a-checkbox>
  94. </a-checkbox-group>
  95. </a-form-item>
  96. </a-col>
  97. <!-- 选择冰箱型号 -->
  98. <div class="dict" v-if="formData.sensorType && formData.monitorDeviceId">
  99. <span>冰箱型号:</span>
  100. <a-radio-group v-model:value="fridgeName" option-type="button" @change="fridgeNameChange(fridgeName)">
  101. <a-radio-button
  102. v-for="e in filteredFridges"
  103. :key="e.value"
  104. :value="e.value"
  105. :label="e.label"
  106. :disabled="e.disabled"
  107. >
  108. <database-outlined /> {{ e.label }}</a-radio-button
  109. >
  110. </a-radio-group>
  111. </div>
  112. <div
  113. class="form_item"
  114. v-if="formData.sensorType == 'W' || formData.sensorType == 'WS' || formData.sensorType == 'WSC'"
  115. >
  116. <a-col :xs="24" :sm="24" :md="12" :lg="12" :xl="12">
  117. <a-form-item label="温度上限" name="temperatureUp">
  118. <a-input-number
  119. id="inputNumber"
  120. v-model:value="formData.temperatureUp"
  121. placeholder="请输入温度上限"
  122. allow-clear
  123. :min="currentMonitorDevice.temperatureDown"
  124. :max="currentMonitorDevice.temperatureUp"
  125. style="width: 100%"
  126. :disabled="!currentMonitorDevice.temperatureUp"
  127. />
  128. </a-form-item>
  129. </a-col>
  130. <a-col :xs="24" :sm="24" :md="12" :lg="12" :xl="12">
  131. <a-form-item label="温度下限" name="temperatureDown">
  132. <a-input-number
  133. id="inputNumber"
  134. v-model:value="formData.temperatureDown"
  135. placeholder="请输入温度下限"
  136. allow-clear
  137. :min="currentMonitorDevice.temperatureDown"
  138. :max="currentMonitorDevice.temperatureUp"
  139. style="width: 100%"
  140. :disabled="!currentMonitorDevice.temperatureDown"
  141. />
  142. </a-form-item>
  143. </a-col>
  144. </div>
  145. <div class="form_item" v-if="formData.sensorType == 'WS' || formData.sensorType == 'WSC'">
  146. <a-col :xs="24" :sm="24" :md="12" :lg="12" :xl="12">
  147. <a-form-item label="湿度上限" name="humidityUp">
  148. <a-input-number
  149. id="inputNumber"
  150. v-model:value="formData.humidityUp"
  151. placeholder="请输入湿度上限"
  152. allow-clear
  153. :min="currentMonitorDevice.humidityDown"
  154. :max="currentMonitorDevice.humidityUp"
  155. style="width: 100%"
  156. :disabled="!currentMonitorDevice.humidityUp"
  157. />
  158. </a-form-item>
  159. </a-col>
  160. <a-col :xs="24" :sm="24" :md="12" :lg="12" :xl="12">
  161. <a-form-item label="湿度下限" name="humidityDown">
  162. <a-input-number
  163. id="inputNumber"
  164. v-model:value="formData.humidityDown"
  165. placeholder="请输入湿度下限"
  166. allow-clear
  167. :min="currentMonitorDevice.humidityDown"
  168. :max="currentMonitorDevice.humidityUp"
  169. style="width: 100%"
  170. :disabled="!currentMonitorDevice.humidityDown"
  171. />
  172. </a-form-item>
  173. </a-col>
  174. </div>
  175. <div class="form_item" v-if="formData.sensorType == 'WSC'">
  176. <a-col :xs="24" :sm="24" :md="12" :lg="12" :xl="12">
  177. <a-form-item label="CO2上限" name="co2Up">
  178. <a-input-number
  179. id="inputNumber"
  180. v-model:value="formData.co2Up"
  181. placeholder="请输入CO2上限"
  182. allow-clear
  183. :max="currentMonitorDevice.co2Up"
  184. :min="currentMonitorDevice.co2Down"
  185. style="width: 100%"
  186. :disabled="!currentMonitorDevice.co2Up"
  187. />
  188. </a-form-item>
  189. </a-col>
  190. <a-col :xs="24" :sm="24" :md="12" :lg="12" :xl="12">
  191. <a-form-item label="CO2下限" name="co2Down">
  192. <a-input-number
  193. id="inputNumber"
  194. v-model:value="formData.co2Down"
  195. placeholder="请输入CO2下限"
  196. allow-clear
  197. :max="currentMonitorDevice.co2Up"
  198. :min="currentMonitorDevice.co2Down"
  199. style="width: 100%"
  200. :disabled="!currentMonitorDevice.co2Down"
  201. />
  202. </a-form-item>
  203. </a-col>
  204. </div>
  205. <a-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24">
  206. <a-form-item label="勿扰设置">
  207. <a-time-range-picker v-model:value="formData.time" value-format="HH:mm:ss" style="width: 80%" show-time />
  208. </a-form-item>
  209. </a-col>
  210. </a-row>
  211. </a-form>
  212. <template #footer>
  213. <a-button class="xn-mr8" @click="onClose">取消</a-button>
  214. <a-button type="primary" @click="onSubmit">保存</a-button>
  215. </template>
  216. </xn-form-container>
  217. </template>
  218. <script setup>
  219. import { message } from 'ant-design-vue'
  220. import { debounce } from 'lodash-es'
  221. import tool from '@/utils/tool'
  222. import { required } from '@/utils/formRules'
  223. import locationApi from '@/api/basicset/locationApi.js'
  224. import setupApi from '@/api/basicset/setupApi'
  225. import memApi from '@/api/basicset/memApi'
  226. const emit = defineEmits({ successful: null })
  227. const visible = ref(false) // 默认是关闭状态
  228. const formRef = ref()
  229. const formData = ref({ alarmUsers: [], time: [] }) // 表单数据
  230. const pointOptions = tool.dictList('MONITORPOINT') // 点位名称
  231. const pointName = ref('上层')
  232. const currentMonitorObj = ref({}) //当前的监测对象
  233. const sensorOptions = tool.dictList('SENSORTYPE') // 传感器类型
  234. const alarmUsersOptions = ref([]) // 报警接收人数据
  235. const fridgeOptions = tool.dictList('REFRIGERATORSMODEL') // 冰箱型号
  236. const monitorTargetOptions = ref([]) // 监测对象
  237. const memListOptions = ref([]) // 监测设备
  238. const currentMonitorDevice = ref({}) //当前的监测设备
  239. const sensorRouteMax = ref(1) //传感器最大值默认1
  240. // 默认要校验的
  241. const formRules = {
  242. name: [required('请输入点位名称')],
  243. monitorTargetId: [required('请选择监测对象')],
  244. monitorDeviceId: [required('请选择监测设备')],
  245. sensorType: [required('请选择传感器类型')],
  246. sensorRoute: [required('请输入传感器路数')],
  247. alarmUsers: [required('请选择报警接收人')],
  248. temperatureUp: [{ validator: validateTemperature, trigger: ['change', 'blur'] }],
  249. temperatureDown: [{ validator: validateTemperature, trigger: ['change', 'blur'] }],
  250. humidityUp: [{ validator: validateHumidity, trigger: ['change', 'blur'] }],
  251. humidityDown: [{ validator: validateHumidity, trigger: ['change', 'blur'] }],
  252. co2Up: [{ validator: validateCo2, trigger: ['change', 'blur'] }],
  253. co2Down: [{ validator: validateCo2, trigger: ['change', 'blur'] }]
  254. }
  255. // 温度上下限校验
  256. function validateTemperature(rule, value, callback) {
  257. if (rule.field == 'temperatureDown') {
  258. if (formData.value.temperatureUp !== null && value >= formData.value.temperatureUp) {
  259. callback(new Error('温度下限不能大于或等于温度上限:' + formData.value.temperatureUp))
  260. } else {
  261. callback()
  262. }
  263. } else if (rule.field == 'temperatureUp') {
  264. if (formData.value.temperatureDown !== null && value <= formData.value.temperatureDown) {
  265. callback(new Error('温度上限不能小于或等于温度下限:' + formData.value.temperatureDown))
  266. } else {
  267. callback()
  268. }
  269. }
  270. }
  271. // 湿度上下限校验
  272. function validateHumidity(rule, value, callback) {
  273. if (rule.field == 'humidityDown') {
  274. if (formData.value.humidityUp !== null && value >= formData.value.humidityUp) {
  275. callback(new Error('湿度下限不能大于或等于湿度上限:' + formData.value.humidityUp))
  276. } else {
  277. callback()
  278. }
  279. } else if (rule.field == 'humidityUp') {
  280. if (formData.value.humidityDown !== null && value <= formData.value.humidityDown) {
  281. callback(new Error('湿度上限不能小于或等于湿度下限:' + formData.value.humidityDown))
  282. } else {
  283. callback()
  284. }
  285. }
  286. }
  287. // CO2上下限校验
  288. function validateCo2(rule, value, callback) {
  289. if (rule.field == 'co2Down') {
  290. if (formData.value.co2Up !== null && value >= formData.value.co2Up) {
  291. callback(new Error('CO2下限不能大于或等于CO2上限:' + formData.value.co2Up))
  292. } else {
  293. callback()
  294. }
  295. } else if (rule.field == 'co2Up') {
  296. if (formData.value.co2Down !== null && value <= formData.value.co2Down) {
  297. callback(new Error('CO2上限不能小于或等于CO2下限:' + formData.value.co2Down))
  298. } else {
  299. callback()
  300. }
  301. }
  302. }
  303. // 打开抽屉
  304. const onOpen = (type, record) => {
  305. setupListData(type, record)
  306. memListData()
  307. visible.value = true
  308. if (!record) {
  309. formData.value = ref({ alarmUsers: [], time: [] })
  310. }
  311. }
  312. // 选中的点位标签
  313. const pointNameChange = (val) => {
  314. pointName.value = val
  315. formData.value.name = currentMonitorObj.value.name + '-' + pointName.value
  316. }
  317. // 选中的冰箱标签
  318. const fridgeNameChange = (val) => {
  319. const data = fridgeRanges.value[val]
  320. formData.value = {
  321. ...formData.value,
  322. temperatureUp: data.up, //温度上限
  323. temperatureDown: data.down //温度下限
  324. }
  325. }
  326. // 获取监测对象
  327. const setupListData = (type, record) => {
  328. setupApi
  329. .setupList({ isAll: false })
  330. .then((res) => {
  331. monitorTargetOptions.value = res || []
  332. currentMonitorObj.value = monitorTargetOptions.value.find((item) => item.id === record.monitorTargetId) //当前的监测对象
  333. alarmUsersOptions.value = currentMonitorObj.value.alarmUsers || [] //报警接收人
  334. })
  335. .finally(() => {
  336. formData.value = Object.assign({}, record)
  337. if (type == 'add') {
  338. formData.value.name = currentMonitorObj.value.name + '-' + pointName.value
  339. } else {
  340. formData.value.time = [
  341. formData.value.ignoreStartTime ? formData.value.ignoreStartTime : null,
  342. formData.value.ignoreEndTime ? formData.value.ignoreEndTime : null
  343. ]
  344. if (formData.value.alarmUsers && formData.value.alarmUsers.length > 0) {
  345. formData.value.alarmUsers = formData.value.alarmUsers.map((item) => item.openId)
  346. }
  347. memListData(formData.value.sensorType)
  348. }
  349. })
  350. }
  351. // 名称输入
  352. const nameInput = (e) => {
  353. const val = e.target.value
  354. if (!val.startsWith(formData.value.name)) {
  355. formData.value.name = formData.value._name
  356. message.warning({
  357. content: '名称必须以 "监测对象名称" + ' + pointName.value + ' 开头',
  358. key: 'name'
  359. })
  360. } else {
  361. formData.value.name = val
  362. }
  363. }
  364. // 选中传感器类型
  365. const sensorTypeChange = (value) => {
  366. if (value) {
  367. memListData(value)
  368. monitorDeviceIdChange()
  369. }
  370. }
  371. // 监测设备通过传感器类型来获取, sensorType可为空
  372. const memListData = (value) => {
  373. memApi.memList({ isAll: false, sensorType: value }).then((res) => {
  374. memListOptions.value = res || []
  375. })
  376. }
  377. // 选中监测设备
  378. const monitorDeviceIdChange = (value) => {
  379. fridgeName.value = null
  380. if (value) {
  381. askRegionByDeviceIdData(value)
  382. const data = memListOptions.value.find((item) => item.id === value)
  383. currentMonitorDevice.value = data //选中的监测设备
  384. formData.value = {
  385. ...formData.value,
  386. sensorCode: data.deviceCode, //传感器编号
  387. modelName: data.modelName, //监测设备型号
  388. deviceCode: data.deviceCode, //冷链编号
  389. temperatureUp: data.temperatureUp, //温度上限
  390. temperatureDown: data.temperatureDown, //温度下限
  391. humidityUp: data.humidityUp, //湿度上限
  392. humidityDown: data.humidityDown, //湿度下限
  393. co2Up: data.co2Up, //CO2上限
  394. co2Down: data.co2Down //CO2下限
  395. }
  396. sensorRouteMax.value = data.sensorCount //传感器路数的最大值
  397. isFridgeDisabled()
  398. } else {
  399. // 清理掉监测设备的一些信息
  400. currentMonitorDevice.value = {}
  401. sensorRouteMax.value = 1
  402. formData.value = {
  403. ...formData.value,
  404. monitorDeviceId: null, //监测设备
  405. sensorRoute: null, //传感器路数
  406. sensorCode: null, //传感器编号
  407. modelName: null, //监测设备型号
  408. deviceCode: null, //冷链编号
  409. temperatureUp: null, //温度上限
  410. temperatureDown: null, //温度下限
  411. humidityUp: null, //湿度上限
  412. humidityDown: null, //湿度下限
  413. co2Up: null, //CO2上限
  414. co2Down: null //CO2下限
  415. }
  416. }
  417. }
  418. const fridgeName = ref() //选择的冰箱型号
  419. const fridgeRanges = ref({
  420. '-80': { up: -70, down: -80 },
  421. '-40': { up: -30, down: -40 },
  422. 4: { up: 14, down: 4 },
  423. '-196': { up: -186, down: -196 }
  424. })
  425. const filteredFridges = ref([])
  426. // 判断 当前的监测设备 的温度范围是否在该冰箱的温度范围内
  427. const isFridgeDisabled = () => {
  428. console.log(currentMonitorDevice.value.temperatureUp, currentMonitorDevice.value.temperatureDown)
  429. filteredFridges.value = fridgeOptions.map((fridge) => {
  430. const { up, down } = fridgeRanges.value[fridge.value]
  431. const isDisabled =
  432. up < currentMonitorDevice.value.temperatureDown || down > currentMonitorDevice.value.temperatureUp
  433. return {
  434. ...fridge,
  435. disabled: isDisabled
  436. }
  437. })
  438. }
  439. const useSensorRoute = ref([]) //已使用的传感器路数
  440. // 根据检测设备id获取已使用的路数
  441. const askRegionByDeviceIdData = (value) => {
  442. if (value) {
  443. memApi.getRegionByDeviceIdData({ deviceId: value }).then((res) => {
  444. useSensorRoute.value = res
  445. })
  446. }
  447. }
  448. // 检查该路是否已被禁用
  449. const isRouteDisabled = (route) => {
  450. // 通过遍历useSensorRoute中的数据,判断该路是否已被占用
  451. return useSensorRoute.value.some((item) => item.sensorRoute === route)
  452. }
  453. // 验证并提交数据
  454. const onSubmit = () => {
  455. formRef.value
  456. .validate()
  457. .then(() => {
  458. const parameter = {
  459. ...formData.value,
  460. alarmUsers: alarmUsersOptions.value.filter((user) => formData.value.alarmUsers.includes(user.openId)),
  461. ignoreStartTime: formData.value.time && formData.value.time.length ? formData.value.time[0] : null,
  462. ignoreEndTime: formData.value.time && formData.value.time.length ? formData.value.time[1] : null
  463. }
  464. delete parameter.time
  465. locationApi.submitForm(parameter, formData.value.id).then(() => {
  466. onClose()
  467. emit('successful')
  468. })
  469. })
  470. .catch((error) => {
  471. console.log(error)
  472. })
  473. }
  474. // 关闭抽屉
  475. const onClose = () => {
  476. memListOptions.value = []
  477. currentMonitorObj.value = {}
  478. pointName.value = '上层'
  479. fridgeName.value = null
  480. formRef.value.resetFields()
  481. visible.value = false
  482. }
  483. // 调用这个函数将子组件的一些数据和方法暴露出去
  484. defineExpose({
  485. onOpen
  486. })
  487. </script>
  488. <style lang="less" scoped>
  489. .dict {
  490. width: 100%;
  491. padding: 0 10px 0px 45px;
  492. :deep(.ant-radio-button-wrapper) {
  493. margin: 5px 5px 10px 0px;
  494. }
  495. :deep(.ant-radio-button-wrapper-checked) {
  496. color: #2b61ff;
  497. background-color: #e6f3ff;
  498. }
  499. }
  500. :deep(.ant-form-item) {
  501. width: 100%;
  502. margin-bottom: 10px;
  503. }
  504. .form_item {
  505. width: 100%;
  506. display: flex;
  507. align-items: center;
  508. justify-content: center;
  509. flex-wrap: wrap;
  510. }
  511. </style>