Преглед изворни кода

fix: 洗车设备页布尔字段交互优化及后端空查询修復

- ExtBoolean: el-select 下拉改为 el-switch 开关组件
- index.vue: hasFoam/hasWater/hasPa 列改用内联 dataRange,避免依赖缺失的 WashDevice.foam/WashDevice.water 字典;查询参数发送前转 boolean,处理 -1("全部") 值
- WashDeviceServiceImpl: list() 空结果提前返回,避免 IN () 非法 SQL

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
skyline пре 4 дана
родитељ
комит
36af0514ed

+ 29 - 17
admin-web/src/components/form/ExtBoolean.vue

@@ -20,27 +20,38 @@
   color: #5FB878;
   border: 1px solid #5FB878;
 }
+
+.switch-wrap {
+  display: flex;
+  align-items: center;
+  gap: 8px;
+}
+
+.switch-label {
+  font-size: 13px;
+  color: var(--el-text-color-regular);
+  white-space: nowrap;
+}
 </style>
 <template>
   <div>
     <span v-if="disabled" class="text" :class="{'true-text':props.modelValue==true}">{{ props.modelValue ? trueLabel : falseLabel }}</span>
-    <el-select v-else
-               transfer
-               :multiple="false"
-               clearable
-               @change="handleChange"
-               style="width: 100%"
-               :placeholder="placeholder"
-               v-model="state.model">
-      <el-option label="是" :value="true"><el-text type="success">{{ trueLabel }}</el-text></el-option>
-      <el-option label="否" :value="false"><el-text type="danger">{{ falseLabel }}</el-text></el-option>
-    </el-select>
+    <div v-else class="switch-wrap">
+      <span class="switch-label">{{ falseLabel }}</span>
+      <el-switch
+        :model-value="state.model"
+        @change="handleSwitchChange"
+        inline-prompt
+        :active-text="trueLabel"
+      />
+      <span class="switch-label">{{ trueLabel }}</span>
+    </div>
   </div>
 </template>
 <script setup lang="ts" name="ExtBoolean">
 import {reactive, onMounted, watch, computed} from 'vue';
 import u from '/@/utils/u';
