diff --git a/gemini.md b/gemini.md
new file mode 100644
index 0000000..7194fd9
--- /dev/null
+++ b/gemini.md
@@ -0,0 +1,16 @@
+# Gemini Project: MyReactNativeApp
+
+This is a React Native application built with TypeScript.
+
+## Project Structure
+
+- `src/`: Contains the main source code for the application.
+ - `components/`: Reusable React components.
+ - `context/`: React context for state management.
+ - `hooks/`: Custom React hooks.
+ - `navigation/`: Navigation logic using React Navigation.
+ - `screens/`: Application screens.
+ - `services/`: Services for API calls and other business logic.
+ - `types/`: TypeScript type definitions.
+- `android/`: Android specific code.
+- `ios/`: iOS specific code.
diff --git a/index.js b/index.js
index 6011123..0bbc29d 100644
--- a/index.js
+++ b/index.js
@@ -8,4 +8,6 @@ import { AppRegistry } from 'react-native';
import App from './App';
import { name as appName } from './app.json';
+
+
AppRegistry.registerComponent(appName, () => App);
diff --git a/package-lock.json b/package-lock.json
index 6e7396c..a0d6ff7 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -19,6 +19,7 @@
"axios": "^1.11.0",
"react": "19.1.0",
"react-native": "0.80.1",
+ "react-native-elements": "^3.4.3",
"react-native-gesture-handler": "^2.27.1",
"react-native-get-random-values": "^1.11.0",
"react-native-safe-area-context": "^5.5.2",
@@ -9203,6 +9204,13 @@
"dev": true,
"license": "MIT"
},
+ "node_modules/lodash.isequal": {
+ "version": "4.5.0",
+ "resolved": "https://registry.npmmirror.com/lodash.isequal/-/lodash.isequal-4.5.0.tgz",
+ "integrity": "sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ==",
+ "deprecated": "This package is deprecated. Use require('node:util').isDeepStrictEqual instead.",
+ "license": "MIT"
+ },
"node_modules/lodash.merge": {
"version": "4.6.2",
"resolved": "https://registry.npmmirror.com/lodash.merge/-/lodash.merge-4.6.2.tgz",
@@ -10297,6 +10305,15 @@
"node": ">=8"
}
},
+ "node_modules/opencollective-postinstall": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmmirror.com/opencollective-postinstall/-/opencollective-postinstall-2.0.3.tgz",
+ "integrity": "sha512-8AV/sCtuzUeTo8gQK5qDZzARrulB3egtLzFgteqB2tcT4Mw7B8Kt7JcDHmltjz6FOAHsvTevk70gZEbhM4ZS9Q==",
+ "license": "MIT",
+ "bin": {
+ "opencollective-postinstall": "index.js"
+ }
+ },
"node_modules/optionator": {
"version": "0.9.4",
"resolved": "https://registry.npmmirror.com/optionator/-/optionator-0.9.4.tgz",
@@ -10938,6 +10955,74 @@
}
}
},
+ "node_modules/react-native-elements": {
+ "version": "3.4.3",
+ "resolved": "https://registry.npmmirror.com/react-native-elements/-/react-native-elements-3.4.3.tgz",
+ "integrity": "sha512-VtZc25EecPZyUBER85zFK9ZbY6kkUdcm1ZwJ9hdoGSCr1R/GFgxor4jngOcSYeMvQ+qimd5No44OVJW3rSJECA==",
+ "hasInstallScript": true,
+ "license": "MIT",
+ "dependencies": {
+ "@types/react-native-vector-icons": "^6.4.6",
+ "color": "^3.1.2",
+ "deepmerge": "^4.2.2",
+ "hoist-non-react-statics": "^3.3.2",
+ "lodash.isequal": "^4.5.0",
+ "opencollective-postinstall": "^2.0.3",
+ "react-native-ratings": "8.0.4",
+ "react-native-size-matters": "^0.3.1"
+ },
+ "peerDependencies": {
+ "react-native-safe-area-context": ">= 3.0.0",
+ "react-native-vector-icons": ">7.0.0"
+ }
+ },
+ "node_modules/react-native-elements/node_modules/color": {
+ "version": "3.2.1",
+ "resolved": "https://registry.npmmirror.com/color/-/color-3.2.1.tgz",
+ "integrity": "sha512-aBl7dZI9ENN6fUGC7mWpMTPNHmWUSNan9tuWN6ahh5ZLNk9baLJOnSMlrQkHcrfFgz2/RigjUVAjdx36VcemKA==",
+ "license": "MIT",
+ "dependencies": {
+ "color-convert": "^1.9.3",
+ "color-string": "^1.6.0"
+ }
+ },
+ "node_modules/react-native-elements/node_modules/color-convert": {
+ "version": "1.9.3",
+ "resolved": "https://registry.npmmirror.com/color-convert/-/color-convert-1.9.3.tgz",
+ "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
+ "license": "MIT",
+ "dependencies": {
+ "color-name": "1.1.3"
+ }
+ },
+ "node_modules/react-native-elements/node_modules/color-name": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmmirror.com/color-name/-/color-name-1.1.3.tgz",
+ "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==",
+ "license": "MIT"
+ },
+ "node_modules/react-native-elements/node_modules/react-native-ratings": {
+ "version": "8.0.4",
+ "resolved": "https://registry.npmmirror.com/react-native-ratings/-/react-native-ratings-8.0.4.tgz",
+ "integrity": "sha512-Xczu5lskIIRD6BEdz9A0jDRpEck/SFxRqiglkXi0u67yAtI1/pcJC76P4MukCbT8K4BPVl+42w83YqXBoBRl7A==",
+ "license": "MIT",
+ "dependencies": {
+ "lodash": "^4.17.15"
+ },
+ "peerDependencies": {
+ "react": "*",
+ "react-native": "*"
+ }
+ },
+ "node_modules/react-native-elements/node_modules/react-native-size-matters": {
+ "version": "0.3.1",
+ "resolved": "https://registry.npmmirror.com/react-native-size-matters/-/react-native-size-matters-0.3.1.tgz",
+ "integrity": "sha512-mKOfBLIBFBcs9br1rlZDvxD5+mAl8Gfr5CounwJtxI6Z82rGrMO+Kgl9EIg3RMVf3G855a85YVqHJL2f5EDRlw==",
+ "license": "MIT",
+ "peerDependencies": {
+ "react-native": "*"
+ }
+ },
"node_modules/react-native-gesture-handler": {
"version": "2.27.1",
"resolved": "https://registry.npmmirror.com/react-native-gesture-handler/-/react-native-gesture-handler-2.27.1.tgz",
diff --git a/package.json b/package.json
index 3633f51..66c7fe1 100644
--- a/package.json
+++ b/package.json
@@ -21,6 +21,7 @@
"axios": "^1.11.0",
"react": "19.1.0",
"react-native": "0.80.1",
+ "react-native-elements": "^3.4.3",
"react-native-gesture-handler": "^2.27.1",
"react-native-get-random-values": "^1.11.0",
"react-native-safe-area-context": "^5.5.2",
diff --git a/src/navigation/AppNavigator.tsx b/src/navigation/AppNavigator.tsx
index 4dab0af..b75943c 100644
--- a/src/navigation/AppNavigator.tsx
+++ b/src/navigation/AppNavigator.tsx
@@ -7,6 +7,7 @@ import TaskEditScreen from '../screens/TaskEditScreen';
import RunScreen from '../screens/RunScreen';
import EditScreen from '../screens/EditScreen';
import SettingsScreen from '../screens/SettingsScreen';
+import LocationScreen from '../screens/LocationScreen';
const HomeStack = createStackNavigator();
const Tab = createBottomTabNavigator();
@@ -74,7 +75,7 @@ export default function AppNavigator() {
options={{ headerShown: false }}
/>
-
+
);
diff --git a/src/screens/EditScreen.tsx b/src/screens/EditScreen.tsx
index 7699e71..e69de29 100644
--- a/src/screens/EditScreen.tsx
+++ b/src/screens/EditScreen.tsx
@@ -1,18 +0,0 @@
-import React from 'react';
-import { StyleSheet, Text, View } from 'react-native';
-
-export default function EditScreen() {
- return (
-
- 编辑!
-
- );
-}
-
-const styles = StyleSheet.create({
- screenContainer: {
- flex: 1,
- justifyContent: 'center',
- alignItems: 'center',
- },
-});
diff --git a/src/screens/LocationScreen.tsx b/src/screens/LocationScreen.tsx
new file mode 100644
index 0000000..2e72ec9
--- /dev/null
+++ b/src/screens/LocationScreen.tsx
@@ -0,0 +1,219 @@
+import React, { useEffect, useState, useCallback } from 'react';
+import { StyleSheet, View, FlatList, Text, ActivityIndicator, Alert } from 'react-native';
+import { SearchBar, CheckBox, Button, useTheme, Overlay, ListItem } from '@rneui/themed';
+import api from '../services/api';
+
+interface Location {
+ id: string;
+ layer_name: string;
+ is_occupied: boolean;
+ is_locked: boolean;
+ is_empty_tray: boolean;
+ is_disabled: boolean;
+}
+
+const LocationScreen = () => {
+ const { theme } = useTheme();
+ const [locations, setLocations] = useState([]);
+ const [search, setSearch] = useState('');
+ const [loading, setLoading] = useState(true);
+ const [selectedLocations, setSelectedLocations] = useState([]);
+ const [isOverlayVisible, setOverlayVisible] = useState(false);
+
+ const fetchData = useCallback(async (query = '') => {
+ setLoading(true);
+ try {
+ const response = await api.get('/api/vwed-operate-point/list', {
+ params: { layer_name: query },
+ });
+ setLocations(response.storage_locations);
+ } catch (error) {
+ console.error(error);
+ Alert.alert('错误', '加载库位列表失败。');
+ } finally {
+ setLoading(false);
+ }
+ }, []);
+
+ useEffect(() => {
+ fetchData();
+ }, [fetchData]);
+
+ const handleSearch = () => {
+ fetchData(search);
+ };
+
+ const toggleSelection = (id: string) => {
+ setSelectedLocations(prev =>
+ prev.includes(id) ? prev.filter(item => item !== id) : [...prev, id]
+ );
+ };
+
+ const handleBatchUpdate = async (action: string) => {
+ if (selectedLocations.length === 0) {
+ Alert.alert('未选择', '请选择要操作的库位。');
+ return;
+ }
+ setOverlayVisible(false);
+ try {
+ const response = await api.put('/api/vwed-operate-point/batch-status', {
+ layer_names: selectedLocations,
+ action: action,
+ });
+
+ const { success_count, failed_count, results } = response;
+ let message = `批量操作完成:\n成功 ${success_count} 个, 失败 ${failed_count} 个。\n\n`;
+ if (failed_count > 0) {
+ message += '失败详情:\n';
+ results.forEach((res: any) => {
+ if (!res.success) {
+ message += `${res.layer_name}: ${res.message}\n`;
+ }
+ });
+ }
+ Alert.alert('操作结果', message);
+
+ fetchData(search);
+ setSelectedLocations([]);
+ } catch (error) {
+ console.error(error);
+ Alert.alert('错误', `批量操作失败: ${error.message}`);
+ }
+ };
+
+ const actions = [
+ { title: '禁用', action: 'disable' },
+ { title: '启用', action: 'enable' },
+ { title: '占用', action: 'occupy' },
+ { title: '释放', action: 'release' },
+ { title: '锁定', action: 'lock' },
+ { title: '解锁', action: 'unlock' },
+ ];
+
+ const renderItem = ({ item }: { item: Location }) => (
+
+ toggleSelection(item.id)}
+ containerStyle={{ backgroundColor: 'transparent' }}
+ />
+ {item.layer_name}
+ {item.is_occupied ? '是' : '否'}
+ {item.is_locked ? '是' : '否'}
+ {item.is_empty_tray ? '是' : '否'}
+ {item.is_disabled ? '是' : '否'}
+
+ );
+
+ if (loading) {
+ return (
+
+
+
+ );
+ }
+
+ return (
+
+
+
+
+
+
+
+ );
+};
+
+const styles = StyleSheet.create({
+ container: {
+ flex: 1,
+ },
+ loader: {
+ flex: 1,
+ justifyContent: 'center',
+ alignItems: 'center',
+ },
+ searchContainer: {
+ flexDirection: 'row',
+ alignItems: 'center',
+ },
+ searchBarContainer: {
+ flex: 1,
+ backgroundColor: 'transparent',
+ borderTopWidth: 0,
+ borderBottomWidth: 0,
+ },
+ searchButton: {
+ marginRight: 10,
+ },
+ batchButtonContainer: {
+ margin: 10,
+ },
+ itemContainer: {
+ flexDirection: 'row',
+ alignItems: 'center',
+ paddingVertical: 8,
+ paddingHorizontal: 10,
+ },
+ itemText: {
+ flex: 1,
+ textAlign: 'center',
+ fontSize: 14,
+ },
+ headerContainer: {
+ flexDirection: 'row',
+ padding: 12,
+ borderBottomWidth: 1,
+ borderBottomColor: '#ccc',
+ },
+ headerText: {
+ flex: 1,
+ textAlign: 'center',
+ fontWeight: 'bold',
+ fontSize: 16,
+ },
+ separator: {
+ height: 1,
+ backgroundColor: '#e0e0e0',
+ },
+});
+
+export default LocationScreen;
\ No newline at end of file
diff --git a/库位管理接口文档.md b/库位管理接口文档.md
new file mode 100644
index 0000000..4b34487
--- /dev/null
+++ b/库位管理接口文档.md
@@ -0,0 +1,1017 @@
+# 库位管理接口文档
+
+## 概述
+
+库位管理接口提供了对库位(基于动作点分层)的全面管理功能,包括库位查询、状态更新、扩展属性管理、操作记录查询等。每个动作点可以包含多个层,每一层对应一个库位。
+
+**重要说明:**
+- 所有接口现在使用 `layer_name`(库位名称)作为库位的主要标识符
+- 路径参数和查询参数均使用 `layer_name` 而不是 `storage_location_id`
+- 这样设计使得接口更加直观和易于使用
+
+## 接口更新历史
+
+**2024年最新更新:**
+- 将 `GET /api/vwed-operate-point/{layer_name}/status` 接口的路径参数改为 `layer_name`
+- 将 `GET /api/vwed-operate-point/{layer_name}` 接口的路径参数改为 `layer_name`
+- 将 `PUT /api/vwed-operate-point/{layer_name}` 接口的路径参数改为 `layer_name`
+- 将 `GET /api/vwed-operate-point/operation-logs` 接口的查询参数改为 `layer_name`
+- 统一使用库位名称作为主要标识符,提升接口的一致性和易用性
+
+## 接口列表
+
+### 1. 获取库位列表 (GET /api/vwed-operate-point/list)
+
+获取库位列表,支持多种筛选条件、排序功能和分页查询。
+
+**排序功能说明:**
+- `layer_name_sort`:支持按层名称排序,如 GSD_1_1_1 格式,先按数字部分排序,然后按字母部分排序
+- `station_name_sort`:支持按站点名称排序,如 AP1 格式,先按数字部分排序,然后按字母部分排序
+- 排序规则:首先按数字排序,如果数字都一样的话,按照字母排序
+- 可以同时使用两种排序,优先按 layer_name_sort 排序,然后按 station_name_sort 排序
+
+#### 请求参数
+
+| 参数名 | 类型 | 必填 | 描述 |
+| --------------------------- | ------- | ---- | --------------------------- |
+| scene_id | string | 否 | 场景ID |
+| storage_area_id | string | 否 | 库区ID |
+| station_name | string | 否 | 站点名称(支持模糊搜索) |
+| layer_name | string | 否 | 层名称(支持模糊搜索) |
+| is_disabled | boolean | 否 | 是否禁用 |
+| is_occupied | boolean | 否 | 是否占用 |
+| is_locked | boolean | 否 | 是否锁定 |
+| is_empty_tray | boolean | 否 | 是否空托盘 |
+| include_operate_point_info | boolean | 否 | 是否包含动作点信息(默认true) |
+| include_extended_fields | boolean | 否 | 是否包含扩展字段(默认true) |
+| layer_name_sort | boolean | 否 | 层名称排序:true(升序,默认)、false(降序) |
+| station_name_sort | boolean | 否 | 站点名称排序:true(升序,默认)、false(降序) |
+| page | integer | 否 | 页码(默认1) |
+| page_size | integer | 否 | 每页数量(默认20,最大100) |
+
+#### 响应格式
+
+```json
+{
+ "code": 200,
+ "message": "查询成功",
+ "data": {
+ "total": 7,
+ "page": 1,
+ "page_size": 20,
+ "total_pages": 1,
+ "storage_locations": [
+ {
+ "id": "45ecea40-032d-47e1-8637-50882fd722f1",
+ "layer_index": 3,
+ "layer_name": "4-3",
+ "is_occupied": false,
+ "is_locked": false,
+ "is_disabled": false,
+ "is_empty_tray": false,
+ "locked_by": null,
+ "goods_content": "",
+ "goods_weight": null,
+ "goods_volume": null,
+ "goods_stored_at": null,
+ "goods_retrieved_at": null,
+ "last_access_at": null,
+ "max_weight": null,
+ "max_volume": null,
+ "layer_height": null,
+ "tags": null,
+ "description": null,
+ "created_at": "2025-07-15T13:27:05.994536",
+ "updated_at": "2025-07-15T13:28:17.825850",
+ "extended_fields": {
+ "真实名字": null,
+ "test": null
+ },
+ "operate_point_id": "637defff-4670-4574-a73e-033bc94941a5",
+ "station_name": "STATION-B-004",
+ "scene_id": "1936411520272753371",
+ "storage_area_id": "df28bb5a-f88f-4825-93e6-a1dae7c34bb1",
+ "storage_area_type": "general",
+ "area_name": "一般存储区C",
+ "max_layers": 3,
+ "current_layers": 0,
+ "position_x": null,
+ "position_y": null,
+ "position_z": null,
+ "operate_point_description": null
+ },
+
+ ]
+ }
+}
+```
+
+#### 返回字段说明
+
+##### 分页信息
+| 字段名 | 类型 | 说明 |
+| ----------- | ------- | -------------- |
+| total | integer | 总记录数 |
+| page | integer | 当前页码 |
+| page_size | integer | 每页记录数 |
+| total_pages | integer | 总页数 |
+
+##### 库位层信息 (storage_locations)
+| 字段名 | 类型 | 说明 |
+| ------------------------- | ------- | -------------------------------- |
+| id | string | 库位ID(唯一标识) |
+| layer_index | integer | 层索引(从1开始) |
+| layer_name | string | 库位名称 |
+| is_occupied | boolean | 是否占用 |
+| is_locked | boolean | 是否锁定 |
+| is_disabled | boolean | 是否禁用 |
+| is_empty_tray | boolean | 是否空托盘 |
+| locked_by | string | 锁定者 |
+| goods_content | string | 货物内容 |
+| goods_weight | integer | 货物重量(克) |
+| goods_volume | integer | 货物体积(立方厘米) |
+| goods_stored_at | string | 货物存放时间 |
+| goods_retrieved_at | string | 货物取出时间 |
+| last_access_at | string | 最后访问时间 |
+| max_weight | integer | 最大承重(克) |
+| max_volume | integer | 最大体积(立方厘米) |
+| layer_height | integer | 层高(毫米) |
+| tags | string | 层标签 |
+| description | string | 层描述 |
+| created_at | string | 创建时间 |
+| updated_at | string | 更新时间 |
+| extended_fields | object | 扩展字段(键值对形式) |
+
+##### 动作点信息 (operate_point_info)
+| 字段名 | 类型 | 说明 |
+| ------------------------- | ------- | -------------------------------- |
+| operate_point_id | string | 动作点ID |
+| station_name | string | 站点名称 |
+| scene_id | string | 场景ID |
+| storage_area_id | string | 库区ID |
+| storage_area_type | string | 库区类型 |
+| area_name | string | 库区名称 |
+| max_layers | integer | 最大层数 |
+| current_layers | integer | 当前层数 |
+| position_x | float | X坐标 |
+| position_y | float | Y坐标 |
+| position_z | float | Z坐标 |
+| operate_point_description | string | 动作点描述 |
+
+#### 调用示例
+
+**基本查询:**
+```bash
+GET /api/vwed-operate-point/list?scene_id=scene-001&is_occupied=false&page=1&page_size=20
+```
+
+**带排序的查询:**
+```bash
+# 按层名称升序排序
+GET /api/vwed-operate-point/list?layer_name_sort=true&page=1&page_size=20
+
+# 按站点名称降序排序
+GET /api/vwed-operate-point/list?station_name_sort=false&page=1&page_size=20
+
+# 组合排序:先按层名称升序,再按站点名称降序
+GET /api/vwed-operate-point/list?layer_name_sort=true&station_name_sort=false&page=1&page_size=20
+```
+
+---
+
+### 2. 更新库位状态 (PUT /api/vwed-operate-point/status)
+
+更新单个库位的状态。
+
+#### 请求参数
+
+```json
+{
+ "layer_name": "layer-001",
+ "action": "occupy",
+ "locked_by": "user123",
+ "reason": "放置货物A"
+}
+```
+
+| 参数名 | 类型 | 必填 | 描述 |
+| --------- | ------ | ---- | ----------------------------------------- |
+| layer_name | string | 是 | 库位名称 |
+| action | string | 是 | 操作类型(见支持的操作类型) |
+| locked_by | string | 否 | 锁定者(锁定操作时必填) |
+| reason | string | 否 | 操作原因 |
+
+#### 支持的操作类型
+
+| 操作类型 | 描述 |
+| ------------------ | ------------------- |
+| occupy | 占用库位 |
+| release | 释放库位 |
+| lock | 锁定库位 |
+| unlock | 解锁库位 |
+| enable | 启用库位 |
+| disable | 禁用库位 |
+| set_empty_tray | 设置为空托盘 |
+| clear_empty_tray | 清除空托盘状态 |
+
+#### 响应格式
+
+```json
+{
+ "code": 200,
+ "message": "状态更新完成",
+ "data": {
+ "layer_name": "layer-001",
+ "action": "occupy",
+ "success": true,
+ "message": "库位占用成功",
+ "new_status": {
+ "is_occupied": true,
+ "is_locked": false,
+ "is_disabled": false,
+ "is_empty_tray": false,
+ "locked_by": null,
+ "updated_at": "2024-01-01T12:00:00"
+ }
+ }
+}
+```
+
+#### 返回字段说明
+
+| 字段名 | 类型 | 说明 |
+| ---------- | ------- | ------------------------------ |
+| layer_name | string | 库位名称 |
+| action | string | 执行的操作类型 |
+| success | boolean | 操作是否成功 |
+| message | string | 操作结果消息 |
+| new_status | object | 更新后的状态信息 |
+
+##### 状态信息 (new_status)
+| 字段名 | 类型 | 说明 |
+| ------------ | ------- | ---------------- |
+| is_occupied | boolean | 是否占用 |
+| is_locked | boolean | 是否锁定 |
+| is_disabled | boolean | 是否禁用 |
+| is_empty_tray| boolean | 是否空托盘 |
+| locked_by | string | 锁定者 |
+| updated_at | string | 更新时间 |
+
+---
+
+### 3. 批量更新库位状态 (PUT /api/vwed-operate-point/batch-status)
+
+批量更新多个库位的状态。
+
+#### 请求参数
+
+```json
+{
+ "layer_names": ["layer-001", "layer-002", "layer-003"],
+ "action": "lock",
+ "locked_by": "user123",
+ "reason": "批量锁定操作"
+}
+```
+
+| 参数名 | 类型 | 必填 | 描述 |
+| ---------- | -------- | ---- | ----------------------------------------- |
+| layer_names | string[] | 是 | 库位名称列表(最多100个) |
+| action | string | 是 | 操作类型(见支持的操作类型) |
+| locked_by | string | 否 | 锁定者(锁定操作时必填) |
+| reason | string | 否 | 操作原因 |
+
+#### 响应格式
+
+```json
+{
+ "code": 200,
+ "message": "批量状态更新完成:成功操作 2 个库位,失败操作 1 个库位",
+ "data": {
+ "total_count": 3,
+ "success_count": 2,
+ "failed_count": 1,
+ "results": [
+ {
+ "layer_name": "layer-001",
+ "action": "lock",
+ "success": true,
+ "message": "库位锁定成功",
+ "new_status": {
+ "is_locked": true,
+ "locked_by": "user123"
+ }
+ },
+ {
+ "layer_name": "layer-002",
+ "action": "lock",
+ "success": false,
+ "message": "库位已被其他用户锁定",
+ "new_status": {}
+ }
+ ]
+ }
+}
+```
+
+#### 返回字段说明
+
+| 字段名 | 类型 | 说明 |
+| ------------- | ------- | ------------------------------ |
+| total_count | integer | 总操作数量 |
+| success_count | integer | 成功操作数量 |
+| failed_count | integer | 失败操作数量 |
+| results | array | 每个库位的操作结果详情 |
+
+##### 操作结果详情 (results[])
+| 字段名 | 类型 | 说明 |
+| ---------- | ------- | ------------------------------ |
+| layer_name | string | 库位名称 |
+| action | string | 执行的操作类型 |
+| success | boolean | 操作是否成功 |
+| message | string | 操作结果消息 |
+| new_status | object | 更新后的状态信息(成功时返回) |
+
+---
+
+### 4. 获取支持的操作类型 (GET /api/vwed-operate-point/actions)
+
+获取系统支持的所有库位操作类型。
+
+#### 响应格式
+
+```json
+{
+ "code": 200,
+ "message": "获取支持的操作类型成功",
+ "data": {
+ "actions": [
+ {
+ "value": "occupy",
+ "description": "占用库位"
+ },
+ {
+ "value": "release",
+ "description": "释放库位"
+ },
+ {
+ "value": "lock",
+ "description": "锁定库位(需要提供锁定者)"
+ }
+ ],
+ "count": 8
+ }
+}
+```
+
+#### 返回字段说明
+
+| 字段名 | 类型 | 说明 |
+| ------- | ------- | ------------------------------ |
+| actions | array | 支持的操作类型列表 |
+| count | integer | 操作类型数量 |
+
+##### 操作类型信息 (actions[])
+| 字段名 | 类型 | 说明 |
+| ----------- | ------ | -------------- |
+| value | string | 操作类型值 |
+| description | string | 操作类型描述 |
+
+---
+
+### 5. 获取库位详情 (GET /api/vwed-operate-point/{layer_name})
+
+获取指定库位的详细信息。
+
+#### 请求参数
+
+| 参数名 | 类型 | 必填 | 描述 |
+| ---------- | ------ | ---- | -------- |
+| layer_name | string | 是 | 库位名称(路径参数) |
+
+#### 响应格式
+
+```json
+{
+ "code": 200,
+ "message": "获取库位详情成功",
+ "data": {
+ "storage_location": {
+ "id": "layer-001",
+ "layer_index": 1,
+ "layer_name": "第一层",
+ "is_occupied": false,
+ "is_locked": false,
+ "is_disabled": false,
+ "is_empty_tray": false,
+ "locked_by": null,
+ "goods_content": "",
+ "goods_weight": null,
+ "goods_volume": null,
+ "max_weight": 5000,
+ "max_volume": 1000,
+ "layer_height": 300,
+ "tags": "高架库,密集存储",
+ "description": "密集存储区第一层",
+ "created_at": "2024-01-01T00:00:00",
+ "updated_at": "2024-01-01T00:00:00",
+ "extended_fields": {
+ "产品类别": "电子产品",
+ "存储温度": "常温"
+ }
+ },
+ "operate_point_info": {
+ "id": "point-001",
+ "station_name": "存储站点A",
+ "scene_id": "scene-001",
+ "area_name": "密集存储区"
+ },
+ "extended_fields_definitions": [
+ {
+ "id": "ext-001",
+ "property_name": "产品类别",
+ "property_type": "select",
+ "is_required": true,
+ "is_enabled": true,
+ "description": "产品分类"
+ }
+ ],
+ "status_history": []
+ }
+}
+```
+
+#### 返回字段说明
+
+##### 库位信息 (storage_location)
+| 字段名 | 类型 | 说明 |
+| --------------- | ------- | ------------------------------ |
+| id | string | 层ID(唯一标识) |
+| layer_index | integer | 层索引(从1开始) |
+| layer_name | string | 层名称 |
+| is_occupied | boolean | 是否占用 |
+| is_locked | boolean | 是否锁定 |
+| is_disabled | boolean | 是否禁用 |
+| is_empty_tray | boolean | 是否空托盘 |
+| locked_by | string | 锁定者 |
+| goods_content | string | 货物内容 |
+| goods_weight | integer | 货物重量(克) |
+| goods_volume | integer | 货物体积(立方厘米) |
+| max_weight | integer | 最大承重(克) |
+| max_volume | integer | 最大体积(立方厘米) |
+| layer_height | integer | 层高(毫米) |
+| tags | string | 层标签 |
+| description | string | 层描述 |
+| created_at | string | 创建时间 |
+| updated_at | string | 更新时间 |
+| extended_fields | object | 扩展字段值(键值对形式) |
+
+##### 动作点信息 (operate_point_info)
+| 字段名 | 类型 | 说明 |
+| --------------------- | ------ | ------------ |
+| id | string | 动作点ID |
+| station_name | string | 站点名称 |
+| scene_id | string | 场景ID |
+| area_name | string | 库区名称 |
+
+##### 扩展字段定义 (extended_fields_definitions[])
+| 字段名 | 类型 | 说明 |
+| ------------- | ------- | ------------------------------ |
+| id | string | 扩展属性ID |
+| property_name | string | 属性名称 |
+| property_type | string | 属性类型 |
+| is_required | boolean | 是否必填 |
+| is_enabled | boolean | 是否启用 |
+| description | string | 属性描述 |
+
+##### 状态历史 (status_history[])
+| 字段名 | 类型 | 说明 |
+| -------------- | ------ | ------------ |
+| operation_time | string | 操作时间 |
+| operation_type | string | 操作类型 |
+| operator | string | 操作人员 |
+| description | string | 操作描述 |
+
+---
+
+### 6. 编辑库位信息 (PUT /api/vwed-operate-point/{layer_name})
+
+编辑库位的各种属性信息。
+
+#### 请求参数
+
+| 参数名 | 类型 | 必填 | 描述 |
+| ------------ | ------ | ---- | -------- |
+| layer_name | string | 是 | 库位名称(路径参数) |
+
+#### 请求体
+
+```json
+{
+ "goods_content": "电子产品A",
+ "goods_weight": 500,
+ "goods_volume": 200,
+ "max_weight": 6000,
+ "is_locked": false,
+ "is_disabled": false,
+ "is_empty_tray": true,
+ "tags": "高架库,密集存储,已更新",
+ "description": "密集存储区第一层 - 已更新",
+ "extended_fields": {
+ "产品类别": "机械配件",
+ "存储温度": "常温",
+ "保质期": "12个月"
+ }
+}
+```
+
+#### 响应格式
+
+```json
+{
+ "code": 200,
+ "message": "库位信息编辑成功",
+ "data": {
+ "layer_name": "layer-001",
+ "success": true,
+ "message": "库位信息更新成功,共更新 8 个字段",
+ "updated_fields": [
+ "goods_content",
+ "goods_weight",
+ "goods_volume",
+ "max_weight",
+ "is_locked",
+ "is_disabled",
+ "is_empty_tray",
+ "tags",
+ "description",
+ "extended_fields.产品类别"
+ ],
+ "updated_storage_location": {
+ "id": "layer-001",
+ "layer_name": "第一层",
+ "goods_content": "电子产品A",
+ "goods_weight": 500,
+ "updated_at": "2024-01-02T10:30:00"
+ }
+ }
+}
+```
+
+#### 返回字段说明
+
+| 字段名 | 类型 | 说明 |
+| ------------------------- | ------- | ------------------------------ |
+| layer_name | string | 库位名称 |
+| success | boolean | 操作是否成功 |
+| message | string | 操作结果消息 |
+| updated_fields | array | 更新的字段列表 |
+| updated_storage_location | object | 更新后的库位信息摘要 |
+
+##### 更新后的库位信息 (updated_storage_location)
+| 字段名 | 类型 | 说明 |
+| ------------- | ------- | ------------------------------ |
+| id | string | 层ID |
+| layer_name | string | 层名称 |
+| goods_content | string | 货物内容 |
+| goods_weight | integer | 货物重量(克) |
+| updated_at | string | 更新时间 |
+
+---
+
+### 7. 获取库位状态 (GET /api/vwed-operate-point/{layer_name}/status)
+
+获取单个库位的状态信息。
+
+#### 请求参数
+
+| 参数名 | 类型 | 必填 | 描述 |
+| ---------- | ------ | ---- | -------- |
+| layer_name | string | 是 | 库位名称(路径参数) |
+
+#### 响应格式
+
+```json
+{
+ "code": 200,
+ "message": "查询成功",
+ "data": {
+ "is_occupied": false,
+ "is_locked": false,
+ "is_disabled": false,
+ "is_empty_tray": false,
+ "locked_by": null,
+ "goods_content": "",
+ "last_access_at": "2024-01-01T12:00:00",
+ "updated_at": "2024-01-01T12:00:00"
+ }
+}
+```
+
+#### 返回字段说明
+
+| 字段名 | 类型 | 说明 |
+| -------------- | ------- | ------------------------------ |
+| is_occupied | boolean | 是否占用 |
+| is_locked | boolean | 是否锁定 |
+| is_disabled | boolean | 是否禁用 |
+| is_empty_tray | boolean | 是否空托盘 |
+| locked_by | string | 锁定者 |
+| goods_content | string | 货物内容 |
+| last_access_at | string | 最后访问时间 |
+| updated_at | string | 更新时间 |
+
+---
+
+### 8. 创建扩展属性 (POST /api/vwed-operate-point/extended-properties)
+
+创建新的扩展属性定义。
+
+#### 请求参数
+
+```json
+{
+ "property_key": "storage_temperature",
+ "property_name": "存储温度",
+ "property_type": "string",
+ "is_required": false,
+ "is_enabled": true,
+ "default_value": "常温",
+ "description": "库位存储温度要求",
+ "category": "环境参数",
+ "display_width": 120,
+ "display_format": "",
+ "validation_rules": "",
+ "options": []
+}
+```
+
+#### 响应格式
+
+```json
+{
+ "code": 200,
+ "message": "扩展属性创建成功",
+ "data": {
+ "property_id": "ext-001",
+ "property_key": "storage_temperature",
+ "property_name": "存储温度",
+ "success": true,
+ "message": "扩展属性创建成功,已同步到 150 个库位层",
+ "affected_layers_count": 150
+ }
+}
+```
+
+#### 返回字段说明
+
+| 字段名 | 类型 | 说明 |
+| -------------------- | ------- | ------------------------------ |
+| property_id | string | 扩展属性ID |
+| property_key | string | 属性键名 |
+| property_name | string | 属性名称 |
+| success | boolean | 操作是否成功 |
+| message | string | 操作结果消息 |
+| affected_layers_count| integer | 影响的库位层数量 |
+
+---
+
+### 9. 获取扩展属性列表 (GET /api/vwed-operate-point/extended-properties)
+
+获取扩展属性定义列表。
+
+#### 请求参数
+
+| 参数名 | 类型 | 必填 | 描述 |
+| ------------- | ------- | ---- | --------------------------- |
+| property_name | string | 否 | 属性名称(支持模糊搜索) |
+| property_type | string | 否 | 属性类型 |
+| category | string | 否 | 属性分类 |
+| is_enabled | boolean | 否 | 是否启用 |
+| page | integer | 否 | 页码(默认1) |
+| page_size | integer | 否 | 每页数量(默认20,最大100) |
+
+#### 响应格式
+
+```json
+{
+ "code": 200,
+ "message": "查询成功",
+ "data": {
+ "total": 10,
+ "page": 1,
+ "page_size": 20,
+ "total_pages": 1,
+ "properties": [
+ {
+ "id": "ext-001",
+ "property_key": "storage_temperature",
+ "property_name": "存储温度",
+ "property_type": "string",
+ "is_required": false,
+ "is_enabled": true,
+ "default_value": "常温",
+ "description": "库位存储温度要求",
+ "category": "环境参数",
+ "created_at": "2024-01-01T00:00:00",
+ "updated_at": "2024-01-01T00:00:00"
+ }
+ ]
+ }
+}
+```
+
+#### 返回字段说明
+
+##### 分页信息
+| 字段名 | 类型 | 说明 |
+| ----------- | ------- | -------------- |
+| total | integer | 总记录数 |
+| page | integer | 当前页码 |
+| page_size | integer | 每页记录数 |
+| total_pages | integer | 总页数 |
+
+##### 扩展属性信息 (properties[])
+| 字段名 | 类型 | 说明 |
+| ------------- | ------- | ------------------------------ |
+| id | string | 扩展属性ID |
+| property_key | string | 属性键名 |
+| property_name | string | 属性名称 |
+| property_type | string | 属性类型 |
+| is_required | boolean | 是否必填 |
+| is_enabled | boolean | 是否启用 |
+| default_value | string | 默认值 |
+| description | string | 属性描述 |
+| category | string | 属性分类 |
+| created_at | string | 创建时间 |
+| updated_at | string | 更新时间 |
+
+---
+
+### 10. 删除扩展属性 (DELETE /api/vwed-operate-point/extended-properties/{property_id})
+
+删除指定的扩展属性。
+
+#### 请求参数
+
+| 参数名 | 类型 | 必填 | 描述 |
+| ----------- | ------ | ---- | ------ |
+| property_id | string | 是 | 属性ID |
+
+#### 响应格式
+
+```json
+{
+ "code": 200,
+ "message": "扩展属性删除成功",
+ "data": {
+ "property_id": "ext-001",
+ "success": true,
+ "message": "扩展属性删除成功,已从 150 个库位层中清除",
+ "affected_layers_count": 150
+ }
+}
+```
+
+#### 返回字段说明
+
+| 字段名 | 类型 | 说明 |
+| -------------------- | ------- | ------------------------------ |
+| property_id | string | 扩展属性ID |
+| success | boolean | 操作是否成功 |
+| message | string | 操作结果消息 |
+| affected_layers_count| integer | 影响的库位层数量 |
+
+---
+### 11. 创建扩展属性
+
+**接口地址:** `POST /api/vwed-operate-point/extended-properties`
+
+**功能说明:** 创建新的扩展属性定义
+
+**重要提示:** 创建扩展属性后,会自动将该属性添加到所有现有的库位层中,每个库位层的config_json会自动更新,包含新的扩展属性配置。
+
+**请求参数:**
+```json
+{
+ "property_name": "温度",
+ "property_type": "float",
+ "is_required": false,
+ "is_enabled": true,
+ "description": "库位温度监控",
+ "placeholder": "请输入温度值",
+ "default_value": "25.0",
+ "options": null,
+ "validation_rules": {
+ "min": -50,
+ "max": 100
+ },
+ "category": "环境监控",
+ "sort_order": 10,
+ "display_width": 150,
+ "display_format": "{{value}}°C"
+}
+```
+
+**响应示例:**
+```json
+{
+ "code": 200,
+ "message": "扩展属性创建成功",
+ "data": {
+ "id": "1",
+ "property_name": "温度",
+ "message": "扩展属性创建成功,已应用到所有库位层"
+ }
+}
+```
+
+### 12. 获取库位操作记录 (GET /api/vwed-operate-point/operation-logs)
+
+获取库位操作记录列表。
+
+#### 请求参数
+
+| 参数名 | 类型 | 必填 | 描述 |
+| ------------ | ------- | ---- | ----------------------------------------- |
+| layer_name | string | 否 | 库位名称 |
+| operator | string | 否 | 操作人(支持模糊搜索) |
+| operation_type | string | 否 | 操作类型 |
+| start_time | string | 否 | 开始时间(格式:YYYY-MM-DD HH:MM:SS) |
+| end_time | string | 否 | 结束时间(格式:YYYY-MM-DD HH:MM:SS) |
+| page | integer | 否 | 页码(默认1) |
+| page_size | integer | 否 | 每页数量(默认20,最大100) |
+
+#### 响应格式
+
+```json
+{
+ "code": 200,
+ "message": "查询操作记录成功",
+ "data": {
+ "total": 25,
+ "page": 1,
+ "page_size": 10,
+ "total_pages": 3,
+ "logs": [
+ {
+ "id": "log-001",
+ "operation_time": "2024-01-02T10:30:00",
+ "operator": "admin",
+ "operation_type": "编辑库位",
+ "affected_storage_locations": ["layer-001"],
+ "description": "编辑库位信息,更新字段: goods_content, goods_weight, is_locked",
+ "created_at": "2024-01-02T10:30:00"
+ },
+ {
+ "id": "log-002",
+ "operation_time": "2024-01-02T09:15:00",
+ "operator": "系统",
+ "operation_type": "occupy",
+ "affected_storage_locations": ["layer-001"],
+ "description": "占用库位操作",
+ "created_at": "2024-01-02T09:15:00"
+ }
+ ]
+ }
+}
+```
+
+#### 返回字段说明
+
+##### 分页信息
+| 字段名 | 类型 | 说明 |
+| ----------- | ------- | -------------- |
+| total | integer | 总记录数 |
+| page | integer | 当前页码 |
+| page_size | integer | 每页记录数 |
+| total_pages | integer | 总页数 |
+
+##### 操作记录信息 (logs[])
+| 字段名 | 类型 | 说明 |
+| -------------------------- | ------ | ------------------------------ |
+| id | string | 操作记录ID |
+| operation_time | string | 操作时间 |
+| operator | string | 操作人员 |
+| operation_type | string | 操作类型 |
+| affected_storage_locations | array | 受影响的库位名称列表 |
+| description | string | 操作描述 |
+| created_at | string | 记录创建时间 |
+
+#### 调用示例
+
+```bash
+GET /api/vwed-operate-point/operation-logs?layer_name=layer-001&start_time=2024-01-01 00:00:00&end_time=2024-01-02 23:59:59&page=1&page_size=10
+```
+
+---
+
+## 错误处理
+
+### 常见错误码
+
+| 错误码 | 描述 | 示例 |
+| ------ | -------------------- | --------------------------------------- |
+| 400 | 请求参数错误 | 缺少必填参数、参数格式错误 |
+| 404 | 资源不存在 | 库位不存在、扩展属性不存在 |
+| 409 | 资源冲突 | 库位已被锁定、扩展属性名称已存在 |
+| 500 | 服务器内部错误 | 数据库连接失败、系统异常 |
+
+### 错误响应格式
+
+```json
+{
+ "code": 400,
+ "message": "请求参数错误:layer_name 不能为空",
+ "data": null
+}
+```
+
+## 注意事项
+
+1. **认证要求**:所有接口都需要有效的认证token
+2. **参数验证**:请确保传入的参数类型和格式正确
+3. **分页限制**:列表接口的每页最多返回100条记录
+4. **批量操作限制**:批量状态更新最多支持100个库位
+5. **扩展属性**:创建或删除扩展属性会影响所有现有的库位层
+6. **时间格式**:所有时间参数使用格式 `YYYY-MM-DD HH:MM:SS`
+7. **库位标识**:所有接口统一使用 `layer_name`(库位名称)作为库位的主要标识符
+8. **事务处理**:所有修改操作都在事务中进行,确保数据一致性
+9. **操作记录**:所有状态更新和编辑操作都会自动记录到操作日志中
+10. **软删除**:扩展属性删除使用软删除机制,不会物理删除数据
+11. **接口统一性**:无论是路径参数还是查询参数,都使用 `layer_name` 确保接口的一致性
+
+## 使用示例
+
+### 查询空闲库位
+
+```bash
+GET /api/vwed-operate-point/list?is_occupied=false&is_locked=false&is_disabled=false&page=1&page_size=20
+```
+
+### 批量占用库位
+
+```bash
+PUT /api/vwed-operate-point/batch-status
+Content-Type: application/json
+
+{
+ "layer_names": ["layer-001", "layer-002"],
+ "action": "occupy",
+ "reason": "批量放置货物"
+}
+```
+
+### 获取特定库位状态
+
+```bash
+GET /api/vwed-operate-point/layer-001/status
+```
+
+### 获取库位详情
+
+```bash
+GET /api/vwed-operate-point/layer-001
+```
+
+### 创建产品类别扩展属性
+
+```bash
+POST /api/vwed-operate-point/extended-properties
+Content-Type: application/json
+
+{
+ "property_key": "product_category",
+ "property_name": "产品类别",
+ "property_type": "select",
+ "is_required": true,
+ "options": [
+ {"value": "electronics", "label": "电子产品"},
+ {"value": "machinery", "label": "机械配件"}
+ ]
+}
+```
+
+### 编辑库位信息
+
+```bash
+PUT /api/vwed-operate-point/layer-001
+Content-Type: application/json
+
+{
+ "goods_content": "iPhone 手机",
+ "goods_weight": 200,
+ "extended_fields": {
+ "产品类别": "电子产品",
+ "存储温度": "常温"
+ }
+}
+```
+
+### 查询库位操作记录
+
+```bash
+GET /api/vwed-operate-point/operation-logs?layer_name=layer-001&start_time=2024-01-01 00:00:00&end_time=2024-01-02 23:59:59
+```
+
+这些接口提供了对库位的全面管理功能,支持状态管理、信息编辑、扩展属性管理和操作记录查询等核心功能。
\ No newline at end of file