Ver Fonte

洗车调试

skyline há 2 dias atrás
pai
commit
6a695f9960

+ 1 - 1
admin-mp/src/pages/device/detail.vue

@@ -24,7 +24,7 @@
         </view>
         <view class="info-item">
           <text class="item-label">工位编号</text>
-          <text class="item-value">{{ deviceDetail.seqName || '无' }}</text>
+          <text class="item-value">{{ deviceDetail.sequence ? deviceDetail.sequence + '号工位' : '无' }}</text>
         </view>
         <view class="info-item">
           <text class="item-label">所属站点</text>

+ 8 - 0
admin-web/src/views/admin/station/device/dialog.vue

@@ -28,6 +28,14 @@
               class="wd200">
           </el-input>
         </el-form-item>
+        <el-form-item label="工位序号" prop="sequence" class="wd350">
+          <el-input-number
+              v-model="state.ruleForm.sequence"
+              placeholder="工位序号"
+              :min="1"
+              class="wd200">
+          </el-input-number>
+        </el-form-item>
         <el-form-item label="产品key" prop="productKey" class="wd350">
           <el-input
               v-model="state.ruleForm.productKey"

+ 1 - 0
admin-web/src/views/admin/station/device/index.vue

@@ -130,6 +130,7 @@ const state = reactive({
       conf: {url: 'washStation/list', labelKey: 'stationName', valueKey: 'stationId', dataKey: 'list'}
     },
     {label: '设备编号', prop: 'shortId', width: 100, query: true, type: 'text', resizable: true, fixed: 'left'},
+    {label: '工位序号', prop: 'sequence', width: 90, query: false, type: 'text', resizable: true},
     {
       label: '站点名称', prop: 'stationName', width: 180, query: false, type: 'render', resizable: true,
       render: (h: any, row: any, rowData: any) => {

+ 186 - 2
admin-web/src/views/admin/station/list/dialog.vue

@@ -1,5 +1,93 @@
 <style scoped lang="scss">
+.device-order-container {
+  padding: 10px 0;
+}
+
+.device-order-list {
+  max-height: 400px;
+  overflow-y: auto;
+}
+
+.device-order-item {
+  display: flex;
+  align-items: center;
+  padding: 12px 16px;
+  margin-bottom: 8px;
+  background: #fafafa;
+  border: 1px solid #ebeef5;
+  border-radius: 6px;
+  cursor: grab;
+  transition: all 0.2s;
+  user-select: none;
+
+  &:hover {
+    background: #f0f2f5;
+    border-color: #d9dce1;
+  }
+
+  &.dragging {
+    opacity: 0.5;
+    background: #e6f7ff;
+    border-color: #409eff;
+  }
+
+  &.drag-over {
+    border-color: #409eff;
+    background: #ecf5ff;
+  }
+}
+
+.drag-handle {
+  margin-right: 12px;
+  cursor: grab;
+  color: #c0c4cc;
+  font-size: 18px;
+  display: flex;
+  align-items: center;
+
+  &:active {
+    cursor: grabbing;
+  }
+}
+
+.order-sequence {
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  width: 32px;
+  height: 32px;
+  background: #409eff;
+  color: #fff;
+  border-radius: 50%;
+  font-size: 14px;
+  font-weight: 600;
+  margin-right: 16px;
+  flex-shrink: 0;
+}
+
+.order-device-info {
+  flex: 1;
+  min-width: 0;
+
+  .order-device-name {
+    font-size: 14px;
+    font-weight: 500;
+    color: #303133;
+  }
+
+  .order-device-id {
+    font-size: 12px;
+    color: #909399;
+    margin-top: 2px;
+  }
+}
 
+.device-order-footer {
+  margin-top: 20px;
+  padding-top: 16px;
+  border-top: 1px solid #ebeef5;
+  text-align: right;
+}
 </style>
 <template>
   <div class="system-dialog-container">
@@ -244,6 +332,43 @@
           </el-form>
 
         </el-tab-pane>
+
+        <el-tab-pane label="调整设备顺序" name="deviceOrder" v-if="state.action !== 'add'">
+          <div class="device-order-container" v-loading="state.deviceOrderLoading">
+            <el-alert
+              title="上下拖动设备行可调整工位顺序,调整后请点击下方保存按钮"
+              type="info" :closable="false" show-icon style="margin-bottom: 16px;" />
+
+            <div class="device-order-list" v-if="state.deviceOrderList.length > 0">
+              <div
+                v-for="(device, index) in state.deviceOrderList"
+                :key="device.id"
+                class="device-order-item"
+                :class="{ 'dragging': state.dragIndex === index, 'drag-over': state.dragOverIndex === index }"
+                draggable="true"
+                @dragstart="handleDragStart($event, index)"
+                @dragover.prevent="handleDragOver($event, index)"
+                @drop="handleDrop($event, index)"
+                @dragend="handleDragEnd"
+              >
+                <div class="drag-handle">
+                  <SvgIcon name="ele-Rank"/>
+                </div>
+                <div class="order-sequence">{{ index + 1 }}</div>
+                <div class="order-device-info">
+                  <div class="order-device-name">{{ device.deviceName }}</div>
+                  <div class="order-device-id">{{ device.shortId || device.productKey }}</div>
+                </div>
+              </div>
+            </div>
+
+            <el-empty v-else description="该站点暂无设备" />
+
+            <div class="device-order-footer">
+              <el-button type="primary" @click="saveDeviceOrder" :loading="state.deviceOrderSaving" :disabled="state.deviceOrderList.length === 0">保存顺序</el-button>
+            </div>
+          </div>
+        </el-tab-pane>
       </el-tabs>
 
 
@@ -257,7 +382,7 @@
               </el-form-item>-->
 
 
-      <template #footer>
+      <template #footer v-if="state.tab !== 'deviceOrder'">
 				<span class="dialog-footer">
 					<el-button @click="onCancel" size="default">取 消</el-button>
 					<el-button :loading="state.btnLoading" type="primary" @click="onSubmit" size="default">{{ state.dialog.submitTxt }}</el-button>
@@ -305,7 +430,12 @@ const initState = () => ({
   tab: 'basic',
   platformFeeRateList: [],
   stationFeeRate: [],
-  action:''
+  action:'',
+  deviceOrderList: [] as any[],
+  deviceOrderLoading: false,
+  deviceOrderSaving: false,
+  dragIndex: -1,
+  dragOverIndex: -1,
 })
 
 // 定义变量内容
@@ -322,6 +452,7 @@ const open = (action: string = 'add', row: any) => {
     loadData(row.id);
     state.feeForm.stationId = row.stationId
     loadStationFeeRate();
+    loadDeviceListForStation(row.stationId);
   } else {
     state.ruleForm = Object.assign(state.ruleForm, row);
 
@@ -401,6 +532,57 @@ const loadPlatformFeeRateList = () => {
   })
 }
 
+const loadDeviceListForStation = (stationId?: string) => {
+  const sid = stationId || state.ruleForm.stationId
+  if (!sid) return
+  state.deviceOrderLoading = true
+  $body('/washDevice/list', { stationId: sid, pageNum: 1, pageSize: 200 }).then((res: any) => {
+    state.deviceOrderList = (res.list || []).map((d: any) => ({ ...d }))
+  }).finally(() => {
+    state.deviceOrderLoading = false
+  })
+}
+
+const handleDragStart = (e: DragEvent, index: number) => {
+  state.dragIndex = index
+  if (e.dataTransfer) {
+    e.dataTransfer.effectAllowed = 'move'
+  }
+}
+
+const handleDragOver = (_e: DragEvent, index: number) => {
+  state.dragOverIndex = index
+}
+
+const handleDrop = (_e: DragEvent, index: number) => {
+  if (state.dragIndex === -1 || state.dragIndex === index) return
+  const list = [...state.deviceOrderList]
+  const [item] = list.splice(state.dragIndex, 1)
+  list.splice(index, 0, item)
+  state.deviceOrderList = list
+}
+
+const handleDragEnd = () => {
+  state.dragIndex = -1
+  state.dragOverIndex = -1
+}
+
+const saveDeviceOrder = () => {
+  state.deviceOrderSaving = true
+  const devices = state.deviceOrderList.map((d: any, idx: number) => ({
+    id: d.id,
+    sequence: idx + 1
+  }))
+  $body('/washDevice/batchUpdateSequence', devices).then(() => {
+    Msg.message('设备顺序保存成功', 'success')
+    loadDeviceListForStation()
+  }).catch(() => {
+    Msg.message('保存失败', 'error')
+  }).finally(() => {
+    state.deviceOrderSaving = false
+  })
+}
+
 const handlePlatformFeeRateChange = (platformFeeRateId: any) => {
   console.log(platformFeeRateId)
   let rate = state.platformFeeRateList.find(k => k.id == platformFeeRateId);
@@ -419,6 +601,8 @@ const handleTabChange = (tab:string) => {
     state.dialog.submitTxt = u.dialog.actions[state.action].btn + "『站点信息』"
   }else if(tab==='fee'){
     state.dialog.submitTxt = u.dialog.actions[state.action].btn + "『站点费率』"
+  }else if(tab==='deviceOrder'){
+    loadDeviceListForStation()
   }
 }
 

+ 10 - 0
car-wash-admin/src/main/java/com/kym/admin/controller/WashDeviceController.java

@@ -8,6 +8,8 @@ import com.kym.entity.queryParams.DeviceQueryParams;
 import com.kym.service.WashDeviceService;
 import org.springframework.web.bind.annotation.*;
 
+import java.util.List;
+
 /**
  * <p>
  * 网点设备
@@ -79,5 +81,13 @@ public class WashDeviceController {
         return R.success();
     }
 
+    @SaCheckPermission("washDevice.modify")
+    @SysLog("批量更新设备序号")
+    @PostMapping("batchUpdateSequence")
+    R<?> batchUpdateSequence(@RequestBody List<WashDevice> devices) {
+        washDeviceService.batchUpdateSequence(devices);
+        return R.success();
+    }
+
 
 }

+ 0 - 5
car-wash-entity/src/main/java/com/kym/entity/DeviceRelation.java

@@ -36,11 +36,6 @@ public class DeviceRelation extends BaseEntity {
      */
     private String shortId;
 
-    /**
-     * 工位序号名称:①号工位
-     */
-    private String seqName;
-
     /**
      * 产品key
      */

+ 5 - 0
car-wash-entity/src/main/java/com/kym/entity/WashDevice.java

@@ -86,4 +86,9 @@ public class WashDevice extends BaseEntity {
      * 设备参数配置
      */
     private Long deviceConfigId;
+
+    /**
+     * 工位序号
+     */
+    private Integer sequence;
 }

+ 0 - 1
car-wash-entity/src/main/java/com/kym/entity/common/RedisKeys.java

@@ -19,7 +19,6 @@ public interface RedisKeys {
     String SHORT_ID_TO_PRODUCT_KEY_AND_DEVICE_NAME = "SHORT_ID_TO_PRODUCT_KEY_AND_DEVICE_NAME:";
     String STATION_ID_TO_INVESTOR_ADMIN_USER_ID = "STATION_ID_TO_INVESTOR_ADMIN_USER_ID:";
     String USER_ID_TO_STATION_ID = "USER_ID_TO_STATION_ID:";
-    String SHORT_ID_TO_SEQ_NAME = "SHORT_ID_TO_SEQ_NAME:";
     String PARKING_COUPON_CODE = "PARKING_COUPON_CODE";
 
     // =======================================洗车======================================

+ 5 - 4
car-wash-entity/src/main/java/com/kym/entity/vo/WashDeviceVo.java

@@ -55,10 +55,6 @@ public class WashDeviceVo extends BaseEntity {
      * 产品密钥
      */
     private String productKey;
-    /**
-     * 工位编号
-     */
-    private String seqName;
 
     /**
      * 功能
@@ -105,4 +101,9 @@ public class WashDeviceVo extends BaseEntity {
      */
     private Integer temperatureChip;
 
+    /**
+     * 工位序号
+     */
+    private Integer sequence;
+
 }

+ 1 - 1
car-wash-mp/src/pages-wash/station/index.vue

@@ -53,7 +53,7 @@
           >
             <view class="device-header">
               <view class="device-name">
-                <text>{{ device.seqName }}</text>
+                <text>{{ device.sequence ? device.sequence + '号工位' : '' }}</text>
                 <text v-if="device.hasPa" class="pa-badge">PA</text>
               </view>
               <view class="device-status" :class="'status-' + getDeviceStatusClass(device.state)">

+ 2 - 0
car-wash-service/src/main/java/com/kym/service/WashDeviceService.java

@@ -36,5 +36,7 @@ public interface WashDeviceService extends MyBaseService<WashDevice> {
     void add(WashDevice device);
 
     PageBean<WashDeviceVo> list(DeviceQueryParams query);
+
+    void batchUpdateSequence(List<WashDevice> devices);
     //endregion
 }

+ 0 - 8
car-wash-service/src/main/java/com/kym/service/cache/KymCache.java

@@ -199,14 +199,6 @@ public enum KymCache {
         return SHORT_ID_TO_PRODUCT_KEY_AND_DEVICE_NAME_MAPPING.entrySet().stream().filter(entry -> (productKey + "," + deviceName).equals(entry.getValue())).map(Map.Entry::getKey).findFirst().get();
     }
 
-    public void putShortId2SeqName(Map<String, String> map) {
-        map.forEach((k, v) -> KymCacheInjector.redisTemplate.opsForValue().set(RedisKeys.SHORT_ID_TO_SEQ_NAME + k, v));
-    }
-
-    public String getSeqNameByShortId(String shortId) {
-        return KymCacheInjector.redisTemplate.opsForValue().get(RedisKeys.SHORT_ID_TO_SEQ_NAME + shortId);
-    }
-
     public void setParkingCouponCode(String code, String parkingCouponUrl, Long seconds) {
         KymCacheInjector.redisTemplate.opsForValue().set(RedisKeys.PARKING_COUPON_CODE + code, parkingCouponUrl, seconds);
     }

+ 0 - 2
car-wash-service/src/main/java/com/kym/service/impl/DeviceRelationServiceImpl.java

@@ -28,8 +28,6 @@ public class DeviceRelationServiceImpl extends MyBaseServiceImpl<DeviceRelationM
             KymCache.INSTANCE.putWashShortId2ProductKeyAndDeviceName(Map.of(item.getShortId(), item.getProductKey() + "," + item.getDeviceName()));
             // shortId和stationId的对应关系
             KymCache.INSTANCE.putShortId2StationId(Map.of(item.getShortId(), item.getStationId()));
-            // shortId和seqName的对应关系
-            KymCache.INSTANCE.putShortId2SeqName(Map.of(item.getShortId(), item.getSeqName()));
         });
     }
 

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

