瀏覽代碼

鹏威统计以及上传页面(后期可删

zouling 2 周之前
父節點
當前提交
63808fbb79
共有 5 個文件被更改,包括 862 次插入182 次删除
  1. 529 159
      package-lock.json
  2. 265 0
      public/sca.html
  3. 11 4
      src/api/work.js
  4. 29 7
      src/views/index.vue
  5. 28 12
      src/views/record.vue

文件差異過大導致無法顯示
+ 529 - 159
package-lock.json


+ 265 - 0
public/sca.html

@@ -0,0 +1,265 @@
+<!DOCTYPE html>
+<html lang="zh-CN">
+<head>
+    <meta charset="UTF-8">
+    <meta name="viewport" content="width=device-width, initial-scale=1.0">
+    <title>视频对象检测</title>
+    <link href="https://cdnjs.cloudflare.com/ajax/libs/tailwindcss/2.2.19/tailwind.min.css" rel="stylesheet">
+    <!-- 使用更可靠的 Vue 2 CDN -->
+    <script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.6.14/vue.js"></script>
+    <style>
+        @import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600&display=swap');
+
+        body {
+            font-family: 'Inter', sans-serif;
+            background-color: #f3f4f6;
+        }
+
+        .upload-area {
+            border: 2px dashed #e5e7eb;
+            transition: all 0.3s ease;
+            background: rgba(255, 255, 255, 0.8);
+            backdrop-filter: blur(10px);
+        }
+
+        .upload-area:hover {
+            border-color: #6366f1;
+            background: rgba(255, 255, 255, 0.9);
+            transform: translateY(-2px);
+        }
+
+        .analyzing {
+            animation: pulse 2s infinite;
+        }
+
+        @keyframes pulse {
+            0% { opacity: 1; }
+            50% { opacity: 0.5; }
+            100% { opacity: 1; }
+        }
+
+        .gradient-bg {
+            background: linear-gradient(135deg, #6366f1 0%, #8b5cf6 100%);
+        }
+
+        .glass-card {
+            background: rgba(255, 255, 255, 0.8);
+            backdrop-filter: blur(10px);
+            border: 1px solid rgba(255, 255, 255, 0.2);
+        }
+
+        .results-container::-webkit-scrollbar {
+            width: 8px;
+        }
+
+        .results-container::-webkit-scrollbar-track {
+            background: #f1f1f1;
+            border-radius: 4px;
+        }
+
+        .results-container::-webkit-scrollbar-thumb {
+            background: #c7d2fe;
+            border-radius: 4px;
+        }
+
+        .results-container::-webkit-scrollbar-thumb:hover {
+            background: #818cf8;
+        }
+    </style>
+</head>
+<body class="min-h-screen py-8">
+    <div id="app" class="max-w-4xl mx-auto px-4">
+        <div class="glass-card rounded-2xl shadow-xl overflow-hidden">
+            <div class="gradient-bg px-6 py-4">
+                <h1 class="text-2xl font-semibold text-white">视频对象检测</h1>
+                <p class="text-indigo-100 text-sm mt-1">上传视频并检测其中的特定对象</p>
+            </div>
+
+            <div class="p-6">
+                <form @submit.prevent="analyzeVideo" class="space-y-6">
+                    <div>
+                        <label class="block text-sm font-medium text-gray-700 mb-2">上传视频</label>
+                        <div class="upload-area rounded-xl p-8 cursor-pointer" 
+                             @click="triggerFileInput"
+                             @dragover.prevent="handleDragOver"
+                             @dragleave.prevent="handleDragLeave"
+                             @drop.prevent="handleDrop"
+                             :class="{'border-indigo-500 bg-indigo-50': isDragging}">
+                            <div v-if="!selectedFile" class="text-center">
+                                <svg class="mx-auto h-12 w-12 text-gray-400" stroke="currentColor" fill="none" viewBox="0 0 48 48">
+                                    <path d="M28 8H12a4 4 0 00-4 4v20m32-12v8m0 0v8a4 4 0 01-4 4H12a4 4 0 01-4-4v-4m32-4l-3.172-3.172a4 4 0 00-5.656 0L28 28M8 32l9.172-9.172a4 4 0 015.656 0L28 28m0 0l4-4m4-4h.01" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" />
+                                </svg>
+                                <p class="mt-4 text-sm text-gray-600">点击或拖拽视频文件到此处上传</p>
+                            </div>
+                            <div v-else class="text-center">
+                                <svg class="mx-auto h-12 w-12 text-indigo-500" fill="none" stroke="currentColor" viewBox="0 0 24 24">
+                                    <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M7 4v16M17 4v16M3 8h4m10 0h4M3 12h18M3 16h4m10 0h4M4 20h16a1 1 0 001-1V5a1 1 0 00-1-1H4a1 1 0 00-1 1v14a1 1 0 001 1z"></path>
+                                </svg>
+                                <p class="mt-4 text-sm text-indigo-600">{{ selectedFile.name }}</p>
+                                <p class="text-xs text-gray-500 mt-1">{{ formatFileSize(selectedFile.size) }}</p>
+                            </div>
+                            <input type="file" ref="fileInput" accept="video/*" class="hidden" @change="handleFileChange">
+                        </div>
+                        <p v-if="selectedFile" class="mt-2 text-sm text-indigo-600">已选择文件: {{ selectedFile.name }}</p>
+                    </div>
+
+                    <div>
+                        <label for="objectInput" class="block text-sm font-medium text-gray-700 mb-2">要查找的对象</label>
+                        <input type="text"
+                               class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-indigo-500 focus:border-indigo-500 transition-all"
+                               id="objectInput"
+                               v-model="objectToFind"
+                               placeholder="例如: '穿红色衣服的人'">
+                    </div>
+
+                    <div v-if="errorMessage" class="rounded-lg bg-red-50 p-4 text-red-700">
+                        {{ errorMessage }}
+                    </div>
+
+                    <button type="submit"
+                            class="w-full bg-indigo-600 text-white py-2 px-4 rounded-lg hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:ring-offset-2 transition-all"
+                            :disabled="isAnalyzing"
+                            :class="{'opacity-50 cursor-not-allowed': isAnalyzing}">
+                        {{ isAnalyzing ? '分析中...' : '开始分析' }}
+                    </button>
+                </form>
+
+                <div v-if="isAnalyzing" class="text-center mt-6">
+                    <div class="inline-flex items-center px-4 py-2 bg-indigo-100 text-indigo-700 rounded-full analyzing">
+                        <svg class="animate-spin -ml-1 mr-3 h-5 w-5 text-indigo-700" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24">
+                            <circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"></circle>
+                            <path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"></path>
+                        </svg>
+                        正在分析视频...
+                    </div>
+                </div>
+
+                <div class="results-container mt-6 space-y-4 max-h-[600px] overflow-y-auto pr-2">
+                    <div v-for="(frame, index) in results" :key="index" class="glass-card rounded-xl overflow-hidden">
+                        <div class="p-4 border-b border-gray-100">
+                            <h3 class="font-medium text-gray-900">第 {{ frame.second }} 秒的帧</h3>
+                        </div>
+                        <div class="p-4">
+                            <img :src="frame.frame_path" :alt="'Frame ' + frame.second" class="w-full rounded-lg">
+                            <p class="mt-4 text-gray-700">{{ frame.description || '暂无描述' }}</p>
+                            <div class="mt-4 flex items-center justify-between text-sm text-gray-500">
+                                <span>置信度: {{ frame.confidence }}/10</span>
+                                <span class="px-2 py-1 rounded-full" :class="frame.is_match ? 'bg-green-100 text-green-700' : 'bg-gray-100 text-gray-700'">
+                                    {{ frame.is_match ? '匹配' : '不匹配' }}
+                                </span>
+                            </div>
+                        </div>
+                    </div>
+                </div>
+            </div>
+        </div>
+    </div>
+
+    <script>
+        document.addEventListener('DOMContentLoaded', function() {
+            new Vue({
+                el: '#app',
+                data: {
+                    selectedFile: null,
+                    objectToFind: '',
+                    isAnalyzing: false,
+                    errorMessage: '',
+                    isDragging: false,
+                    results: []
+                },
+                methods: {
+                    triggerFileInput() {
+                        this.$refs.fileInput.click();
+                    },
+                    handleFileChange(e) {
+                        if (e.target.files.length) {
+                            const file = e.target.files[0];
+                            if (!file.type.startsWith('video/')) {
+                                this.errorMessage = '请上传有效的视频文件';
+                                return;
+                            }
+                            this.selectedFile = file;
+                            this.errorMessage = '';
+                        }
+                    },
+                    handleDragOver() {
+                        this.isDragging = true;
+                    },
+                    handleDragLeave() {
+                        this.isDragging = false;
+                    },
+                    handleDrop(e) {
+                        this.isDragging = false;
+                        const files = e.dataTransfer.files;
+                        if (files.length) {
+                            const file = files[0];
+                            if (!file.type.startsWith('video/')) {
+                                this.errorMessage = '请上传有效的视频文件';
+                                return;
+                            }
+                            this.selectedFile = file;
+                            this.errorMessage = '';
+                        }
+                    },
+                    formatFileSize(bytes) {
+                        if (bytes === 0) return '0 Bytes';
+                        const k = 1024;
+                        const sizes = ['Bytes', 'KB', 'MB', 'GB'];
+                        const i = Math.floor(Math.log(bytes) / Math.log(k));
+                        return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];
+                    },
+                    async analyzeVideo() {
+                        if (!this.selectedFile) {
+                            this.errorMessage = '请选择视频文件';
+                            return;
+                        }
+                        if (!this.objectToFind.trim()) {
+                            this.errorMessage = '请输入要查找的对象描述';
+                            return;
+                        }
+
+                        this.isAnalyzing = true;
+                        this.errorMessage = '';
+                        this.results = [];
+
+                        try {
+                            // 这里是模拟API请求,实际使用时替换为真实API调用
+                            // 模拟延迟
+                            await new Promise(resolve => setTimeout(resolve, 1500));
+                            
+                            // 模拟返回结果
+                            const mockResults = [
+                                {
+                                    second: 5,
+                                    frame_path: 'https://via.placeholder.com/640x360?text=视频帧+5秒',
+                                    description: '检测到穿红色衣服的人',
+                                    confidence: 8,
+                                    is_match: true
+                                },
+                                {
+                                    second: 12,
+                                    frame_path: 'https://via.placeholder.com/640x360?text=视频帧+12秒',
+                                    description: '检测到多个对象',
+                                    confidence: 5,
+                                    is_match: false
+                                }
+                            ];
+                            
+                            // 模拟流式响应
+                            for (const result of mockResults) {
+                                await new Promise(resolve => setTimeout(resolve, 500));
+                                this.results.unshift(result);
+                            }
+                        } catch (error) {
+                            console.error('分析错误:', error);
+                            this.errorMessage = '分析过程中发生错误: ' + error.message;
+                        } finally {
+                            this.isAnalyzing = false;
+                        }
+                    }
+                }
+            });
+        });
+    </script>
+</body>
+</html>

+ 11 - 4
src/api/work.js

@@ -56,12 +56,19 @@ export function getrecentData(data) {
 	'params':data,
   })
 }
