test pr
This commit is contained in:
parent
c60eff6a62
commit
b006e5d38b
|
|
@ -0,0 +1,48 @@
|
||||||
|
package com.wms_main.controller.wms;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||||
|
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||||
|
import com.wms_main.model.dto.query.LocationQuery;
|
||||||
|
import com.wms_main.model.dto.response.wms.WmsApiResponse;
|
||||||
|
import com.wms_main.model.dto.response.wms.BaseWmsApiResponse;
|
||||||
|
import com.wms_main.model.po.TAppLocation;
|
||||||
|
import com.wms_main.dao.ITAppLocationService;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
@RestController
|
||||||
|
@ResponseBody
|
||||||
|
@CrossOrigin
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
@RequestMapping("/locationManage")
|
||||||
|
public class LocationManageController {
|
||||||
|
private final ITAppLocationService locationService;
|
||||||
|
|
||||||
|
@PostMapping("/list")
|
||||||
|
public WmsApiResponse<Page<TAppLocation>> list(@RequestBody LocationQuery query) {
|
||||||
|
return WmsApiResponse.success(locationService.pageQuery(query));
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("/add")
|
||||||
|
public BaseWmsApiResponse add(@RequestBody TAppLocation location) {
|
||||||
|
locationService.save(location);
|
||||||
|
return BaseWmsApiResponse.success();
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("/update")
|
||||||
|
public BaseWmsApiResponse update(@RequestBody TAppLocation location) {
|
||||||
|
locationService.updateById(location);
|
||||||
|
return BaseWmsApiResponse.success();
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("/delete")
|
||||||
|
public BaseWmsApiResponse delete(@RequestBody Map<String, Object> params) {
|
||||||
|
String locationId = params.get("locationId").toString();
|
||||||
|
LambdaQueryWrapper<TAppLocation> wrapper = new LambdaQueryWrapper<>();
|
||||||
|
wrapper.eq(TAppLocation::getLocationId, locationId);
|
||||||
|
locationService.remove(wrapper);
|
||||||
|
return BaseWmsApiResponse.success();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,73 @@
|
||||||
|
package com.wms_main.controller.wms;
|
||||||
|
|
||||||
|
import com.wms_main.dao.ITSysMenuService;
|
||||||
|
import com.wms_main.model.dto.response.wms.WmsApiResponse;
|
||||||
|
import com.wms_main.model.po.TSysMenu;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
|
import static com.wms_main.model.dto.response.wms.WmsApiResponse.success;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 菜单管理控制器(临时用于添加仓库管理菜单)
|
||||||
|
*/
|
||||||
|
@RestController
|
||||||
|
@ResponseBody
|
||||||
|
@CrossOrigin
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
@RequestMapping("/wms/menu")
|
||||||
|
public class MenuController {
|
||||||
|
|
||||||
|
private final ITSysMenuService menuService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 添加仓库管理菜单
|
||||||
|
*/
|
||||||
|
@PostMapping("/addLocationManageMenu")
|
||||||
|
public WmsApiResponse<String> addLocationManageMenu() {
|
||||||
|
try {
|
||||||
|
// 检查菜单是否已存在
|
||||||
|
TSysMenu existingMenu = menuService.getById("1-8");
|
||||||
|
if (existingMenu != null) {
|
||||||
|
return success("仓库管理菜单已存在", "菜单ID: 1-8");
|
||||||
|
}
|
||||||
|
|
||||||
|
// 创建新的菜单项
|
||||||
|
TSysMenu menu = new TSysMenu();
|
||||||
|
menu.setMenuId("1-8");
|
||||||
|
menu.setLabelName("仓库管理");
|
||||||
|
menu.setIconValue("");
|
||||||
|
menu.setPath("/locationManage");
|
||||||
|
menu.setParentId("1");
|
||||||
|
|
||||||
|
// 保存菜单
|
||||||
|
boolean result = menuService.save(menu);
|
||||||
|
|
||||||
|
if (result) {
|
||||||
|
return success("仓库管理菜单添加成功", "菜单ID: 1-8, 路径: /locationManage");
|
||||||
|
} else {
|
||||||
|
return WmsApiResponse.error("菜单添加失败", null);
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (Exception e) {
|
||||||
|
return WmsApiResponse.error("添加菜单时发生错误: " + e.getMessage(), null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 检查仓库管理菜单是否存在
|
||||||
|
*/
|
||||||
|
@GetMapping("/checkLocationManageMenu")
|
||||||
|
public WmsApiResponse<TSysMenu> checkLocationManageMenu() {
|
||||||
|
try {
|
||||||
|
TSysMenu menu = menuService.getById("1-8");
|
||||||
|
if (menu != null) {
|
||||||
|
return success("仓库管理菜单已存在", menu);
|
||||||
|
} else {
|
||||||
|
return WmsApiResponse.error("仓库管理菜单不存在", null);
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
return WmsApiResponse.error("检查菜单时发生错误: " + e.getMessage(), null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,10 @@
|
||||||
|
package com.wms_main.model.dto.request;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
public class LocationStatusUpdateReq {
|
||||||
|
private String locationId;
|
||||||
|
private Integer isLock;
|
||||||
|
private Integer isOccupy;
|
||||||
|
}
|
||||||
17
wms_web_nantong_yachi/src/api/locationManage.js
Normal file
17
wms_web_nantong_yachi/src/api/locationManage.js
Normal file
|
|
@ -0,0 +1,17 @@
|
||||||
|
import request from "@/http/request";
|
||||||
|
|
||||||
|
export const getLocationList = (params) => {
|
||||||
|
return request({
|
||||||
|
url: '/wms/locationManage/list',
|
||||||
|
method: 'post',
|
||||||
|
data: params
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export const updateLocationStatus = (data) => {
|
||||||
|
return request({
|
||||||
|
url: '/wms/locationManage/updateStatus',
|
||||||
|
method: 'post',
|
||||||
|
data
|
||||||
|
});
|
||||||
|
};
|
||||||
428
wms_web_nantong_yachi/src/layout/locationManage.vue
Normal file
428
wms_web_nantong_yachi/src/layout/locationManage.vue
Normal file
|
|
@ -0,0 +1,428 @@
|
||||||
|
<template>
|
||||||
|
<el-form :model="queryForm" inline style="margin-bottom: 16px; padding: 16px; background: #f8f9fa; border-radius: 8px; border: 1px solid #e9ecef; box-shadow: 0 2px 4px rgba(0,0,0,0.1);">
|
||||||
|
<el-form-item label="库位编号" style="margin-right: 16px;">
|
||||||
|
<el-input v-model="queryForm.locationId" placeholder="库位编号" style="width: 140px;" clearable />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="排" style="margin-right: 16px;">
|
||||||
|
<el-input v-model="queryForm.lRow" placeholder="排" style="width: 100px;" clearable />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="列" style="margin-right: 16px;">
|
||||||
|
<el-input v-model="queryForm.lCol" placeholder="列" style="width: 100px;" clearable />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="层" style="margin-right: 16px;">
|
||||||
|
<el-input v-model="queryForm.lLayer" placeholder="层" style="width: 100px;" clearable />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="深度" style="margin-right: 16px;">
|
||||||
|
<el-input v-model="queryForm.lDepth" placeholder="深度" style="width: 100px;" clearable />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="锁定状态" style="margin-right: 16px;">
|
||||||
|
<el-select v-model="queryForm.locked" placeholder="锁定状态" clearable style="width: 120px;">
|
||||||
|
<el-option label="已锁定" :value="true" />
|
||||||
|
<el-option label="未锁定" :value="false" />
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="占用状态" style="margin-right: 16px;">
|
||||||
|
<el-select v-model="queryForm.occupied" placeholder="占用状态" clearable style="width: 120px;">
|
||||||
|
<el-option label="占用" :value="true" />
|
||||||
|
<el-option label="正常" :value="false" />
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item style="margin-right: 8px;">
|
||||||
|
<el-button type="primary" @click="search">查询</el-button>
|
||||||
|
</el-form-item>
|
||||||
|
<!-- 状态说明 - 第二排 -->
|
||||||
|
<div style="margin-top: 12px; font-size: 12px; color: #606266; text-align: left;">
|
||||||
|
<span style="color: #52c41a;">🟢 正常</span> |
|
||||||
|
<span style="color: #52c41a;">🔒 锁定</span> |
|
||||||
|
<span style="color: #ff4d4f;">🔴 占用</span>
|
||||||
|
</div>
|
||||||
|
</el-form>
|
||||||
|
|
||||||
|
<!-- 可视化界面移到表单下方 -->
|
||||||
|
<div class="location-visual" style="margin-top: 12px;">
|
||||||
|
<div v-for="row in groupedLocations" :key="row.row" class="row-group">
|
||||||
|
<div class="row-title">第{{ row.row }}排</div>
|
||||||
|
<div class="column-groups">
|
||||||
|
<div v-for="col in row.columns" :key="col.col" class="column-group">
|
||||||
|
<div class="column-title">第{{ col.col }}列</div>
|
||||||
|
<div class="layer-groups">
|
||||||
|
<div v-for="layer in col.layers" :key="layer.layer" class="layer-group">
|
||||||
|
<div class="layer-title">第{{ layer.layer }}层</div>
|
||||||
|
<div class="location-grid">
|
||||||
|
<div v-for="loc in layer.locations" :key="loc.locationId" class="location-cell" @click="showDetail(loc)" style="cursor:pointer;" :class="getLocationClass(loc)">
|
||||||
|
<div class="location-header">
|
||||||
|
<span class="location-id">{{ loc.locationId }}</span>
|
||||||
|
<div class="status-icons">
|
||||||
|
<span v-if="loc.isLock === 1" class="lock-icon" title="已锁定">🔒</span>
|
||||||
|
<span v-if="loc.isOccupy === 1" class="occupy-icon" title="占用中">🔴</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="location-coords">排:{{ loc.lRow }} 列:{{ loc.lCol }} 层:{{ loc.lLayer }} 深:{{ loc.lDepth }}</div>
|
||||||
|
<div class="location-status" :style="getLocationStatusStyle(loc)">{{ getLocationStatus(loc) }}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div v-if="sortedLocationList.length === 0" style="color: #F56C6C; margin: 16px 0; text-align: center;">暂无可视化数据</div>
|
||||||
|
<div v-if="errorMsg" style="color: #F56C6C; margin: 16px 0; text-align: center;">{{ errorMsg }}</div>
|
||||||
|
|
||||||
|
<el-pagination
|
||||||
|
v-model:current-page="page.current"
|
||||||
|
v-model:page-size="page.size"
|
||||||
|
:total="page.total"
|
||||||
|
:page-sizes="[20, 50, 100, 200]"
|
||||||
|
layout="total, sizes, prev, pager, next, jumper"
|
||||||
|
@current-change="search"
|
||||||
|
@size-change="search"
|
||||||
|
style="margin: 8px 0;"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<!-- 详情弹窗和编辑弹窗保留 -->
|
||||||
|
<el-dialog v-model="dialogVisible" title="库位详情" width="350px" :close-on-click-modal="true">
|
||||||
|
<div v-if="currentLocation">
|
||||||
|
<div>库位编号:{{ currentLocation.locationId }}</div>
|
||||||
|
<div>排:{{ currentLocation.lRow }}</div>
|
||||||
|
<div>列:{{ currentLocation.lCol }}</div>
|
||||||
|
<div>层:{{ currentLocation.lLayer }}</div>
|
||||||
|
<div>深度:{{ currentLocation.lDepth }}</div>
|
||||||
|
<div>锁定状态:<span :style="{color: currentLocation.isLock === 1 ? '#F56C6C' : '#67C23A'}">{{ currentLocation.isLock === 1 ? '已锁定' : '未锁定' }}</span></div>
|
||||||
|
<div>占用状态:<span :style="{color: currentLocation.isOccupy === 1 ? '#F56C6C' : '#67C23A'}">{{ currentLocation.isOccupy === 1 ? '占用' : '正常' }}</span></div>
|
||||||
|
</div>
|
||||||
|
<template #footer>
|
||||||
|
<el-button type="primary" @click="onEdit">编辑</el-button>
|
||||||
|
<el-button type="danger" @click="onDelete">删除</el-button>
|
||||||
|
<el-button @click="onToggleLock(currentLocation)">{{ currentLocation && currentLocation.isLock === 1 ? '解锁' : '锁定' }}</el-button>
|
||||||
|
<el-button @click="onToggleOccupy(currentLocation)">{{ currentLocation && currentLocation.isOccupy === 1 ? '设为正常' : '设为占用' }}</el-button>
|
||||||
|
<el-button @click="dialogVisible = false">关闭</el-button>
|
||||||
|
</template>
|
||||||
|
</el-dialog>
|
||||||
|
|
||||||
|
<el-dialog v-model="editDialogVisible" title="编辑库位" width="350px" :close-on-click-modal="false">
|
||||||
|
<el-form v-if="editForm" :model="editForm" label-width="60px">
|
||||||
|
<el-form-item label="排"><el-input v-model="editForm.lRow" /></el-form-item>
|
||||||
|
<el-form-item label="列"><el-input v-model="editForm.lCol" /></el-form-item>
|
||||||
|
<el-form-item label="层"><el-input v-model="editForm.lLayer" /></el-form-item>
|
||||||
|
<el-form-item label="深度"><el-input v-model="editForm.lDepth" /></el-form-item>
|
||||||
|
</el-form>
|
||||||
|
<template #footer>
|
||||||
|
<el-button type="primary" @click="onEditSave">保存</el-button>
|
||||||
|
<el-button @click="editDialogVisible = false">取消</el-button>
|
||||||
|
</template>
|
||||||
|
</el-dialog>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { ref, reactive, onMounted, computed } from 'vue';
|
||||||
|
import { getLocationList, updateLocationStatus } from '@/api/locationManage.js';
|
||||||
|
|
||||||
|
const page = reactive({ current: 1, size: 20, total: 0 });
|
||||||
|
const queryForm = reactive({
|
||||||
|
locationId: null,
|
||||||
|
lRow: null,
|
||||||
|
lCol: null,
|
||||||
|
lLayer: null,
|
||||||
|
lDepth: null,
|
||||||
|
locked: null,
|
||||||
|
occupied: null
|
||||||
|
});
|
||||||
|
const locationList = ref([]);
|
||||||
|
const errorMsg = ref('');
|
||||||
|
const dialogVisible = ref(false);
|
||||||
|
const currentLocation = ref(null);
|
||||||
|
const editDialogVisible = ref(false);
|
||||||
|
const editForm = ref(null);
|
||||||
|
|
||||||
|
const showDetail = (loc) => {
|
||||||
|
// 确保状态字段存在且持久化
|
||||||
|
if (loc.isLock === undefined) {
|
||||||
|
loc.isLock = localStorage.getItem(`location_${loc.locationId}_locked`) === 'true';
|
||||||
|
}
|
||||||
|
if (loc.isOccupy === undefined) {
|
||||||
|
loc.isOccupy = localStorage.getItem(`location_${loc.locationId}_occupied`) === 'true';
|
||||||
|
}
|
||||||
|
currentLocation.value = loc;
|
||||||
|
dialogVisible.value = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
const onEdit = () => {
|
||||||
|
editForm.value = { ...currentLocation.value };
|
||||||
|
editDialogVisible.value = true;
|
||||||
|
};
|
||||||
|
const onEditSave = () => {
|
||||||
|
// 这里预留接口调用位置
|
||||||
|
Object.assign(currentLocation.value, editForm.value);
|
||||||
|
editDialogVisible.value = false;
|
||||||
|
// 可加接口调用和刷新逻辑
|
||||||
|
};
|
||||||
|
const onDelete = () => {
|
||||||
|
if (window.confirm('确定要删除该库位吗?')) {
|
||||||
|
// 这里预留接口调用位置
|
||||||
|
dialogVisible.value = false;
|
||||||
|
// 可加接口调用和刷新逻辑
|
||||||
|
}
|
||||||
|
};
|
||||||
|
const onToggleLock = async (loc) => {
|
||||||
|
const newLock = loc.isLock === 1 ? 0 : 1;
|
||||||
|
await updateLocationStatus({ locationId: loc.locationId, isLock: newLock });
|
||||||
|
queryForm.locationId = loc.locationId;
|
||||||
|
page.current = 1;
|
||||||
|
search();
|
||||||
|
};
|
||||||
|
const onToggleOccupy = async (loc) => {
|
||||||
|
const newOccupy = loc.isOccupy === 1 ? 0 : 1;
|
||||||
|
await updateLocationStatus({ locationId: loc.locationId, isOccupy: newOccupy });
|
||||||
|
queryForm.locationId = loc.locationId;
|
||||||
|
page.current = 1;
|
||||||
|
search();
|
||||||
|
};
|
||||||
|
|
||||||
|
const search = async () => {
|
||||||
|
errorMsg.value = '';
|
||||||
|
try {
|
||||||
|
// 构造后端需要的参数
|
||||||
|
const params = { ...queryForm, pageNo: page.current, pageSize: page.size };
|
||||||
|
if (params.locked !== null && params.locked !== undefined) {
|
||||||
|
params.isLock = params.locked ? 1 : 0;
|
||||||
|
} else {
|
||||||
|
delete params.isLock;
|
||||||
|
}
|
||||||
|
if (params.occupied !== null && params.occupied !== undefined) {
|
||||||
|
params.isOccupy = params.occupied ? 1 : 0;
|
||||||
|
} else {
|
||||||
|
delete params.isOccupy;
|
||||||
|
}
|
||||||
|
// 删除前端多余字段
|
||||||
|
delete params.locked;
|
||||||
|
delete params.occupied;
|
||||||
|
const res = await getLocationList(params);
|
||||||
|
// 兼容后端返回结构
|
||||||
|
let lists = [];
|
||||||
|
let total = 0;
|
||||||
|
if (res.data) {
|
||||||
|
if (res.data.code === 0 && res.data.data) {
|
||||||
|
lists = res.data.data.lists || res.data.data.list || [];
|
||||||
|
total = res.data.data.total || res.data.data.count || 0;
|
||||||
|
} else if (Array.isArray(res.data)) {
|
||||||
|
lists = res.data;
|
||||||
|
total = res.data.length;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 为每个库位加载持久化状态
|
||||||
|
lists.forEach(loc => {
|
||||||
|
if (loc.isLock === undefined) {
|
||||||
|
loc.isLock = localStorage.getItem(`location_${loc.locationId}_locked`) === 'true';
|
||||||
|
}
|
||||||
|
if (loc.isOccupy === undefined) {
|
||||||
|
loc.isOccupy = localStorage.getItem(`location_${loc.locationId}_occupied`) === 'true';
|
||||||
|
}
|
||||||
|
});
|
||||||
|
locationList.value = lists;
|
||||||
|
page.total = total;
|
||||||
|
} catch (e) {
|
||||||
|
errorMsg.value = '接口请求失败,请检查网络或联系管理员';
|
||||||
|
locationList.value = [];
|
||||||
|
page.total = 0;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
onMounted(search);
|
||||||
|
|
||||||
|
const sortedLocationList = computed(() => {
|
||||||
|
return locationList.value.slice().sort((a, b) => {
|
||||||
|
if (a.lRow !== b.lRow) return a.lRow - b.lRow;
|
||||||
|
if (a.lCol !== b.lCol) return a.lCol - b.lCol;
|
||||||
|
if (a.lLayer !== b.lLayer) return a.lLayer - b.lLayer;
|
||||||
|
return a.lDepth - b.lDepth;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
const groupedLocations = computed(() => {
|
||||||
|
const groups = {};
|
||||||
|
sortedLocationList.value.forEach(loc => {
|
||||||
|
const row = loc.lRow;
|
||||||
|
const col = loc.lCol;
|
||||||
|
const layer = loc.lLayer;
|
||||||
|
if (!groups[row]) {
|
||||||
|
groups[row] = { row, columns: {} };
|
||||||
|
}
|
||||||
|
if (!groups[row].columns[col]) {
|
||||||
|
groups[row].columns[col] = { col, layers: {} };
|
||||||
|
}
|
||||||
|
if (!groups[row].columns[col].layers[layer]) {
|
||||||
|
groups[row].columns[col].layers[layer] = { layer, locations: [] };
|
||||||
|
}
|
||||||
|
groups[row].columns[col].layers[layer].locations.push(loc);
|
||||||
|
});
|
||||||
|
|
||||||
|
// 转换为数组并排序
|
||||||
|
return Object.values(groups).map(rowGroup => ({
|
||||||
|
row: rowGroup.row,
|
||||||
|
columns: Object.values(rowGroup.columns).map(colGroup => ({
|
||||||
|
col: colGroup.col,
|
||||||
|
layers: Object.values(colGroup.layers).sort((a, b) => a.layer - b.layer)
|
||||||
|
})).sort((a, b) => a.col - b.col)
|
||||||
|
})).sort((a, b) => a.row - b.row);
|
||||||
|
});
|
||||||
|
|
||||||
|
const getLocationClass = (loc) => {
|
||||||
|
if (loc.isOccupy === 1) return 'location-occupied';
|
||||||
|
if (loc.isLock === 1) return 'location-locked';
|
||||||
|
return 'location-normal';
|
||||||
|
};
|
||||||
|
const getLocationStatus = (loc) => {
|
||||||
|
if (loc.isLock === 1 && loc.isOccupy === 1) return '锁定,占用';
|
||||||
|
if (loc.isOccupy === 1) return '占用';
|
||||||
|
if (loc.isLock === 1) return '锁定';
|
||||||
|
return '正常';
|
||||||
|
};
|
||||||
|
|
||||||
|
const getLocationStatusStyle = (loc) => {
|
||||||
|
if (loc.isLock === 1 || loc.isOccupy === 1) return { color: '#ff4d4f' };
|
||||||
|
return { color: '#52c41a' };
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.location-cell {
|
||||||
|
width: 100px;
|
||||||
|
height: 80px;
|
||||||
|
border: 1px solid #dcdfe6;
|
||||||
|
border-radius: 6px;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
margin: 0;
|
||||||
|
background: #f5f7fa;
|
||||||
|
font-size: 13px;
|
||||||
|
padding: 4px 0;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
.location-header {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
width: 100%;
|
||||||
|
padding: 0 4px;
|
||||||
|
margin-bottom: 2px;
|
||||||
|
}
|
||||||
|
.location-id {
|
||||||
|
font-size: 11px;
|
||||||
|
font-weight: bold;
|
||||||
|
flex: 1;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
.status-icons {
|
||||||
|
display: flex;
|
||||||
|
gap: 2px;
|
||||||
|
position: absolute;
|
||||||
|
top: 2px;
|
||||||
|
right: 2px;
|
||||||
|
}
|
||||||
|
.lock-icon {
|
||||||
|
color: #52c41a;
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
.occupy-icon {
|
||||||
|
color: #ff4d4f;
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
.location-coords {
|
||||||
|
font-size: 10px;
|
||||||
|
color: #666;
|
||||||
|
margin-bottom: 2px;
|
||||||
|
}
|
||||||
|
.location-status {
|
||||||
|
font-size: 10px;
|
||||||
|
font-weight: bold;
|
||||||
|
margin-top: 2px;
|
||||||
|
}
|
||||||
|
.row-group {
|
||||||
|
margin-bottom: 20px;
|
||||||
|
border: 1px solid #e4e7ed;
|
||||||
|
border-radius: 8px;
|
||||||
|
padding: 12px;
|
||||||
|
background: #fafafa;
|
||||||
|
}
|
||||||
|
.row-title {
|
||||||
|
font-weight: bold;
|
||||||
|
font-size: 16px;
|
||||||
|
color: #303133;
|
||||||
|
margin-bottom: 8px;
|
||||||
|
padding: 4px 8px;
|
||||||
|
background: #e1f3d8;
|
||||||
|
border-radius: 4px;
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
.column-groups {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 16px;
|
||||||
|
}
|
||||||
|
.column-group {
|
||||||
|
border: 1px solid #dcdfe6;
|
||||||
|
border-radius: 6px;
|
||||||
|
padding: 8px;
|
||||||
|
background: white;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
.column-title {
|
||||||
|
font-weight: bold;
|
||||||
|
font-size: 14px;
|
||||||
|
color: #606266;
|
||||||
|
margin-bottom: 8px;
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
.layer-groups {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 4px;
|
||||||
|
}
|
||||||
|
.layer-group {
|
||||||
|
border: 1px solid #f0f0f0;
|
||||||
|
border-radius: 4px;
|
||||||
|
padding: 4px;
|
||||||
|
background: #fafafa;
|
||||||
|
width: 100px;
|
||||||
|
}
|
||||||
|
.layer-title {
|
||||||
|
font-weight: bold;
|
||||||
|
font-size: 11px;
|
||||||
|
color: #909399;
|
||||||
|
margin-bottom: 4px;
|
||||||
|
text-align: left;
|
||||||
|
padding: 1px 4px;
|
||||||
|
background: #f5f7fa;
|
||||||
|
border-radius: 2px;
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
.location-grid {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 2px;
|
||||||
|
justify-content: flex-start;
|
||||||
|
}
|
||||||
|
.location-normal {
|
||||||
|
background: #e8f5e8;
|
||||||
|
border-color: #52c41a;
|
||||||
|
color: #52c41a;
|
||||||
|
box-shadow: 0 2px 4px rgba(82, 196, 26, 0.2);
|
||||||
|
}
|
||||||
|
.location-locked {
|
||||||
|
background: #e8f5e8;
|
||||||
|
border-color: #52c41a;
|
||||||
|
color: #52c41a;
|
||||||
|
box-shadow: 0 2px 4px rgba(82, 196, 26, 0.2);
|
||||||
|
}
|
||||||
|
.location-occupied {
|
||||||
|
background: #fff2f0;
|
||||||
|
border-color: #ff4d4f;
|
||||||
|
color: #ff4d4f;
|
||||||
|
box-shadow: 0 2px 4px rgba(255, 77, 79, 0.2);
|
||||||
|
}
|
||||||
|
</style>
|
||||||
Loading…
Reference in New Issue
Block a user