@@ -59,6 +59,7 @@ public class WashDeviceServiceImpl extends MyBaseServiceImpl<WashDeviceMapper, W
         var list = lambdaQuery()
                 .eq(CommUtil.isNotEmptyAndNull(params.getId()), WashDevice::getId, params.getId())
                 .eq(CommUtil.isNotEmptyAndNull(params.getStationId()), WashDevice::getStationId, params.getStationId())
+                .orderByAsc(WashDevice::getSequence)
                 .orderByAsc(WashDevice::getState)
                 .orderByAsc(WashDevice::getDeviceName)
                 .list();
@@ -70,7 +71,6 @@ public class WashDeviceServiceImpl extends MyBaseServiceImpl<WashDeviceMapper, W
 //            .setCurrentUserId(currentUserId);
             BeanUtils.copyProperties(washDevice, vo);
             vo.setShortId(KymCache.INSTANCE.getShortIdByProductKeyAndDeviceName(washDevice.getProductKey(), washDevice.getDeviceName()));
-            vo.setSeqName(KymCache.INSTANCE.getSeqNameByShortId(vo.getShortId()));
             voList.add(vo);
         }
         return voList;
@@ -147,6 +147,14 @@ public class WashDeviceServiceImpl extends MyBaseServiceImpl<WashDeviceMapper, W
         if (list.size() == 1) {
             CommUtil.asserts(list.get(0).getDeviceName().equalsIgnoreCase(device.getDeviceName()), "站点已存在");
         }
