You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

146 lines
3.4 KiB

  1. <script setup lang="ts">
  2. import { ref } from 'vue'
  3. const props = withDefaults(defineProps<{ data: Home.HeatArea }>(), {
  4. data: () => ({ label: 'A-1', value: 'heat_module_01', selected: false, temperature: undefined }),
  5. })
  6. const emits = defineEmits(['selectChange', 'setTemperature'])
  7. const mousedownHandle = (e: Event) => {
  8. let event
  9. if ('touches' in e) {
  10. event = (e.touches as TouchList)[0]
  11. }
  12. else {
  13. event = e
  14. }
  15. if (event.target!.classList!.contains('tube-inner')) {
  16. activeTubeNum.value = event.target!.getAttribute('index')
  17. }
  18. }
  19. const activeTubeNum = ref(0)
  20. const activeTubeBox = ref(false)
  21. const tubeSelect = () => {
  22. emits('selectChange')
  23. }
  24. const setTemperature = () => {
  25. emits('setTemperature', props.data.value)
  26. }
  27. defineExpose({
  28. activeTubeBox,
  29. })
  30. </script>
  31. <template>
  32. <div class="tube" :class="{ 'tube-active': data.selected }">
  33. <div class="header">
  34. <span>{{ data.label }}</span>
  35. <span>已放置</span>
  36. </div>
  37. <div class="tube-item" @mousedown.prevent="mousedownHandle" @touchstart.prevent="mousedownHandle">
  38. <div v-if="false" class="tube-disable" />
  39. <span v-for="item in 16" :key="item" class="tube-inner" :class="{ 'tube-inner-active': item <= activeTubeNum }" :index="item" />
  40. </div>
  41. <div v-if="data.temperature" class="temperature-box" @click="setTemperature">
  42. <span>
  43. <span>目标温度: </span>
  44. <span>{{ data.temperature }}</span>
  45. <span></span>
  46. </span>
  47. <span>加热中</span>
  48. </div>
  49. <div v-else class="temperature-box" style="justify-content: center" @click="setTemperature">
  50. 点击设置目标温度
  51. </div>
  52. <div class="footer">
  53. <span :class="{ 'active-footer': data.selected }"> 200</span>
  54. <ft-button size="small" :type="data.selected ? 'primary' : 'default'" @click="tubeSelect">
  55. 选择
  56. </ft-button>
  57. </div>
  58. </div>
  59. </template>
  60. <style scoped lang="scss">
  61. .tube-active {
  62. border-color: #275EFB !important;
  63. }
  64. .tube {
  65. box-sizing: border-box;
  66. width: 100%;
  67. height: 95%;
  68. background: #E9F3FF;
  69. border-radius: 10px;
  70. padding: 10px;
  71. font-size: 14px;
  72. display: flex;
  73. flex-direction: column;
  74. justify-content: space-between;
  75. border: 2px solid #E9F3FF;
  76. transition: border 0.3s;
  77. .header {
  78. display: flex;
  79. justify-content: space-between;
  80. align-items: center;
  81. color: #4D6882;
  82. }
  83. .tube-item {
  84. padding: 5px;
  85. background: #384D5D;
  86. border-radius: 10px;
  87. display: grid;
  88. grid-template-columns: repeat(4, 1fr);
  89. grid-template-rows: repeat(4, 1fr);
  90. grid-gap: 5px;
  91. position: relative;
  92. .tube-disable {
  93. position: absolute;
  94. width: 100%;
  95. height: 100%;
  96. top: 0;
  97. left: 0;
  98. background: rgba(255,255,255,0.9);
  99. border-radius: 9px;
  100. }
  101. .tube-inner {
  102. display: inline-block;
  103. width: 25px;
  104. height: 25px;
  105. border-radius: 50%;
  106. background: #fff;
  107. margin: 2px;
  108. transition: background 0.5s;
  109. }
  110. .tube-inner-active {
  111. background: #26D574;
  112. }
  113. }
  114. .temperature-box {
  115. display: flex;
  116. justify-content: space-between;
  117. background: #fff;
  118. padding: 5px;
  119. border-radius: 5px;
  120. font-size: 12px;
  121. }
  122. .footer {
  123. display: flex;
  124. justify-content: space-between;
  125. align-items: center;
  126. font-weight: bold;
  127. color: #4D6882;
  128. .active-footer {
  129. color: #1562B7;
  130. }
  131. .ft-button {
  132. margin-right: 0;
  133. }
  134. }
  135. }
  136. </style>