-//数据字典的布尔值类型的下拉选择组件
+// 布尔值开关组件
 
 const props = defineProps({
   modelValue: {
@@ -71,15 +82,16 @@ onMounted(() => {
 })
 
 watch(() => props.modelValue, (val, oldVal) => {
-  //console.log('ExtBoolean watch modelValue', val, oldVal)
   state.model = props.modelValue;
 })
 
 const emit = defineEmits(['on-change', 'update:modelValue']);
 
-const handleChange = () => {
-  //console.log(state.model)
-  emit('update:modelValue', state.model)
-  emit('on-change', state.model)
+const handleSwitchChange = (val: boolean) => {
+  state.model = val
+  emit('update:modelValue', val)
+  emit('on-change', val)
 }
+
+
 </script>

+ 22 - 4
admin-web/src/views/admin/station/device/index.vue

@@ -159,9 +159,9 @@ const state = reactive({
       }
     },
     {label: '功能', prop: 'functions', width: 180, query: true, type: 'text', resizable: true},
-    {label: '是否有泡沫', prop: 'hasFoam', width: 120, query: true, type: 'dict', conf: {dict: 'WashDevice.foam'}, resizable: true},
-    {label: '是否有水', prop: 'hasWater', width: 120, query: true, type: 'dict', conf: {dict: 'WashDevice.water'}, resizable: true},
-    {label: '是否支持PA', prop: 'hasPa', width: 120, query: true, type: 'dict', conf: {dict: 'yes_no'}, resizable: true},
+    {label: '是否有泡沫', prop: 'hasFoam', width: 120, query: true, type: 'dict', conf: {range: [{label: '有', value: '1'}, {label: '无', value: '0'}], dataRange: [{label: '有', value: '1'}, {label: '无', value: '0'}]}, resizable: true},
+    {label: '是否有水', prop: 'hasWater', width: 120, query: true, type: 'dict', conf: {range: [{label: '有', value: '1'}, {label: '无', value: '0'}], dataRange: [{label: '有', value: '1'}, {label: '无', value: '0'}]}, resizable: true},
+    {label: '是否支持PA', prop: 'hasPa', width: 120, query: true, type: 'dict', conf: {range: [{label: '是', value: '1'}, {label: '否', value: '0'}], dataRange: [{label: '是', value: '1'}, {label: '否', value: '0'}]}, resizable: true},
     // {label: '当前温度', prop: 'temperatureChip', width: 180, query: false, type: 'text', resizable: true},
     {label: '创建时间', prop: 'createTime', query: false, sortable: 'custom', type: 'datetime', resizable: true, conf: {format: (val: any) => u.fmt.fmtDateTime(val)}},
     {label: '更新时间', prop: 'updateTime', query: false, sortable: 'custom', type: 'datetime', resizable: true, conf: {format: (val: any) => u.fmt.fmtDateTime(val)}},
@@ -268,6 +268,23 @@ onBeforeUnmount(() => {
 })
 
 
+// 将 dict 返回的字符串 "0"/"1" 转为 boolean,避免后端 Boolean 字段反序列化失败
+const BOOL_QUERY_FIELDS = ['hasFoam', 'hasWater', 'hasPa']
+
+const normalizeQueryBooleans = (query: Record<string, any>) => {
+  BOOL_QUERY_FIELDS.forEach((key) => {
+    const v = query[key]
+    if (v === undefined || v === null || v === '' || v === -1 || v === '-1') {
+      delete query[key]
+    } else if (v === '1' || v === 1) {
+      query[key] = true
+    } else if (v === '0' || v === 0) {
+      query[key] = false
+    }
+  })
+  return query
+}
+
 //region 方法区
 // 初始化表格数据
 const loadData = (refresh: boolean = false) => {
@@ -275,7 +292,8 @@ const loadData = (refresh: boolean = false) => {
     state.pageQuery.pageNum = 1;
   }
   state.tableData.loading = true;
-  $body(`/washDevice/list`, {...state.formQuery, ...state.pageQuery}).then((res: any) => {
+  const query = normalizeQueryBooleans({...state.formQuery, ...state.pageQuery})
+  $body(`/washDevice/list`, query).then((res: any) => {
     let {list, total} = res;
     state.tableData.data = list;
     state.pageQuery.total = total;

+ 8 - 1
car-wash-service/src/main/java/com/kym/service/impl/WashDeviceServiceImpl.java

@@ -23,6 +23,7 @@ import org.springframework.beans.BeanUtils;
 import org.springframework.stereotype.Service;
 
 import java.util.ArrayList;
+import java.util.Collections;
 import java.util.List;
 import java.util.function.Function;
 import java.util.stream.Collectors;
@@ -214,8 +215,14 @@ public class WashDeviceServiceImpl extends MyBaseServiceImpl<WashDeviceMapper, W
                 .orderByAsc(WashDevice::getSequence)
                 .list();
 
+        if (list.isEmpty()) {
+            return new PageBean<>(Collections.emptyList());
+        }
+
         // 设备配置ID-设备配置Map
-        var deviceConfigMap = deviceConfigService.lambdaQuery().in(DeviceConfig::getId, list.stream().map(WashDevice::getDeviceConfigId).toList()).list().stream().collect(Collectors.toMap(DeviceConfig::getId, Function.identity()));
+        var deviceConfigMap = deviceConfigService.lambdaQuery()
+                .in(DeviceConfig::getId, list.stream().map(WashDevice::getDeviceConfigId).toList())
+                .list().stream().collect(Collectors.toMap(DeviceConfig::getId, Function.identity()));
 
         var voList = new ArrayList<WashDeviceVo>();
         list.forEach(item -> {