Quellcode durchsuchen

修改检验任务二级页面,添加新的拍照点

ZhangLeo vor 3 Monaten
Ursprung
Commit
1cbbafd4cb
5 geänderte Dateien mit 1114 neuen und 265 gelöschten Zeilen
  1. 16 0
      api/work.uts
  2. 8 2
      pages.json
  3. 136 58
      pages/work/download/DownloadDetail.uvue
  4. 339 205
      pages/work/download/DownloadList.uvue
  5. 615 0
      pages/work/download/PhotoRecord.uvue

+ 16 - 0
api/work.uts

@@ -67,6 +67,22 @@ export type RecordCalculate = {
 	status : number
 	status : number
 }
 }
 
 
+//检验任务
+export type TaskInfo = {
+	gxid : string, 
+	itemTitle: string,
+	photoitemStep : number,
+	photoitemTotal: number,
+	photoitemStatus: string,
+	recordStep : number,
+	recordTotal : number,
+	recordStatus : string,
+	keypointStep : number,
+	keypointTotal : number
+	keypointStatus : string
+}
+
+
 export function offlineData(data : UTSJSONObject) : Promise<UTSJSONObject> {
 export function offlineData(data : UTSJSONObject) : Promise<UTSJSONObject> {
 	return new Promise((resolve, reject) => {
 	return new Promise((resolve, reject) => {
 		let result = JSON.parseObject(JSON.stringify(data)) as UTSJSONObject
 		let result = JSON.parseObject(JSON.stringify(data)) as UTSJSONObject

+ 8 - 2
pages.json

@@ -136,7 +136,7 @@
         {
         {
             "path" : "pages/work/download/DownloadDetail",
             "path" : "pages/work/download/DownloadDetail",
             "style" : {
             "style" : {
-                "navigationBarTitleText" : "检验任务"
+                "navigationBarTitleText" : "检验任务详情"
             }
             }
         },
         },
         {
         {
@@ -144,7 +144,13 @@
             "style" : {
             "style" : {
                 "navigationBarTitleText" : "任务管理"
                 "navigationBarTitleText" : "任务管理"
             }
             }
-        }
+        },
+		{
+		    "path" : "pages/work/download/PhotoRecord",
+		    "style" : {
+		        "navigationBarTitleText" : "拍照点"
+		    }
+		}
     ],
     ],
     "tabBar" : {
     "tabBar" : {
         "color" : "#000000",
         "color" : "#000000",

+ 136 - 58
pages/work/download/DownloadDetail.uvue

@@ -5,7 +5,7 @@
 		<!-- 报告基础信息 -->
 		<!-- 报告基础信息 -->
 		<view class="section">
 		<view class="section">
 			<view class="info-item">
 			<view class="info-item">
-				<text class="label">声像记录任务</text>
+				<text class="label">检验任务</text>
 				<text class="value">{{ download.workorder}}</text>
 				<text class="value">{{ download.workorder}}</text>
 			</view>
 			</view>
 			<view class="info-item">
 			<view class="info-item">
@@ -15,30 +15,24 @@
 		</view>
 		</view>
 
 
 		<view class="section">
 		<view class="section">
-			<uni-table>
-				<uni-tr class="section-title" v-for="(item,index) in titleList" :key="index">
-					<uni-td class="grid-text">{{item.title1}}</uni-td>
-					<uni-td class="grid-text">{{item.title2}}</uni-td>
-					<uni-td class="grid-text">{{item.title3}}</uni-td>
+			<uni-table v-for="(item,index) in demoData" :key="index">
+				<uni-tr>
+					<uni-td class="grid-text">{{item.itemTitle}}</uni-td>
 				</uni-tr>
 				</uni-tr>
-				<uni-tr class="section-title" v-for="(taskProcess : RecordCalculate,index2 : number) in taskProcessList"
-					:key="index2" @click="enterProcess(taskProcess.photoitem)">
-					<uni-td class="grid-text">{{taskProcess.photoitem}}</uni-td>
-					<uni-td class="grid-text">
-						<text :class="{
-							'bg-green bg-text': taskProcess.status === 3,
-							'bg-yellow bg-text': taskProcess.status === 2,
-							'bg-black bg-text': taskProcess.status === 1,
-							'bg-red bg-text': taskProcess.status === 4
-						  }">
-							{{taskProcess.step}}/{{taskProcess.total}}
-						</text>
-					</uni-td>
-					<uni-td class="grid-text">
-						<text :class="{
-							'ft-red': taskProcess.status === 4
-						  }">{{ statusDict[taskProcess.status.toString()] }}</text>
-					</uni-td>
+				<uni-tr class="section-title" @click="enterItem(item.gxid, 0)">
+					<uni-td class="grid-text">拍照点</uni-td>
+					<uni-td class="grid-text">{{item.photoitemStep}} / {{item.photoitemTotal}}</uni-td>
+					<uni-td class="grid-text">{{item.photoitemStatus}}</uni-td>
+				</uni-tr>
+				<uni-tr class="section-title" @click="enterItem(item.gxid, 1)">
+					<uni-td class="grid-text">检验记录</uni-td>
+					<uni-td class="grid-text">{{item.recordStep}} / {{item.recordTotal}}</uni-td>
+					<uni-td class="grid-text">{{item.recordStatus}}</uni-td>
+				</uni-tr>
+				<uni-tr class="section-title" @click="enterItem(item.gxid, 2)">
+					<uni-td class="grid-text">关键工序记录</uni-td>
+					<uni-td class="grid-text">{{item.keypointStep}} / {{item.keypointTotal}}</uni-td>
+					<uni-td class="grid-text">{{item.keypointStatus}}</uni-td>
 				</uni-tr>
 				</uni-tr>
 			</uni-table>
 			</uni-table>
 		</view>
 		</view>
@@ -53,7 +47,7 @@
 		ref,
 		ref,
 		onMounted
 		onMounted
 	} from 'vue'
 	} from 'vue'
-	import { getList, Download, TaskProcess, getRecordCalculate, RecordCalculate, statusDict } from '@/api/work';
+	import { getList, Download, TaskProcess, getRecordCalculate, RecordCalculate, statusDict, TaskInfo } from '@/api/work';
 
 
 	const titleList = [{
 	const titleList = [{
 		title1: "部位", title2: "进度", title3: "状态"
 		title1: "部位", title2: "进度", title3: "状态"
@@ -62,6 +56,62 @@
 	var initTasks = [] as RecordCalculate[]
 	var initTasks = [] as RecordCalculate[]
 	//const statusMap = ref(new Map<number, string>([[1,'未执行'],[2,'执行中'],[3,'执行完'],[4,'检验失败']]))
 	//const statusMap = ref(new Map<number, string>([[1,'未执行'],[2,'执行中'],[3,'执行完'],[4,'检验失败']]))
 	
 	
+	var demoData = ref<TaskInfo[]>([]);
+	demoData.value = [
+		{
+			gxid: '1',
+			itemTitle : '20-检验',
+			photoitemStep : 10,
+			photoitemTotal: 10,
+			photoitemStatus : '',
+			recordStep : 5,
+			recordTotal : 5,
+			recordStatus : '不合格',
+			keypointStep : 4,
+			keypointTotal : 4,
+			keypointStatus : ''
+		} as TaskInfo,
+		{
+			gxid: '2',
+			itemTitle : '50-检验',
+			photoitemStep : 2,
+			photoitemTotal: 5,
+			photoitemStatus : '',
+			recordStep : 2,
+			recordTotal : 11,
+			recordStatus : '',
+			keypointStep : 3,
+			keypointTotal : 4,
+			keypointStatus : ''
+		} as TaskInfo,
+		{
+			gxid: '3',
+			itemTitle : '80-检验',
+			photoitemStep : 2,
+			photoitemTotal: 5,
+			photoitemStatus : '',
+			recordStep : 2,
+			recordTotal : 11,
+			recordStatus : '',
+			keypointStep : 3,
+			keypointTotal : 4,
+			keypointStatus : ''
+		} as TaskInfo,
+		{
+			gxid: '4',
+			itemTitle: '100-总检',
+			photoitemStep: 0,
+			photoitemTotal: 5,
+			photoitemStatus: '',
+			recordStep: 0,
+			recordTotal: 13,
+			recordStatus: '',
+			keypointStep: 0,
+			keypointTotal: 4,
+			keypointStatus: ''
+		} as TaskInfo
+	]
+	
 	const download = ref<Download>({
 	const download = ref<Download>({
 		pdid: 0,
 		pdid: 0,
 		workorder: "",
 		workorder: "",
@@ -75,32 +125,6 @@
 		progress: "",
 		progress: "",
 		status: 1
 		status: 1
 	})
 	})
-     
-    // #ifdef H5
-	download.value = {
-		pdid: 1,
-		workorder: "632-P-01",
-		invname: "箱间段",
-		productno: "1CFA1040-00#S",
-		graphid: "HBJ0100-00",
-		cardno: "LK20230707070012",
-		processno: "Pb/XXX-E11",
-		ver: "A.1",
-		updatetime: "2025-06-23",
-		progress: "1/3"
-	}
-	
-	 taskProcessList.value = [
-		{ id: 1, name: "前底-外侧", num: 5, step: 5, status: 3 },
-		{ id: 2, name: "后底-外侧", num: 3, step: 3, status: 4 },
-		{ id: 3, name: "简段-外侧", num: 12, step: 2, status: 2 },
-		{ id: 4, name: "前底-内侧", num: 5, step: 0, status: 1 },
-		{ id: 5, name: "后底-内侧", num: 6, step: 0, status: 1 },
-		{ id: 6, name: "简段-内侧", num: 3, step: 0, status: 1 },
-		{ id: 7, name: "隧道管", num: 5, step: 0, status: 1 },
-	];
-	
-	// #endif
 
 
 	onLoad((options) => {
 	onLoad((options) => {
 		const downloadId = options?.id ?? ""
 		const downloadId = options?.id ?? ""
@@ -147,15 +171,23 @@
 		uni.navigateBack()
 		uni.navigateBack()
 	}
 	}
 
 
-	const enterProcess = (photoitem : string) => {
-		console.log(photoitem);
-		uni.navigateTo({
-			url: `/pages/work/record/RecordList?photoitem=${photoitem}`
-		});
+	const enterItem = (id : string, type : number) => {
+		let url = ''
+	  if (type == 0) {
+		  url = `/pages/work/download/PhotoRecord`
+	  }	else if (type == 1) {
+		  url = `/pages/work/report/InspectionList`
+	  } else if (type == 2) {
+		  url = `/pages/work/process/ProcessList`
+	  }
+	  uni.navigateTo({
+	    url
+	  });
 	}
 	}
 </script>
 </script>
 
 
 <style scoped>
 <style scoped>
+	
 	.container {
 	.container {
 		padding: 40rpx;
 		padding: 40rpx;
 		background-color: #f5f7fa;
 		background-color: #f5f7fa;
@@ -210,15 +242,61 @@
 		white-space: normal;
 		white-space: normal;
 	}
 	}
 
 
+	/* 表格容器样式 */
+	uni-table {
+		width: 100%;
+		background-color: #fff; /* 设置表格背景色 */
+		border-radius: 8rpx;
+		overflow: hidden;
+		/* 去除列表样式,解决第一列前的小短横 */
+		list-style-type: none;
+	}
+	
+	/* 表格行样式 */
+	uni-tr {
+		width: 100%;
+		/* #ifdef APP-ANDROID */
+		border-bottom: 1rpx solid #f0f0f0; /* Android设备添加底边框 */
+		/* #endif */
+	}
+	
+	/* 表格单元格样式 */
+	uni-td {
+		/* #ifdef APP-ANDROID */
+		border-right: 1rpx solid #f0f0f0; /* Android设备添加右边框 */
+		/* #endif */
+	}
+	
+	/* 最后一列去除右边框 */
+	uni-tr uni-td:last-child {
+		/* #ifdef APP-ANDROID */
+		border-right: none;
+		/* #endif */
+	}
+	
+	/* 最后一行去除底边框 */
+	uni-table uni-tr:last-child {
+		/* #ifdef APP-ANDROID */
+		border-bottom: none;
+		/* #endif */
+	}
+	
 	.grid-text {
 	.grid-text {
 		/* #ifdef APP-NVUE */
 		/* #ifdef APP-NVUE */
 		font-size: 24rpx;
 		font-size: 24rpx;
 		color: #000;
 		color: #000;
 		/* #endif */
 		/* #endif */
-		padding: 10rpx 0 10rpx 0rpx;
+		/* #ifdef APP-ANDROID */
+		font-size: 28rpx; /* Android设备上字体稍大一些 */
+		/* #endif */
+		padding: 20rpx 16rpx; /* 增加内边距 */
 		box-sizing: border-box;
 		box-sizing: border-box;
-		margin: 10rpx 10rpx;
+		margin: 0;
 		min-width: 180rpx;
 		min-width: 180rpx;
+		background-color: #fff; /* 确保单元格背景色 */
+		/* 去除列表样式标记 */
+		list-style-type: none;
+		list-style-position: inside;
 	}
 	}
 
 
 	.footer-btn {
 	.footer-btn {

+ 339 - 205
pages/work/download/DownloadList.uvue

@@ -1,250 +1,384 @@
 <template>
 <template>
-	<view class="info-row btn-panel">
-		<button class="btn btn-first" @click="download">
-			下载数据
-		</button>
-		<button class="btn btn-second" @click="upload">
-			上传数据
-		</button>
-	</view>
-	<!-- #ifdef APP -->
-	<scroll-view style="flex:1">
-	<!-- #endif -->
-		<view class="download-card" v-for="(item, index) in downloads" :key="index" @click="enterItem(item.pdid)">
+  <view class="container">
+    <!-- 搜索栏 -->
+    <view class="info-row btn-panel search-bar">
+      <view class="search-input">
+		  <input type="text" v-model="productNo" placeholder="请输入产品号"/>
+	  </view>
+      <view class="scan-btn" @click="scanQRCode">
+        <uni-icons type="scan" size="32" color="#00aaff"></uni-icons>
+      </view>
+    </view>
+    <!-- 按钮面板 -->
+    <view class="info-row btn-panel">
+      <button class="btn btn-first" @click="download">
+        下载数据
+      </button>
+    </view>
+    <!-- 列表内容 -->
+    <!-- #ifdef APP -->
+    <scroll-view style="flex:1">
+    <!-- #endif -->
+      <view class="download-card" v-for="(item, index) in downloads" :key="index" >
+		<view @click="enterItem(item.pdid)">
 			<view class="info-row">
 			<view class="info-row">
-				<text class="label">工作令:</text>
-				<text class="value">{{ item.workorder }}</text>
+			  <text class="label">工作令:</text>
+			  <text class="value">{{ item.workorder }}</text>
 			</view>
 			</view>
 			<view class="info-row">
 			<view class="info-row">
-				<text class="label">产品名称:</text>
-				<text class="value">{{ item.invname }}</text>
+			  <text class="label">产品名称:</text>
+			  <text class="value">{{ item.invname }}</text>
 			</view>
 			</view>
 			<view class="info-row">
 			<view class="info-row">
-				<text class="label">图号:</text>
-				<text class="value">{{ item.graphid }}</text>
+			  <text class="label">图号:</text>
+			  <text class="value">{{ item.graphid }}</text>
 			</view>
 			</view>
 			<view class="info-row">
 			<view class="info-row">
-				<text class="label">产品编码:</text>
-				<text class="value">{{ item.productno }}</text>
+			  <text class="label">路卡号:</text>
+			  <text class="value">{{ item.cardno }}</text>
 			</view>
 			</view>
 			<view class="info-row">
 			<view class="info-row">
-				<text class="label">路卡号:</text>
-				<text class="value">{{ item.cardno }}</text>
+			  <text class="label">工艺编号:</text>
+			  <text class="value">{{ item.processno }}</text>
 			</view>
 			</view>
 			<view class="info-row">
 			<view class="info-row">
-				<text class="label">工艺编号:</text>
-				<text class="value">{{ item.processno }}</text>
+			  <text class="label">版本号:</text>
+			  <text class="value">{{ item.ver }}</text>
 			</view>
 			</view>
 			<view class="info-row">
 			<view class="info-row">
-				<text class="label">版本号:</text>
-				<text class="value">{{ item.ver }}</text>
+			  <text class="label">最近更新时间:</text>
+			  <text class="value">{{ item.updatetime == "" ? item.createtime : item.updatetime }}</text>
 			</view>
 			</view>
 			<view class="info-row">
 			<view class="info-row">
-				<text class="label">最近更新时间:</text>
-				<text class="value">{{ item.updatetime }}</text>
-			</view>
-			<view class="info-row">
-				<text class="label">进度:</text>
-				<text class="process-value" :class="{
-					'bg-green': item.status === 3,
-					'bg-yellow': item.status === 2,
-					'bg-black': item.status === 1
-				  }">{{ item.progress }}</text>
+			  <text class="label">进度:</text>
+			  <text class="process-value" :class="{
+			    'bg-green': item.statusRecordCount === item.totalRecord,
+			    'bg-yellow': item.statusRecordCount < item.totalRecord,
+			    'bg-black': item.statusRecordCount === 0
+			  }"> {{ item.statusRecordCount }} / {{ item.totalRecord }} </text>
 			</view>
 			</view>
+		</view>  
+		
+		<view class="info-row">
+			<button class="btn btn-second" @click="upload(item)">
+			  上传数据
+			</button>
 		</view>
 		</view>
-	<!-- #ifdef APP -->
-	</scroll-view>
-	<!-- #endif -->
+      </view>
+	  
+    <!-- #ifdef APP -->
+    </scroll-view>
+    <!-- #endif -->
+  </view>
 </template>
 </template>
 
 
 <script setup>
 <script setup>
-	import {
-		ref
-	} from 'vue'
-	import { getList, Download } from '@/api/work';
-	
-	var initDownloads = [] as Download[]
-	var downloads = ref<Download[]>([]);
-	
-	// #ifdef APP-ANDROID	 
-	 getList('app_product', null, null, null, null, null).then((res:UTSJSONObject) => {
-	  		console.log(res)
-			let dataList = res?.['data'] as UTSJSONObject[] ?? Array<UTSJSONObject>()
-			if(dataList!=null && dataList.length>0){
-				dataList.forEach(item =>{
-					if(item!=null){
-						let download = JSON.parse<Download>(item.toJSONString());
-						if(download!=null){
-							initDownloads.push(download)
-						}
-					}
-				});
-			}
-			console.log(initDownloads)
-			downloads.value = initDownloads
-	  })		
-	// #endif
-		
-		// #ifdef H5
-		downloads = [{
-			pdid: 1,
-			workorder: "632-P-01",
-			invname: "箱间段",
-			productno: "1CFA1040-00#S",
-			graphid: "HBJ0100-00",
-			cardno: "LK20230707070012",
-			processno: "Pb/XXX-E11",
-			ver: "A.1",
-			updatetime: "2025-06-23",
-			progress: "3/3",
-			status: 3
-		
-		}, {
-			pdid: 2,
-			workorder: "712-SY-10-6",
-			invname: "级间架",
-			productno: "1XA1020-00A",
-			graphid: "1XC002-00",
-			cardno: "LK20250215003",
-			processno: "Pb/XXX-E11",
-			ver: "B.1",
-			updatetime: "2025-08-25",
-			progress: "2/4",
-			status: 2
-		}, {
-			pdid: 3,
-			workorder: "712-SY-10-6",
-			invname: "级间架",
-			productno: "1XA1020-00A",
-			graphid: "1XC002-00",
-			cardno: "LK20250215003",
-			processno: "Pb/XXX-E11",
-			ver: "B.1",
-			updatetime: "2025-08-25",
-			progress: "0/4",
-			status: 1
-		}] as Download[];
-		// #endif
-	
+  import { ref, reactive } from 'vue'
+  import { getRecordInfoList } from '@/api/work';
+  import { downloadDataFromAPI, uploadDataToAPI } from '@/utils/dataProcessor';
+
+  // 产品号输入框数据
+  const productNo = ref('');
+  
+  const backPressOptions = reactive({
+    from: 'backbutton'
+  } as OnBackPressOptions)
+
+  onBackPress((options : OnBackPressOptions) : boolean | null => {
+    console.log('onBackPress', options)
+    // 使用reLaunch代替switchTab,避免多层跳转时的闪回问题
+    // reLaunch会关闭所有页面并打开到目标页面,适合需要完全重置导航栈的场景
+    uni.reLaunch({
+      url: `/pages/work/index`,
+    })
+    // 返回true表示拦截默认返回行为
+    return true
+  })
+
+  type Download = {
+    pdid : number,
+	productno : string,
+	cardno : string,
+    workorder : string,
+    invname : string,
+    graphid : string,
+    processno : string,
+    ver : string,
+    updatetime : string,
+    createtime : string,
+    status : number,
+    totalRecord : number,
+    statusRecordCount : number,
+	uploadflag: number
+  }
 
 
-	const download = (e : any) => {
-		console.log("开始下载...")
+  var initDownloads = [] as Download[]
+  var downloads = ref<Download[]>([]);
+  const map = ref(new Map<number, string>([[1, '未执行'], [2, '执行中'], [3, '执行完'], [4, '有错误']]))
+
+  // #ifdef APP-ANDROID
+  getRecordInfoList(null).then((res : UTSJSONObject) => {
+    console.log(res)
+    let dataList = res?.['data'] as UTSJSONObject[] ?? Array<UTSJSONObject>()
+    if (dataList != null && dataList.length > 0) {
+      dataList.forEach(item => {
+        if (item != null) {
+          let download = JSON.parse<Download>(item.toJSONString());
+          if (download != null) {
+            initDownloads.push(download)
+          }
+        }
+      });
+    }
+    downloads.value = initDownloads
+    console.log(initDownloads)
+  })
+  // #endif
+
+  // #ifdef H5
+  downloads = [{
+    pdid: 1,
+    workorder: "632-P-01",
+    invname: "箱间段",
+    productno: "1CFA1040-00#S",
+    cardno: "LK20230707070012",
+    processno: "Pb/XXX-E11",
+    updatetime: "2025-06-23",
+    progress: "3/3",
+    status: 3
+
+  }, {
+    pdid: 2,
+    workorder: "712-SY-10-6",
+    invname: "级间架",
+    productno: "1XA1020-00A",
+    cardno: "LK20250215003",
+    processno: "Pb/XXX-E11",
+    updatetime: "2025-08-25",
+    progress: "2/4",
+    status: 2
+  }, {
+    pdid: 3,
+    workorder: "712-SY-10-6",
+    invname: "级间架",
+    productno: "1XA1020-00A",
+    cardno: "LK20250215003",
+    processno: "Pb/XXX-E11",
+    updatetime: "2025-08-25",
+    progress: "0/4",
+    status: 1
+  }] as Download[];
+
+  // #endif
+
+  const download = async (e : any) => {
+    console.log("开始下载...")
+    // 调用数据处理工具中的方法下载数据
+	if(productNo.value == null || productNo.value == '') {
+		uni.showToast({
+		  title: '请先扫描或者输入产品号',
+		  icon: 'error'
+		});
+		return
 	}
 	}
-	const upload = (e : any) => {
-		console.log("开始上传...")
+	
+    await downloadDataFromAPI(productNo.value, () => {
+      // 回调函数中执行刷新,确保数据都保存好,进度条跑完
+      uni.reLaunch({ url: '/pages/work/record/InfoList' })
+    }).then((res) => {
+      // 移除这里的刷新逻辑,避免过早刷新
+    })
+  }
+  
+  const upload = async (e : Download) => {
+	if(e.statusRecordCount != e.totalRecord) {
+		uni.showToast({
+		  title: '当前任务还未完成!',
+		  icon: 'error'
+		});
+		return
 	}
 	}
-	const enterItem = (id : number) => {
-		uni.navigateTo({
-			url: `/pages/work/download/DownloadDetail?id=${id}`
+	if(e.uploadflag > 0) {
+		uni.showToast({
+		  title: '当前任务已上传!',
+		  icon: 'error'
 		});
 		});
+		return
 	}
 	}
+    console.log("开始上传...")
+    uploadDataToAPI(productNo.value, () => {
+	  // 回调函数中执行刷新,确保数据都保存好,进度条跑完
+	  uni.reLaunch({ url: '/pages/work/record/InfoList' })
+	}).then((res) => {
+	  // 移除这里的刷新逻辑,避免过早刷新
+	  // 处理断点续传
+	})
+
+  }
+  
+  const enterItem = (id : number) => {
+    uni.navigateTo({
+      url: `/pages/work/download/DownloadDetail?id=${id}`
+    });
+  }
+  
+  // 扫描二维码功能
+  const scanQRCode = () => {
+    uni.scanCode({
+      success: (res) => {
+        // 扫描成功,将结果填充到输入框
+        productNo.value = res.result;
+        console.log('扫描结果:', res.result);
+      },
+      fail: (err) => {
+        console.error('扫描失败:', err);
+        uni.showToast({
+          title: '扫描失败,请重试',
+          icon: 'error'
+        });
+      }
+    });
+  }
+
+  defineExpose({
+    backPressOptions
+  })
 </script>
 </script>
 
 
 <style scope>
 <style scope>
-	.container {
-		padding: 24rpx;
-		background-color: #f0f4f8;
-		flex: 1;
-		display: flex;
-		flex-direction: column;
-		font-family: "PingFang SC", "Helvetica Neue", Helvetica, Arial, sans-serif;
-		/* #ifndef APP-ANDROID */
-		min-height: 100vh;
-		/* #endif */
-		height: 120rpx;
-	}
+  .container {
+    padding: 24rpx;
+    background-color: #f0f4f8;
+    flex: 1;
+    display: flex;
+    flex-direction: column;
+    font-family: "PingFang SC", "Helvetica Neue", Helvetica, Arial, sans-serif;
+    /* #ifndef APP-ANDROID */
+    min-height: 100vh;
+    /* #endif */
+    height: 120rpx;
+  }
 
 
-	.download-card {
-		background: #ffffff;
-		border-radius: 20rpx;
-		padding: 24rpx 32rpx;
-		box-shadow: 0 8rpx 15rpx rgba(0, 43, 92, 0.1);
-		display: flex;
-		flex-direction: column;
-		margin-bottom: 20rpx;
-		margin-top: 40rpx;
-	}
+  .search-bar {
+	  background-color: #ffffff;
+	  border-radius: 10rpx;
+	  box-shadow: 0 2rpx 10rpx rgba(0, 0, 0, 0.1);
+}
 
 
-	.download-card .view {
-		margin-bottom: 16rpx;
+/* 搜索输入框:占满容器剩余空间,放在按钮左侧 */
+	.search-input {
+	  /* 清除默认输入框样式 */
+	  border: none;
+	  background: transparent;
+	  width: 70%;
+	  margin-left: 10rpx;
 	}
 	}
 
 
-	/* 信息行 */
-	.info-row {
-		display: flex;
-		flex-direction: row;
-		font-size: 28rpx;
-		color: #33475b;
-		align-items: center;
+/* 扫描按钮:放在输入框右侧,距离最右10rpx */
+	.scan-btn {
+	  justify-content: center;
+	  align-items: center; /* 新增:按钮内部图标垂直居中 */
+	  /* 关键:右侧10rpx边距,实现"距离最右10rpx" */
+	  margin-left: auto; /* 自动推到flex容器最右侧 */
+	  margin-right: 10rpx; /* 与容器右边缘保持10rpx间距 */
 	}
 	}
 
 
-	.info-row>.label {
-		margin-left: 10rpx;
-	}
+  .download-card {
+    background: #ffffff;
+    border-radius: 20rpx;
+    padding: 24rpx 32rpx;
+    box-shadow: 0 8rpx 15rpx rgba(0, 43, 92, 0.1);
+    display: flex;
+    flex-direction: column;
+    margin-bottom: 20rpx;
+    margin-top: 40rpx;
+    margin-left: 20rpx;
+    margin-right: 20rpx;
+  }
 
 
-	.info-row>.value {
-		margin-left: 10rpx;
-	}
+  .download-card .view {
+    margin-bottom: 16rpx;
+  }
 
 
-	.btn-panel {
-		display: flex;
-		justify-content: space-between;
-		align-items: center;
-		margin-left: 5rpx;
-		margin-right: 5rpx;
-	}
+  /* 信息行 */
+  .info-row {
+    display: flex;
+    flex-direction: row;
+    font-size: 28rpx;
+    color: #33475b;
+    align-items: center;
+  }
 
 
-	.label {
-		font-weight: bold;
-		color: #102a43;
-		min-width: 100rpx;
-	}
+  .info-row>.label {
+    margin-left: 10rpx;
+  }
 
 
-	.value {
-		flex: 1;
-		white-space: nowrap;
-		overflow: hidden;
-		text-overflow: ellipsis;
-	}
+  .info-row>.value {
+    margin-left: 10rpx;
+  }
 
 
-	.btn {
-		align-self: flex-end;
-		background-color: #00aaff;
-		color: #fff;
-		border: none;
-		border-radius: 32rpx;
-		padding: 2rpx 30rpx;
-		font-size: 24rpx;
-		font-weight: bold;
-		/* #ifndef APP-ANDROID */
-		transition: background-color 0.3s ease;
-		/* #endif */
-		margin-top: 30rpx;
-	}
+  .btn-panel {
+    display: flex;
+    justify-content: space-between;
+    align-items: center;
+    margin-left: 5rpx;
+    margin-right: 5rpx;
+  }
 
 
-	.process-value {
-		width: 120rpx;
-		min-width: 100rpx;
-		text-align: center;
-		border-radius: 10rpx;
-	}
+  .label {
+    font-weight: bold;
+    color: #102a43;
+    min-width: 100rpx;
+  }
 
 
-	.bg-green {
-		background-color: seagreen;
-	}
+  .value {
+    flex: 1;
+    white-space: nowrap;
+    overflow: hidden;
+    text-overflow: ellipsis;
+  }
 
 
-	.bg-yellow {
-		background-color: yellow;
-	}
+  .btn {
+    align-self: flex-end;
+    background-color: #00aaff;
+    color: #fff;
+    border: none;
+    border-radius: 32rpx;
+    padding: 2rpx 30rpx;
+    font-size: 24rpx;
+    font-weight: bold;
+    /* #ifndef APP-ANDROID */
+    transition: background-color 0.3s ease;
+    /* #endif */
+    margin-top: 30rpx;
+  }
 
 
-	.bg-black {
-		background-color: #102a43;
-	}
-	
-	.btn-first {
-		margin-left: 5rpx;
-	}
-	.btn-second {
-		margin-right: 5rpx;
-	}
+  .process-value {
+    width: 120rpx;
+    min-width: 100rpx;
+    text-align: center;
+    border-radius: 10rpx;
+  }
+
+  .bg-green {
+    background-color: seagreen;
+  }
+
+  .bg-yellow {
+    background-color: yellow;
+  }
+
+  .bg-black {
+    background-color: #102a43;
+  }
+
+  .btn-first {
+    margin-left: 5rpx;
+  }
+
+  .btn-second {
+    margin-right: 5rpx;
+	margin-left: auto;
+  }
+  
 </style>
 </style>

+ 615 - 0
pages/work/download/PhotoRecord.uvue

@@ -0,0 +1,615 @@
+<template>
+	<scroll-view class="tag-scroll-container" scroll-x="true">
+		<view class="record-card2 flex-row">
+			<view class="tag-circle" v-for="(item, index) in initRecords" :key="index" @click="tabsClick(item.senum)"
+				:class="{'checked-tag' : item.senum == current}">
+				<text class="circle" :class="{
+								'bg-green': item.status == 3,
+								'bg-yellow': item.status == 2,
+								'bg-red': item.status == 4,
+								'bg-black': item.status == 1
+							  }">{{item.senum}}</text>
+			</view>
+		</view>
+	</scroll-view>
+
+	<!-- #ifdef APP -->
+	<scroll-view style="flex:1">
+	<!-- #endif -->
+		<view class="record-card" v-for="(item, index) in records" :key="index"
+			v-show="current == item.senum as number">
+			<view class="header-row">
+				<text class="label">序号:</text>
+				<text class="value">{{ item.senum }}</text>
+				<text class="status"
+					:class="{'status-cancelled': item.status === 5, 'bg-red': item.status == 4}">{{ recordStatusDict[item.status.toString()] }}</text>
+			</view>
+
+			<view class="info-row">
+				<text class="label">产品码:</text>
+				<text class="value">{{ item.productno }}</text>
+			</view>
+
+			<view class="info-row">
+				<text class="label">拍照点:</text>
+				<text class="value">{{ item.part }}</text>
+			</view>
+
+			<view class="info-row">
+				<text class="label">拍照位置:</text>
+				<text class="value">{{ item.photoitem }}</text>
+			</view>
+
+			<view class="info-row">
+				<text class="label">描述:</text>
+				<text class="value">{{ item.descb }}</text>
+			</view>
+
+			<view class="info-row">
+				<text class="label">位置编号:</text>
+				<text class="value">{{ item.partno }}</text>
+			</view>
+
+			<view class="info-row">
+				<text class="label">数量:</text>
+				<text class="value">{{ item.num }}</text>
+			</view>
+
+			<button class="cancel-btn" v-if="item.status == 1 || item.status == 2" @click="cancel(item.sxid, item.num)">
+				拍照
+			</button>
+
+			<view class="tag-banner" style="">
+				<view class="tag-banner" v-for="(tag,index) in item.imgname" :key="index" v-if="item.imgname.length>0">
+					<text class="img-banner" v-if="item.imgname[index]!=''&& closeTags[index]"
+						@click="closeTag(index)">{{tag}}</text>
+				</view>
+
+			</view>
+			<view class="my-page">
+				<swiper class="swiper-box my-swiper" :current="0" :indicator-dots="true" v-if="item.urlpdt.length>0">
+					<swiper-item v-for="(url, index) in item.urlpdt" :key="index" @tap="preview(uni.env.USER_DATA_PATH+url)">
+						<view class="swiper-item ">
+							<image class="my-image" :src="uni.env.USER_DATA_PATH+url" mode="aspectFill" />
+						</view>
+						<view v-if="item.imgname.length>0">
+							<text class="demo-view-label">{{ item.imgname?.[index] ?? ''}}</text>
+						</view>
+					</swiper-item>
+				</swiper>
+
+				<swiper class="swiper-box my-swiper mg-top" :current="0" :indicator-dots="true"
+					v-if="item.urlspl.length>0">
+					<swiper-item v-for="(url, index) in item.urlspl" :key="index" @tap="preview(url)">
+						<view class="swiper-item ">
+							<image class="my-image" :src="url" mode="aspectFill" />
+						</view>
+					</swiper-item>
+				</swiper>
+
+				<view v-if="item.urlspl">
+					<text class="demo-view-label">样张</text>
+				</view>
+			</view>
+
+		</view>
+
+		<view class="info-row btn-panel">
+			<button class="btn btn-first" @click="tabsClick(current-1)" v-if="current > 1">
+				前一项
+			</button>
+			<button class="btn btn-second" @click="tabsClick(current+1)" v-if="current < maxcount">
+				下一项
+			</button>
+		</view>
+
+	<!-- #ifdef APP -->
+	</scroll-view>
+	<!-- #endif -->
+</template>
+
+<script setup>
+	import {
+		ref
+	} from 'vue'
+	import { getList, Record, recordStatusDict, updateData } from '@/api/work';
+
+	// 存储页面参数
+	let photoitem = "";
+	let pid = "";
+	let senum = "";
+
+	//自定义返回行为,覆盖系统默认返回按钮
+	const backPressOptions = reactive({
+		from: 'backbutton'
+	} as OnBackPressOptions)
+
+	onBackPress((options : OnBackPressOptions) : boolean | null => {
+		console.log('onBackPress', options)
+		uni.navigateTo({
+			url: `/pages/work/record/InfoDetail?id=${pid}`,
+			// 修改动画方向为从左到右退回
+			animationType: 'slide-in-left', // 使用从左到右滑出的动画效果
+			animationDuration: 300 // 动画持续时间,单位ms
+		})
+		// 返回true表示拦截默认返回行为
+		return true
+	})
+
+	//检查项目最大数量
+	var maxcount = 5
+	var current = ref(1)
+	var records = ref<Record[]>([]);
+	const closeTags = ref<boolean[]>([]);
+	var initRecords = [] as Record[]
+
+	// 定义数据刷新函数
+	const refreshRecords = (index : number) => {
+		// 清空现有数据
+		initRecords = [];
+		closeTags.value = [];
+
+		// #ifdef APP-ANDROID
+		getList('app_media_record', 'photoitem', photoitem, 'pid', pid, null).then((res : UTSJSONObject) => {
+			let dataList = res?.['data'] as UTSJSONObject[] ?? Array<UTSJSONObject>()
+			if (dataList != null && dataList.length > 0) {
+				dataList.forEach(item => {
+					if (item != null) {
+						const imgnameStr = item?.['imgname'] as string ?? ''
+						const urlpdtStr = item?.['urlpdt'] as string ?? ''
+						const urlsplStr = item?.['urlspl'] as string ?? ''
+						const imgnameArr = imgnameStr.indexOf(",") > -1 ? imgnameStr.split(",") : (imgnameStr != '' ? [imgnameStr] : [])
+						const urlpdtArr = urlpdtStr.indexOf(",") > -1 ? urlpdtStr.split(",") : (urlpdtStr != '' ? [urlpdtStr] : [])
+						const urlsplArr = urlsplStr.indexOf(",") > -1 ? urlsplStr.split(",") : (urlsplStr != '' ? [urlsplStr] : [])
+						item['imgname'] = imgnameArr
+						item['urlpdt'] = urlpdtArr
+						item['urlspl'] = urlsplArr
+						let record = JSON.parse<Record>(item.toJSONString());
+						if (record != null) {
+							for (let i : Int = 0; i < record.num; i++) {
+								closeTags.value.push(true)
+							}
+							initRecords.push(record)
+						}
+					}
+				});
+			}
+			if (initRecords.length > 0) {
+				console.log(initRecords)
+				console.log(index)
+				if (index > 0) {
+					current.value = index
+				} else {
+					current.value = initRecords[0].senum
+				}
+				console.log(current.value)
+				records.value = initRecords.filter(item => item['senum'] == current.value)
+				console.log(records)
+			}
+		});
+		// #endif
+	}
+
+
+
+	onLoad((options) => {
+		photoitem = options?.photoitem ?? ""
+		const num = options?.num ?? "1"
+		pid = options?.pid ?? "1"
+		senum = options?.senum ?? "1"
+		maxcount = parseInt(num)
+
+		// 加载初始数据
+		refreshRecords(parseInt(senum));
+	});
+
+
+	// #ifdef H5
+	initRecords = [{
+		sxid: 1,
+		senum: 1,
+		photoitem: '前底-外侧',
+		productno: 'YH0001',
+		part: '角焊缝',
+		descb: '角片角焊缝',
+		date: '2025-06-05',
+		partno: 'TD10-01',
+		num: 2,
+		status: '未执行',
+		urlspl: ['/static/images/demo.png'],
+		imgname: ['1.jpg', '2.jpg'],
+		urlpdt: ['/static/images/demo.png', '/static/images/demo.png']
+	},
+	{
+		sxid: 2,
+		senum: 2,
+		photoitem: '后底-外侧',
+		productno: 'YH0002',
+		part: '角焊缝',
+		descb: '角片角焊缝',
+		date: '2025-06-05',
+		partno: 'TD10-02',
+		num: 3,
+		status: '未执行',
+		urlspl: ['/static/images/demo.png'],
+		imgname: ['1.jpg', '2.jpg', '3.jpg'],
+		urlpdt: ['/static/images/demo.png', '/static/images/demo.png', '/static/images/demo.png']
+	}] as Record[];
+	records.value = initRecords.filter(item => item['senum'] == current.value)
+	// #endif
+
+	const tabsClick = (obj : number) => {
+		current.value = obj
+		records.value = initRecords.filter(item => item['senum'] == current.value)
+	}
+	const closeTag = (index : number) => {
+		let record = records.value[0]
+		// if(record.status==3){
+		// 	uni.showToast({
+		// 	  title: '拍照任务已完成',
+		// 	  icon: 'error', 
+		// 	  duration: 2000 
+		// 	});
+		// 	return;
+		// }
+
+		uni.showModal({
+			title: '系统提示',
+			content: '确认是否删除图片',
+			cancelText: '取消',
+			confirmText: '确定',
+			success: function (res) {
+				if (res.confirm) {
+					closeTags.value[index] = false
+					let imgname = record.imgname.filter((img, i) => i != index)
+					let urlpdt = record.urlpdt.filter((url, i) => i != index)
+					let updatedData = ''
+					if (imgname.length != urlpdt.length) {
+						uni.showToast({
+							title: '图片数据不正确',
+							icon: 'error',
+							duration: 2000
+						});
+						return;
+					}
+					console.log(urlpdt)
+					if (imgname.length == 0 && urlpdt.length == 0) {
+						updatedData = "imgname='',urlpdt=''"
+					} else if (imgname.length == 1 && urlpdt.length == 1) {
+						updatedData = "imgname='" + imgname[0] + "',urlpdt='" + urlpdt[0] + "'"
+					} else {
+						updatedData = "imgname='" + imgname.join(",") + "',urlpdt='" + urlpdt.join(",") + "'"
+					}
+
+					if (imgname.length == 0) {
+						updatedData += ',status=1  '
+					} else if (imgname.length < record.num) {
+						updatedData += ',status=2 '
+					} else if (imgname.length + 1 == record.num){
+						updatedData += ',status=3 '
+					}
+
+					updateData('app_media_record', updatedData, 'sxid', record.sxid.toString()).then((res : UTSJSONObject) => {
+						let dataRes = res?.['data'] as boolean ?? false
+						if (dataRes) {
+							uni.showToast({
+								title: "删除成功!",
+							});
+							// 刷新页面数据
+							refreshRecords(record.senum);
+						}
+					});
+				}
+			}
+		})
+	}
+
+	const preview = (imageUrl : string) => {
+		uni.previewImage({
+			urls: [imageUrl], // 需要预览的图片链接列表
+			current: 0, // 当前显示图片的索引
+			indicator: 'number', // 图片指示器样式
+			loop: false // 是否可循环预览
+		});
+	}
+
+	const cancel = (id : number, num : number) => {
+		uni.navigateTo({
+			url: `/pages/work/record/Camera?id=${id}&num=${num}`
+		})
+	}
+	defineExpose({
+		backPressOptions
+	})
+</script>
+
+<style scoped>
+	.container {
+		padding: 24rpx;
+		background-color: #f0f4f8;
+		flex: 1;
+		display: flex;
+		flex-direction: column;
+		font-family: "PingFang SC", "Helvetica Neue", Helvetica, Arial, sans-serif;
+		/* #ifndef APP-ANDROID */
+		min-height: 100vh;
+		/* #endif */
+	}
+
+	.banner {
+		background: linear-gradient(135deg, #6dd5ed, #2193b0);
+		border-radius: 24rpx;
+		padding: 40rpx 30rpx;
+		margin-bottom: 40rpx;
+		box-shadow: 0 8rpx 16rpx rgba(33, 147, 176, 0.3);
+	}
+
+	.banner-title {
+		color: white;
+		font-size: 36rpx;
+		font-weight: bold;
+		text-align: center;
+	}
+
+	/* 卡片整体 */
+	.record-card {
+		background: #ffffff;
+		border-radius: 20rpx;
+		padding: 24rpx 32rpx;
+		box-shadow: 0 8rpx 15rpx rgba(0, 43, 92, 0.1);
+		display: flex;
+		flex-direction: column;
+		margin-bottom: 15rpx;
+		margin-top: 10rpx;
+	}
+
+	/* 卡片整体 */
+	.record-card2 {
+		background: #ffffff;
+		border-radius: 20rpx;
+		padding: 24rpx 32rpx;
+		display: flex;
+		flex-direction: column;
+		margin-bottom: 20rpx;
+		margin-top: 20rpx;
+	}
+
+	/* 头部:科室 和 状态 */
+	.header-row {
+		display: flex;
+		flex-direction: row;
+		justify-content: space-between;
+		align-items: center;
+	}
+
+	.department {
+		font-size: 32rpx;
+		font-weight: 700;
+		color: #004a99;
+	}
+
+	.status {
+		font-size: 28rpx;
+		color: #1890ff;
+		padding: 6rpx 18rpx;
+		border-radius: 16rpx;
+		background-color: #e6f7ff;
+	}
+
+	.status-cancelled {
+		color: #ff4d4f;
+		background-color: #fff1f0;
+	}
+
+	/* 信息行 */
+	.info-row {
+		display: flex;
+		flex-direction: row;
+		font-size: 28rpx;
+		color: #33475b;
+		align-items: center;
+	}
+
+	.label {
+		color: #102a43;
+		min-width: 100rpx;
+		width: 180rpx;
+		line-height: 1.5;
+	}
+
+	.value {
+		flex: 1;
+		white-space: nowrap;
+		overflow: hidden;
+		text-overflow: ellipsis;
+	}
+
+	.fee {
+		color: #fa541c;
+		font-weight: 700;
+	}
+
+	/* 取消按钮 */
+	.cancel-btn {
+		align-self: flex-end;
+		background-color: #ff4d4f;
+		color: #fff;
+		border: none;
+		border-radius: 32rpx;
+		padding: 5rpx 30rpx;
+		font-size: 28rpx;
+		font-weight: 700;
+	}
+
+	.cancel-btn:hover {
+		background-color: #d9363e;
+	}
+
+	.cancel-btn:active {
+		background-color: #a93232;
+	}
+
+	.swiper {
+		height: 300rpx;
+		margin: 20rpx 0;
+	}
+
+	.swiper-box {
+		height: 500rpx;
+	}
+
+	.swiper-item {
+		/* #ifndef APP-NVUE */
+		display: flex;
+		/* #endif */
+		flex-direction: column;
+		justify-content: center;
+		align-items: center;
+		color: #fff;
+		height: 500rpx;
+		line-height: 300rpx;
+	}
+
+	.my-page {
+		display: flex;
+		flex-direction: column;
+		box-sizing: border-box;
+		background-color: #fff;
+		/* #ifndef APP-ANDROID */
+		min-height: 100%;
+		/* #endif */
+		height: 100%;
+	}
+
+	.flex-row {
+		flex-direction: row;
+		flex-wrap: nowrap;
+		width: auto;
+		min-width: 100%;
+		/* 确保容器宽度至少为屏幕宽度 */
+	}
+
+	.demo-view-label {
+		text-align: center;
+		color: #102a43;
+		line-height: 1.5;
+		margin-top: 5rpx;
+	}
+
+	.tag-circle {
+		width: 60rpx;
+		height: 60rpx;
+		margin: 0 10rpx;
+		display: flex;
+		justify-content: center;
+		align-items: center;
+		flex-shrink: 0;
+	}
+
+	.circle {
+		height: 50rpx;
+		width: 50rpx;
+		background-color: #004a99;
+		text-align: center;
+		color: #fff;
+		line-height: 50rpx;
+		border-radius: 50rpx;
+	}
+
+	.checked-tag {
+		height: 60rpx;
+		width: 60rpx;
+		line-height: 60rpx;
+		border: 2rpx solid #ffffff;
+		box-shadow: 0 0 0 2rpx #007aff;
+		position: relative;
+		z-index: 10;
+	}
+
+	.bg-green {
+		background-color: seagreen;
+	}
+
+	.bg-yellow {
+		background-color: yellow;
+	}
+
+	.bg-black {
+		background-color: #102a43;
+	}
+
+	.bg-red {
+		background-color: red;
+	}
+
+	.btn-panel {
+		position: relative;
+		width: 100%;
+		height: 90rpx;
+		overflow: visible;
+	}
+
+	.btn {
+		position: absolute;
+		height: 70rpx;
+		line-height: 70rpx;
+		padding: 0 20rpx;
+		top: 50%;
+		transform: translateY(-50%);
+		background-color: #00aaff;
+		color: #fff;
+		border: 0 none;
+		border-radius: 25rpx;
+	}
+
+	.btn-first {
+		left: 15rpx;
+	}
+
+	.btn-second {
+		right: 15rpx;
+	}
+
+	/* 安卓兼容的滚动容器样式 */
+	.tag-scroll-container {
+		width: 100%;
+		overflow-x: auto;
+		overflow-y: hidden;
+		-webkit-overflow-scrolling: touch;
+		box-sizing: border-box;
+		padding: 10rpx 15rpx;
+		white-space: nowrap;
+		display: flex;
+		flex-direction: row;
+	}
+
+
+	.tag-scroll-container::-webkit-scrollbar-thumb {
+		background-color: rgba(0, 0, 0, 0.2) !important;
+		border-radius: 3rpx !important;
+	}
+
+	.img-banner {
+		height: 50rpx;
+		width: 100%;
+		background-color: #004a99;
+		text-align: center;
+		color: #fff;
+		line-height: 50rpx;
+		border-radius: 10rpx;
+		margin-left: 2rpx;
+		font-size: 12px;
+		padding: 0 10rpx;
+	}
+
+	.tag-banner {
+		flex-direction: column;
+		flex-wrap: wrap;
+		margin: 4px 0;
+		font-size: 12px;
+	}
+
+	.mg-top {
+		margin-top: 20rpx;
+	}
+</style>