DeviceCtrlModal.vue 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393
  1. <script setup lang="ts">
  2. import { computed, onUnmounted, ref, watch } from 'vue';
  3. import { useRouter } from 'vue-router';
  4. import { useFullscreen } from '@vueuse/core';
  5. import { Modal } from 'ant-design-vue';
  6. import SvgIcon from '@/components/SvgIcon.vue';
  7. import { useRequest } from '@/hooks/request';
  8. import { useViewVisible } from '@/hooks/view-visible';
  9. import { t } from '@/i18n';
  10. import { getGroupModuleDevData, updateGroupModuleDevData } from '@/api';
  11. import { isNotEmptyVal } from '@/utils';
  12. import { DevParamChillerUnit, DevParamCoolingPump, DevParamCoolingTower } from '@/constants/device-params';
  13. import { DeviceType } from '../device-work-status/device-card';
  14. import type { EquipmentDetailsItem } from '@/types';
  15. interface Props {
  16. info?: EquipmentDetailsItem;
  17. }
  18. const props = defineProps<Props>();
  19. defineEmits<{
  20. openDevBatchExe: [];
  21. }>();
  22. const { visible, showView, hideView } = useViewVisible();
  23. const { isLoading, handleRequest } = useRequest();
  24. const deviceRealTimeData = ref<Record<string, number | string | undefined>>({});
  25. let deviceRTDTimer: number | undefined;
  26. const deviceType = computed(() => {
  27. return props.info?.deviceQueryVo.deviceType;
  28. });
  29. const disableStartStopCtrl = computed(() => {
  30. const { isLocale, isAuto, isDisable } = getDeviceStatus();
  31. return isLocale || isAuto || isDisable;
  32. });
  33. const startStopTip = computed(() => {
  34. const { isLocale, isAuto, isDisable } = getDeviceStatus();
  35. const tips: string[] = [];
  36. if (isLocale) {
  37. tips.push(t('realTimeMonitor.startStopControlTipLocal'));
  38. }
  39. if (isAuto) {
  40. tips.push(t('realTimeMonitor.startStopControlTipAuto'));
  41. }
  42. if (isDisable) {
  43. tips.push(t('realTimeMonitor.startStopControlTipDisable'));
  44. }
  45. let tipText = '';
  46. tips.forEach((item, index) => {
  47. tipText += `${index + 1}. ${item};\n`;
  48. });
  49. return tipText;
  50. });
  51. const getDeviceStatus = () => {
  52. const { localRemoteStatus, manualAutoStatus, disableEnableStatus } = deviceRealTimeData.value;
  53. return {
  54. isLocale: localRemoteStatus === '本地',
  55. isAuto: manualAutoStatus === 1,
  56. isDisable: disableEnableStatus === 0,
  57. };
  58. };
  59. watch(visible, () => {
  60. if (visible.value) {
  61. getDeviceData();
  62. } else {
  63. deviceRealTimeData.value = {};
  64. clearTimeout(deviceRTDTimer);
  65. }
  66. });
  67. onUnmounted(() => {
  68. deviceRealTimeData.value = {};
  69. clearTimeout(deviceRTDTimer);
  70. });
  71. const getDeviceData = () => {
  72. clearTimeout(deviceRTDTimer);
  73. handleRequest(async () => {
  74. if (!props.info?.deviceQueryVo) {
  75. return;
  76. }
  77. const { id, deviceType } = props.info.deviceQueryVo;
  78. const data = await getGroupModuleDevData(id, deviceType);
  79. data.dataList.forEach((item) => {
  80. deviceRealTimeData.value[item.dataCode] = item.value;
  81. });
  82. });
  83. deviceRTDTimer = window.setTimeout(getDeviceData, 3000);
  84. };
  85. const updateDeviceData = (paramCode: string, value?: string | number | null) => {
  86. handleRequest(async () => {
  87. if (!props.info?.deviceQueryVo) {
  88. return;
  89. }
  90. const { id } = props.info.deviceQueryVo;
  91. if (isNotEmptyVal(value)) {
  92. await updateGroupModuleDevData(id, paramCode, value);
  93. }
  94. });
  95. };
  96. const handleDisableEnableSwitch = () => {
  97. const { disableEnableStatus } = deviceRealTimeData.value;
  98. const title = disableEnableStatus ? t('common.disable') : t('common.enable');
  99. const value = disableEnableStatus ? 0 : 1;
  100. Modal.confirm({
  101. title: t('realTimeMonitor.confirmSwitchToMode', { mode: title }),
  102. closable: true,
  103. centered: true,
  104. onOk() {
  105. updateDeviceData('disableEnableStatus', value);
  106. },
  107. });
  108. };
  109. const handleAutoManualSwitch = () => {
  110. const { manualAutoStatus } = deviceRealTimeData.value;
  111. const title = manualAutoStatus ? t('common.manual') : t('common.automatic');
  112. const content = manualAutoStatus
  113. ? t('realTimeMonitor.confirmSwitchToManualTip')
  114. : t('realTimeMonitor.confirmSwitchToAutoTip');
  115. const value = manualAutoStatus ? 0 : 1;
  116. Modal.confirm({
  117. title: t('realTimeMonitor.confirmSwitchToMode', { mode: title }),
  118. content,
  119. closable: true,
  120. centered: true,
  121. onOk() {
  122. updateDeviceData('manualAutoStatus', value);
  123. },
  124. });
  125. };
  126. const handleStartStopSwitch = () => {
  127. const { startStopOrder } = deviceRealTimeData.value;
  128. const title = startStopOrder ? t('common.confirmClose') : t('common.confirmOpen');
  129. const value = startStopOrder ? 0 : 1;
  130. Modal.confirm({
  131. title: title + props.info?.deviceQueryVo.deviceName,
  132. closable: true,
  133. centered: true,
  134. onOk() {
  135. updateDeviceData('startStopOrder', value);
  136. },
  137. });
  138. };
  139. const router = useRouter();
  140. const { exit } = useFullscreen();
  141. const goDevWorkStatus = () => {
  142. if (!props.info?.deviceQueryVo) {
  143. return;
  144. }
  145. const { id, groupId, deviceType } = props.info.deviceQueryVo;
  146. exit();
  147. router.push({
  148. path: `/ai-smart-ctrl/device-group/${groupId}`,
  149. query: {
  150. tab: 'deviceWorkStatus',
  151. deviceId: id,
  152. deviceType,
  153. r: Date.now(),
  154. },
  155. });
  156. };
  157. defineExpose({
  158. showView,
  159. hideView,
  160. });
  161. </script>
  162. <template>
  163. <AModal
  164. v-model:open="visible"
  165. wrap-class-name="hvac-modal"
  166. :closable="false"
  167. :centered="true"
  168. :width="460"
  169. :footer="null"
  170. >
  171. <template #title>
  172. <div class="dev-ctrl-modal-header">
  173. <span>{{ info?.deviceQueryVo.deviceName }}</span>
  174. <span class="dev-ctrl-modal-operate" @click="goDevWorkStatus">
  175. {{ $t('common.viewMore') }}
  176. <SvgIcon name="right" />
  177. </span>
  178. </div>
  179. </template>
  180. <template v-if="deviceType === DeviceType.冷水主机">
  181. <div class="dev-ctrl-modal-item">
  182. <span>{{ $t('realTimeMonitor.chilledWaterOutletTemperature') }}</span>
  183. <span>{{ deviceRealTimeData[DevParamChillerUnit.冷冻水出水温度] ?? '-' }}℃</span>
  184. </div>
  185. <div class="dev-ctrl-modal-item">
  186. <span>{{ $t('realTimeMonitor.loadRate') }}</span>
  187. <span>{{ deviceRealTimeData[DevParamChillerUnit.负载率] ?? '-' }}%</span>
  188. </div>
  189. <div class="dev-ctrl-modal-item">
  190. <span>{{ $t('realTimeMonitor.activePower') }}</span>
  191. <span>{{ deviceRealTimeData[DevParamChillerUnit.有功功率] ?? '-' }}kW</span>
  192. </div>
  193. </template>
  194. <template v-if="deviceType === DeviceType.冷却塔">
  195. <div class="dev-ctrl-modal-item">
  196. <span>{{ $t('realTimeMonitor.localRemoteStatus') }}</span>
  197. <span>{{ deviceRealTimeData[DevParamCoolingTower.本地远程状态] ?? '-' }}</span>
  198. </div>
  199. <div class="dev-ctrl-modal-item">
  200. <span>{{ $t('realTimeMonitor.activePower') }}</span>
  201. <span>{{ deviceRealTimeData[DevParamCoolingTower.有功功率] ?? '-' }}kW</span>
  202. </div>
  203. <div class="dev-ctrl-modal-item">
  204. <span>{{ $t('realTimeMonitor.runningTime') }}</span>
  205. <span>{{ deviceRealTimeData[DevParamCoolingTower.运行时间] ?? '-' }}{{ $t('common.hour') }}</span>
  206. </div>
  207. </template>
  208. <template v-if="deviceType === DeviceType.冷冻泵 || deviceType === DeviceType.冷却泵">
  209. <div class="dev-ctrl-modal-item">
  210. <span>{{ $t('realTimeMonitor.localRemoteStatus') }}</span>
  211. <span>{{ deviceRealTimeData[DevParamCoolingPump.本地远程状态] ?? '-' }}</span>
  212. </div>
  213. <div class="dev-ctrl-modal-item">
  214. <span>{{ $t('realTimeMonitor.activePower') }}</span>
  215. <span>{{ deviceRealTimeData[DevParamCoolingPump.有功功率] ?? '-' }}kW</span>
  216. </div>
  217. <div class="dev-ctrl-modal-item">
  218. <span>{{ $t('realTimeMonitor.runningTime') }}</span>
  219. <span>{{ deviceRealTimeData[DevParamCoolingPump.运行时间] ?? '-' }}{{ $t('common.hour') }}</span>
  220. </div>
  221. </template>
  222. <div class="dev-ctrl-modal-separator"></div>
  223. <div class="dev-ctrl-modal-item">
  224. <span></span>
  225. <span class="dev-ctrl-modal-operate" @click="$emit('openDevBatchExe')">
  226. {{ $t('common.batchExecution') }}
  227. <SvgIcon name="right" />
  228. </span>
  229. </div>
  230. <div class="dev-ctrl-modal-item">
  231. <span>{{ $t('realTimeMonitor.enableDisable') }}</span>
  232. <ASwitch
  233. :checked="deviceRealTimeData.disableEnableStatus"
  234. :checked-value="1"
  235. :un-checked-value="0"
  236. @click="handleDisableEnableSwitch"
  237. />
  238. </div>
  239. <div class="dev-ctrl-modal-item">
  240. <span>{{ $t('realTimeMonitor.autoManual') }}</span>
  241. <ASwitch
  242. :checked="deviceRealTimeData.manualAutoStatus"
  243. :checked-value="1"
  244. :un-checked-value="0"
  245. @click="handleAutoManualSwitch"
  246. />
  247. </div>
  248. <div class="dev-ctrl-modal-item">
  249. <span>{{ $t('realTimeMonitor.startStopControl') }}</span>
  250. <span class="dev-ctrl-modal-start-stop-right">
  251. <ATooltip overlay-class-name="hvac-tooltip">
  252. <template #title>{{ startStopTip }}</template>
  253. <SvgIcon v-show="disableStartStopCtrl" name="info-cirlce-o" />
  254. </ATooltip>
  255. <ASwitch
  256. :checked="deviceRealTimeData.startStopOrder"
  257. :checked-value="1"
  258. :un-checked-value="0"
  259. :disabled="disableStartStopCtrl"
  260. @click="handleStartStopSwitch"
  261. />
  262. </span>
  263. </div>
  264. <template v-if="deviceType === DeviceType.冷水主机">
  265. <div class="dev-ctrl-modal-item">
  266. <span>{{ $t('realTimeMonitor.chilledWaterOutletSetValue') }}</span>
  267. <AInputNumber
  268. class="dev-ctrl-chiller-input"
  269. v-model:value="deviceRealTimeData[DevParamChillerUnit.冷冻水出水温度设定值]"
  270. :controls="false"
  271. @change="updateDeviceData(DevParamChillerUnit.冷冻水出水温度设定值, $event)"
  272. />
  273. </div>
  274. <div class="dev-ctrl-modal-item">
  275. <span>{{ $t('realTimeMonitor.loadRateLimitSetValue') }}</span>
  276. <AInputNumber
  277. class="dev-ctrl-chiller-input"
  278. v-model:value="deviceRealTimeData[DevParamChillerUnit.负载率限制设定值]"
  279. :controls="false"
  280. @change="updateDeviceData(DevParamChillerUnit.负载率限制设定值, $event)"
  281. />
  282. </div>
  283. </template>
  284. <ASpin v-if="isLoading" class="center-loading" :spinning="true" />
  285. </AModal>
  286. </template>
  287. <style lang="scss" scoped>
  288. .dev-ctrl-modal-header {
  289. display: flex;
  290. align-items: center;
  291. justify-content: space-between;
  292. }
  293. .dev-ctrl-modal-item {
  294. display: flex;
  295. align-items: center;
  296. justify-content: space-between;
  297. line-height: 24px;
  298. > span {
  299. &:first-child {
  300. color: var(--antd-color-text-secondary);
  301. }
  302. &:last-child {
  303. color: var(--antd-color-text);
  304. }
  305. }
  306. > span.dev-ctrl-modal-operate {
  307. color: var(--antd-color-primary);
  308. }
  309. & + & {
  310. margin-top: 16px;
  311. }
  312. }
  313. .dev-ctrl-modal-separator {
  314. margin-block: 16px;
  315. border: 1px solid #e4e7ed;
  316. }
  317. .dev-ctrl-modal-operate {
  318. display: flex;
  319. align-items: center;
  320. font-size: 14px;
  321. font-weight: 500;
  322. color: var(--antd-color-primary);
  323. cursor: pointer;
  324. i {
  325. margin-left: 8px;
  326. font-size: 12px;
  327. }
  328. }
  329. .dev-ctrl-modal-start-stop-right {
  330. display: flex;
  331. align-items: center;
  332. i {
  333. margin-right: 8px;
  334. font-size: 12px;
  335. color: #999;
  336. }
  337. }
  338. .dev-ctrl-chiller-input {
  339. width: 120px;
  340. }
  341. </style>