+        if (device.getSequence() != null) {
+            Long seqCount = lambdaQuery()
+                    .eq(WashDevice::getStationId, device.getStationId())
+                    .eq(WashDevice::getSequence, device.getSequence())
+                    .ne(WashDevice::getId, device.getId())
+                    .count();
+            CommUtil.asserts(seqCount == 0, "该站点下工位序号已存在");
+        }
         updateById(device);
     }
 
@@ -157,6 +165,13 @@ public class WashDeviceServiceImpl extends MyBaseServiceImpl<WashDeviceMapper, W
                 .eq(WashDevice::getDeviceName, device.getDeviceName())
                 .eq(WashDevice::getProductKey, device.getProductKey()).count();
         CommUtil.asserts(count == 0, "设备已存在");
+        if (device.getSequence() != null) {
+            Long seqCount = lambdaQuery()
+                    .eq(WashDevice::getStationId, device.getStationId())
+                    .eq(WashDevice::getSequence, device.getSequence())
+                    .count();
+            CommUtil.asserts(seqCount == 0, "该站点下工位序号已存在");
+        }
         save(device);
 
     }
@@ -166,6 +181,7 @@ public class WashDeviceServiceImpl extends MyBaseServiceImpl<WashDeviceMapper, W
         PageHelper.startPage(query.getPageNum(), query.getPageSize());
         List<WashDevice> list = lambdaQuery()
                 .eq(CommUtil.isNotEmptyAndNull(query.getStationId()), WashDevice::getStationId, query.getStationId())
+                .orderByAsc(WashDevice::getSequence)
                 .list();
 
         // 设备配置ID-设备配置Map
@@ -183,6 +199,16 @@ public class WashDeviceServiceImpl extends MyBaseServiceImpl<WashDeviceMapper, W
         return new PageBean<>(voList);
     }
 
+    @Override
+    public void batchUpdateSequence(List<WashDevice> devices) {
+        devices.forEach(device -> {
+            lambdaUpdate()
+                    .eq(WashDevice::getId, device.getId())
+                    .set(WashDevice::getSequence, device.getSequence())
+                    .update();
+        });
+    }
+
     //endregion
 
 }