| doc/20260604_common_file迁移到storage_blob_storage_attachment.sql | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| doc/20260604_物联设备接口新增存放位置字段前端联调文档.md | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| doc/update_blob_file.sh | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| doc/update_file_size.sh | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| src/main/java/com/ruoyi/http/service/controller/JclyController.java | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| src/main/java/com/ruoyi/quality/controller/QualityInspectController.java | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| src/main/java/com/ruoyi/quality/utils/QualityInspectTemplateExportHelper.java | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| src/main/java/com/ruoyi/stock/controller/StockInventoryController.java | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| src/main/resources/static/百事模版模板说明.md | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 |
doc/20260604_common_fileÇ¨ÒÆµ½storage_blob_storage_attachment.sql
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,283 @@ -- ============================================================ -- éä»¶æ°æ®è¿ç§»èæ¬ï¼ä» common_file è¿ç§»å° storage_blob + storage_attachment -- æ§è¡å请å¤ä»½æ°æ®ï¼ -- ============================================================ -- 说æï¼ -- 1. common_file è¡¨ï¼æ§é件表ï¼å å«æä»¶ä¿¡æ¯ -- 2. storage_blob è¡¨ï¼æ°æä»¶å®ä½è¡¨ï¼å卿件å ä¿¡æ¯ -- 3. storage_attachment è¡¨ï¼æ°éä»¶å ³è表ï¼å ³èä¸å¡è®°å½ä¸æä»¶ -- æ§è¡¨å段说æï¼ -- common_file.id - 主é®ID -- common_file.common_id - å ³èä¸å¡ID -- common_file.name - æä»¶åç§° -- common_file.url - æä»¶è·¯å¾ -- common_file.type - ä¸å¡ç±»åï¼æ´æ°æä¸¾ï¼ -- common_file.file_size - æä»¶å¤§å° -- common_file.create_time, update_time, create_user, dept_id -- æ°è¡¨å段说æï¼ -- storage_blob.id - 主é®ID -- storage_blob.resource_key - èµæºå¯ä¸æ è¯ï¼å¯ç¨åIDæUUIDï¼ -- storage_blob.content_type - MIMEç±»åï¼éæ ¹æ®æä»¶æ©å±åæ¨æï¼ -- storage_blob.original_filename- åå§æä»¶å -- storage_blob.uid_filename - å¯ä¸æä»¶åï¼å¯ç¨ånameæçæï¼ -- storage_blob.byte_size - æä»¶å¤§å° -- storage_blob.path - æä»¶è·¯å¾ -- storage_attachment.id - 主é®ID -- storage_attachment.record_type- è®°å½ç±»åï¼å符串æä¸¾ï¼ -- storage_attachment.record_id - å ³èä¸å¡ID -- storage_attachment.application- æä»¶ç¨éï¼é»è®¤ 'file'ï¼ -- storage_attachment.storage_blob_id - å ³è storage_blob.id -- storage_attachment.deleted - é»è¾å 餿 è®° -- storage_attachment.create_time, update_time -- ============================================================ -- ç±»åæ å°ï¼æ§ type(int) -> æ° record_type(string) -- æ ¹æ® FileNameType æä¸¾å®ä¹æ å°å ³ç³» -- ============================================================ -- æ§ç±»åæä¸¾å¼ï¼ -- 1 = SALE (éå®) -- 2 = PURCHASE (éè´) -- 3 = INVOICE (å票) -- 4 = PURCHASELEDGER (éè´å°è´¦) -- 5 = MEASURING (计éå¨å ·å°è´¦) -- 6 = MEASURINGRecord (计éå¨å ·å°è´¦è®°å½) -- 7 = ApproveNode (åå审æ¹èç¹å®¡æ ¸) -- 8 = ApproveProcess (åå审æ¹ä¸»æ°æ®) -- 9 = SHIP (åè´§å°è´¦) -- 10 = INSPECTION_PRODUCTION_BEFORE (ç产åå·¡æ£) -- 11 = INSPECTION_PRODUCTION_AFTER (ç产åå·¡æ£) -- 12 = INSPECTION (å·¡æ£) -- 13 = APP -- æ°ç±»å对åºç record_type åç¬¦ä¸²ï¼æ ¹æ® RecordTypeEnum æ¨æï¼ï¼ -- 1 -> 'sales_ledger' -- 2 -> 'purchase_ledger' -- 3 -> 'invoice_ledger' -- 4 -> 'purchase_ledger_file' -- 5 -> 'measuring_instrument_ledger' -- 6 -> 'measuring_instrument_ledger_record' -- 7 -> 'approve_node' -- 8 -> 'approve_process' -- 9 -> 'shipping_info' -- 10 -> 'inspection_task' -- 11 -> 'inspection_task' -- 12 -> 'inspection_task' -- 13 -> 'common_file'ï¼éç¨ç±»åå åºï¼ -- ============================================================ -- æ¥éª¤1ï¼è¿ç§»æä»¶æ°æ®å° storage_blob -- 注æï¼byte_size å ä½¿ç¨ common_file.file_sizeï¼åç»éè¦å¨æå¡å¨ä¸æ´æ°å®é å¤§å° -- ============================================================ INSERT INTO storage_blob ( resource_key, content_type, original_filename, uid_filename, byte_size, path ) SELECT CONCAT('legacy_', cf.id) AS resource_key, CASE -- æ ¹æ®æä»¶æ©å±åæ¨æ MIME ç±»å WHEN LOWER(cf.name) LIKE '%.jpg' OR LOWER(cf.name) LIKE '%.jpeg' THEN 'image/jpeg' WHEN LOWER(cf.name) LIKE '%.png' THEN 'image/png' WHEN LOWER(cf.name) LIKE '%.gif' THEN 'image/gif' WHEN LOWER(cf.name) LIKE '%.bmp' THEN 'image/bmp' WHEN LOWER(cf.name) LIKE '%.webp' THEN 'image/webp' WHEN LOWER(cf.name) LIKE '%.pdf' THEN 'application/pdf' WHEN LOWER(cf.name) LIKE '%.doc' THEN 'application/msword' WHEN LOWER(cf.name) LIKE '%.docx' THEN 'application/vnd.openxmlformats-officedocument.wordprocessingml.document' WHEN LOWER(cf.name) LIKE '%.xls' THEN 'application/vnd.ms-excel' WHEN LOWER(cf.name) LIKE '%.xlsx' THEN 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' WHEN LOWER(cf.name) LIKE '%.ppt' THEN 'application/vnd.ms-powerpoint' WHEN LOWER(cf.name) LIKE '%.pptx' THEN 'application/vnd.openxmlformats-officedocument.presentationml.presentation' WHEN LOWER(cf.name) LIKE '%.txt' THEN 'text/plain' WHEN LOWER(cf.name) LIKE '%.zip' THEN 'application/zip' WHEN LOWER(cf.name) LIKE '%.rar' THEN 'application/x-rar-compressed' WHEN LOWER(cf.name) LIKE '%.mp4' THEN 'video/mp4' WHEN LOWER(cf.name) LIKE '%.mp3' THEN 'audio/mpeg' WHEN LOWER(cf.name) LIKE '%.xml' THEN 'application/xml' ELSE 'application/octet-stream' END AS content_type, cf.name AS original_filename, -- ä» url 䏿ªåæåçæä»¶åé¨å -- url 示ä¾: /javaWork/product-inventory-management/file/prod/uploads2026-05-19/1652_1779177065596_61abcb44.jpg -- æªåç»æ: 1652_1779177065596_61abcb44.jpg CASE WHEN cf.url IS NOT NULL AND cf.url != '' THEN SUBSTRING_INDEX(cf.url, '/', -1) ELSE cf.name END AS uid_filename, COALESCE(cf.file_size, 0) AS byte_size, cf.url AS path FROM common_file cf WHERE NOT EXISTS ( SELECT 1 FROM storage_blob sb WHERE sb.resource_key = CONCAT('legacy_', cf.id) ); -- ============================================================ -- æ¥éª¤1.5ï¼å¨Linuxæå¡å¨ä¸æ´æ°å®é æä»¶å¤§å° -- ç´æ¥å¤å¶ä»¥ä¸å 容尿å¡å¨æ§è¡ -- ============================================================ -- 卿å¡å¨ä¸æ§è¡ä»¥ä¸å½ä»¤åå»ºèæ¬ï¼ -- cat > update_blob_file.sh << 'EOF' -- #!/bin/bash -- FILE_ROOT="/javaWork/product-inventory-management/file/prod" -- OUTPUT_SQL="update_blob_file_size.sql" -- DB_USER="root" -- DB_PASS="xd@123456.." -- DB_NAME="product_inventory_management" -- echo "å¼å§æ«æç®å½: $FILE_ROOT" -- echo "-- æ´æ°æä»¶å¤§å° SQL" > "$OUTPUT_SQL" -- find "$FILE_ROOT" -type f | while read filepath; do -- filesize=$(stat -c%s "$filepath" 2>/dev/null || echo "0") -- filename=$(basename "$filepath") -- filename_escaped=$(echo "$filename" | sed "s/'/''/g") -- echo "UPDATE storage_blob SET byte_size = $filesize WHERE uid_filename = '$filename_escaped';" >> "$OUTPUT_SQL" -- done -- echo "SQLæä»¶å·²çæ: $OUTPUT_SQL" -- docker exec -i mysql mysql -u"$DB_USER" -p"$DB_PASS" "$DB_NAME" < "$OUTPUT_SQL" -- echo "æ´æ°å®æ!" -- EOF -- -- ç¶åæ§è¡ï¼ -- chmod +x update_blob_file.sh && ./update_blob_file.sh -- ============================================================ -- æ¥éª¤2ï¼è¿ç§»éä»¶å ³èæ°æ®å° storage_attachment -- ============================================================ INSERT INTO storage_attachment ( create_time, update_time, deleted, record_type, record_id, application, storage_blob_id ) SELECT cf.create_time, cf.update_time, 0 AS deleted, CASE cf.type WHEN 1 THEN 'sales_ledger' WHEN 2 THEN 'purchase_ledger' WHEN 3 THEN 'invoice_ledger' WHEN 4 THEN 'purchase_ledger_file' WHEN 5 THEN 'measuring_instrument_ledger' WHEN 6 THEN 'measuring_instrument_ledger_record' WHEN 7 THEN 'approve_node' WHEN 8 THEN 'approve_process' WHEN 9 THEN 'shipping_info' WHEN 10 THEN 'inspection_task' WHEN 11 THEN 'inspection_task' WHEN 12 THEN 'inspection_task' WHEN 13 THEN 'common_file' ELSE 'common_file' END AS record_type, cf.common_id AS record_id, 'file' AS application, sb.id AS storage_blob_id FROM common_file cf INNER JOIN storage_blob sb ON sb.resource_key = CONCAT('legacy_', cf.id) WHERE NOT EXISTS ( SELECT 1 FROM storage_attachment sa WHERE sa.storage_blob_id = sb.id ); -- ============================================================ -- æ¥éª¤3ï¼éªè¯è¿ç§»ç»æ -- ============================================================ -- æ£æ¥è¿ç§»æ°éæ¯å¦ä¸è´ SELECT 'common_file åå§è®°å½æ°' AS description, COUNT(*) AS count FROM common_file UNION ALL SELECT 'storage_blob è¿ç§»è®°å½æ°' AS description, COUNT(*) AS count FROM storage_blob WHERE resource_key LIKE 'legacy_%' UNION ALL SELECT 'storage_attachment è¿ç§»è®°å½æ°' AS description, COUNT(*) AS count FROM storage_attachment sa WHERE EXISTS ( SELECT 1 FROM storage_blob sb WHERE sb.id = sa.storage_blob_id AND sb.resource_key LIKE 'legacy_%' ); -- æç±»åç»è®¡è¿ç§»æ°é SELECT cf.type AS old_type, CASE cf.type WHEN 1 THEN 'sales_ledger' WHEN 2 THEN 'purchase_ledger' WHEN 3 THEN 'invoice_ledger' WHEN 4 THEN 'purchase_ledger_file' WHEN 5 THEN 'measuring_instrument_ledger' WHEN 6 THEN 'measuring_instrument_ledger_record' WHEN 7 THEN 'approve_node' WHEN 8 THEN 'approve_process' WHEN 9 THEN 'shipping_info' WHEN 10 THEN 'inspection_task' WHEN 11 THEN 'inspection_task' WHEN 12 THEN 'inspection_task' WHEN 13 THEN 'common_file' ELSE 'unknown' END AS new_record_type, COUNT(*) AS count FROM common_file cf GROUP BY cf.type ORDER BY cf.type; -- ============================================================ -- æ¥éª¤4ï¼æ°æ®æ ¡éªï¼æ§è¡åæ£æ¥æ¯å¦æå¼å¸¸æ°æ®ï¼ -- ============================================================ -- æ£æ¥æ¯å¦æ common_id 为空çè®°å½ SELECT COUNT(*) AS 'common_id为空çè®°å½æ°' FROM common_file WHERE common_id IS NULL; -- æ£æ¥æ¯å¦æ name 为空çè®°å½ SELECT COUNT(*) AS 'name为空çè®°å½æ°' FROM common_file WHERE name IS NULL OR name = ''; -- æ£æ¥æ¯å¦æ url 为空çè®°å½ SELECT COUNT(*) AS 'url为空çè®°å½æ°' FROM common_file WHERE url IS NULL OR url = ''; -- ============================================================ -- æ¥éª¤5ï¼è¿ç§»å®æåçæ¸ çï¼è°¨æ æ§è¡ï¼å»ºè®®å å¤ä»½æ°æ®ï¼ -- ============================================================ -- å¤ä»½ common_file 表ï¼å¯éï¼ -- CREATE TABLE common_file_backup AS SELECT * FROM common_file; -- æ¸ ç©º common_file 表ï¼ç¡®è®¤è¿ç§»æ è¯¯åæ§è¡ï¼ -- TRUNCATE TABLE common_file; -- æè å é¤å·²è¿ç§»çè®°å½ -- DELETE FROM common_file WHERE EXISTS ( -- SELECT 1 FROM storage_blob sb -- WHERE sb.resource_key = CONCAT('legacy_', common_file.id) -- ); -- ============================================================ -- 注æäºé¡¹ï¼ -- 1. æ§è¡åå¡å¿ å¤ä»½ common_file è¡¨æ°æ® -- 2. å»ºè®®å¨æµè¯ç¯å¢å éªè¯è¿ç§»èæ¬çæ£ç¡®æ§ -- 3. è¿ç§»å®æåï¼æ£æ¥æä»¶æ¯å¦è½æ£å¸¸è®¿é® -- 4. 确认ä¸å¡åè½æ£å¸¸åï¼åèèæ¸ çæ§æ°æ® -- 5. resource_key ä½¿ç¨ 'legacy_' + åID çæ ¼å¼ï¼ä¾¿äºè¿½æº¯åå»é -- ============================================================ doc/20260604_ÎïÁªÉ豸½Ó¿ÚÐÂÔö´æ·ÅλÖÃ×Ö¶Îǰ¶ËÁªµ÷Îĵµ.md
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,233 @@ # ç©èè®¾å¤æ¥å£æ°å¢åæ¾ä½ç½®å段å端èè°ææ¡£ ## åæ´æ¦è¿° æ¬æ¬¡åæ´å¨ä¸¤ä¸ªç©è设å¤ç¸å ³æ¥å£çè¿åæ°æ®ä¸æ°å¢äº `storageLocation`ï¼åæ¾ä½ç½®ï¼å段ï¼ä¾å端å±ç¤ºè®¾å¤æå¨çç©çä½ç½®ä¿¡æ¯ã --- ## ä¸ãæ°éæ¥å£ - getRealData ### æ¥å£ä¿¡æ¯ | é¡¹ç® | å¼ | |------|-----| | æ¥å£è·¯å¾ | `/iot/getRealData` | | è¯·æ±æ¹å¼ | GET | | æ¥å£æè¿° | 宿¶è·åç©è设å¤ç温湿度ãäºæ°§åç¢³çæ°éæ°æ® | ### 请æ±åæ° æ åæ° ### è¿åæ°æ®ç»æ ```json { "code": 200, "msg": "æä½æå", "data": [ { "guid": "设å¤å¤é¨ç¼ç ", "deviceName": "设å¤åç§°", "storageLocation": "åæ¾ä½ç½®ãæ°å¢ã", "status": "å¨çº¿/离线/error", "statusMessage": "ç¶æè¯´æï¼ä» å¨å¼å¸¸æ¶è¿åï¼", "light": "å ç §å¼+åä½ï¼å¦ï¼150Luxï¼", "temperature": "温度å¼+åä½ï¼å¦ï¼25.5âï¼", "humidity": "湿度å¼+åä½ï¼å¦ï¼60%RHï¼", "co2": "äºæ°§å碳å¼+åä½ï¼å¦ï¼400ppmï¼", "battery": "çµæ± çµé+åä½ï¼å¦ï¼85%ï¼" } ] } ``` ### è¿ååæ®µè¯´æ | åæ®µå | ç±»å | 说æ | æ¯å¦æ°å¢ | |--------|------|------|----------| | guid | String | 设å¤å¤é¨ç¼ç ï¼externalCodeï¼ | å¦ | | deviceName | String | 设å¤åç§° | å¦ | | **storageLocation** | String | **设å¤åæ¾ä½ç½®** | **æ¯** | | status | String | 设å¤ç¶æï¼å¨çº¿ã离线ãerror | å¦ | | statusMessage | String | ç¶æè¡¥å 说æï¼ä» å¨å¼å¸¸æ¶åå¨ï¼ | å¦ | | light | String | å ç §å¼ï¼å¸¦åä½ï¼ | å¦ | | temperature | String | 温度å¼ï¼å¸¦åä½ï¼ | å¦ | | humidity | String | 湿度å¼ï¼å¸¦åä½ï¼ | å¦ | | co2 | String | äºæ°§å碳å¼ï¼å¸¦åä½ï¼ | å¦ | | battery | String | çµæ± çµéï¼å¸¦åä½ï¼ | å¦ | ### å端èè°ç¤ºä¾ ```javascript // è°ç¨æ¥å£ axios.get('/iot/getRealData').then(res => { const devices = res.data; devices.forEach(device => { console.log(`设å¤ï¼${device.deviceName}`); console.log(`åæ¾ä½ç½®ï¼${device.storageLocation}`); // æ°å¢å段 console.log(`温度ï¼${device.temperature}`); console.log(`湿度ï¼${device.humidity}`); console.log(`CO2ï¼${device.co2}`); console.log(`ç¶æï¼${device.status}`); }); }); ``` --- ## äºãåºåç©èè®¾å¤æ¥å£ - iotRealtime ### æ¥å£ä¿¡æ¯ | é¡¹ç® | å¼ | |------|-----| | æ¥å£è·¯å¾ | `/stockInventory/iotRealtime` | | è¯·æ±æ¹å¼ | POST | | Content-Type | application/json | | æ¥å£æè¿° | è·ååºåç»å®çç©è设å¤å®æ¶æ°éæ°æ® | ### 请æ±åæ° ```json [设å¤ID1, 设å¤ID2, 设å¤ID3] ``` **åæ°è¯´æï¼** | åæ°å | ç±»å | å¿ å¡« | 说æ | |--------|------|------|------| | - | List<Long> | æ¯ | ç©è设å¤IDæ°ç» | ### è¿åæ°æ®ç»æ ```json { "code": 200, "msg": "æä½æå", "data": { "devices": [ { "deviceId": "设å¤ID", "deviceName": "设å¤åç§°", "deviceModel": "设å¤è§æ ¼åå·", "externalCode": "设å¤å¤é¨ç¼ç ", "storageLocation": "åæ¾ä½ç½®ãæ°å¢ã", "guid": "设å¤å¤é¨ç¼ç ", "status": "å¨çº¿/离线/error", "statusMessage": "ç¶æè¯´æï¼ä» å¨å¼å¸¸æ¶è¿åï¼", "light": "å ç §å¼+åä½", "temperature": "温度å¼+åä½", "humidity": "湿度å¼+åä½", "co2": "äºæ°§å碳å¼+åä½", "battery": "çµæ± çµé+åä½" } ] } } ``` ### è¿ååæ®µè¯´æï¼devices æ°ç»å ç´ ï¼ | åæ®µå | ç±»å | 说æ | æ¯å¦æ°å¢ | |--------|------|------|----------| | deviceId | String | 设å¤ID | å¦ | | deviceName | String | 设å¤åç§° | å¦ | | deviceModel | String | 设å¤è§æ ¼åå· | å¦ | | externalCode | String | 设å¤å¤é¨ç¼ç | å¦ | | **storageLocation** | String | **设å¤åæ¾ä½ç½®** | **æ¯** | | guid | String | 设å¤å¤é¨ç¼ç ï¼æ¥èªæ°éå¹³å°ï¼ | å¦ | | status | String | 设å¤ç¶æï¼å¨çº¿ã离线ãerror | å¦ | | statusMessage | String | ç¶æè¡¥å 说æï¼ä» å¨å¼å¸¸æ¶åå¨ï¼ | å¦ | | light | String | å ç §å¼ï¼å¸¦åä½ï¼ | å¦ | | temperature | String | 温度å¼ï¼å¸¦åä½ï¼ | å¦ | | humidity | String | 湿度å¼ï¼å¸¦åä½ï¼ | å¦ | | co2 | String | äºæ°§å碳å¼ï¼å¸¦åä½ï¼ | å¦ | | battery | String | çµæ± çµéï¼å¸¦åä½ï¼ | å¦ | ### å端èè°ç¤ºä¾ ```javascript // è°ç¨æ¥å£ const deviceIds = [1, 2, 3]; axios.post('/stockInventory/iotRealtime', deviceIds).then(res => { const result = res.data; result.devices.forEach(device => { console.log(`设å¤IDï¼${device.deviceId}`); console.log(`设å¤åç§°ï¼${device.deviceName}`); console.log(`åæ¾ä½ç½®ï¼${device.storageLocation}`); // æ°å¢å段 console.log(`è§æ ¼åå·ï¼${device.deviceModel}`); console.log(`温度ï¼${device.temperature}`); console.log(`湿度ï¼${device.humidity}`); console.log(`ç¶æï¼${device.status}`); }); }); ``` --- ## ä¸ãå端æ¹é è¦ç¹ ### 1. å表/å¡çå±ç¤ºæ¹é è¥å端æè®¾å¤å表æå¡çå±ç¤ºï¼éæ°å¢åæ¾ä½ç½®å±ç¤ºåºåï¼ ```html <!-- 示ä¾ï¼è®¾å¤ä¿¡æ¯å¡ç --> <div class="device-card"> <div class="device-name">{{ device.deviceName }}</div> <!-- æ°å¢åæ¾ä½ç½®å±ç¤º --> <div class="storage-location">åæ¾ä½ç½®ï¼{{ device.storageLocation || 'ææ ' }}</div> <div class="device-status">ç¶æï¼{{ device.status }}</div> <div class="device-data"> <span>温度ï¼{{ device.temperature }}</span> <span>湿度ï¼{{ device.humidity }}</span> <span>CO2ï¼{{ device.co2 }}</span> </div> </div> ``` ### 2. è¡¨æ ¼åæ°å¢ è¥å端使ç¨è¡¨æ ¼å±ç¤ºè®¾å¤æ°æ®ï¼éæ°å¢åæ¾ä½ç½®åï¼ | åå | åæ®µ | 说æ | |------|------|------| | 设å¤åç§° | deviceName | - | | **åæ¾ä½ç½®** | **storageLocation** | **æ°å¢å** | | 温度 | temperature | - | | 湿度 | humidity | - | | CO2 | co2 | - | | ç¶æ | status | - | ### 3. 空å¼å¤ç `storageLocation` åæ®µå¯è½ä¸ºç©ºå符串ï¼å端éåå åºå¤çï¼ ```javascript const location = device.storageLocation || 'ææ åæ¾ä½ç½®ä¿¡æ¯'; ``` --- ## åãæ°æ®æ¥æºè¯´æ `storageLocation` åæ®µæ¥æºäºè®¾å¤å°è´¦è¡¨ï¼`device_ledger`ï¼ç `storage_location` åæ®µï¼è¯¥å段å¨è®¾å¤å°è´¦ç®¡ç模åç»´æ¤ã --- ## äºãæµè¯è¦ç¹ 1. **æ£å¸¸åºæ¯**ï¼è®¾å¤å°è´¦ä¸å·²ç»´æ¤åæ¾ä½ç½®ï¼æ¥å£è¿ååºå å«è¯¥åæ®µå¼ 2. **空å¼åºæ¯**ï¼è®¾å¤å°è´¦ä¸åæ¾ä½ç½®ä¸ºç©ºï¼æ¥å£åºè¿å空å符串ï¼å端éå åºå±ç¤ºï¼ 3. **离线设å¤**ï¼è®¾å¤ç¦»çº¿æ¶ï¼`storageLocation` åæ®µä»åºæ£å¸¸è¿å 4. **æ¹éæ¥è¯¢**ï¼å¤ä¸ªè®¾å¤IDæ¥è¯¢æ¶ï¼æ¯ä¸ªè®¾å¤é½åºè¿å `storageLocation` åæ®µ --- ## å ãçæ¬è®°å½ | çæ¬ | æ¥æ | åæ´å 容 | |------|------|----------| | v1.0 | 2026-06-04 | æ°å¢ storageLocationï¼åæ¾ä½ç½®ï¼å段 | doc/update_blob_file.sh
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,32 @@ #!/bin/bash # æä»¶å卿 ¹ç®å½ FILE_ROOT="/javaWork/product-inventory-management/file/prod" # è¾åºSQLæä»¶å OUTPUT_SQL="update_blob_file_size.sql" # æ°æ®åºé ç½® DB_USER="root" DB_PASS="xd@123456.." DB_NAME="product_inventory_management" echo "å¼å§æ«æç®å½: $FILE_ROOT" echo "-- æ´æ°æä»¶å¤§å° SQL" > "$OUTPUT_SQL" echo "-- çææ¶é´: $(date '+%Y-%m-%d %H:%M:%S')" >> "$OUTPUT_SQL" echo "" >> "$OUTPUT_SQL" # æ«æç®å½ä¸æææä»¶å¹¶çææ´æ°SQL find "$FILE_ROOT" -type f | while read filepath; do filesize=$(stat -c%s "$filepath" 2>/dev/null || echo "0") filename=$(basename "$filepath") filename_escaped=$(echo "$filename" | sed "s/'/''/g") echo "UPDATE storage_blob SET byte_size = $filesize WHERE uid_filename = '$filename_escaped';" >> "$OUTPUT_SQL" done echo "SQLæä»¶å·²çæ: $OUTPUT_SQL" echo "æ£å¨æ§è¡SQLæ´æ°..." docker exec -i mysql mysql -u"$DB_USER" -p"$DB_PASS" "$DB_NAME" < "$OUTPUT_SQL" echo "æ´æ°å®æ!" doc/update_file_size.sh
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,49 @@ #!/bin/bash # ============================================================ # æ´æ° storage_blob 表çæä»¶å¤§å°å段 # æ«ææä»¶ç®å½è·åå®é æä»¶å¤§å°ï¼çææ´æ°SQL # ============================================================ # æä»¶å卿 ¹ç®å½ï¼æ ¹æ®å®é è·¯å¾ä¿®æ¹ï¼ FILE_ROOT="/javaWork/product-inventory-management/file/prod" # è¾åºSQLæä»¶å OUTPUT_SQL="update_blob_file_size.sql" echo "å¼å§æ«æç®å½: $FILE_ROOT" echo "-- æ´æ°æä»¶å¤§å° SQL" > "$OUTPUT_SQL" echo "-- çææ¶é´: $(date '+%Y-%m-%d %H:%M:%S')" >> "$OUTPUT_SQL" echo "" >> "$OUTPUT_SQL" # ç»è®¡è®¡æ° count=0 # æ«æç®å½ä¸æææä»¶å¹¶çææ´æ°SQL find "$FILE_ROOT" -type f | while read filepath; do # è·åæä»¶å¤§å°ï¼åèï¼ filesize=$(stat -c%s "$filepath" 2>/dev/null || echo "0") # è·åæä»¶åï¼æå䏿®µè·¯å¾ï¼ filename=$(basename "$filepath") # è½¬ä¹æä»¶åä¸çåå¼å·ï¼SQLè¯æ³è¦æ±ï¼ filename_escaped=$(echo "$filename" | sed "s/'/''/g") # çææ´æ°SQL echo "UPDATE storage_blob SET byte_size = $filesize WHERE uid_filename = '$filename_escaped';" >> "$OUTPUT_SQL" # 计æ°ï¼åshell䏿 æ³ä¼ éï¼ä» ç¨äºæ¾ç¤ºè¿åº¦ï¼ echo "å·²å¤ç: $filename ($filesize bytes)" done echo "" echo "==========================================" echo "SQLæä»¶å·²çæ: $OUTPUT_SQL" echo "==========================================" echo "" echo "æ§è¡æ¹æ³:" echo " mysql -uç¨æ·å -på¯ç æ°æ®åºå < $OUTPUT_SQL" echo "" echo "æè å æ£æ¥SQLå 容:" echo " cat $OUTPUT_SQL" src/main/java/com/ruoyi/http/service/controller/JclyController.java
@@ -41,24 +41,29 @@ .isNotNull(DeviceLedger::getExternalCode) .ne(DeviceLedger::getExternalCode, "")); Map<String, String> guidDeviceNameMap = iotDevices.stream() Map<String, DeviceLedger> guidDeviceMap = iotDevices.stream() .filter(item -> StringUtils.isNotEmpty(item.getExternalCode())) .collect(Collectors.toMap( item -> item.getExternalCode().trim(), item -> StringUtils.isNotEmpty(item.getDeviceName()) ? item.getDeviceName().trim() : "", (oldValue, newValue) -> StringUtils.isNotEmpty(oldValue) ? oldValue : newValue, item -> item, (oldValue, newValue) -> StringUtils.isNotEmpty(oldValue.getDeviceName()) ? oldValue : newValue, LinkedHashMap::new )); List<String> guidList = new ArrayList<>(guidDeviceNameMap.keySet()); List<String> guidList = new ArrayList<>(guidDeviceMap.keySet()); List<Map<String, String>> maps = realTimeEnergyConsumptionService .getRealData(guidList); for (Map<String, String> item : maps) { String guid = item.get("guid"); if (StringUtils.isNotEmpty(guid)) { String deviceName = guidDeviceNameMap.get(guid.trim()); if (StringUtils.isNotEmpty(deviceName)) { item.put("deviceName", deviceName); DeviceLedger device = guidDeviceMap.get(guid.trim()); if (device != null) { if (StringUtils.isNotEmpty(device.getDeviceName())) { item.put("deviceName", device.getDeviceName().trim()); } if (StringUtils.isNotEmpty(device.getStorageLocation())) { item.put("storageLocation", device.getStorageLocation().trim()); } } } } src/main/java/com/ruoyi/quality/controller/QualityInspectController.java
@@ -140,7 +140,6 @@ /** * æäº¤ * * @param qualityInspect * @return */ @GetMapping("/export/baishi/{id}") src/main/java/com/ruoyi/quality/utils/QualityInspectTemplateExportHelper.java
@@ -1,7 +1,10 @@ package com.ruoyi.quality.utils; import com.baomidou.mybatisplus.core.toolkit.Wrappers; import com.deepoove.poi.XWPFTemplate; import com.deepoove.poi.config.Configure; import com.ruoyi.common.exception.ServiceException; import com.ruoyi.common.utils.HackLoopTableRenderPolicy; import com.ruoyi.quality.mapper.QualityInspectMapper; import com.ruoyi.quality.pojo.QualityInspect; import com.ruoyi.quality.pojo.QualityInspectParam; @@ -22,7 +25,7 @@ import java.io.OutputStream; import java.net.URLEncoder; import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.HashMap; import java.util.LinkedHashMap; import java.util.LinkedHashSet; import java.util.List; @@ -47,7 +50,54 @@ } public void exportBaiShi(HttpServletResponse response, Long inspectId) { export(response, inspectId, BAISHI_TEMPLATE, "ç¾äºæ¨¡çæ£éªç»æ"); if (inspectId == null) { throw new ServiceException("æ£éªåIDä¸è½ä¸ºç©º"); } QualityInspect inspect = qualityInspectMapper.selectById(inspectId); if (inspect == null) { throw new ServiceException("æ£éªåä¸åå¨"); } List<QualityInspectParam> paramList = qualityInspectParamService.list( Wrappers.<QualityInspectParam>lambdaQuery() .eq(QualityInspectParam::getInspectId, inspectId) .orderByAsc(QualityInspectParam::getId)); int index = 1; for (QualityInspectParam detail : paramList) { detail.setIndex(index); index++; } try (InputStream inputStream = getClass().getResourceAsStream("/static/ç¾äºæ¨¡ç.docx")) { if (inputStream == null) { throw new ServiceException("æ¨¡æ¿æä»¶ä¸åå¨ï¼/static/ç¾äºæ¨¡ç.docx"); } Configure configure = Configure.builder() .bind("paramList", new HackLoopTableRenderPolicy()) .build(); XWPFTemplate template = XWPFTemplate.compile(inputStream, configure).render( new HashMap<String, Object>() {{ put("inspect", inspect); put("paramList", paramList); }}); response.reset(); response.setContentType("application/msword"); response.setCharacterEncoding("UTF-8"); String encodedName = URLEncoder.encode("ç¾äºæ¨¡çæ£éªç»æ", StandardCharsets.UTF_8).replace("+", "%20"); response.setHeader("Access-Control-Expose-Headers", "Content-Disposition"); response.setHeader("Content-Disposition", "attachment;filename=" + encodedName + ".docx"); try (OutputStream outputStream = response.getOutputStream()) { template.write(outputStream); outputStream.flush(); } } catch (IOException e) { throw new RuntimeException("导åºå¤±è´¥", e); } } public void exportDaLi(HttpServletResponse response, Long inspectId) { src/main/java/com/ruoyi/stock/controller/StockInventoryController.java
@@ -192,6 +192,7 @@ data.put("deviceName", device.getDeviceName() != null ? device.getDeviceName() : ""); data.put("deviceModel", device.getDeviceModel() != null ? device.getDeviceModel() : ""); data.put("externalCode", device.getExternalCode() != null ? device.getExternalCode() : ""); data.put("storageLocation", device.getStorageLocation() != null ? device.getStorageLocation() : ""); Map<String, String> rt = realTimeDataMap.getOrDefault( device.getExternalCode() != null ? device.getExternalCode().trim() : "", Collections.emptyMap()); src/main/resources/static/°ÙÊÂÄ£°æÄ£°å˵Ã÷.md
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,100 @@ # ç¾äºæ¨¡ç.docx 模æ¿å建说æ ## æä»¶ä½ç½® `src/main/resources/static/ç¾äºæ¨¡ç.docx` --- ## Word ä¸å建æ¥éª¤ ### 1. æ°å»º Word ææ¡£ ### 2. åå»ºåºæ¬ä¿¡æ¯è¡¨ æå ¥ä¸ä¸ª 2åNè¡çè¡¨æ ¼ï¼ | é¡¹ç® | å 容 | |------|------| | 产ååç§° | {{inspect.productName}} | | è§æ ¼åå· | {{inspect.model}} | | ä¾åºå | {{inspect.supplier}} | | æ°é | {{inspect.quantity}} | | åä½ | {{inspect.unit}} | | æ£æµæ¥æ | {{inspect.checkTime}} | | æ£éªå | {{inspect.checkName}} | | æ£æµç»æ | {{inspect.checkResult}} | | åæ ¼æ°é | {{inspect.qualifiedQuantity}} | | ä¸åæ ¼æ°é | {{inspect.unqualifiedQuantity}} | ### 3. å建æ£éªåæ°å表表ï¼å ³é®ï¼ï¼ æå ¥ä¸ä¸ª 6å2è¡çè¡¨æ ¼ï¼ **表头è¡ï¼** | åºå· | æ£æµææ | åä½ | æ åå¼ | å æ§å¼ | æ£éªå¼ | **æ°æ®è¡ï¼å¾ªç¯æ¨¡æ¿ï¼**ï¼æ¯ä¸ªåå æ ¼è¾å ¥ï¼ | {{#paramList}}{{index}}{{/paramList}} | {{#paramList}}{{parameterItem}}{{/paramList}} | {{#paramList}}{{unit}}{{/paramList}} | {{#paramList}}{{standardValue}}{{/paramList}} | {{#paramList}}{{controlValue}}{{/paramList}} | {{#paramList}}{{testValue}}{{/paramList}} | ### 4. ä¿å ä¿å为 `ç¾äºæ¨¡ç.docx`ï¼æ¾å° `src/main/resources/static/` ç®å½ã --- ## ç¤ºä¾æ¨¡æ¿å 容 ``` ç¾äºæ£éªæ¥å ãåºæ¬ä¿¡æ¯ã 产ååç§°ï¼{{inspect.productName}} è§æ ¼åå·ï¼{{inspect.model}} ä¾åºåï¼{{inspect.supplier}} æ°éï¼{{inspect.quantity}} {{inspect.unit}} æ£æµæ¥æï¼{{inspect.checkTime}} æ£éªåï¼{{inspect.checkName}} æ£æµç»æï¼{{inspect.checkResult}} ãæ£éªåæ°ã | åºå· | æ£æµææ | åä½ | æ åå¼ | å æ§å¼ | æ£éªå¼ | | {{#paramList}}{{index}}{{/paramList}} | {{#paramList}}{{parameterItem}}{{/paramList}} | {{#paramList}}{{unit}}{{/paramList}} | {{#paramList}}{{standardValue}}{{/paramList}} | {{#paramList}}{{controlValue}}{{/paramList}} | {{#paramList}}{{testValue}}{{/paramList}} | åæ ¼æ°éï¼{{inspect.qualifiedQuantity}} ä¸åæ ¼æ°éï¼{{inspect.unqualifiedQuantity}} ``` --- ## 注æäºé¡¹ 1. **è¡¨æ ¼å¾ªç¯å¿ é¡»ä½¿ç¨ `{{#paramList}}...{{/paramList}}` å 裹æ¯ä¸ªå段** 2. 表头è¡åæ°æ®è¡é½è¦ä¿çï¼æ°æ®è¡ä¼èªå¨å¤å¶å¤è¡ 3. å ä½ç¬¦è¦å®å ¨å¹é ï¼å æ¬å¤§å°å 4. ä¿å为 `.docx` æ ¼å¼ï¼ä¸æ¯ `.doc` --- ## å¯ç¨å段å表 ### inspectï¼æ£éªåï¼åæ®µï¼ - `productName` - 产ååç§° - `model` - è§æ ¼åå· - `supplier` - ä¾åºå - `customer` - 客æ·åç§° - `quantity` - æ°é - `unit` - åä½ - `checkTime` - æ£æµæ¥æ - `checkName` - æ£éªå - `checkResult` - æ£æµç»æ - `checkCompany` - æ£æµåä½ - `qualifiedQuantity` - åæ ¼æ°é - `unqualifiedQuantity` - ä¸åæ ¼æ°é ### paramListï¼æ£éªåæ°å表ï¼åæ®µï¼ - `index` - åºå·ï¼èªå¨çæï¼ - `parameterItem` - æ£æµææ - `unit` - åä½ - `standardValue` - æ åå¼ - `controlValue` - å æ§å¼ - `testValue` - æ£éªå¼