-// 成品检验记录
-export function getCameraList(data) {
+// 查询异常类型统计
+export function getabnormalTypes(data) {
   return request({
-    url: '/system/camera/list',
+    url: '/visualization/mes/dv/abnormalTypesStatistics',
+    method: 'get',
+	'params':data,
+  })
+}
+// 查询物流列表(分页)
+export function getlogisticsList(data) {
+  return request({
+    url: '/visualization/mes/wm/logistics/list',
     method: 'get',
-	type:true,
 	'params':data,
   })
 }

+ 29 - 7
src/views/index.vue

@@ -116,7 +116,7 @@ import pieCharts from "./components/piecharts.vue"
 import mixbarCharts from "./components/mixbarcharts.vue"
 import ycmixbarCharts from "./components/ycmixbarcharts.vue"
 import hbarCharts from "./components/hbarcharts.vue"
-import {getWorkorderList,getlistGanttTaskList,getMaintenrecordList,getabnormalStatistics,getrecentData} from "@/api/work.js"
+import {getWorkorderList,getlistGanttTaskList,getMaintenrecordList,getabnormalStatistics,getrecentData,getabnormalTypes} from "@/api/work.js"
   export default {
 	components:{boxTable,pieCharts,mixbarCharts,ycmixbarCharts,hbarCharts},
     data() {
@@ -144,8 +144,9 @@ import {getWorkorderList,getlistGanttTaskList,getMaintenrecordList,getabnormalSt
         steplist:[{tit:'原料',val:1},{tit:'检测',val:2},{tit:'涂布',val:3},{tit:'熟化',val:4},{tit:'分切',val:5},{tit:'检验',val:6},{tit:'包装',val:7},{tit:'入库',val:8},],
 		stepval:4,
 		timer:null,
+		refresh:null,
 		refval:1,//刷新
-		pageNum:1.,
+		pageNum:1,
 		pageSize:20
       }
     },
@@ -153,13 +154,12 @@ import {getWorkorderList,getlistGanttTaskList,getMaintenrecordList,getabnormalSt
 	    this.clearTimer();
 	  },
 	  created() {
-	  	this.getList()
-		this.getWorkorderList()
-		this.getlistGanttTaskList()
+	  	
 		this.init()
 	  },
     async mounted() {
 		clearInterval(this.timer);
+		clearInterval(this.refresh);
 		var len=this.steplist.length;
 		this.timer=setInterval(() => {
 			// this.hbarDatab.bara=[];
@@ -169,6 +169,9 @@ import {getWorkorderList,getlistGanttTaskList,getMaintenrecordList,getabnormalSt
 			// 	this.stepval = 1;
 			// }
 		}, 10000); // 10秒
+		// this.refresh=setInterval(()=>{
+		// 	this.init()
+		// },45000)
     },
 	
     methods: {
@@ -177,10 +180,18 @@ import {getWorkorderList,getlistGanttTaskList,getMaintenrecordList,getabnormalSt
               clearInterval(this.timer);
               this.timer = null; // 防止内存泄漏
             }
+			if(this.refresh){
+				clearInterval(this.refresh);
+				this.refresh = null; // 防止内存泄漏
+			}
         },
 		init(){
-			this.getabnormalStatistics();
-			this.getrecentData();
+			this.getList() // 查询设备保养记录列表
+			this.getWorkorderList() // 生产工单列表
+			this.getlistGanttTaskList() // 生产排产:获取甘特图中需要显示的TASK
+			this.getabnormalStatistics(); //设备异常统计
+			this.getrecentData(); // 巡检记录
+			this.getabnormalTypes() // 查询异常类型统计
 		},
 		getabnormalStatistics(){
 			var params={
@@ -233,6 +244,17 @@ import {getWorkorderList,getlistGanttTaskList,getMaintenrecordList,getabnormalSt
 					this.dataListc=res.rows
 				}
 			})
+		},
+		// 查询异常类型统计
+		getabnormalTypes(){
+			// var params={
+			// 	days:6
+			// }
+			getabnormalTypes().then(res=>{
+				if(res.code==200){
+					this.hbarDatab=JSON.parse(JSON.stringify(res.data))
+				}
+			})
 		}
     },
   }

