qaz преди 3 дни
родител
ревизия
18e1b933a4

+ 1 - 1
.env.development

@@ -5,7 +5,7 @@ ENV = 'development'
 #线下:http://192.168.100.187:8083
 # 本地环境接口地址 121.36.251.245
 
-VITE_API_URL = 'http://1.94.168.85:8086'
+VITE_API_URL = 'http://192.168.100.101:8086'
 # VITE_API_URL = 'http://192.168.100.187:9084'
 # VITE_API_URL = 'https://backend.qicai321.com'
 VITE_API_WX_URL='https://api.weixin.qq.com/'

+ 67 - 5
package-lock.json

@@ -1561,6 +1561,7 @@
       "cpu": [
         "ppc64"
       ],
+      "dev": true,
       "license": "MIT",
       "optional": true,
       "os": [
@@ -1577,6 +1578,7 @@
       "cpu": [
         "arm"
       ],
+      "dev": true,
       "license": "MIT",
       "optional": true,
       "os": [
@@ -1593,6 +1595,7 @@
       "cpu": [
         "arm64"
       ],
+      "dev": true,
       "license": "MIT",
       "optional": true,
       "os": [
@@ -1609,6 +1612,7 @@
       "cpu": [
         "x64"
       ],
+      "dev": true,
       "license": "MIT",
       "optional": true,
       "os": [
@@ -1625,6 +1629,7 @@
       "cpu": [
         "arm64"
       ],
+      "dev": true,
       "license": "MIT",
       "optional": true,
       "os": [
@@ -1641,6 +1646,7 @@
       "cpu": [
         "x64"
       ],
+      "dev": true,
       "license": "MIT",
       "optional": true,
       "os": [
@@ -1657,6 +1663,7 @@
       "cpu": [
         "arm64"
       ],
+      "dev": true,
       "license": "MIT",
       "optional": true,
       "os": [
@@ -1673,6 +1680,7 @@
       "cpu": [
         "x64"
       ],
+      "dev": true,
       "license": "MIT",
       "optional": true,
       "os": [
@@ -1689,6 +1697,7 @@
       "cpu": [
         "arm"
       ],
+      "dev": true,
       "license": "MIT",
       "optional": true,
       "os": [
@@ -1705,6 +1714,7 @@
       "cpu": [
         "arm64"
       ],
+      "dev": true,
       "license": "MIT",
       "optional": true,
       "os": [
@@ -1721,6 +1731,7 @@
       "cpu": [
         "ia32"
       ],
+      "dev": true,
       "license": "MIT",
       "optional": true,
       "os": [
@@ -1737,6 +1748,7 @@
       "cpu": [
         "loong64"
       ],
+      "dev": true,
       "license": "MIT",
       "optional": true,
       "os": [
@@ -1753,6 +1765,7 @@
       "cpu": [
         "mips64el"
       ],
+      "dev": true,
       "license": "MIT",
       "optional": true,
       "os": [
@@ -1769,6 +1782,7 @@
       "cpu": [
         "ppc64"
       ],
+      "dev": true,
       "license": "MIT",
       "optional": true,
       "os": [
@@ -1785,6 +1799,7 @@
       "cpu": [
         "riscv64"
       ],
+      "dev": true,
       "license": "MIT",
       "optional": true,
       "os": [
@@ -1801,6 +1816,7 @@
       "cpu": [
         "s390x"
       ],
+      "dev": true,
       "license": "MIT",
       "optional": true,
       "os": [
@@ -1817,6 +1833,7 @@
       "cpu": [
         "x64"
       ],
+      "dev": true,
       "license": "MIT",
       "optional": true,
       "os": [
@@ -1833,6 +1850,7 @@
       "cpu": [
         "x64"
       ],
+      "dev": true,
       "license": "MIT",
       "optional": true,
       "os": [
@@ -1849,6 +1867,7 @@
       "cpu": [
         "x64"
       ],
+      "dev": true,
       "license": "MIT",
       "optional": true,
       "os": [
@@ -1865,6 +1884,7 @@
       "cpu": [
         "x64"
       ],
+      "dev": true,
       "license": "MIT",
       "optional": true,
       "os": [
@@ -1881,6 +1901,7 @@
       "cpu": [
         "arm64"
       ],
+      "dev": true,
       "license": "MIT",
       "optional": true,
       "os": [
@@ -1897,6 +1918,7 @@
       "cpu": [
         "ia32"
       ],
+      "dev": true,
       "license": "MIT",
       "optional": true,
       "os": [
@@ -1913,6 +1935,7 @@
       "cpu": [
         "x64"
       ],
+      "dev": true,
       "license": "MIT",
       "optional": true,
       "os": [
@@ -2614,6 +2637,7 @@
       "version": "2.5.1",
       "resolved": "https://registry.npmmirror.com/@parcel/watcher/-/watcher-2.5.1.tgz",
       "integrity": "sha512-dfUnCxiN9H4ap84DvD2ubjw+3vUNpstxa0TneY/Paat8a3R4uQZDLSvWjmznAY/DoahqTHl9V46HF/Zs3F29pg==",
+      "dev": true,
       "hasInstallScript": true,
       "license": "MIT",
       "optional": true,
@@ -2653,6 +2677,7 @@
       "cpu": [
         "arm64"
       ],
+      "dev": true,
       "license": "MIT",
       "optional": true,
       "os": [
@@ -2673,6 +2698,7 @@
       "cpu": [
         "arm64"
       ],
+      "dev": true,
       "license": "MIT",
       "optional": true,
       "os": [
@@ -2693,6 +2719,7 @@
       "cpu": [
         "x64"
       ],
+      "dev": true,
       "license": "MIT",
       "optional": true,
       "os": [
@@ -2713,6 +2740,7 @@
       "cpu": [
         "x64"
       ],
+      "dev": true,
       "license": "MIT",
       "optional": true,
       "os": [
@@ -2733,6 +2761,7 @@
       "cpu": [
         "arm"
       ],
+      "dev": true,
       "license": "MIT",
       "optional": true,
       "os": [
@@ -2753,6 +2782,7 @@
       "cpu": [
         "arm"
       ],
+      "dev": true,
       "license": "MIT",
       "optional": true,
       "os": [
@@ -2773,6 +2803,7 @@
       "cpu": [
         "arm64"
       ],
+      "dev": true,
       "license": "MIT",
       "optional": true,
       "os": [
@@ -2793,6 +2824,7 @@
       "cpu": [
         "arm64"
       ],
+      "dev": true,
       "license": "MIT",
       "optional": true,
       "os": [
@@ -2813,6 +2845,7 @@
       "cpu": [
         "x64"
       ],
+      "dev": true,
       "license": "MIT",
       "optional": true,
       "os": [
@@ -2833,6 +2866,7 @@
       "cpu": [
         "x64"
       ],
+      "dev": true,
       "license": "MIT",
       "optional": true,
       "os": [
@@ -2853,6 +2887,7 @@
       "cpu": [
         "arm64"
       ],
+      "dev": true,
       "license": "MIT",
       "optional": true,
       "os": [
@@ -2873,6 +2908,7 @@
       "cpu": [
         "ia32"
       ],
+      "dev": true,
       "license": "MIT",
       "optional": true,
       "os": [
@@ -2893,6 +2929,7 @@
       "cpu": [
         "x64"
       ],
+      "dev": true,
       "license": "MIT",
       "optional": true,
       "os": [
@@ -2991,6 +3028,7 @@
       "cpu": [
         "arm"
       ],
+      "dev": true,
       "license": "MIT",
       "optional": true,
       "os": [
@@ -3004,6 +3042,7 @@
       "cpu": [
         "arm64"
       ],
+      "dev": true,
       "license": "MIT",
       "optional": true,
       "os": [
@@ -3017,6 +3056,7 @@
       "cpu": [
         "arm64"
       ],
+      "dev": true,
       "license": "MIT",
       "optional": true,
       "os": [
@@ -3030,6 +3070,7 @@
       "cpu": [
         "x64"
       ],
+      "dev": true,
       "license": "MIT",
       "optional": true,
       "os": [
@@ -3043,6 +3084,7 @@
       "cpu": [
         "arm64"
       ],
+      "dev": true,
       "license": "MIT",
       "optional": true,
       "os": [
@@ -3056,6 +3098,7 @@
       "cpu": [
         "x64"
       ],
+      "dev": true,
       "license": "MIT",
       "optional": true,
       "os": [
@@ -3069,6 +3112,7 @@
       "cpu": [
         "arm"
       ],
+      "dev": true,
       "license": "MIT",
       "optional": true,
       "os": [
@@ -3082,6 +3126,7 @@
       "cpu": [
         "arm"
       ],
+      "dev": true,
       "license": "MIT",
       "optional": true,
       "os": [
@@ -3095,6 +3140,7 @@
       "cpu": [
         "arm64"
       ],
+      "dev": true,
       "license": "MIT",
       "optional": true,
       "os": [
@@ -3108,6 +3154,7 @@
       "cpu": [
         "arm64"
       ],
+      "dev": true,
       "license": "MIT",
       "optional": true,
       "os": [
@@ -3121,6 +3168,7 @@
       "cpu": [
         "loong64"
       ],
+      "dev": true,
       "license": "MIT",
       "optional": true,
       "os": [
@@ -3134,6 +3182,7 @@
       "cpu": [
         "ppc64"
       ],
+      "dev": true,
       "license": "MIT",
       "optional": true,
       "os": [
@@ -3147,6 +3196,7 @@
       "cpu": [
         "riscv64"
       ],
+      "dev": true,
       "license": "MIT",
       "optional": true,
       "os": [
@@ -3160,6 +3210,7 @@
       "cpu": [
         "riscv64"
       ],
+      "dev": true,
       "license": "MIT",
       "optional": true,
       "os": [
@@ -3173,6 +3224,7 @@
       "cpu": [
         "s390x"
       ],
+      "dev": true,
       "license": "MIT",
       "optional": true,
       "os": [
@@ -3186,6 +3238,7 @@
       "cpu": [
         "x64"
       ],
+      "dev": true,
       "license": "MIT",
       "optional": true,
       "os": [
@@ -3199,6 +3252,7 @@
       "cpu": [
         "x64"
       ],
+      "dev": true,
       "license": "MIT",
       "optional": true,
       "os": [
@@ -3212,6 +3266,7 @@
       "cpu": [
         "arm64"
       ],
+      "dev": true,
       "license": "MIT",
       "optional": true,
       "os": [
@@ -3225,6 +3280,7 @@
       "cpu": [
         "ia32"
       ],
+      "dev": true,
       "license": "MIT",
       "optional": true,
       "os": [
@@ -3238,6 +3294,7 @@
       "cpu": [
         "x64"
       ],
+      "dev": true,
       "license": "MIT",
       "optional": true,
       "os": [
@@ -5984,6 +6041,7 @@
       "version": "1.0.3",
       "resolved": "https://registry.npmmirror.com/detect-libc/-/detect-libc-1.0.3.tgz",
       "integrity": "sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg==",
+      "dev": true,
       "license": "Apache-2.0",
       "optional": true,
       "bin": {
@@ -6379,6 +6437,7 @@
       "version": "0.21.5",
       "resolved": "https://registry.npmmirror.com/esbuild/-/esbuild-0.21.5.tgz",
       "integrity": "sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==",
+      "dev": true,
       "hasInstallScript": true,
       "license": "MIT",
       "bin": {
@@ -7467,7 +7526,7 @@
       "version": "5.1.3",
       "resolved": "https://registry.npmmirror.com/immutable/-/immutable-5.1.3.tgz",
       "integrity": "sha512-+chQdDfvscSF1SJqv2gn4SRO2ZyS3xL3r7IW/wWEEzrzLisnOlKiQu5ytC/BVNcS15C39WT2Hg/bjKjDMcu+zg==",
-      "devOptional": true,
+      "dev": true,
       "license": "MIT"
     },
     "node_modules/import-fresh": {
@@ -8590,6 +8649,7 @@
       "version": "7.1.1",
       "resolved": "https://registry.npmmirror.com/node-addon-api/-/node-addon-api-7.1.1.tgz",
       "integrity": "sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ==",
+      "dev": true,
       "license": "MIT",
       "optional": true
     },
@@ -9670,6 +9730,7 @@
       "version": "4.44.2",
       "resolved": "https://registry.npmmirror.com/rollup/-/rollup-4.44.2.tgz",
       "integrity": "sha512-PVoapzTwSEcelaWGth3uR66u7ZRo6qhPHc0f2uRO9fX6XDVNrIiGYS0Pj9+R8yIIYSD/mCx2b16Ws9itljKSPg==",
+      "dev": true,
       "license": "MIT",
       "dependencies": {
         "@types/estree": "1.0.8"
@@ -9758,7 +9819,7 @@
       "version": "1.89.2",
       "resolved": "https://registry.npmmirror.com/sass/-/sass-1.89.2.tgz",
       "integrity": "sha512-xCmtksBKd/jdJ9Bt9p7nPKiuqrlBMBuuGkQlkhZjjQk3Ty48lv93k5Dq6OPkKt4XwxDJ7tvlfrTa1MPA9bf+QA==",
-      "devOptional": true,
+      "dev": true,
       "license": "MIT",
       "dependencies": {
         "chokidar": "^4.0.0",
@@ -9779,7 +9840,7 @@
       "version": "4.0.3",
       "resolved": "https://registry.npmmirror.com/chokidar/-/chokidar-4.0.3.tgz",
       "integrity": "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==",
-      "devOptional": true,
+      "dev": true,
       "license": "MIT",
       "dependencies": {
         "readdirp": "^4.0.1"
@@ -9795,7 +9856,7 @@
       "version": "4.1.2",
       "resolved": "https://registry.npmmirror.com/readdirp/-/readdirp-4.1.2.tgz",
       "integrity": "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==",
-      "devOptional": true,
+      "dev": true,
       "license": "MIT",
       "engines": {
         "node": ">= 14.18.0"
@@ -10648,7 +10709,7 @@
       "version": "4.9.5",
       "resolved": "https://registry.npmmirror.com/typescript/-/typescript-4.9.5.tgz",
       "integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==",
-      "devOptional": true,
+      "dev": true,
       "license": "Apache-2.0",
       "bin": {
         "tsc": "bin/tsc",
@@ -10958,6 +11019,7 @@
       "version": "5.4.19",
       "resolved": "https://registry.npmmirror.com/vite/-/vite-5.4.19.tgz",
       "integrity": "sha512-qO3aKv3HoQC8QKiNSTuUM1l9o/XX3+c+VTgLHbJWHZGeTPVAg2XwazI9UWzoxjIJCGCV2zU60uqMzjeLZuULqA==",
+      "dev": true,
       "license": "MIT",
       "dependencies": {
         "esbuild": "^0.21.3",

+ 43 - 14
src/views/system/borrow/component/CollectEquipment/AbnormalDialog/index.vue

@@ -18,17 +18,20 @@
       <el-form-item label="照片">
         <el-upload
           class="upload-demo"
-          action="#"
-          :auto-upload="false"
-          :on-change="handleChange"
+          :action="action"
+          :headers="{ Authorization: 'JWT ' + Session.get('token') }"
+          :on-success="handleUploadSuccess"
+          :on-error="handleUploadError"
+          :before-upload="beforeUpload"
           :file-list="fileList"
           list-type="picture"
           multiple
+          :on-remove="handleRemove"
         >
           <el-button type="primary">选择图片</el-button>
           <template #tip>
             <div class="el-upload__tip">
-              只能上传jpg/png文件
+              只能上传jpg/png文件,且不超过5MB
             </div>
           </template>
         </el-upload>
@@ -45,6 +48,9 @@
 
 <script setup lang="ts">
 import { ref, watch } from 'vue';
+import { ElMessage } from 'element-plus';
+import request from '@/utils/request';
+import { Session } from '/@/utils/storage';
 
 const props = defineProps<{
   visible: boolean;
@@ -53,6 +59,7 @@ const props = defineProps<{
 const emit = defineEmits(['update:visible', 'confirm']);
 
 const dialogVisible = ref(props.visible);
+const action = ref(`${import.meta.env.VITE_API_URL}/api/system/upload/`);
 
 // 监听 props.visible 的变化
 watch(() => props.visible, (newVal) => {
@@ -74,16 +81,38 @@ const form = ref({
   }>
 });
 
-const handleChange = (file: any) => {
-  // 将文件转换为Base64
-  const reader = new FileReader();
-  reader.readAsDataURL(file.raw);
-  reader.onload = () => {
-    form.value.photos.push({
-      filename: file.name,
-      data: reader.result?.toString().split(',')[1] || ''
-    });
-  };
+const beforeUpload = (file: File) => {
+  const isJPGOrPNG = file.type === 'image/jpeg' || file.type === 'image/png';
+  if (!isJPGOrPNG) {
+    ElMessage.error('只能上传JPG/PNG格式的图片!');
+    return false;
+  }
+  const isLt5M = file.size / 1024 / 1024 < 5;
+  if (!isLt5M) {
+    ElMessage.error('图片大小不能超过5MB!');
+    return false;
+  }
+  return true;
+};
+
+const handleUploadSuccess = (response: any, file: any) => {
+  if (response.code === 2000) {
+    form.value.photos.push(response.data.url);
+    ElMessage.success('上传成功');
+  } else {
+    ElMessage.error(response.msg || '上传失败');
+  }
+};
+
+const handleUploadError = (error: any) => {
+  ElMessage.error('上传失败:' + (error.message || '未知错误'));
+};
+
+const handleRemove = (file: any) => {
+  const index = form.value.photos.findIndex(photo => photo.filename === file.name);
+  if (index !== -1) {
+    form.value.photos.splice(index, 1);
+  }
 };
 
 const onCancel = () => {

+ 11 - 4
src/views/system/borrow/component/CollectEquipment/SelectDeviceDialog/index.vue

@@ -32,7 +32,10 @@ import * as deviceApi from '../../../../device/api';
 import * as storeapi from '../../../../storelist/api';
 import { status } from 'nprogress';
 
-const props = defineProps<{ visible: boolean }>();
+const props = defineProps<{ 
+    visible: boolean;
+    deviceIds?: (string | number)[];
+}>();
 const emit = defineEmits(['update:visible', 'confirm']);
 
 const visible = ref(props.visible);
@@ -67,12 +70,16 @@ async function fetchData(resetPage = false) {
 	await fetchWarehouseMap(); 
 	deviceApi.GetList({ page: page.value, limit: pageSize.value, code: search.value,status:1 })
 	.then((res) => {
-		const devices = res.data
-		/* .filter(device => device.available_quantity > 0) */
-		.map((device) => ({
+		let devices = res.data.map((device) => ({
             ...device,
             warehouse: `${warehouseMap.value[device.warehouse] || `ID:${device.warehouse}`} (${device.available_quantity})`
         }));
+        
+        // 如果有deviceIds,只显示指定的设备
+        if (props.deviceIds && props.deviceIds.length > 0) {
+            devices = devices.filter(device => props.deviceIds?.includes(device.id));
+        }
+        
 		tableData.value = devices;
 		// tableData.value = [...res.data];
 		total.value = res.total;

+ 385 - 78
src/views/system/borrow/component/CollectEquipment/SettlementDialog.vue

@@ -10,66 +10,85 @@
         <img src="../../../../../assets/u2855.svg" alt="">
         <span>已领取</span>
     </div> -->
-    <el-form :model="formData" label-width="110px" label-position="top">
-      <el-row :gutter="16">
-        <el-col :span="8">
-          <el-form-item label="借用单编号">
-            <el-input v-model="formData.application_no" disabled />
-          </el-form-item>
-        </el-col>
-        <el-col :span="8">
-          <el-form-item label="借用人">
-            <el-input v-model="name" disabled />
-          </el-form-item>
-        </el-col>
-        <el-col :span="8">
-          <el-form-item label="学号/工号">
-            <el-input v-model="userCode" disabled />
-          </el-form-item>
-        </el-col>
-        <el-col :span="8">
-          <el-form-item label="借用性质">
-            <el-input v-model="borrowType" disabled />
-          </el-form-item>
-        </el-col>
-        <el-col :span="8">
-          <el-form-item label="借出时间">
-            <el-input v-model="formData.expected_start_time" disabled />
-          </el-form-item>
-        </el-col>
-        <el-col :span="8">
-          <el-form-item label="预计归还时间">
-            <el-input v-model="formData.expected_end_time" disabled />
-          </el-form-item>
-        </el-col>
-      </el-row>
-
-      <div style="margin: 16px 0 8px 0; font-weight: bold">借用明细表</div>
-      <el-table :data="filteredItems" border style="width: 100%">
-        <el-table-column type="index" label="序号" width="60" align="center" />
-        <el-table-column prop="device_code" label="设备编号" align="center" />
-        <el-table-column prop="device_category_name" label="设备分类" align="center" />
-        <el-table-column prop="device_name" label="设备名称" align="center" />
-        <el-table-column prop="quantity" label="借用数量" align="center" />
-        <el-table-column prop="device_specification" label="规格型号" align="center" />
-        <el-table-column prop="device_storage_location" label="存放位置" align="center">
-          <template #default="scope">
-            {{ scope.row.device_storage_location || '-' }}
-          </template>
-        </el-table-column>
-        <el-table-column prop="remark" label="备注" align="center">
-          <template #default="scope">
-            {{ scope.row.remark || '-' }}
-          </template>
-        </el-table-column>
-      </el-table>
-
-      <div style="margin: 16px 0 8px 0; font-weight: bold">配件信息</div>
-      <el-input v-model="formData.accessories" disabled />
-
-      <div style="margin: 16px 0 8px 0; font-weight: bold">备注</div>
-      <el-input v-model="formData.remark" type="textarea" disabled />
-    </el-form>
+    <div ref="printContent" class="print-container">
+      <el-form :model="formData" label-width="110px" label-position="top" class="print-form">
+        <el-row :gutter="16">
+          <el-col :span="8">
+            <el-form-item label="借用单编号">
+              <div class="form-content">{{ formData.application_no }}</div>
+            </el-form-item>
+          </el-col>
+          <el-col :span="8">
+            <el-form-item label="借用人">
+              <div class="form-content">{{ name }}</div>
+            </el-form-item>
+          </el-col>
+          <el-col :span="8">
+            <el-form-item label="学号/工号">
+              <div class="form-content">{{ userCode }}</div>
+            </el-form-item>
+          </el-col>
+        </el-row>
+        <el-row :gutter="16">
+          <el-col :span="8">
+            <el-form-item label="借用性质">
+              <div class="form-content">{{ borrowType }}</div>
+            </el-form-item>
+          </el-col>
+          <el-col :span="8">
+            <el-form-item label="借出时间">
+              <div class="form-content">{{ formData.expected_start_time }}</div>
+            </el-form-item>
+          </el-col>
+          <el-col :span="8">
+            <el-form-item label="预计归还时间">
+              <div class="form-content">{{ formData.expected_end_time }}</div>
+            </el-form-item>
+          </el-col>
+        </el-row>
+
+        <div class="detail-title">借用明细表</div>
+        <div class="table-container">
+          <table class="detail-table">
+            <thead>
+              <tr>
+                <th width="60">序号</th>
+                <th>设备编号</th>
+                <th>设备分类</th>
+                <th>设备名称</th>
+                <th>借用数量</th>
+                <th>规格型号</th>
+                <th>存放位置</th>
+                <th>备注</th>
+              </tr>
+            </thead>
+            <tbody>
+              <tr v-for="(item, index) in filteredItems" :key="index">
+                <td>{{ index + 1 }}</td>
+                <td>{{ item.device_code }}</td>
+                <td>{{ item.device_category_name }}</td>
+                <td>{{ item.device_name }}</td>
+                <td>{{ item.quantity }}</td>
+                <td>{{ item.device_specification }}</td>
+                <td>{{ item.device_storage_location || '-' }}</td>
+                <td>{{ item.remark || '-' }}</td>
+              </tr>
+            </tbody>
+          </table>
+        </div>
+
+        <div class="accessories-info">
+          <div class="detail-title">配件信息</div>
+          <div class="form-content">{{ formData.accessories || '-' }}</div>
+        </div>
+
+        <div class="remark-info">
+          <div class="detail-title">备注</div>
+          <div class="form-content">{{ formData.remark || '-' }}</div>
+        </div>
+      </el-form>
+    </div>
+
    
 
     <template #footer>
@@ -81,6 +100,7 @@
 
 <script setup lang="ts">
 import { ref, defineProps, defineEmits, watch, computed } from 'vue';
+import { ElMessage } from 'element-plus';
 
 const props = defineProps<{
   visible: boolean;
@@ -146,8 +166,203 @@ const handleClose = () => {
   emit('update:modelValue', formData.value);
 };
 
-const handlePrint = () => {
+/* const handlePrint = () => {
   window.print();
+}; */
+// 定义打印区域的ref
+const printContent = ref<HTMLElement | null>(null);
+
+const handlePrint = () => {
+  try {
+    if (!printContent.value) {
+      ElMessage.error('打印区域未找到');
+      return;
+    }
+
+    // 1. 克隆打印区域内容
+    const printElement = printContent.value.cloneNode(true);
+    
+    // 2. 创建打印专用iframe
+    const iframe = document.createElement('iframe');
+    iframe.style.position = 'absolute';
+    iframe.style.width = '0px';
+    iframe.style.height = '0px';
+    iframe.style.left = '-9999px';
+    document.body.appendChild(iframe);
+
+    // 确保iframe和其document已经准备好
+    if (!iframe.contentWindow || !iframe.contentWindow.document) {
+      throw new Error('iframe初始化失败');
+    }
+
+    const printDocument = iframe.contentWindow.document;
+    
+    // 3. 添加打印样式
+    printDocument.write(`
+      <!DOCTYPE html>
+      <html>
+        <head>
+          <meta charset="utf-8">
+          <title>设备借用单打印</title>
+          <style>
+                          /* 打印样式 */
+              @media print {
+                body {
+                  font-family: Arial, sans-serif;
+                  padding: 20px;
+                  margin: 0;
+                }
+                .no-print {
+                  display: none !important;
+                }
+                /* 表单布局优化 */
+                .el-form {
+                  width: 100%;
+                }
+                .el-row {
+                  display: flex !important;
+                  flex-wrap: nowrap !important;
+                  margin: 0 -8px;
+                }
+                .el-col {
+                  padding: 0 8px;
+                  flex: 1;
+                }
+                /* 表单项样式 */
+                .el-form-item {
+                  margin-bottom: 12px;
+                  page-break-inside: avoid;
+                }
+                .el-form-item__label {
+                  font-weight: bold;
+                  margin-bottom: 4px;
+                  display: block;
+                }
+                .el-form-item__content {
+                  line-height: 1.5;
+                }
+                /* 表格样式优化 */
+                table {
+                  page-break-inside: auto;
+                  width: 100% !important;
+                  border-collapse: collapse;
+                  margin: 20px 0;
+                  table-layout: fixed;
+                }
+                tr {
+                  page-break-inside: avoid;
+                  page-break-after: auto;
+                }
+                th, td {
+                  border: 1px solid #000;
+                  padding: 8px;
+                  text-align: center;
+                  word-break: break-all;
+                }
+                /* 隐藏Element Plus的默认样式 */
+                .el-input__inner {
+                  border: none !important;
+                  padding: 0 !important;
+                }
+                .el-form--label-top .el-form-item__label {
+                  padding: 0;
+                }
+                /* 标题样式 */
+                h2 {
+                  text-align: center;
+                  margin-bottom: 30px;
+                  font-size: 24px;
+                }
+                /* 明细表标题 */
+                .detail-title {
+                  font-weight: bold;
+                  margin: 20px 0 10px;
+                  font-size: 16px;
+                }
+                /* 配件信息和备注 */
+                .accessories-info,
+                .remark-info {
+                  margin-top: 20px;
+                }
+                .accessories-info .el-input,
+                .remark-info .el-input {
+                  width: 100%;
+                }
+            }
+            /* 屏幕预览样式 */
+            @media screen {
+              body {
+                background-color: #fff;
+                padding: 20px;
+              }
+            }
+          </style>
+        </head>
+        <body>
+          <h2 style="text-align: center; margin-bottom: 30px;">设备借用单</h2>
+        </body>
+      </html>
+    `);
+    
+    // 4. 插入内容并添加打印类
+    const body = printDocument.body;
+    body.appendChild(printElement);
+    
+    // 5. 添加打印按钮(仅屏幕显示)
+    const printBtn = printDocument.createElement('button');
+    printBtn.className = 'no-print';
+    printBtn.textContent = '打印';
+    printBtn.style.cssText = `
+      position: fixed;
+      top: 20px;
+      right: 20px;
+      padding: 10px 20px;
+      background: #409EFF;
+      color: white;
+      border: none;
+      border-radius: 4px;
+      cursor: pointer;
+      z-index: 9999;
+    `;
+    printBtn.onclick = () => {
+      try {
+        if (iframe.contentWindow) {
+          iframe.contentWindow.print();
+        } else {
+          throw new Error('打印窗口未准备好');
+        }
+      } catch (error) {
+        console.error('打印过程出错:', error);
+        ElMessage.error('打印失败,请重试');
+      }
+    };
+    body.appendChild(printBtn);
+    
+    // 6. 自动触发打印
+    if (iframe.contentWindow) {
+      iframe.contentWindow.focus();
+      setTimeout(() => {
+        try {
+          if (iframe.contentWindow) {
+            iframe.contentWindow.print();
+          } else {
+            throw new Error('打印窗口未准备好');
+          }
+        } catch (error) {
+          console.error('打印过程出错:', error);
+          ElMessage.error('打印失败,请重试');
+        } finally {
+          // 确保iframe被移除
+          document.body.removeChild(iframe);
+        }
+      }, 500);
+    } else {
+      throw new Error('打印窗口未准备好');
+    }
+  } catch (error) {
+    console.error('打印准备过程出错:', error);
+    ElMessage.error('打印准备失败,请重试');
+  }
 };
 </script>
 
@@ -157,25 +372,117 @@ const handlePrint = () => {
     display: none;
   }
 }
-.title{
-    display: flex;
-    justify-content: flex-end;
-    position: relative;
 
+.print-container {
+  padding: 20px;
+}
+
+.print-form {
+  width: 100%;
+}
+
+.form-content {
+  min-height: 20px;
+  line-height: 20px;
+  padding: 4px 0;
+}
+
+.detail-title {
+  font-weight: bold;
+  margin: 20px 0 10px;
+  font-size: 16px;
+}
+
+.table-container {
+  margin: 20px 0;
+  width: 100%;
+  overflow-x: auto;
+}
+
+.detail-table {
+  width: 100%;
+  border-collapse: collapse;
+  table-layout: fixed;
+}
+
+.detail-table th,
+.detail-table td {
+  border: 1px solid #000;
+  padding: 8px;
+  text-align: center;
+  word-break: break-all;
+}
+
+.detail-table th {
+  background-color: #f5f7fa;
+  font-weight: bold;
 }
-.title span{
-    position: absolute;
-    right:10px ;
-    bottom: 30%;
-    align-self: flex-start;
-    padding: 0px 0px 0px 0px;
-    box-sizing: border-box;
-    transform: rotate(315deg);
-    font-family: "Impact Bold", "Impact Normal", "Impact", sans-serif;
-    font-weight: 700;
-    font-style: normal;
-    font-size: 17px;
-    color: #F77105;
+
+.accessories-info,
+.remark-info {
+  margin-top: 20px;
 }
 
+.form-content {
+  /* border: 1px solid #dcdfe6; */
+  padding: 8px;
+  min-height: 32px;
+  line-height: 1.5;
+  border-radius: 4px;
+}
+
+@media print {
+  .print-container {
+    padding: 0;
+  }
+
+  .form-content {
+    border: none;
+    padding: 4px 0;
+  }
+
+  .el-form-item {
+    margin-bottom: 16px !important;
+  }
+
+  .el-form-item__label {
+    color: #000 !important;
+    line-height: 1.5 !important;
+  }
+
+  .detail-table th {
+    background-color: #fff !important;
+  }
+
+  /* 确保分页时表头重复 */
+  thead {
+    display: table-header-group;
+  }
+
+  /* 避免元素被分页截断 */
+  tr, .el-form-item, .accessories-info, .remark-info {
+    page-break-inside: avoid;
+  }
+}
+
+.title {
+  display: flex;
+  justify-content: flex-end;
+  position: relative;
+}
+
+.title span {
+  position: absolute;
+  right: 10px;
+  bottom: 30%;
+  align-self: flex-start;
+  padding: 0;
+  box-sizing: border-box;
+  transform: rotate(315deg);
+  font-family: "Impact Bold", "Impact Normal", "Impact", sans-serif;
+  font-weight: 700;
+  font-style: normal;
+  font-size: 17px;
+  color: #F77105;
+}
 </style> 

+ 3 - 3
src/views/system/borrow/component/CollectEquipment/ViewAbnormalDialog/index.vue

@@ -12,13 +12,13 @@
           {{ abnormalData?.condition || '暂无异常说明' }}
         </div>
       </el-form-item>
-      <el-form-item label="照片" v-if="abnormalData?.photos?.length">
+      <el-form-item label="照片" v-if="abnormalData.photos.length">
         <el-image
           v-for="(photo, index) in abnormalData.photos"
           :key="index"
           style="width: 100px; height: 100px; margin-right: 10px;"
-          :src="'data:image/jpeg;base64,' + photo.data"
-          :preview-src-list="getPhotoUrls()"
+          :src="photo"
+         
           fit="cover"
         />
       </el-form-item>

+ 59 - 25
src/views/system/borrow/component/CollectEquipment/index.vue

@@ -241,42 +241,51 @@
             <el-form :model="form" label-width="110px">
                 <el-row :gutter="16">
                     <el-col :span="24">
-                        <div style="margin: 8px 0">
+                        <div style="margin: 8px 0" v-if="!isView" >
                             <el-input :disabled="isView" v-model="returnSearchText" placeholder="请扫描设备条码添加" style="width: 300px" @keyup.enter="handleReturnScanSearch" />
                             <el-button type="primary" style="margin-left: 16px" @click="handleAdd" :disabled="isView">手动归还</el-button>
                         </div>
-                        <el-table :data="returnDeviceList" border style="width: 100%" @selection-change="handleSelectionChange">
-                            <el-table-column type="selection" width="55" align="center" />
+                        <el-table :data="returnDeviceList" border style="width: 100%" >
+                            <!-- <el-table-column type="selection" width="55" align="center" />@selection-change="handleSelectionChange" -->
                             <el-table-column type="index" label="序号" width="60" align="center" />
                             <el-table-column prop="device_no" label="设备编号" align="center" />
                             <el-table-column prop="device_type" label="设备分类" align="center" />
                             <el-table-column prop="device_name" label="设备名称" align="center" />
                             <el-table-column prop="borrow_count" label="借用数量" align="center" width="150">
                                 <template #default="{ row }">
-                                    <el-input-number v-model="row.borrow_count" :min="1" :max="999" size="small" :disabled="isView" />
+                                    <el-input-number v-model="row.borrow_count" :min="1" :max="999" size="small" :disabled="true" />
                                 </template>
                             </el-table-column>
                             <el-table-column prop="brand" label="品牌" align="center" />
                             <el-table-column prop="model" label="规格型号" align="center" />
                             <el-table-column prop="warehouse" label="存放仓库" align="center" />
-                            <el-table-column prop="status" label="状态" align="center" v-if="['已领取', '已归还','已借出'].includes(form.status_label)">
+                            <el-table-column prop="status" label="状态" align="center">
                                 <template #default="{ row }">
-                                    <el-tag v-if="!isView" :type="row.status === '已归还' ? 'success' : 'warning'">{{ row.status }}</el-tag>
-                                    <el-tag v-else-if="['已领取', '已归还'].includes(form.status_label)">{{ form.status_label }}</el-tag>
+                                  {{ row.return_status.label }}
+                                   <!--  <el-tag v-if="!isView" :type="row.status === '已归还' ? 'success' : 'warning'">{{ row.status }}</el-tag>
+                                    <el-tag v-else-if="['已领取', '已归还'].includes(form.status_label)">{{ form.status_label }}</el-tag> -->
                                     <!-- <span v-else>{{ form.status_label }}</span> -->
                                 </template>
                             </el-table-column>
+                            <el-table-column prop="status" label="归还时间" align="center">
+                              <template #default="{ row }">
+                                {{ row.return_time ? dayjs(row.return_time).format('YYYY-MM-DD HH:mm:ss') : (row.return_status?.label === '已归还' ? dayjs().format('YYYY-MM-DD HH:mm:ss') : '') }}
+                              </template>
+                            </el-table-column>
                             <el-table-column label="操作" width="150" align="center">
-                                <template #default="{ $index }">
-                                  <el-button :disabled="isView" type="text" style="color: red"  v-if="!returnDeviceList[$index]?.condition || returnDeviceList[$index]?.photos?.length==0" @click="handleAbnormal($index)">异常操作</el-button>
+                                <template #default="{ $index,row }">
+                                 
+                                  <el-button :disabled="isView" type="text" style="color: red"  
+                                   v-if="!isView && (!returnDeviceList[$index]?.condition || returnDeviceList[$index]?.photos?.length==0)&& row.problem_records?.length ==0"
+                                  @click="handleAbnormal($index)">异常操作</el-button>
                                   <el-button 
-                                  :disabled="isView"
+                                    
                                     type="text" 
                                     style="color: #409EFF" 
                                     @click="handleViewAbnormal($index)"
-                                    v-if="returnDeviceList[$index]?.condition || returnDeviceList[$index]?.photos?.length"
+                                    v-if="row.problem_records?.length || (returnDeviceList[$index]?.condition || returnDeviceList[$index]?.photos?.length)"
                                   >查看异常</el-button>
-                                    <el-button type="text" :disabled="isView" style="color: red" @click="handleReturnRemove($index)">移除</el-button>
+                                    <!-- <el-button type="text" v-if="!isView" :disabled="isView" style="color: red" @click="handleReturnRemove($index)">移除</el-button> -->
                                 </template>
                             </el-table-column>
                         </el-table>
@@ -289,8 +298,10 @@
                     </el-col>
                     <el-col :span="8">
                         <div style="font-weight: bold; margin-bottom: 8px">当前状态</div>
-                        <el-input v-model="returnStatus"  :disabled="true" placeholder="" style="width: 150px" />
-                      <el-button type="primary"  style="margin-left: 16px" @click="clickReturn" :disabled="returnStatus=='已归还'||isView">归还</el-button>
+                        <el-input v-model="returnStatus" v-if="!isView"  :disabled="true" placeholder="" style="width: 150px" />
+                        <el-input value="已归还" v-else  :disabled="true" placeholder="" style="width: 150px" />
+                      <el-button type="primary" v-if="!isView"  style="margin-left: 16px" @click="clickReturn"
+                       :disabled="returnStatus=='已归还'||isView">归还</el-button>
                     </el-col>
                     <el-col :span="24" style="margin-top: 16px">
                         <div style="font-weight: bold; margin-bottom: 8px">备注</div>
@@ -332,7 +343,11 @@
 			<el-button type="primary" @click="onSubmit" v-if="!isView"> {{ isCollect ? '提交' : '确认' }}</el-button>
 		</template>
 	</el-dialog>
-	<SelectDeviceDialog v-model:visible="showSelectDeviceDialog" @confirm="onDeviceSelected" />
+	<SelectDeviceDialog 
+    v-model:visible="showSelectDeviceDialog"  
+    @confirm="onDeviceSelected" 
+    :device-ids="returnDeviceList.filter(item => item.return_status.label !== '已归还').map(item => item.device_no)"
+/>
 	<SettlementDialog v-model:visible="showSettlementDialog" :settlement-data="settlementData" />
     <AbnormalDialog v-model:visible="showAbnormalDialog" @confirm="onAbnormalConfirm" />
     <ViewAbnormalDialog 
@@ -546,11 +561,19 @@ const onAbnormalConfirm = (data: { condition: string; photos: any[] }) => {
 // 处理查看异常
 const handleViewAbnormal = (index: number) => {
   const device = returnDeviceList.value[index];
+  console.log("device:::",device);
   if (device) {
-    currentAbnormalData.value = {
-      condition: device.condition || '',
-      photos: device.photos || []
-    };
+    if(device.problem_records?.length){
+      currentAbnormalData.value = {
+        condition: device.problem_records?.[0].device_condition_after ||'',
+        photos: device.problem_records?.[0].returned_images.map((item:any)=>item.image_url) ||[]
+      };
+    }else{
+      currentAbnormalData.value = {
+        condition: device.condition ||'',
+        photos: device.photos ||[]
+      };
+    }
     showViewAbnormalDialog.value = true;
   }
 };
@@ -633,7 +656,8 @@ const handleReturnScanSearch = async () => {
                     brand: device.brand || '',
                     model: device.model || '',
                     warehouse: device.warehouse,
-                    status: '已归还'
+                    return_status:device.return_status,
+                    return_time:device.return_times
                 });
                 ElMessage.success('设备已添加到列表');
             }
@@ -723,7 +747,10 @@ function onDeviceSelected(devices: Device[]) {
       const existingDeviceIndex = returnDeviceList.value.findIndex(item => item.device_no === d.id);
       if (existingDeviceIndex !== -1) {
         // 如果设备已存在,更新其状态
-        returnDeviceList.value[existingDeviceIndex].status = '已归还';
+        returnDeviceList.value[existingDeviceIndex].return_status.value = 2;
+        returnDeviceList.value[existingDeviceIndex].return_status.label = '已归还';
+        returnDeviceList.value[existingDeviceIndex].is_return = true;
+        returnDeviceList.value[existingDeviceIndex].return_time = dayjs().format('YYYY-MM-DD HH:mm:ss');
         ElMessage.success(`设备 ${d.category_name} 状态已更新为已归还`);
       } else {
         // 如果设备不存在,添加新记录
@@ -880,7 +907,10 @@ watch(() => props.modelValue, async (val) => {
                             brand: '',
                             model: item.device_specification,
                             warehouse: item.location,
-                            status: '未归还'
+                            problem_records: item.problem_records,
+                            /* status: '未归还' */
+                            return_status:item.return_status,
+                            return_time:item.return_times
                         }));
                 }
                 // 同步 form.records 到 returnAbnormalList
@@ -933,7 +963,9 @@ watch(() => props.modelValue, async (val) => {
                             brand: '',
                             model: item.device_specification,
                             warehouse: item.location,
-                            status: '未归还'
+                            problem_records: item.problem_records,
+                            return_status:item.return_status,
+                            return_time:item.return_times
                         }));
                 }
 			}
@@ -1085,14 +1117,16 @@ function onSubmit() {
   } else {
     // 归还逻辑修改
     // 使用所有设备列表而不是选中的设备
-    const allDevices = returnDeviceList.value.map(item => ({
+    const allDevices = returnDeviceList.value
+  .filter(item => item.is_return === true)  // 只选择 return_status 为 2 的设备
+  .map(item => ({
       device: item.device_no,
       quantity: item.borrow_count,
       remark: returnRemark.value,
       device_id: Number(item.device_no) || 0,
        // 添加异常相关字段
        condition: item.condition, // 异常说明
-       photos: item.photos || [], // 异常照片
+       photo_urls: item.photos || [], // 异常照片
     }));
     
     const submitData = {

+ 1 - 1
src/views/system/borrow/crud.tsx

@@ -87,7 +87,7 @@ export const createCrudOptions = function ({ crudExpose }: CreateCrudOptionsProp
 					returnEquipment:{
 						order:3,
 						show:compute( ({row})=>{
-							return row.status === 5;
+							return row.status === 5||row.status===6;
 						}), 
 						text: '归还',
 						click: ({ row }) => {

+ 10 - 5
src/views/system/device/crud.tsx

@@ -117,7 +117,7 @@ export const createCrudOptions = function ({ crudExpose }: CreateCrudOptionsProp
 					search: { show: true },
 					type: 'dict-select',
 					dict: dict({
-						url: '/api/system/device/category/',
+						url: '/api/system/device/category/?page=1&limit=100',
 						value: 'id',
 						label: 'name',
 					}),
@@ -401,12 +401,15 @@ export const createCrudOptions = function ({ crudExpose }: CreateCrudOptionsProp
 					type: 'dict-select',
 					column: { show: false,minWidth: 120 },
 					dict: dict({
-						url: '/api/system/device/category/',
+						url: '/api/system/device/category/?page=1&limit=100',
 						value: 'id', 
 						label: 'name'
 					}),
 					form: {
-						component: { placeholder: '请输入设备类别' },
+						component: { 
+							placeholder: '请输入设备类别',
+							filterable: true 
+						},
 						rules: [{ required: true, message: '请输入设备类别' }],
 					}
 				},
@@ -440,7 +443,7 @@ export const createCrudOptions = function ({ crudExpose }: CreateCrudOptionsProp
 					type: 'dict-select',
 					column: { show: false,minWidth: 120 },
 					dict: dict({
-						url: '/api/system/device_tags/',
+						url: '/api/system/device_tags/?page=1&limit=100',
 						value: 'id', 
 						label: 'name'
 					}),
@@ -448,7 +451,9 @@ export const createCrudOptions = function ({ crudExpose }: CreateCrudOptionsProp
 						component:{placeholder:""}
 					},
 					form: {
-						component: { placeholder: '请选择设备标签' },
+						component: { placeholder: '请选择设备标签',
+							filterable: true 
+						 },
 						rules: [{ required: true, message: '请选择设备标签' }],
 						valueResolve({ form, value }) {
 							form.tags = Array.from(String(value), Number);