|
@@ -0,0 +1,290 @@
|
|
|
|
+<script setup lang="ts">
|
|
|
|
+import { computed, ref } from 'vue';
|
|
|
|
+import { message, Modal } from 'ant-design-vue';
|
|
|
|
+
|
|
|
|
+import SvgIcon from '@/components/SvgIcon.vue';
|
|
|
|
+import { t } from '@/i18n';
|
|
|
|
+
|
|
|
|
+import type { SegmentedBaseOption } from 'ant-design-vue/es/segmented/src/segmented';
|
|
|
|
+
|
|
|
|
+type ModeValue = 'fullAuto' | 'halfAuto' | 'jog';
|
|
|
|
+
|
|
|
|
+interface ModeTypeItem extends SegmentedBaseOption {
|
|
|
|
+ value: ModeValue;
|
|
|
|
+ payload: {
|
|
|
|
+ title: string;
|
|
|
|
+ confirmTip: string;
|
|
|
|
+ };
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+const modeTypes = computed<ModeTypeItem[]>(() => {
|
|
|
|
+ return [
|
|
|
|
+ {
|
|
|
|
+ value: 'fullAuto',
|
|
|
|
+ payload: {
|
|
|
|
+ title: t('realTimeMonitor.fullAutoMode'),
|
|
|
|
+ confirmTip: t('realTimeMonitor.fullAutoConfirmTip'),
|
|
|
|
+ },
|
|
|
|
+ },
|
|
|
|
+ {
|
|
|
|
+ value: 'halfAuto',
|
|
|
|
+ payload: {
|
|
|
|
+ title: t('realTimeMonitor.halfAutoMode'),
|
|
|
|
+ confirmTip: t('realTimeMonitor.halfAutoConfirmTip'),
|
|
|
|
+ },
|
|
|
|
+ },
|
|
|
|
+ {
|
|
|
|
+ value: 'jog',
|
|
|
|
+ disabled: true,
|
|
|
|
+ payload: {
|
|
|
|
+ title: t('realTimeMonitor.jogMode'),
|
|
|
|
+ confirmTip: '',
|
|
|
|
+ },
|
|
|
|
+ },
|
|
|
|
+ ];
|
|
|
|
+});
|
|
|
|
+
|
|
|
|
+const currentModeType = ref<ModeValue>('fullAuto');
|
|
|
|
+
|
|
|
|
+const handleModeClick = (option: ModeTypeItem) => {
|
|
|
|
+ if (option.disabled || option.value === currentModeType.value) {
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ Modal.confirm({
|
|
|
|
+ title: t('realTimeMonitor.confirmSwitchToMode', { mode: option.payload.title }),
|
|
|
|
+ content: option.payload.confirmTip,
|
|
|
|
+ closable: true,
|
|
|
|
+ async onOk() {
|
|
|
|
+ try {
|
|
|
|
+ currentModeType.value = option.value;
|
|
|
|
+ } catch (err) {
|
|
|
|
+ message.error((err as Error).message);
|
|
|
|
+ console.error(err);
|
|
|
|
+ }
|
|
|
|
+ },
|
|
|
|
+ });
|
|
|
|
+};
|
|
|
|
+
|
|
|
|
+type DeviceStatus = 'on' | 'off';
|
|
|
|
+
|
|
|
|
+interface DeviceItem {
|
|
|
|
+ name: string;
|
|
|
|
+ status: DeviceStatus;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+const deviceList = ref<DeviceItem[]>([
|
|
|
|
+ { name: '五期-1#冷水主机', status: 'off' },
|
|
|
|
+ { name: '五期-2#冷水主机', status: 'on' },
|
|
|
|
+ { name: '五期-3#冷水主机', status: 'off' },
|
|
|
|
+ { name: '五期-3#冷水主机', status: 'off' },
|
|
|
|
+]);
|
|
|
|
+</script>
|
|
|
|
+
|
|
|
|
+<template>
|
|
|
|
+ <div class="ai-start-stop-container">
|
|
|
|
+ <ASegmented :value="currentModeType" :options="modeTypes">
|
|
|
|
+ <template #label="option">
|
|
|
|
+ <span @click="handleModeClick(option as ModeTypeItem)">{{ option.payload.title }}</span>
|
|
|
|
+ </template>
|
|
|
|
+ </ASegmented>
|
|
|
|
+ <template v-if="currentModeType === 'fullAuto'">
|
|
|
|
+ <div class="power-button">
|
|
|
|
+ <div class="power-button-content">
|
|
|
|
+ <SvgIcon name="power-off" />
|
|
|
|
+ <div>{{ $t('realTimeMonitor.fullPowerOff') }}</div>
|
|
|
|
+ </div>
|
|
|
|
+ <div class="power-button-segmented-border"></div>
|
|
|
|
+ </div>
|
|
|
|
+ </template>
|
|
|
|
+ <template v-else-if="currentModeType === 'halfAuto'">
|
|
|
|
+ <div v-for="(item, index) in deviceList" :key="index" class="device-item">
|
|
|
|
+ <div>
|
|
|
|
+ <span :class="['device-item-tag', { 'device-tag-run': item.status === 'on' }]">
|
|
|
|
+ {{ item.status === 'on' ? $t('common.run') : $t('common.shutDown') }}
|
|
|
|
+ </span>
|
|
|
|
+ <span class="device-item-title">{{ item.name }}</span>
|
|
|
|
+ </div>
|
|
|
|
+ <ASwitch
|
|
|
|
+ v-model:checked="item.status"
|
|
|
|
+ checked-value="on"
|
|
|
|
+ un-checked-value="off"
|
|
|
|
+ :checked-children="$t('common.on')"
|
|
|
|
+ :un-checked-children="$t('common.off')"
|
|
|
|
+ />
|
|
|
|
+ </div>
|
|
|
|
+ </template>
|
|
|
|
+ </div>
|
|
|
|
+</template>
|
|
|
|
+
|
|
|
|
+<style lang="scss" scoped>
|
|
|
|
+:deep(.ant-segmented) {
|
|
|
|
+ padding: 4px;
|
|
|
|
+ margin-bottom: 16px;
|
|
|
|
+ color: #fff;
|
|
|
|
+ background-color: rgb(255 255 255 / 8%);
|
|
|
|
+ border-radius: 4px;
|
|
|
|
+
|
|
|
|
+ .ant-segmented-group > div {
|
|
|
|
+ background-color: var(--antd-color-primary);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ .ant-segmented-item-label {
|
|
|
|
+ display: flex;
|
|
|
|
+ align-items: center;
|
|
|
|
+ padding-inline: 0;
|
|
|
|
+
|
|
|
|
+ span {
|
|
|
|
+ padding-inline: 12px;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ .ant-segmented-item-selected {
|
|
|
|
+ color: #fff;
|
|
|
|
+ background-color: var(--antd-color-primary);
|
|
|
|
+ box-shadow: none;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ .ant-segmented-item {
|
|
|
|
+ + .ant-segmented-item {
|
|
|
|
+ margin-left: 8px;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ &:hover:not(.ant-segmented-item-selected, .ant-segmented-item-disabled) {
|
|
|
|
+ color: #fff;
|
|
|
|
+
|
|
|
|
+ &::after {
|
|
|
|
+ background-color: var(--antd-color-primary-opacity-15);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ .ant-segmented-item-disabled,
|
|
|
|
+ .ant-segmented-item-disabled:hover,
|
|
|
|
+ .ant-segmented-item-disabled:focus {
|
|
|
|
+ color: rgb(255 255 255 / 25%);
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+.power-button {
|
|
|
|
+ display: flex;
|
|
|
|
+ align-items: center;
|
|
|
|
+ justify-content: center;
|
|
|
|
+ width: 214px;
|
|
|
|
+ color: #fff;
|
|
|
|
+ cursor: pointer;
|
|
|
|
+ background-color: rgba(var(--antd-color-primary-rgb), 0.04);
|
|
|
|
+ border: 1px solid rgba(var(--antd-color-primary-rgb), 0.08);
|
|
|
|
+
|
|
|
|
+ &,
|
|
|
|
+ &::before,
|
|
|
|
+ &::after {
|
|
|
|
+ position: absolute;
|
|
|
|
+ top: 50%;
|
|
|
|
+ left: 50%;
|
|
|
|
+ aspect-ratio: 1;
|
|
|
|
+ border-radius: 50%;
|
|
|
|
+ transform: translate(-50%, -50%);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ &::before,
|
|
|
|
+ &::after {
|
|
|
|
+ display: block;
|
|
|
|
+ content: '';
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ &::before {
|
|
|
|
+ width: 166px;
|
|
|
|
+ background-color: rgba(var(--antd-color-primary-rgb), 0.1);
|
|
|
|
+ border: 1px solid rgba(var(--antd-color-primary-rgb), 0.12);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ &::after {
|
|
|
|
+ width: 120px;
|
|
|
|
+ background: linear-gradient(
|
|
|
|
+ 219deg,
|
|
|
|
+ var(--antd-color-primary-border-hover) 0%,
|
|
|
|
+ var(--antd-color-primary) 51%,
|
|
|
|
+ var(--antd-color-primary-active) 100%
|
|
|
|
+ );
|
|
|
|
+ box-shadow: inset 0 0 8px 0 var(--antd-color-primary-bg-hover);
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+.power-button-segmented-border {
|
|
|
|
+ position: absolute;
|
|
|
|
+ width: calc(100% + 4px);
|
|
|
|
+ height: calc(100% + 4px);
|
|
|
|
+ content: '';
|
|
|
|
+
|
|
|
|
+ /* 生成三段60度的深色边框,间隔60度 */
|
|
|
|
+ background: conic-gradient(
|
|
|
|
+ var(--antd-color-primary-active) 0deg 60deg,
|
|
|
|
+ transparent 60deg 120deg,
|
|
|
|
+ var(--antd-color-primary-active) 120deg 180deg,
|
|
|
|
+ transparent 180deg 240deg,
|
|
|
|
+ var(--antd-color-primary-active) 240deg 300deg,
|
|
|
|
+ transparent 300deg 360deg
|
|
|
|
+ );
|
|
|
|
+ border-radius: 50%;
|
|
|
|
+
|
|
|
|
+ /* 通过遮罩仅显示边框区域 */
|
|
|
|
+ mask: radial-gradient(
|
|
|
|
+ circle,
|
|
|
|
+ transparent calc(53% - 1px),
|
|
|
|
+ #000 calc(53% - 1px) calc(53% + 1px),
|
|
|
|
+ transparent calc(53% + 1px)
|
|
|
|
+ );
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+.power-button-content {
|
|
|
|
+ z-index: 5;
|
|
|
|
+ font-size: 16px;
|
|
|
|
+ font-weight: 500;
|
|
|
|
+ line-height: 22px;
|
|
|
|
+ color: #fff;
|
|
|
|
+ text-align: center;
|
|
|
|
+
|
|
|
|
+ i {
|
|
|
|
+ font-size: 24px;
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+.device-item {
|
|
|
|
+ display: flex;
|
|
|
|
+ align-items: center;
|
|
|
|
+ justify-content: space-between;
|
|
|
|
+ padding: 16px 24px;
|
|
|
|
+ background: rgb(255 255 255 / 8%);
|
|
|
|
+ border-radius: 4px;
|
|
|
|
+
|
|
|
|
+ & + & {
|
|
|
|
+ margin-top: 16px;
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+.device-item-tag {
|
|
|
|
+ padding: 2px 8px;
|
|
|
|
+ margin-right: 16px;
|
|
|
|
+ font-size: 12px;
|
|
|
|
+ font-weight: 500;
|
|
|
|
+ line-height: 20px;
|
|
|
|
+ color: rgb(255 255 255 / 65%);
|
|
|
|
+ background: rgb(255 255 255 / 16%);
|
|
|
|
+ border: 1px solid rgb(255 255 255 / 24%);
|
|
|
|
+ border-radius: 4px;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+.device-tag-run {
|
|
|
|
+ color: #52c41a;
|
|
|
|
+ background: rgb(103 194 58 / 16%);
|
|
|
|
+ border-color: rgb(82 196 26 / 50%);
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+.device-item-title {
|
|
|
|
+ font-size: 14px;
|
|
|
|
+ font-weight: 500;
|
|
|
|
+ line-height: 22px;
|
|
|
|
+ color: #fff;
|
|
|
|
+}
|
|
|
|
+</style>
|