+ 28 - 12
src/views/record.vue

@@ -38,19 +38,20 @@
 						      <el-carousel-item v-for="(ite,idx) in stepInfo" :key="idx">
 						        <div class="wlbox" >
 						        	<div class="wlbtop">
-						        		<div><span>收货地址</span>{{ite.adr}}</div>
-						        		<div><span>物流公司</span>{{ite.gs}}</div>
-						        		<div><span>运单号码</span>{{ite.dh}}</div>
+						        		<div><span>收货地址</span>{{ite.clientName}}</div>
+						        		<!-- <div><span>收货地址</span>{{ite.address}}</div> -->
+						        		<div><span>物流公司</span>{{ite.carrier}}</div>
+						        		<div><span>运单号码</span>{{ite.shippingNumber}}</div>
 						        	</div>
 						        	<img src="@/assets/images/record/line.png" class="line"/>
 						        	<div class="stepbox">
-						        		<div class="step flext" v-for="(aite,aidx) in ite.children" :key="aidx">
-						        			<div class="time flex0">{{aite.time}}</div>
+						        		<div class="step flext" v-for="(aite,aidx) in ite.logisticsTraceList" :key="aidx">
+						        			<div class="time flex0">{{aite.traceTime}}</div>
 						        			<div class="cir flex0">
 						        				<img src="@/assets/images/record/cir.png" v-if="aidx==0"/>
 						        				<img src="@/assets/images/record/ccir.png" v-else/>
 						        			</div>
-						        			<div class="tit overtwo">{{aite.tit}}</div>
+						        			<div class="tit overtwo">{{aite.traceDetail}}</div>
 						        		</div>
 						        	</div>
 						        </div>
@@ -79,7 +80,7 @@
 import boxTable from "./components/table.vue"
 import recordbarChart from "./components/recordbarChart.vue"
 import { visualization, ipqc, } from "@/api/record"
-
+import {getlogisticsList} from "@/api/work.js"
 export default {
 	components: {boxTable,recordbarChart},
   data() {
@@ -144,15 +145,14 @@ export default {
 		
 		rbarDataa:{data:['黑点','杂质','色差','取样','接头','皱痕','刮痕','缺胶','拉线','制程异常','原料异常','设备异常 ',],bara:[110,135,88,91,50,98,26,30,80,26,53,46],},
 		steplist:[{time:'2025-05-10 17:03',tit:'已到达深圳,正在配送...'},{time:'2025-05-10 06:03',tit:'已到达惠州,发往深圳'},{time:'2025-05-09 14:03',tit:'已到达赣州,发往惠州'},{time:'2025-05-08 17:03',tit:'南昌市 离开处理中心,发往赣州'},],
-		stepInfo:[{adr:"深圳鹏威新材",gs:"EMS经济快递",dh:"5066937639801",children:[{time:'2025-05-10 17:03',tit:'已到达深圳,正在配送...'},{time:'2025-05-10 06:03',tit:'已到达惠州,发往深圳'},{time:'2025-05-09 14:03',tit:'已到达赣州,发往惠州'},{time:'2025-05-08 17:03',tit:'南昌市 离开处理中心,发往赣州'}],},{adr:"123456",gs:"EMS经济快递",dh:"5066937639801",children:[{time:'2025-05-10 17:03',tit:'已到达深圳,正在配送...'},{time:'2025-05-10 06:03',tit:'已到达惠州,发往深圳'},{time:'2025-05-09 14:03',tit:'已到达赣州,发往惠州'},{time:'2025-05-08 17:03',tit:'南昌市 离开处理中心,发往赣州'}],}],
+		stepInfo:[{adr:"深圳鹏威新材",gs:"EMS经济快递",dh:"5066937639801",children:[{time:'2025-05-10 17:03',tit:'已到达深圳,正在配送...'},{time:'2025-05-10 06:03',tit:'已到达惠州,发往深圳'},{time:'2025-05-09 14:03',tit:'已到达赣州,发往惠州'},{time:'2025-05-08 17:03',tit:'南昌市 离开处理中心,发往赣州'}]}],
 		isautoplay:false,
+		pageNum:1,
+		pageSize:20
 	};
   },
   created() {
-  	this.getList()
-	this.getListFPQC()
-	this.getListPPQC()
-	this.getListFQC()
+  	this.init()
   },
   mounted(){
 	  
@@ -164,6 +164,13 @@ export default {
    
   },
   methods:{
+	init(){
+		this.getList()
+		this.getListFPQC()
+		this.getListPPQC()
+		this.getListFQC()
+		this.getlogisticsList()
+	},
 	/** 查询原料列表 */
 	getList() {
 	  visualization().then(response => {
@@ -188,6 +195,15 @@ export default {
 	    this.dataListd   = response.rows;
 	  });
 	},
+	getlogisticsList(){
+		var params={
+			pageNum:this.pageNum,
+			pageSize:this.pageSize
+		}
+		getlogisticsList(params).then(res=>{
+			this.stepInfo=res.rows
+		})
+	},
   }
 };
 </script>

部分文件因文件數量過多而無法顯示