Browse Source

Merge remote-tracking branch 'origin/master'

lipenghui 1 tuần trước cách đây
mục cha
commit
e7338fb293

+ 3 - 0
.env.dev

@@ -35,3 +35,6 @@ VITE_APP_CAPTCHA_ENABLE=false
 
 # GoView域名
 VITE_GOVIEW_URL='http://127.0.0.1:3000'
+
+VITE_DD_CORPID='dingc0dfd4cc2e69187d35c2f4657eb6378f'
+VITE_DD_CLIENTID='dingh3nuuagvbkahgvjh'

+ 3 - 1
.env.local

@@ -31,4 +31,6 @@ VITE_MALL_H5_DOMAIN='http://localhost:3000'
 VITE_APP_CAPTCHA_ENABLE=false
 
 # GoView域名
-VITE_GOVIEW_URL='http://127.0.0.1:3000'
+VITE_GOVIEW_URL='http://127.0.0.1:3000'
+
+

+ 3 - 0
.env.prod

@@ -34,3 +34,6 @@ VITE_MALL_H5_DOMAIN='http://mall.yudao.iocoder.cn'
 VITE_APP_CAPTCHA_ENABLE=false
 # GoView域名
 VITE_GOVIEW_URL='http://127.0.0.1:3000'
+
+VITE_DD_CORPID='dingbe7f9a7e8cffa2bd35c2f4657eb6378f'
+VITE_DD_CLIENTID='dingmr9ez0ecgbmscfeb'

+ 1 - 1
.eslintrc.js

@@ -43,7 +43,7 @@ module.exports = defineConfig({
     '@typescript-eslint/no-unused-vars': 'off',
     'no-unused-vars': 'off',
     'space-before-function-paren': 'off',
-
+    'vue/comment-directive': 'off',
     'vue/attributes-order': 'off',
     'vue/one-component-per-file': 'off',
     'vue/html-closing-bracket-newline': 'off',

+ 1 - 1
.vscode/settings.json

@@ -87,7 +87,7 @@
     "source.fixAll.stylelint": "explicit"
   },
   "[vue]": {
-    "editor.defaultFormatter": "octref.vetur"
+    "editor.defaultFormatter": "esbenp.prettier-vscode"
   },
   "i18n-ally.localesPaths": ["src/locales"],
   "i18n-ally.keystyle": "nested",

+ 11 - 13
index.html

@@ -1,21 +1,19 @@
-<!DOCTYPE html>
+<!doctype html>
 <html lang="en">
   <head>
-      <script src="https://g.alicdn.com/dingding/dinglogin/0.0.5/ddLogin.js"></script>
-      <script type="text/javascript" src="https://cdn.jsdelivr.net/npm/js-base64@3.6.0/base64.min.js"></script>
-      <script src="https://api.map.baidu.com/api?v=3.0&ak=c0crhdxQ5H7WcqbcazGr7mnHrLa4GmO0"></script>
-      <meta charset="UTF-8" />
+    <script src="https://g.alicdn.com/code/npm/@ali/dingtalk-h5-remote-debug/0.1.3/index.js"></script>
+    <script src="https://g.alicdn.com/dingding/dinglogin/0.0.5/ddLogin.js"></script>
+    <script
+      type="text/javascript"
+      src="https://cdn.jsdelivr.net/npm/js-base64@3.6.0/base64.min.js"
+    ></script>
+    <script src="https://api.map.baidu.com/api?v=3.0&ak=c0crhdxQ5H7WcqbcazGr7mnHrLa4GmO0"></script>
+    <meta charset="UTF-8" />
     <link rel="icon" href="/favicon.ico" />
     <meta http-equiv="X-UA-Compatible" content="IE=edge" />
     <meta name="viewport" content="width=device-width, initial-scale=1.0" />
-    <meta
-      name="keywords"
-      content="DeepOil"
-    />
-    <meta
-      name="description"
-      content="DeepOil"
-    />
+    <meta name="keywords" content="DeepOil" />
+    <meta name="description" content="DeepOil" />
     <title>%VITE_APP_TITLE%</title>
   </head>
   <body>

+ 168 - 143
pnpm-lock.yaml

@@ -269,7 +269,7 @@ importers:
         version: 17.11.1
       bpmn-js-properties-panel:
         specifier: 5.23.0
-        version: 5.23.0(@bpmn-io/properties-panel@3.25.0(@lezer/common@1.2.3))(bpmn-js@17.11.1)(camunda-bpmn-js-behaviors@1.7.2(bpmn-js@17.11.1)(camunda-bpmn-moddle@7.0.1)(zeebe-bpmn-moddle@1.7.0))(diagram-js@12.8.1)
+        version: 5.23.0(@bpmn-io/properties-panel@3.25.0)(bpmn-js@17.11.1)(camunda-bpmn-js-behaviors@1.7.2(bpmn-js@17.11.1)(camunda-bpmn-moddle@7.0.1)(zeebe-bpmn-moddle@1.7.0))(diagram-js@12.8.1)
       consola:
         specifier: ^3.2.3
         version: 3.2.3
@@ -921,38 +921,45 @@ packages:
   '@bpmn-io/extract-process-variables@0.8.0':
     resolution: {integrity: sha512-yAS7ZYX+D56K+luC36u96eRMLb4VHcPUwTUqMZ/Z/Je2gou2DJLRbuBTHAB4jjKt4wFCHSG4B8Y+TrBciEYf4w==}
 
-  '@bpmn-io/feel-editor@1.9.1':
-    resolution: {integrity: sha512-UxSORdh5cwKM4fib4f9ov6J1/BHGpQVNtA+wPyEdKQyCyz3wqwE2/xe5wneVR1j5QFC5m2Na8nTy4a1TDFvZTw==}
+  '@bpmn-io/feel-editor@1.12.1':
+    resolution: {integrity: sha512-XEsbglURtQsphlvGQll3aiGYsM8Qc22y7fDGmxUqSYv3AVzORBzYdFhFFwfYMfKfzln/qwa3Wlrl0amvELRJ2A==}
     engines: {node: '>= 16'}
 
-  '@bpmn-io/feel-lint@1.3.1':
-    resolution: {integrity: sha512-wcFkJKhOm/iqCt5bzkKvxL5Dr9wKwUD+t164bQYbJsTYouAqmkkxiGsoqck42hXwdIhMSguZ+vqQ3hj5QdiYCA==}
+  '@bpmn-io/feel-lint@1.4.0':
+    resolution: {integrity: sha512-1bsdR/9vPD7RQVqWWPk0X0tpjLsYTDrCxIzOVtN/h32o4nPGl0dZBU5m07qaFUGD4wG3eOH4Qim1wexHG8YkBw==}
+
+  '@bpmn-io/feel-lint@2.1.0':
+    resolution: {integrity: sha512-fUGye6KppyowiwUqlfRHpMtXQ8so8jv1rh2LEQp+fhKf+WeLkbokmQwXZbCQe/4Kam/OLQRlx+p3Qnu0IrZQ6A==}
+
+  '@bpmn-io/lang-feel@2.4.0':
+    resolution: {integrity: sha512-0c1pratAD/YTOaivwLd7MljT0/MoDUMpfm87JbtAOBvivRfEr8mel5l8Ig3kgpYJ+xkznLaA9s79ZDKLh/O8ag==}
+
+  '@bpmn-io/lezer-feel@1.9.0':
+    resolution: {integrity: sha512-mV+pj+x0++9zT5/RkOOUNtkT2hpKpGWbXuFR8trJlvJeRe1dL/5yPal/RBcnk3z73tILK4kP6LzXelcsshQCEw==}
 
   '@bpmn-io/properties-panel@3.25.0':
     resolution: {integrity: sha512-SRGgj8uJc1Yyjcht2g36Q+xKR7sTx5VZXvcwDrdmQKlx5Y3nRmvmMjDGzeGDJDb7pNU1DSlaBJic84uISDBMWg==}
 
-  '@codemirror/autocomplete@6.18.3':
-    resolution: {integrity: sha512-1dNIOmiM0z4BIBwxmxEfA1yoxh1MF/6KPBbh20a5vphGV0ictKlgQsbJs6D6SkR6iJpGbpwRsa6PFMNlg9T9pQ==}
-    peerDependencies:
-      '@codemirror/language': ^6.0.0
-      '@codemirror/state': ^6.0.0
-      '@codemirror/view': ^6.0.0
-      '@lezer/common': ^1.0.0
+  '@camunda/feel-builtins@0.2.0':
+    resolution: {integrity: sha512-Jusm8x3Onqze9E5Y0lGGdPj66bnFKLYNwDz+uG4otsEXgSL0FpF+koGHK48LkF9Jqo67KaP1y3zr2y/HIWRePw==}
 
-  '@codemirror/commands@6.7.1':
-    resolution: {integrity: sha512-llTrboQYw5H4THfhN4U3qCnSZ1SOJ60ohhz+SzU0ADGtwlc533DtklQP0vSFaQuCPDn3BPpOd1GbbnUtwNjsrw==}
+  '@codemirror/autocomplete@6.20.0':
+    resolution: {integrity: sha512-bOwvTOIJcG5FVo5gUUupiwYh8MioPLQ4UcqbcRf7UQ98X90tCa9E1kZ3Z7tqwpZxYyOvh1YTYbmZE9RTfTp5hg==}
 
-  '@codemirror/language@6.10.6':
-    resolution: {integrity: sha512-KrsbdCnxEztLVbB5PycWXFxas4EOyk/fPAfruSOnDDppevQgid2XZ+KbJ9u+fDikP/e7MW7HPBTvTb8JlZK9vA==}
+  '@codemirror/commands@6.10.0':
+    resolution: {integrity: sha512-2xUIc5mHXQzT16JnyOFkh8PvfeXuIut3pslWGfsGOhxP/lpgRm9HOl/mpzLErgt5mXDovqA0d11P21gofRLb9w==}
 
-  '@codemirror/lint@6.8.4':
-    resolution: {integrity: sha512-u4q7PnZlJUojeRe8FJa/njJcMctISGgPQ4PnWsd9268R4ZTtU+tfFYmwkBvgcrK2+QQ8tYFVALVb5fVJykKc5A==}
+  '@codemirror/language@6.11.3':
+    resolution: {integrity: sha512-9HBM2XnwDj7fnu0551HkGdrUrrqmYq/WC5iv6nbY2WdicXdGbhR/gfbZOH73Aqj4351alY1+aoG9rCNfiwS1RA==}
 
-  '@codemirror/state@6.4.1':
-    resolution: {integrity: sha512-QkEyUiLhsJoZkbumGZlswmAhA7CBU02Wrz7zvH4SrcifbsqwlXShVXg65f3v/ts57W3dqyamEriMhij1Z3Zz4A==}
+  '@codemirror/lint@6.9.2':
+    resolution: {integrity: sha512-sv3DylBiIyi+xKwRCJAAsBZZZWo82shJ/RTMymLabAdtbkV5cSKwWDeCgtUq3v8flTaXS2y1kKkICuRYtUswyQ==}
 
-  '@codemirror/view@6.35.0':
-    resolution: {integrity: sha512-I0tYy63q5XkaWsJ8QRv5h6ves7kvtrBWjBcnf/bzohFJQc5c14a1AQRdE8QpPF9eMp5Mq2FMm59TCj1gDfE7kw==}
+  '@codemirror/state@6.5.2':
+    resolution: {integrity: sha512-FVqsPqtPWKVVL3dPSxy8wEF/ymIEuVzF1PK3VbUgrxXpJUSHQWWZz4JMToquRxnkw+36LTamCZG2iua2Ptq0fA==}
+
+  '@codemirror/view@6.38.8':
+    resolution: {integrity: sha512-XcE9fcnkHCbWkjeKyi0lllwXmBLtyYb5dt89dJyx23I9+LSh5vZDIuk7OLG4VM1lgrXZQcY6cxyZyk5WVPRv/A==}
 
   '@commitlint/cli@19.6.0':
     resolution: {integrity: sha512-v17BgGD9w5KnthaKxXnEg6KLq6DYiAxyiN44TpiRtqyW8NSq+Kx99mkEG8Qo6uu6cI5eMzMojW2muJxjmPnF8w==}
@@ -1396,17 +1403,20 @@ packages:
   '@jridgewell/trace-mapping@0.3.25':
     resolution: {integrity: sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==}
 
-  '@lezer/common@1.2.3':
-    resolution: {integrity: sha512-w7ojc8ejBqr2REPsWxJjrMFsA/ysDCFICn8zEOR9mrqzOu2amhITYuLD8ag6XZf0CFXDrhKqw7+tW8cX66NaDA==}
+  '@lezer/common@1.3.0':
+    resolution: {integrity: sha512-L9X8uHCYU310o99L3/MpJKYxPzXPOS7S0NmBaM7UO/x2Kb2WbmMLSkfvdr1KxRIFYOpbY0Jhn7CfLSUDzL8arQ==}
+
+  '@lezer/highlight@1.2.3':
+    resolution: {integrity: sha512-qXdH7UqTvGfdVBINrgKhDsVTJTxactNNxLk7+UMwZhU13lMHaOBlJe9Vqp907ya56Y3+ed2tlqzys7jDkTmW0g==}
 
-  '@lezer/highlight@1.2.1':
-    resolution: {integrity: sha512-Z5duk4RN/3zuVO7Jq0pGLJ3qynpxUVsh7IbUbGj88+uV2ApSAn6kWg2au3iJb+0Zi7kKtqffIESgNcRXWZWmSA==}
+  '@lezer/lr@1.4.3':
+    resolution: {integrity: sha512-yenN5SqAxAPv/qMnpWW0AT7l+SxVrgG+u0tNsRQWqbrz66HIl8DnEbBObvy21J5K7+I1v7gsAnlE2VQ5yYVSeA==}
 
-  '@lezer/lr@1.4.2':
-    resolution: {integrity: sha512-pu0K1jCIdnQ12aWNaAVU5bzi7Bd1w54J3ECgANPmYLtQKP0HBj2cE/5coBD66MT10xbtIuUr7tg0Shbsvk0mDA==}
+  '@lezer/markdown@1.6.0':
+    resolution: {integrity: sha512-AXb98u3M6BEzTnreBnGtQaF7xFTiMA92Dsy5tqEjpacbjRxDSFdN4bKJo9uvU4cEEOS7D2B9MT7kvDgOEIzJSw==}
 
-  '@lezer/markdown@1.3.2':
-    resolution: {integrity: sha512-Wu7B6VnrKTbBEohqa63h5vxXjiC4pO5ZQJ/TDbhJxPQaaIoRD/6UVDhSDtVsCwVZV12vvN9KxuLL3ATMnlG0oQ==}
+  '@marijn/find-cluster-break@1.0.2':
+    resolution: {integrity: sha512-l0h88YhZFyKdXIFNfSWpyjStDjGHwZ/U7iobcK1cQQD8sejsONdQtTVU+1wVN1PBw40PiiHB1vA5S7VTfQiP9g==}
 
   '@microsoft/fetch-event-source@2.0.1':
     resolution: {integrity: sha512-W6CLUJ2eBMw3Rec70qrsEW0jOm/3twwJv21mrmj2yORiaVmVYGS4sSS5yUwvQc1ZlDLYGPnClVWmUUMagKNsfA==}
@@ -2589,8 +2599,8 @@ packages:
   camunda-bpmn-moddle@7.0.1:
     resolution: {integrity: sha512-Br8Diu6roMpziHdpl66Dhnm0DTnCFMrSD9zwLV08LpD52QA0UsXxU87XfHf08HjuB7ly0Hd1bvajZRpf9hbmYQ==}
 
-  caniuse-lite@1.0.30001684:
-    resolution: {integrity: sha512-G1LRwLIQjBQoyq0ZJGqGIJUXzJ8irpbjHLpVRXDvBEScFJ9b17sgK6vlx0GAJFE21okD7zXl08rRRUfq6HdoEQ==}
+  caniuse-lite@1.0.30001756:
+    resolution: {integrity: sha512-4HnCNKbMLkLdhJz3TToeVWHSnfJvPaq6vu/eRP0Ahub/07n484XHhBF5AJoSGHdVrS8tKFauUQz8Bp9P7LVx7A==}
 
   chalk@1.1.3:
     resolution: {integrity: sha512-U3lRVLMSlsCfjqYPbLyVv11M9CPW4I728d6TCKMAOJueEeB9/8o+eSsMnxPJD+Q+K909sdESg7C+tIkoH6on1A==}
@@ -3357,8 +3367,8 @@ packages:
   flatted@3.3.2:
     resolution: {integrity: sha512-AiwGJM8YcNOaobumgtng+6NHuOqC3A7MixFeDafM3X9cIUM+xUXoS5Vfgf+OihAYe20fxqNM9yPBXJzRtZ/4eA==}
 
-  focus-trap@7.6.2:
-    resolution: {integrity: sha512-9FhUxK1hVju2+AiQIDJ5Dd//9R2n2RAfJ0qfhF4IHGHgcoEUTMpbTeG/zbEuwaiYXfuAH6XE0/aCyxDdRM+W5w==}
+  focus-trap@7.6.6:
+    resolution: {integrity: sha512-v/Z8bvMCajtx4mEXmOo7QEsIzlIOqRXTIwgUfsFOF9gEsespdbD0AkPIka1bSXZ8Y8oZ+2IVDQZePkTfEHZl7Q==}
 
   follow-redirects@1.15.9:
     resolution: {integrity: sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ==}
@@ -3770,15 +3780,12 @@ packages:
   kolorist@1.8.0:
     resolution: {integrity: sha512-Y+60/zizpJ3HRH8DCss+q95yr6145JXZo46OTpFvDZWLfRCE4qChOyk1b26nMaNpfHHgxagk9dXT5OP0Tfe+dQ==}
 
-  lang-feel@2.2.0:
-    resolution: {integrity: sha512-Ebo5nftYsMfJzB3Ny8Oy4oaDXZXb5x61qtVVmKv6aImvAZUbT76mD60ZbEilizjZQzsR2CcU1iMK5sacIa1NVA==}
-
   levn@0.4.1:
     resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==}
     engines: {node: '>= 0.8.0'}
 
-  lezer-feel@1.4.0:
-    resolution: {integrity: sha512-kNxG7O38gwpuYy+C3JCRxQNTCE2qu9uTuH5dE3EGVnRhIQMe6rPDz0S8t3urLEOsMud6HI795m6zX2ujfUaqTw==}
+  lezer-feel@1.9.0:
+    resolution: {integrity: sha512-x8z6pCih3I3BOq3kBbhw6VUOU9Sg61PBJ1nigTgDl1yM5f0OPzEjK7GRJXutrSJDiUK8zwgqBvUJFlSfGLNZUg==}
 
   lilconfig@3.1.2:
     resolution: {integrity: sha512-eop+wDAvpItUys0FWkHIKeC9ybYrTGbU41U5K7+bttZZeohvnY7M9dZ5kB21GNWiFT2q1OoPTvncPCgSOVO5ow==}
@@ -3897,8 +3904,8 @@ packages:
   lru-cache@5.1.1:
     resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==}
 
-  luxon@3.5.0:
-    resolution: {integrity: sha512-rh+Zjr6DNfUYR3bPwJEnuwDdqMbxZW7LOQfUN4B54+Cl+0o5zaU9RJ6bcidfDtC1cWCZXQ+nvX8bf6bAji37QQ==}
+  luxon@3.7.2:
+    resolution: {integrity: sha512-vtEhXh/gNjI9Yg1u4jX/0YVPMvxzHuGgCm6tC5kZyb08yjGWGnqAjGJvcXbqQR2P3MyMEFnRbpcdFS6PBcLqew==}
     engines: {node: '>=12'}
 
   m3u8-parser@4.8.0:
@@ -3996,6 +4003,9 @@ packages:
   min-dash@4.2.2:
     resolution: {integrity: sha512-qbhSYUxk6mBaF096B3JOQSumXbKWHenmT97cSpdNzgkWwGjhjhE/KZODCoDNhI2I4C9Cb6R/Q13S4BYkUSXoXQ==}
 
+  min-dash@4.2.3:
+    resolution: {integrity: sha512-VLMYQI5+FcD9Ad24VcB08uA83B07OhueAlZ88jBK6PyupTvEJwllTMUqMy0wPGYs7pZUEtEEMWdHB63m3LtEcg==}
+
   min-document@2.19.0:
     resolution: {integrity: sha512-9Wy1B3m3f66bPPmU5hdA4DR4PB2OfDU/+GS3yAB7IQozE3tqXaVv2zOjgla7MEGSRv95+ILmOuvhLkOK6wJtCQ==}
 
@@ -4723,8 +4733,8 @@ packages:
   strnum@1.0.5:
     resolution: {integrity: sha512-J8bbNyKKXl5qYcR36TIO8W3mVGVHrmmxsd5PAItGkmyzwJvybiw2IVq5nqd0i4LSNSkB/sx9VHllbfFdr9k1JA==}
 
-  style-mod@4.1.2:
-    resolution: {integrity: sha512-wnD1HyVqpJUI2+eKZ+eo1UwghftP6yuFheBqqe+bWCotBjC2K1YnteJILRMs3SM4V/0dLEW1SC27MWP5y+mwmw==}
+  style-mod@4.1.3:
+    resolution: {integrity: sha512-i/n8VsZydrugj3Iuzll8+x/00GH2vnYsk1eomD8QiRrSAeW6ItbCQDtfXCeJHd0iwiNagqjQkvpvREEPtW3IoQ==}
 
   stylelint-config-html@1.1.0:
     resolution: {integrity: sha512-IZv4IVESjKLumUGi+HWeb7skgO6/g4VMuAYrJdlqQFndgbj6WJAXPhaysvBiXefX79upBdQVumgYcdd17gCpjQ==}
@@ -4790,8 +4800,8 @@ packages:
   systemjs@6.15.1:
     resolution: {integrity: sha512-Nk8c4lXvMB98MtbmjX7JwJRgJOL8fluecYCfCeYBznwmpOs8Bf15hLM6z4z71EDAhQVrQrI+wt1aLWSXZq+hXA==}
 
-  tabbable@6.2.0:
-    resolution: {integrity: sha512-Cat63mxsVJlzYvN51JmVXIgNoUokrIaT2zLclCXjRd8boZ0004U4KCs/sToJ75C6sdlByWxpYnb5Boif1VSFew==}
+  tabbable@6.3.0:
+    resolution: {integrity: sha512-EIHvdY5bPLuWForiR/AN2Bxngzpuwn1is4asboytXtpTgsArc+WmSJKVLlhdh71u7jFcryDqB2A8lQvj78MkyQ==}
 
   table@6.8.2:
     resolution: {integrity: sha512-w2sfv80nrAh2VCbqR5AK27wswXhqcck2AhfnNW76beQXskGZ1V12GwS//yYVa3d3fcvAip2OUnbDAjW2k3v9fA==}
@@ -5989,9 +5999,9 @@ snapshots:
 
   '@bpmn-io/cm-theme@0.1.0-alpha.2':
     dependencies:
-      '@codemirror/language': 6.10.6
-      '@codemirror/view': 6.35.0
-      '@lezer/highlight': 1.2.1
+      '@codemirror/language': 6.11.3
+      '@codemirror/view': 6.38.8
+      '@lezer/highlight': 1.2.3
 
   '@bpmn-io/diagram-js-ui@0.2.3':
     dependencies:
@@ -6002,73 +6012,93 @@ snapshots:
     dependencies:
       min-dash: 4.2.2
 
-  '@bpmn-io/feel-editor@1.9.1(@lezer/common@1.2.3)':
-    dependencies:
-      '@bpmn-io/feel-lint': 1.3.1
-      '@codemirror/autocomplete': 6.18.3(@codemirror/language@6.10.6)(@codemirror/state@6.4.1)(@codemirror/view@6.35.0)(@lezer/common@1.2.3)
-      '@codemirror/commands': 6.7.1
-      '@codemirror/language': 6.10.6
-      '@codemirror/lint': 6.8.4
-      '@codemirror/state': 6.4.1
-      '@codemirror/view': 6.35.0
-      '@lezer/highlight': 1.2.1
-      lang-feel: 2.2.0
+  '@bpmn-io/feel-editor@1.12.1':
+    dependencies:
+      '@bpmn-io/feel-lint': 2.1.0
+      '@bpmn-io/lang-feel': 2.4.0
+      '@camunda/feel-builtins': 0.2.0
+      '@codemirror/autocomplete': 6.20.0
+      '@codemirror/commands': 6.10.0
+      '@codemirror/language': 6.11.3
+      '@codemirror/lint': 6.9.2
+      '@codemirror/state': 6.5.2
+      '@codemirror/view': 6.38.8
+      '@lezer/highlight': 1.2.3
       min-dom: 4.2.1
-    transitivePeerDependencies:
-      - '@lezer/common'
 
-  '@bpmn-io/feel-lint@1.3.1':
+  '@bpmn-io/feel-lint@1.4.0':
+    dependencies:
+      '@codemirror/language': 6.11.3
+      lezer-feel: 1.9.0
+
+  '@bpmn-io/feel-lint@2.1.0':
+    dependencies:
+      '@bpmn-io/lezer-feel': 1.9.0
+      '@codemirror/language': 6.11.3
+
+  '@bpmn-io/lang-feel@2.4.0':
+    dependencies:
+      '@bpmn-io/lezer-feel': 1.9.0
+      '@codemirror/autocomplete': 6.20.0
+      '@codemirror/language': 6.11.3
+      '@lezer/common': 1.3.0
+
+  '@bpmn-io/lezer-feel@1.9.0':
     dependencies:
-      '@codemirror/language': 6.10.6
-      lezer-feel: 1.4.0
+      '@lezer/highlight': 1.2.3
+      '@lezer/lr': 1.4.3
+      min-dash: 4.2.3
 
-  '@bpmn-io/properties-panel@3.25.0(@lezer/common@1.2.3)':
+  '@bpmn-io/properties-panel@3.25.0':
     dependencies:
-      '@bpmn-io/feel-editor': 1.9.1(@lezer/common@1.2.3)
-      '@codemirror/view': 6.35.0
+      '@bpmn-io/feel-editor': 1.12.1
+      '@codemirror/view': 6.38.8
       classnames: 2.5.1
       feelers: 1.4.0
-      focus-trap: 7.6.2
-      min-dash: 4.2.2
+      focus-trap: 7.6.6
+      min-dash: 4.2.3
       min-dom: 4.2.1
-    transitivePeerDependencies:
-      - '@lezer/common'
 
-  '@codemirror/autocomplete@6.18.3(@codemirror/language@6.10.6)(@codemirror/state@6.4.1)(@codemirror/view@6.35.0)(@lezer/common@1.2.3)':
+  '@camunda/feel-builtins@0.2.0': {}
+
+  '@codemirror/autocomplete@6.20.0':
     dependencies:
-      '@codemirror/language': 6.10.6
-      '@codemirror/state': 6.4.1
-      '@codemirror/view': 6.35.0
-      '@lezer/common': 1.2.3
+      '@codemirror/language': 6.11.3
+      '@codemirror/state': 6.5.2
+      '@codemirror/view': 6.38.8
+      '@lezer/common': 1.3.0
 
-  '@codemirror/commands@6.7.1':
+  '@codemirror/commands@6.10.0':
     dependencies:
-      '@codemirror/language': 6.10.6
-      '@codemirror/state': 6.4.1
-      '@codemirror/view': 6.35.0
-      '@lezer/common': 1.2.3
+      '@codemirror/language': 6.11.3
+      '@codemirror/state': 6.5.2
+      '@codemirror/view': 6.38.8
+      '@lezer/common': 1.3.0
 
-  '@codemirror/language@6.10.6':
+  '@codemirror/language@6.11.3':
     dependencies:
-      '@codemirror/state': 6.4.1
-      '@codemirror/view': 6.35.0
-      '@lezer/common': 1.2.3
-      '@lezer/highlight': 1.2.1
-      '@lezer/lr': 1.4.2
-      style-mod: 4.1.2
+      '@codemirror/state': 6.5.2
+      '@codemirror/view': 6.38.8
+      '@lezer/common': 1.3.0
+      '@lezer/highlight': 1.2.3
+      '@lezer/lr': 1.4.3
+      style-mod: 4.1.3
 
-  '@codemirror/lint@6.8.4':
+  '@codemirror/lint@6.9.2':
     dependencies:
-      '@codemirror/state': 6.4.1
-      '@codemirror/view': 6.35.0
+      '@codemirror/state': 6.5.2
+      '@codemirror/view': 6.38.8
       crelt: 1.0.6
 
-  '@codemirror/state@6.4.1': {}
+  '@codemirror/state@6.5.2':
+    dependencies:
+      '@marijn/find-cluster-break': 1.0.2
 
-  '@codemirror/view@6.35.0':
+  '@codemirror/view@6.38.8':
     dependencies:
-      '@codemirror/state': 6.4.1
-      style-mod: 4.1.2
+      '@codemirror/state': 6.5.2
+      crelt: 1.0.6
+      style-mod: 4.1.3
       w3c-keyname: 2.2.8
 
   '@commitlint/cli@19.6.0(@types/node@20.17.9)(typescript@5.3.3)':
@@ -6525,20 +6555,22 @@ snapshots:
       '@jridgewell/resolve-uri': 3.1.2
       '@jridgewell/sourcemap-codec': 1.5.0
 
-  '@lezer/common@1.2.3': {}
+  '@lezer/common@1.3.0': {}
 
-  '@lezer/highlight@1.2.1':
+  '@lezer/highlight@1.2.3':
     dependencies:
-      '@lezer/common': 1.2.3
+      '@lezer/common': 1.3.0
 
-  '@lezer/lr@1.4.2':
+  '@lezer/lr@1.4.3':
     dependencies:
-      '@lezer/common': 1.2.3
+      '@lezer/common': 1.3.0
 
-  '@lezer/markdown@1.3.2':
+  '@lezer/markdown@1.6.0':
     dependencies:
-      '@lezer/common': 1.2.3
-      '@lezer/highlight': 1.2.1
+      '@lezer/common': 1.3.0
+      '@lezer/highlight': 1.2.3
+
+  '@marijn/find-cluster-break@1.0.2': {}
 
   '@microsoft/fetch-event-source@2.0.1': {}
 
@@ -7799,7 +7831,7 @@ snapshots:
   autoprefixer@10.4.20(postcss@8.4.49):
     dependencies:
       browserslist: 4.24.2
-      caniuse-lite: 1.0.30001684
+      caniuse-lite: 1.0.30001756
       fraction.js: 4.3.7
       normalize-range: 0.1.2
       picocolors: 1.1.1
@@ -7860,10 +7892,10 @@ snapshots:
 
   bootstrap-icons@1.12.1: {}
 
-  bpmn-js-properties-panel@5.23.0(@bpmn-io/properties-panel@3.25.0(@lezer/common@1.2.3))(bpmn-js@17.11.1)(camunda-bpmn-js-behaviors@1.7.2(bpmn-js@17.11.1)(camunda-bpmn-moddle@7.0.1)(zeebe-bpmn-moddle@1.7.0))(diagram-js@12.8.1):
+  bpmn-js-properties-panel@5.23.0(@bpmn-io/properties-panel@3.25.0)(bpmn-js@17.11.1)(camunda-bpmn-js-behaviors@1.7.2(bpmn-js@17.11.1)(camunda-bpmn-moddle@7.0.1)(zeebe-bpmn-moddle@1.7.0))(diagram-js@12.8.1):
     dependencies:
       '@bpmn-io/extract-process-variables': 0.8.0
-      '@bpmn-io/properties-panel': 3.25.0(@lezer/common@1.2.3)
+      '@bpmn-io/properties-panel': 3.25.0
       array-move: 4.0.0
       bpmn-js: 17.11.1
       camunda-bpmn-js-behaviors: 1.7.2(bpmn-js@17.11.1)(camunda-bpmn-moddle@7.0.1)(zeebe-bpmn-moddle@1.7.0)
@@ -7916,7 +7948,7 @@ snapshots:
 
   browserslist@4.24.2:
     dependencies:
-      caniuse-lite: 1.0.30001684
+      caniuse-lite: 1.0.30001756
       electron-to-chromium: 1.5.67
       node-releases: 2.0.18
       update-browserslist-db: 1.1.1(browserslist@4.24.2)
@@ -7942,12 +7974,12 @@ snapshots:
       bpmn-js: 17.11.1
       camunda-bpmn-moddle: 7.0.1
       ids: 1.0.5
-      min-dash: 4.2.2
+      min-dash: 4.2.3
       zeebe-bpmn-moddle: 1.7.0
 
   camunda-bpmn-moddle@7.0.1: {}
 
-  caniuse-lite@1.0.30001684: {}
+  caniuse-lite@1.0.30001756: {}
 
   chalk@1.1.3:
     dependencies:
@@ -8771,26 +8803,26 @@ snapshots:
   feelers@1.4.0:
     dependencies:
       '@bpmn-io/cm-theme': 0.1.0-alpha.2
-      '@bpmn-io/feel-lint': 1.3.1
-      '@codemirror/autocomplete': 6.18.3(@codemirror/language@6.10.6)(@codemirror/state@6.4.1)(@codemirror/view@6.35.0)(@lezer/common@1.2.3)
-      '@codemirror/commands': 6.7.1
-      '@codemirror/language': 6.10.6
-      '@codemirror/lint': 6.8.4
-      '@codemirror/state': 6.4.1
-      '@codemirror/view': 6.35.0
-      '@lezer/common': 1.2.3
-      '@lezer/highlight': 1.2.1
-      '@lezer/lr': 1.4.2
-      '@lezer/markdown': 1.3.2
+      '@bpmn-io/feel-lint': 1.4.0
+      '@codemirror/autocomplete': 6.20.0
+      '@codemirror/commands': 6.10.0
+      '@codemirror/language': 6.11.3
+      '@codemirror/lint': 6.9.2
+      '@codemirror/state': 6.5.2
+      '@codemirror/view': 6.38.8
+      '@lezer/common': 1.3.0
+      '@lezer/highlight': 1.2.3
+      '@lezer/lr': 1.4.3
+      '@lezer/markdown': 1.6.0
       feelin: 3.2.0
-      lezer-feel: 1.4.0
+      lezer-feel: 1.9.0
       min-dom: 5.1.1
 
   feelin@3.2.0:
     dependencies:
-      '@lezer/lr': 1.4.2
-      lezer-feel: 1.4.0
-      luxon: 3.5.0
+      '@lezer/lr': 1.4.3
+      lezer-feel: 1.9.0
+      luxon: 3.7.2
 
   file-entry-cache@6.0.1:
     dependencies:
@@ -8837,9 +8869,9 @@ snapshots:
 
   flatted@3.3.2: {}
 
-  focus-trap@7.6.2:
+  focus-trap@7.6.6:
     dependencies:
-      tabbable: 6.2.0
+      tabbable: 6.3.0
 
   follow-redirects@1.15.9(debug@4.3.7):
     optionalDependencies:
@@ -9198,25 +9230,16 @@ snapshots:
 
   kolorist@1.8.0: {}
 
-  lang-feel@2.2.0:
-    dependencies:
-      '@codemirror/autocomplete': 6.18.3(@codemirror/language@6.10.6)(@codemirror/state@6.4.1)(@codemirror/view@6.35.0)(@lezer/common@1.2.3)
-      '@codemirror/language': 6.10.6
-      '@codemirror/state': 6.4.1
-      '@codemirror/view': 6.35.0
-      '@lezer/common': 1.2.3
-      lezer-feel: 1.4.0
-
   levn@0.4.1:
     dependencies:
       prelude-ls: 1.2.1
       type-check: 0.4.0
 
-  lezer-feel@1.4.0:
+  lezer-feel@1.9.0:
     dependencies:
-      '@lezer/highlight': 1.2.1
-      '@lezer/lr': 1.4.2
-      min-dash: 4.2.2
+      '@lezer/highlight': 1.2.3
+      '@lezer/lr': 1.4.3
+      min-dash: 4.2.3
 
   lilconfig@3.1.2: {}
 
@@ -9332,7 +9355,7 @@ snapshots:
     dependencies:
       yallist: 3.1.1
 
-  luxon@3.5.0: {}
+  luxon@3.7.2: {}
 
   m3u8-parser@4.8.0:
     dependencies:
@@ -9438,6 +9461,8 @@ snapshots:
 
   min-dash@4.2.2: {}
 
+  min-dash@4.2.3: {}
+
   min-document@2.19.0:
     dependencies:
       dom-walk: 0.1.2
@@ -9451,7 +9476,7 @@ snapshots:
   min-dom@5.1.1:
     dependencies:
       domify: 2.0.0
-      min-dash: 4.2.2
+      min-dash: 4.2.3
 
   minimatch@3.1.2:
     dependencies:
@@ -10105,7 +10130,7 @@ snapshots:
 
   strnum@1.0.5: {}
 
-  style-mod@4.1.2: {}
+  style-mod@4.1.3: {}
 
   stylelint-config-html@1.1.0(postcss-html@1.7.0)(stylelint@16.11.0(typescript@5.3.3)):
     dependencies:
@@ -10208,7 +10233,7 @@ snapshots:
 
   systemjs@6.15.1: {}
 
-  tabbable@6.2.0: {}
+  tabbable@6.3.0: {}
 
   table@6.8.2:
     dependencies:

+ 5 - 0
src/api/login/index.ts

@@ -15,6 +15,11 @@ export interface SmsLoginVO {
 export const login = (data: UserLoginVO) => {
   return request.post({ url: '/system/auth/login', data })
 }
+
+export const dingTalkLogin = (data:{code:string,type:number,state:number}) => {
+  return request.post({ url: '/system/auth/h5SocialLogin', data,headers:{'tenant-id':1} })
+}
+
 export const simpleLogin = (id: any) => {
   return request.post({ url: '/system/auth/simple/login/'+id })
 }

+ 5 - 0
src/api/pms/iotrhdailyreport/index.ts

@@ -42,6 +42,11 @@ export const IotRhDailyReportApi = {
     return await request.get({ url: `/pms/iot-rh-daily-report/page`, params })
   },
 
+  // 累计工作量统计
+  totalWorkload: async (params: any) => {
+    return await request.get({ url: `/pms/iot-rh-daily-report/totalWorkload`, params })
+  },
+
   // 按照日期查询瑞恒日报统计数据 已填报 未填报 数量
   rhDailyReportStatistics: async (params: any) => {
     return await request.get({ url: `/pms/iot-rh-daily-report/rhDailyReportStatistics`, params })

+ 15 - 1
src/config/axios/service.ts

@@ -8,7 +8,7 @@ import errorCode from './errorCode'
 
 import { resetRouter } from '@/router'
 import { deleteUserCache } from '@/hooks/web/useCache'
-import {langHelper} from '@/utils/langHelper'
+import { langHelper } from '@/utils/langHelper'
 import { useLocaleStore } from '@/store/modules/locale'
 const tenantEnable = import.meta.env.VITE_APP_TENANT_ENABLE
 const { result_code, base_url, request_timeout } = config
@@ -49,20 +49,32 @@ service.interceptors.request.use(
         return (isToken = false)
       }
     })
+
+    debugger
+
     if (getAccessToken() && !isToken) {
       config.headers.Authorization = 'Bearer ' + getAccessToken() // 让每个请求携带自定义token
     }
+
+    debugger
+
     // 设置租户
     if (tenantEnable && tenantEnable === 'true') {
       const tenantId = getTenantId()
       if (tenantId) config.headers['tenant-id'] = tenantId
     }
+
+    debugger
+
     const method = config.method?.toUpperCase()
+
+    debugger
     // 防止 GET 请求缓存
     if (method === 'GET') {
       config.headers['Cache-Control'] = 'no-cache'
       config.headers['Pragma'] = 'no-cache'
     }
+
     // 自定义参数序列化函数
     else if (method === 'POST') {
       const contentType = config.headers['Content-Type'] || config.headers['content-type']
@@ -72,6 +84,8 @@ service.interceptors.request.use(
         }
       }
     }
+
+    debugger
     return config
   },
   (error: AxiosError) => {

+ 5 - 0
src/layout/components/Message/src/Message.vue

@@ -66,6 +66,11 @@ const routerDetail = (item) =>{
       name: 'FillDailyReportForm',
       params: { id: id, mode: 'fill' }
     })
+  } else if (item.businessType === 'rdReportApproval') {
+    push({
+      name: 'FillDailyReportForm',
+      params: { id: id, mode: 'approval' }
+    })
   } else if (item.businessType === 'generateOperation') {
     const param = item.templateParams
     id = param.deptId+','+param.userId+','+param.createTime+','+param.businessId+','+param.orderStatus;

+ 13 - 0
src/router/modules/remaining.ts

@@ -984,6 +984,19 @@ const remainingRouter: AppRouteRecordRaw[] = [
           title: t('project.fillReport'),
           activeMenu: '/dailyReport/fill'
         }
+      },
+      {
+        path: 'dailyReport/approval/:id(\\d+)',
+        component: () => import('@/views/pms/iotrddailyreport/DailyReportApprovalForm.vue'),
+        name: 'DailyReportApprovalForm',
+        meta: {
+          noCache: false,
+          hidden: true,
+          canTo: true,
+          icon: 'ep:add',
+          title: t('project.fillReport'),
+          activeMenu: '/dailyReport/approval'
+        }
       }
     ]
   },

+ 104 - 9
src/views/Login/Login.vue

@@ -19,9 +19,9 @@
             enter-active-class="animate__animated animate__bounceInLeft"
             tag="div"
           >
-<!--            <img key="1" alt="" class="w-350px" src="@/assets/svgs/login-box-bg.svg" />-->
-<!--            <img key="1" alt="" class="w-350px" src="@/assets/imgs/yf.jpg" />-->
-<!--            <div key="2" class="text-3xl text-white">{{ t('login.welcome') }}</div>-->
+            <!--            <img key="1" alt="" class="w-350px" src="@/assets/svgs/login-box-bg.svg" />-->
+            <!--            <img key="1" alt="" class="w-350px" src="@/assets/imgs/yf.jpg" />-->
+            <!--            <div key="2" class="text-3xl text-white">{{ t('login.welcome') }}</div>-->
             <div key="3" class="mt-5 text-14px font-normal text-white">
               {{ t('login.message') }}
             </div>
@@ -34,11 +34,11 @@
         <!-- 右上角的主题、语言选择 -->
         <div
           class="flex items-center justify-between at-2xl:justify-end at-xl:justify-end"
-          style="color: var(--el-text-color-primary);"
+          style="color: var(--el-text-color-primary)"
         >
           <div class="flex items-center at-2xl:hidden at-xl:hidden">
             <img alt="" class="mr-10px h-48px w-48px" src="@/assets/imgs/logo.png" />
-            <span class="text-20px font-bold" >{{ underlineToHump(appStore.getTitle) }}</span>
+            <span class="text-20px font-bold">{{ underlineToHump(appStore.getTitle) }}</span>
           </div>
           <div class="flex items-center justify-end space-x-10px h-48px">
             <ThemeSwitch />
@@ -53,13 +53,13 @@
             <!-- 账号登录 -->
             <LoginForm class="m-auto h-auto p-20px lt-xl:(rounded-3xl light:bg-white)" />
             <!-- 手机登录 -->
-<!--            <MobileForm class="m-auto h-auto p-20px lt-xl:(rounded-3xl light:bg-white)" />-->
+            <!--            <MobileForm class="m-auto h-auto p-20px lt-xl:(rounded-3xl light:bg-white)" />-->
             <!-- 二维码登录 -->
             <QrCodeForm class="m-auto h-auto p-20px lt-xl:(rounded-3xl light:bg-white)" />
             <!-- 注册 -->
             <RegisterForm class="m-auto h-auto p-20px lt-xl:(rounded-3xl light:bg-white)" />
             <!-- 三方登录 -->
-<!--            <SSOLoginVue class="m-auto h-auto p-20px lt-xl:(rounded-3xl light:bg-white)" />-->
+            <!--            <SSOLoginVue class="m-auto h-auto p-20px lt-xl:(rounded-3xl light:bg-white)" />-->
             <!-- 忘记密码 -->
             <ForgetPasswordForm class="m-auto h-auto p-20px lt-xl:(rounded-3xl light:bg-white)" />
           </div>
@@ -75,8 +75,17 @@ import { useDesign } from '@/hooks/web/useDesign'
 import { useAppStore } from '@/store/modules/app'
 import { ThemeSwitch } from '@/layout/components/ThemeSwitch'
 import { LocaleDropdown } from '@/layout/components/LocaleDropdown'
+import * as dd from 'dingtalk-jsapi'
 
-import { LoginForm, MobileForm, QrCodeForm, RegisterForm, SSOLoginVue, ForgetPasswordForm } from './components'
+import { LoginForm, QrCodeForm, RegisterForm, ForgetPasswordForm } from './components'
+import { dingTalkLogin } from '../../api/login'
+
+import * as authUtil from '@/utils/auth'
+import { RouteLocationNormalizedLoaded } from 'vue-router'
+import { usePermissionStore } from '../../store/modules/permission'
+
+import * as LoginApi from '@/api/login'
+import { ElLoading } from 'element-plus'
 
 defineOptions({ name: 'Login' })
 
@@ -84,6 +93,92 @@ const { t } = useI18n()
 const appStore = useAppStore()
 const { getPrefixCls } = useDesign()
 const prefixCls = getPrefixCls('login')
+
+const loading = ref<any>(null)
+
+const redirect = ref<string>('')
+
+const router = useRouter()
+
+watch(
+  () => router.currentRoute.value,
+  (route: RouteLocationNormalizedLoaded) => {
+    redirect.value = route?.query?.redirect as string
+  },
+  {
+    immediate: true
+  }
+)
+
+const getTenantId = async () => {
+  if (import.meta.env.VITE_APP_TENANT_ENABLE === 'true') {
+    const res = await LoginApi.getTenantIdByName('芋道源码')
+    debugger
+    authUtil.setTenantId(res)
+  }
+}
+
+const permissionStore = usePermissionStore()
+
+async function loginWithDingTalk() {
+  const ddCorpId = import.meta.env.VITE_DD_CORPID
+  const ddClientId = import.meta.env.VITE_DD_CLIENTID
+
+  if (!ddCorpId || !ddClientId) return
+
+  await getTenantId()
+
+  dd.requestAuthCode({
+    corpId: ddCorpId,
+    clientId: ddClientId,
+    success: (res: any) => {
+      const { code } = res
+      dingTalkLogin({ code, type: 10, state: new Date().getTime() }).then(async (res) => {
+        console.log('res :>> ', res)
+        loading.value = ElLoading.service({
+          lock: true,
+          text: '正在加载系统中...',
+          background: 'rgba(0, 0, 0, 0.7)'
+        })
+
+        // authUtil.removeLoginForm()
+
+        authUtil.setToken(res)
+
+        if (!redirect.value) {
+          redirect.value = '/'
+        }
+        if (redirect.value.indexOf('sso') !== -1) {
+          window.location.href = window.location.href.replace('/login?redirect=', '')
+        } else {
+          router.push({ path: redirect.value || permissionStore.addRouters[0].path }).then(() => {
+            loading.value.close()
+          })
+        }
+      })
+    },
+    fail: (err: any) => {
+      console.log('err :>> ', err)
+    },
+    complete: () => {
+      console.log('11 :>> ', 11)
+    }
+  })
+}
+
+function dingTalkAutoLogin() {
+  const ua = window.navigator.userAgent.toLowerCase()
+
+  console.log('ua :>> ', ua)
+
+  if (!ua.includes('dingtalk') && !ua.includes('dingtalkwork')) return
+
+  loginWithDingTalk()
+}
+
+onMounted(() => {
+  dingTalkAutoLogin()
+})
 </script>
 
 <style lang="scss" scoped>
@@ -103,8 +198,8 @@ $prefix-cls: #{$namespace}-login;
       background-image: url('@/assets/imgs/yf.png');
       background-position: center;
       background-repeat: no-repeat;
+      background-size: cover; /* 关键:图片覆盖整个容器 */
       content: '';
-      background-size: cover;                 /* 关键:图片覆盖整个容器 */
     }
   }
 }

+ 2 - 1
src/views/Login/components/LoginForm.vue

@@ -263,11 +263,13 @@ const handleLogin = async (params: any) => {
     // if (!res) {
     //   return
     // }
+    console.log('res :>> ', res)
     loading.value = ElLoading.service({
       lock: true,
       text: '正在加载系统中...',
       background: 'rgba(0, 0, 0, 0.7)'
     })
+    console.log('loginDataLoginForm.rememberMe :>> ', loginDataLoginForm.rememberMe)
     if (loginDataLoginForm.rememberMe) {
       authUtil.setLoginForm(loginDataLoginForm)
     } else {
@@ -360,4 +362,3 @@ onMounted(() => {
   }
 }
 </style>
-

+ 103 - 51
src/views/pms/dingding.vue

@@ -1,64 +1,111 @@
-
 <template>
-  <div v-if="isMobileDevice&&!isDingTalk()" class="loading">跳转处理中...</div>
-<!--  <a ref="myLink" :href="href" v-show="false">跳转app</a>-->
-<!--  <div v-if="isMobileDevice()&&isDingTalk()" class="wxtip" id="JweixinTip">-->
-<!--    <span class="wxtip-icon"></span>-->
-<!--  </div>-->
+  <div v-if="isMobileDevice() && !isDingTalk()" class="loading">跳转处理中...</div>
+  <!--  <a ref="myLink" :href="href" v-show="false">跳转app</a>-->
+  <!--  <div v-if="isMobileDevice()&&isDingTalk()" class="wxtip" id="JweixinTip">-->
+  <!--    <span class="wxtip-icon"></span>-->
+  <!--  </div>-->
 </template>
 
 <script setup lang="ts">
 import { onMounted } from 'vue'
 import { useRouter, useRoute } from 'vue-router'
-import * as LoginApi from "@/api/login";
-import * as authUtil from "@/utils/auth";
+import * as LoginApi from '@/api/login'
+import * as authUtil from '@/utils/auth'
 
 const { push } = useRouter()
 const route = useRoute()
 
 // 设备检测
 const isMobileDevice = (): boolean => {
-  const userAgentInfo = navigator.userAgent;
-  const mobileAgents = ["Android", "iPhone", "SymbianOS", "Windows Phone", "iPad", "iPod","OpenHarmony"];
+  const userAgentInfo = navigator.userAgent
+
+  const mobileAgents = [
+    'Android',
+    'iPhone',
+    'SymbianOS',
+    'Windows Phone',
+    'iPad',
+    'iPod',
+    'OpenHarmony'
+  ]
 
   const mobileFlag = mobileAgents.some((mobileAgent) => {
-    return userAgentInfo.indexOf(mobileAgent) > 0;
-  });
+    return userAgentInfo.indexOf(mobileAgent) > 0
+  })
 
-  return mobileFlag;
+  return mobileFlag
 }
 
 // 判断是否是钉钉环境
 const isDingTalk = (): boolean => {
-  const userAgent = navigator.userAgent.toLowerCase();
-  return userAgent.includes('dingtalk');
+  const userAgent = navigator.userAgent.toLowerCase()
+  return userAgent.includes('dingtalk')
 }
 
 // 业务路由映射
 const businessRoutes: Record<string, string> = {
-  'generateInspect': 'InspectOrderWrite',
-  'failureReport': 'BpmProcessInstanceDetail',
-  'maintainOut': 'BpmProcessInstanceDetail',
-  'generateOperation' :'',
-  'generateMaintenance' : '',
-  'generateMaintain':''
+  generateInspect: 'InspectOrderWrite',
+  failureReport: 'BpmProcessInstanceDetail',
+  maintainOut: 'BpmProcessInstanceDetail',
+  generateOperation: '',
+  generateMaintenance: '',
+  generateMaintain: '',
+  rdReportApproval: 'rdReportApproval'
 }
 
-const href = ref('')
-const myLink = ref(null);
+// const href = ref('')
+// const myLink = ref(null)
 
-const clickA = () =>{
-  myLink.value.click();
-}
+// const clickA = () => {
+//   myLink.value?.click()
+// }
 
 onMounted(async () => {
-  let { type = '', id = '', userId='', deptId='',createTime='',orderStatus='',orderName='',userName='' } = route.query
+  let {
+    type = '',
+    id = '',
+    userId = '',
+    deptId = '',
+    createTime = '',
+    orderStatus = '',
+    orderName = '',
+    userName = ''
+  } = route.query
+
   const isValidType = Object.keys(businessRoutes).includes(type as string)
+
   if (isMobileDevice()) {
-    if (type==='generateOperation') {
-      window.location.href = import.meta.env.VITE_BASE_URL + '/deepoil/#/?type=' + type+'&id='+id+'&userId='+userId+'&deptId='+deptId+'&createTime='+createTime+'&orderStatus='+orderStatus+'&orderName='+orderName+'&userName='+userName;
-    }else {
-      window.location.href = import.meta.env.VITE_BASE_URL + '/deepoil/#/?type=' + type+'&id='+id+'&userId='+userId;
+    if (type === 'generateOperation') {
+      window.location.href =
+        import.meta.env.VITE_BASE_URL +
+        '/deepoil/#/?type=' +
+        type +
+        '&id=' +
+        id +
+        '&userId=' +
+        userId +
+        '&deptId=' +
+        deptId +
+        '&createTime=' +
+        createTime +
+        '&orderStatus=' +
+        orderStatus +
+        '&orderName=' +
+        orderName +
+        '&userName=' +
+        userName
+    } else if (type === 'rdReportApproval') {
+      window.location.href =
+        import.meta.env.VITE_BASE_URL + '/deepoil/#/pages/ruiDu/approval?id=' + id
+    } else {
+      window.location.href =
+        import.meta.env.VITE_BASE_URL +
+        '/deepoil/#/?type=' +
+        type +
+        '&id=' +
+        id +
+        '&userId=' +
+        userId
     }
     // 移动端跳转deepoil协议
     // try{
@@ -72,17 +119,17 @@ onMounted(async () => {
     //   setTimeout(clickA,1000)
     // })
   } else if (isValidType) {
-    authUtil.setTenantId(1)
+    authUtil.setTenantId('1')
     const res = await LoginApi.simpleLogin(userId)
     if (!res) {
       return
     }
+
     authUtil.setToken(res)
     // PC端路由跳转
-    debugger
     if (type === 'generateInspect') {
-      push({ name:'InspectOrderWrite', params:{id} })
-    }else if(type === 'failureReport') {
+      push({ name: 'InspectOrderWrite', params: { id } })
+    } else if (type === 'failureReport') {
       push({
         name: 'BpmProcessInstanceDetail',
         query: {
@@ -91,7 +138,7 @@ onMounted(async () => {
       })
     } else if (type === 'generateMaintain') {
       debugger
-      push({ name: 'MaintainEdit', params: {id } })
+      push({ name: 'MaintainEdit', params: { id } })
     } else if (type === 'maintainOut') {
       push({
         name: 'BpmProcessInstanceDetail',
@@ -99,13 +146,13 @@ onMounted(async () => {
           id: id
         }
       })
-    } else if(type === 'generateOperation'){
+    } else if (type === 'generateOperation') {
       // push({
       //   name: 'FillOrderInfo',
       //   params: { deptId,userId,createTime,id,orderStatus }
       // })
-      id = deptId+','+userId+','+createTime+','+id+','+orderStatus
-      push({ name: 'FillOrderInfo',params:{id}})
+      id = deptId + ',' + userId + ',' + createTime + ',' + id + ',' + orderStatus
+      push({ name: 'FillOrderInfo', params: { id } })
     } else if (type === 'generateMaintenance') {
       push({
         name: 'IotMainWorkOrderBom',
@@ -116,47 +163,52 @@ onMounted(async () => {
         name: 'FillDailyReportForm',
         params: { id: id, mode: 'fill' }
       })
+    } else if (type === 'rdReportApproval') {
+      push({
+        name: 'DailyReportApprovalForm',
+        params: { id }
+      })
     }
   } else {
     // 默认跳转
-    push({ name:'Login' })
+    push({ name: 'Login' })
   }
 })
-
 </script>
 
 <style scoped>
 .loading {
-  text-align: center;
   padding-top: 100px;
   font-size: 16px;
   color: #666;
+  text-align: center;
 }
+
 .wxtip {
-  background: rgba(0, 0, 0, 0.8);
-  text-align: center;
   position: fixed;
-  left: 0;
   top: 0;
-  width: 100%;
-  height: 100%;
+  left: 0;
   z-index: 998;
   display: block;
+  width: 100%;
+  height: 100%;
+  text-align: center;
+  background: rgb(0 0 0 / 80%);
 }
 
 .wxtip-icon {
+  position: absolute;
+  display: block;
   width: 100%;
   height: 100%;
-  background: url(@/assets/imgs/bgzz.png) center center no-repeat;
+  background: url('@/assets/imgs/bgzz.png') center center no-repeat;
   background-size: cover; /* 新增样式,使背景图片覆盖整个元素 */
-  display: block;
-  position: absolute;
 }
 
 .wxtip-txt {
   margin-top: 107px;
-  color: #fff;
   font-size: 16px;
   line-height: 1.5;
+  color: #fff;
 }
 </style>

+ 17 - 14
src/views/pms/iotprojectinfo/IotProjectInfoForm.vue

@@ -45,20 +45,6 @@
           </el-form-item>
         </el-col>
       </el-row>
-      <!--
-      <el-row>
-        <el-col :span="12">
-          <el-form-item label="总数" prop="workloadTotal">
-            <el-input v-model="formData.workloadTotal" placeholder="请输入工作量总数" />
-          </el-form-item>
-        </el-col>
-        <el-col :span="12">
-          <el-form-item label="已完成" prop="workloadFinish">
-            <el-input v-model="formData.workloadFinish" placeholder="已完成工作量" disabled/>
-          </el-form-item>
-        </el-col>
-      </el-row>
-      -->
       <el-row>
         <el-col :span="12">
           <el-form-item label="开始时间" prop="startTime">
@@ -177,7 +163,22 @@
             </div>
           </el-form-item>
         </el-col>
+
         <el-col :span="12">
+          <el-form-item label="虚拟项目" prop="contractSubject">
+            <el-switch
+              v-model="formData.contractSubject"
+              active-value="Y"
+              inactive-value="N"
+              active-text="是"
+              inactive-text="否"
+            />
+          </el-form-item>
+        </el-col>
+      </el-row>
+
+      <el-row>
+        <el-col :span="24">
           <el-form-item label="备注" prop="remark">
             <el-input v-model="formData.remark" placeholder="请输入备注" type="textarea" />
           </el-form-item>
@@ -286,6 +287,7 @@ const formData = ref({
   deptName: undefined,
   contractName: undefined,
   contractCode: undefined,
+  contractSubject: 'N', // 添加虚拟项目字段,默认值为'N'
   workloadTotal: undefined,
   workloadFinish: undefined,
   startTime: undefined,
@@ -587,6 +589,7 @@ const resetForm = () => {
     deptName: undefined,
     contractName: undefined,
     contractCode: undefined,
+    contractSubject: 'N', // 重置时设置默认值
     workloadTotal: undefined,
     workloadFinish: undefined,
     startTime: undefined,

Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 654 - 101
src/views/pms/iotprojecttask/IotProjectTaskForm.vue


+ 21 - 6
src/views/pms/iotprojecttask/index.vue

@@ -23,9 +23,9 @@
           />
         </el-select>
       </el-form-item>
-      <el-form-item label="客户名称" prop="project_name">
+      <el-form-item label="客户名称" prop="manufactureName">
         <el-input
-          v-model="queryParams.projectId"
+          v-model="queryParams.manufactureName"
           placeholder="请输入客户名称"
           clearable
           @keyup.enter="handleQuery"
@@ -59,6 +59,19 @@
           class="!w-240px"
         />
       </el-form-item>
+      <el-form-item label="平台井" prop="platformFlag">
+        <el-select
+          v-model="queryParams.platformFlag"
+          placeholder="请选择平台井"
+          clearable
+          class="!w-240px"
+          @change="handleQuery"
+        >
+          <el-option label="全部" value="A" />
+          <el-option label="是" value="Y" />
+          <el-option label="否" value="N" />
+        </el-select>
+      </el-form-item>
       <el-form-item label="创建时间" prop="createTime">
         <el-date-picker
           v-model="queryParams.createTime"
@@ -108,20 +121,20 @@
         <el-table-column label="合同名称" align="center" prop="contractName" :width="columnWidths.contractName" show-overflow-tooltip/>
         <el-table-column label="合同编号" align="center" prop="contractCode" :width="columnWidths.contractCode" />
         <el-table-column label="井号" align="center" prop="wellName" :width="columnWidths.wellName" />
-        <!-- <el-table-column label="井型/井别" align="center" prop="wellType" /> -->
+        <!-- <el-table-column label="井型/井别" align="center" prop="wellType" />
         <el-table-column :label="t('project.wellType')" align="center" prop="wellType" :width="columnWidths.wellType">
           <template #default="scope">
             <dict-tag :type="DICT_TYPE.PMS_PROJECT_WELL_TYPE" :value="scope.row.wellType" />
           </template>
-        </el-table-column>
+        </el-table-column> -->
         <el-table-column label="施工地点" align="center" prop="location" :width="columnWidths.location" />
         <el-table-column label="施工队伍" align="center" prop="deptNames" :width="columnWidths.deptNames" />
-        <el-table-column :label="t('project.technology')" align="center" prop="technique" :width="columnWidths.technique">
+        <!-- <el-table-column :label="t('project.technology')" align="center" prop="technique" :width="columnWidths.technique">
           <template #default="scope">
             <dict-tag :type="DICT_TYPE.PMS_PROJECT_TECHNOLOGY" :value="scope.row.technique" />
           </template>
         </el-table-column>
-        <el-table-column label="设计工作量" align="center" prop="workloadDesign" :width="columnWidths.workloadDesign"/>
+        <el-table-column label="设计工作量" align="center" prop="workloadDesign" :width="columnWidths.workloadDesign"/> -->
         <el-table-column
           label="创建时间"
           align="center"
@@ -285,6 +298,8 @@ const queryParams = reactive({
   createTime: [],
   userName: undefined,
   userId: undefined,
+  manufactureName: '',
+  platformFlag: '',
   remark: undefined,
 })
 

+ 2105 - 0
src/views/pms/iotrddailyreport/DailyReportApprovalForm.vue

@@ -0,0 +1,2105 @@
+<template>
+  <ContentWrap v-loading="formLoading">
+    <!-- 第一部分:日报标题 -->
+    <div class="daily-report-title">
+      <h2>{{ pageTitle  }}</h2>
+      <!-- 在审批模式下显示审批状态提示 -->
+      <div v-if="isReadonlyMode" class="approval-notice">
+        <el-alert :title="modeNotice" type="info" :closable="false" />
+      </div>
+    </div>
+
+    <!-- 第二部分:项目/任务信息 -->
+    <ContentWrap>
+      <div class="info-table" style="margin-top: 1em">
+        <!-- 表格行 -->
+        <div class="table-row">
+          <div class="table-cell">
+            <div class="cell-content">
+              <span class="cell-label">甲方:</span>
+              <!-- 甲方字段:添加 single-line-ellipsis 类 + title 绑定完整内容 -->
+              <span
+                class="cell-value single-line-ellipsis"
+                :title="dailyReportData.manufactureName || '-'"
+              >
+              {{ dailyReportData.manufactureName || '-' }}
+            </span>
+            </div>
+          </div>
+          <div class="table-cell">
+            <div class="cell-content">
+              <span class="cell-label">合同号:</span>
+              <span class="cell-value">{{ dailyReportData.contractName || '-' }}</span>
+            </div>
+          </div>
+          <div class="table-cell">
+            <div class="cell-content">
+              <span class="cell-label">井号:</span>
+              <span class="cell-value">{{ dailyReportData.wellName || dailyReportData.taskName || '-' }}</span>
+            </div>
+          </div>
+        </div>
+
+        <div class="table-row">
+          <div class="table-cell">
+            <div class="cell-content">
+              <span class="cell-label">施工队伍:</span>
+              <span class="cell-value">{{ dailyReportData.deptName || '-' }}</span>
+            </div>
+          </div>
+          <div class="table-cell">
+            <div class="cell-content">
+              <span class="cell-label">施工地点:</span>
+              <span class="cell-value">{{ dailyReportData.location || '-' }}</span>
+            </div>
+          </div>
+          <div class="table-cell">
+            <div class="cell-content">
+              <span class="cell-label">工艺:</span>
+              <span class="cell-value">{{ dailyReportData.techniqueNames || '-' }}</span>
+            </div>
+          </div>
+        </div>
+
+        <div class="table-row">
+          <div class="table-cell">
+            <div class="cell-content">
+              <span class="cell-label">搬迁日期:</span>
+              <span class="cell-value">{{ formatDate(dailyReportData.dpDate) || '-' }}</span>
+            </div>
+          </div>
+          <div class="table-cell">
+            <div class="cell-content">
+              <span class="cell-label">开工日期:</span>
+              <span class="cell-value">{{ formatDate(dailyReportData.sgDate) || '-' }}</span>
+            </div>
+          </div>
+          <div class="table-cell">
+            <div class="cell-content">
+              <span class="cell-label">完工日期:</span>
+              <span class="cell-value">{{ formatDate(dailyReportData.wgDate) || '-' }}</span>
+            </div>
+          </div>
+        </div>
+
+        <div class="table-row">
+          <div class="table-cell">
+            <div class="cell-content">
+              <span class="cell-label">施工周期D:</span>
+              <span class="cell-value">{{ constructionPeriod || 0 }}</span>
+            </div>
+          </div>
+          <div class="table-cell">
+            <div class="cell-content">
+              <span class="cell-label">停待时间D:</span>
+              <span class="cell-value">{{ dailyReportData.faultDowntime || 0 }}</span>
+            </div>
+          </div>
+          <div class="table-cell">
+            <div class="cell-content">
+              <span class="cell-label">带班干部:</span>
+              <span class="cell-value">{{ dailyReportData.responsiblePersonNames || '-' }}</span>
+            </div>
+          </div>
+        </div>
+
+        <!-- 第五行:设备配置(单独一行) -->
+        <div class="table-row">
+          <div class="table-cell full-width">
+            <div class="cell-content">
+              <span class="cell-label">设备配置:</span>
+              <span class="cell-value indent-multiline">{{ dailyReportData.deviceNames || '-' }}</span>
+            </div>
+          </div>
+        </div>
+      </div>
+    </ContentWrap>
+
+    <!-- 第三部分:日报填报表单 -->
+    <ContentWrap class="section-padding">
+      <el-form
+        ref="formRef"
+        :model="formData"
+        :rules="isReadonlyMode ? {} : formRules"
+        v-loading="formLoading"
+        style="margin-top: 1em"
+        label-width="200px"
+        :disabled="isReadonlyMode"
+      >
+        <!-- 第一行:时间节点、施工状态 -->
+        <el-row :gutter="30">
+          <el-col :span="12">
+            <el-form-item label="时间节点" prop="timeRange">
+              <el-time-picker
+                is-range
+                v-model="formData.timeRange"
+                range-separator="至"
+                start-placeholder="开始时间"
+                end-placeholder="结束时间"
+                placeholder="选择时间范围"
+                style="width: 100%"
+                :readonly="isReadonlyMode"
+                :disabled="isReadonlyMode"
+              />
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="施工状态" prop="rdStatus">
+              <el-select v-model="formData.rdStatus" placeholder="请选择施工状态"
+                         style="width: 100%" :disabled="isReadonlyMode">
+                <el-option
+                  v-for="dict in rdStatusOptions"
+                  :key="dict.value"
+                  :label="dict.label"
+                  :value="dict.value"
+                />
+              </el-select>
+            </el-form-item>
+          </el-col>
+        </el-row>
+
+        <!-- 平台井 -->
+        <el-row v-if="showPlatformField">
+          <el-col :span="24">
+            <el-form-item label="平台井" prop="platformId">
+              <el-select
+                v-model="formData.platformId"
+                placeholder="请选择平台井"
+                style="width: 100%"
+                :disabled="isReadonlyMode"
+              >
+                <el-option
+                  v-for="platform in platformOptions"
+                  :key="platform.id"
+                  :label="platform.wellName"
+                  :value="platform.id"
+                />
+              </el-select>
+            </el-form-item>
+          </el-col>
+        </el-row>
+
+        <!-- 施工设备字段 -->
+        <el-row>
+          <el-col :span="24">
+            <el-form-item label="施工设备" prop="deviceIds">
+              <!-- 编辑模式:显示选择按钮 -->
+              <template v-if="isEditMode">
+                <el-button
+                  @click="openDeviceDialog"
+                  type="primary"
+                  size="small"
+                  :disabled="formLoading"
+                >
+                  选择设备
+                </el-button>
+                <el-tooltip
+                  v-if="formData.deviceIds && formData.deviceIds.length > 0"
+                  :content="getAllDeviceNamesForDisplay"
+                  placement="top"
+                >
+                <span class="device-display-container">
+                  {{ formatDevicesForDisplay }}
+                </span>
+                </el-tooltip>
+                <span v-else class="no-device">
+                  未选择设备
+                </span>
+              </template>
+
+              <!-- 只读模式:只显示设备信息 -->
+              <template v-else>
+                <el-tooltip
+                  v-if="formData.deviceIds && formData.deviceIds.length > 0"
+                  :content="getAllDeviceNamesForDisplay"
+                  placement="top"
+                >
+                <span class="device-display-container">
+                  {{ formatDevicesForDisplay }}
+                </span>
+                </el-tooltip>
+                <span v-else class="no-device">-</span>
+              </template>
+            </el-form-item>
+          </el-col>
+        </el-row>
+
+        <!-- 未施工设备 -->
+        <el-row>
+          <el-col :span="24">
+            <el-form-item label="未施工设备" prop="unSelectedDeviceNames">
+              <el-input
+                v-model="unSelectedDeviceNames"
+                type="textarea"
+                :rows="2"
+                placeholder="未施工的设备将显示在这里"
+                :readonly="true"
+                class="unselected-device"
+              />
+            </el-form-item>
+          </el-col>
+        </el-row>
+
+        <!-- 第二行:施工工艺 -->
+        <el-row>
+          <el-col :span="24">
+            <el-form-item label="施工工艺" prop="techniqueIds">
+              <el-select v-model="formData.techniqueIds" placeholder="请选择施工工艺"
+                         style="width: 100%" multiple :disabled="isReadonlyMode">
+                <el-option
+                  v-for="dict in techniqueOptions"
+                  :key="dict.value"
+                  :label="dict.label"
+                  :value="dict.value"
+                />
+              </el-select>
+            </el-form-item>
+          </el-col>
+        </el-row>
+
+        <!-- 动态属性区域:施工工艺与当日生产动态之间 -->
+        <el-row v-if="dynamicAttrs.length > 0" :gutter="30">
+          <el-col
+            v-for="attr in dynamicAttrs"
+            :key="attr.id"
+            :span="attr.dataType === 'textarea' ? 24 : 12"
+          >
+            <el-form-item
+              :label="attr.name + (attr.unit ? `(${attr.unit})` : '')"
+              :prop="'dynamicFields.' + attr.identifier"
+              :rules="isReadonlyMode ? [] : getDynamicAttrRules(attr)"
+            >
+              <!-- 文本类型 -->
+              <el-input
+                v-if="attr.dataType === 'text'"
+                v-model="formData.dynamicFields[attr.identifier]"
+                :placeholder="`请输入${attr.name}`"
+                :readonly="isReadonlyMode"
+              />
+
+              <!-- 文本域类型 -->
+              <el-input
+                v-else-if="attr.dataType === 'textarea'"
+                v-model="formData.dynamicFields[attr.identifier]"
+                :placeholder="`请输入${attr.name}`"
+                type="textarea"
+                :rows="3"
+                :readonly="isReadonlyMode"
+              />
+
+              <!-- 数字类型 -->
+              <el-input
+                v-else-if="attr.dataType === 'double'"
+                v-model="formData.dynamicFields[attr.identifier]"
+                :placeholder="`请输入${attr.name}`"
+                type="number"
+                :min="attr.minValue || undefined"
+                :max="attr.maxValue || undefined"
+                :readonly="isReadonlyMode"
+              />
+
+              <!-- 日期类型 -->
+              <el-date-picker
+                v-else-if="attr.dataType === 'date'"
+                v-model="formData.dynamicFields[attr.identifier]"
+                type="date"
+                value-format="x"
+                :placeholder="`选择${attr.name}`"
+                style="width: 100%"
+                :readonly="isReadonlyMode"
+              />
+
+              <!-- 默认文本输入 -->
+              <el-input
+                v-else
+                v-model="formData.dynamicFields[attr.identifier]"
+                :placeholder="`请输入${attr.name}`"
+                :readonly="isReadonlyMode"
+              />
+            </el-form-item>
+          </el-col>
+        </el-row>
+
+        <!-- 第三行:当日生产动态 -->
+        <el-row>
+          <el-col :span="24">
+            <el-form-item label="当日生产动态" prop="productionStatus">
+              <el-input
+                v-model="formData.productionStatus"
+                type="textarea"
+                :rows="3"
+                placeholder="请输入当日生产动态"
+                :readonly="isReadonlyMode"
+              />
+            </el-form-item>
+          </el-col>
+        </el-row>
+
+        <!-- 第四行:下步工作计划 -->
+        <el-row>
+          <el-col :span="24">
+            <el-form-item label="下步工作计划" prop="nextPlan">
+              <el-input
+                v-model="formData.nextPlan"
+                type="textarea"
+                :rows="3"
+                placeholder="请输入下步工作计划"
+                :readonly="isReadonlyMode"
+              />
+            </el-form-item>
+          </el-col>
+        </el-row>
+
+        <!-- 第五行:外租设备 -->
+        <el-row>
+          <el-col :span="24">
+            <el-form-item label="外租设备" prop="externalRental">
+              <el-input
+                v-model="formData.externalRental"
+                type="textarea"
+                :rows="3"
+                placeholder="请输入外租设备信息"
+                :readonly="isReadonlyMode"
+              />
+            </el-form-item>
+          </el-col>
+        </el-row>
+
+        <!-- 故障情况 -->
+        <el-row>
+          <el-col :span="24">
+            <el-form-item label="故障情况" prop="malfunction">
+              <el-input
+                v-model="formData.malfunction"
+                type="textarea"
+                :rows="3"
+                placeholder="请输入故障情况"
+                :readonly="isReadonlyMode"
+              />
+            </el-form-item>
+          </el-col>
+        </el-row>
+
+        <!-- 故障误工H -->
+        <el-row>
+          <el-col :span="24">
+            <el-form-item label="故障误工H" prop="faultDowntime">
+              <el-input
+                v-model="formData.faultDowntime"
+                type="number"
+                :rows="3"
+                placeholder="请输入故障误工H"
+                :readonly="isReadonlyMode"
+              />
+            </el-form-item>
+          </el-col>
+        </el-row>
+
+        <!-- 第六行:上传附件 -->
+        <el-row>
+          <el-col :span="24">
+            <el-form-item label="附件">
+              <!-- 文件上传组件 -->
+              <FileUpload
+                v-if="!isReadonlyMode"
+                ref="fileUploadRef"
+                :device-id="deviceId"
+                :show-folder-button="false"
+                @upload-success="handleUploadSuccess"
+              />
+
+              <!-- 已上传附件列表显示 -->
+              <div v-if="formData.attachments && formData.attachments.length > 0" class="attachment-container">
+                <div class="attachment-list">
+                  <div
+                    v-for="(attachment, index) in formData.attachments"
+                    :key="attachment.id || index"
+                    class="attachment-item"
+                  >
+                    <!-- 为附件名称添加点击事件,传递整个附件对象 -->
+                    <a class="attachment-name" @click="inContent(attachment)">
+                      {{ attachment.filename }}
+                    </a>
+                    <el-button
+                      v-if="!isReadonlyMode"
+                      type="danger"
+                      link
+                      size="small"
+                      @click="removeAttachment(index)"
+                    >
+                      删除
+                    </el-button>
+                  </div>
+                </div>
+              </div>
+
+              <!-- 审批模式下只显示附件列表 -->
+              <div v-else-if="isApprovalMode && (!formData.attachments || formData.attachments.length === 0)" class="no-attachment">
+                无附件
+              </div>
+            </el-form-item>
+          </el-col>
+        </el-row>
+
+      </el-form>
+    </ContentWrap>
+
+    <!-- 平台井工作量区域 - 只在平台井的详情或审批模式下显示 -->
+    <ContentWrap class="platform-workload-section" v-if="(isDetailMode || isApprovalMode) && dailyReportData?.platformWell === 1">
+      <h2 class="text-lg font-semibold mb-4">平台井工作量</h2>
+
+      <div class="platform-workload-table" v-if="dailyReportData?.platforms && dailyReportData.platforms.length > 0">
+        <el-table :data="dailyReportData.platforms" border style="width: 100%" class="platform-workload-el-table" table-layout="fixed">
+          <!-- 固定列 -->
+          <el-table-column prop="wellName" label="井号" align="center" :show-overflow-tooltip="true"/>
+          <el-table-column label="施工状态" align="center" :show-overflow-tooltip="true">
+            <template #default="scope">
+              {{ scope.row.rdStatusLabel || '' }}
+            </template>
+          </el-table-column>
+          <el-table-column label="施工工艺" align="center" :show-overflow-tooltip="true">
+            <template #default="scope">
+              {{ scope.row.techniqueNames || '' }}
+            </template>
+          </el-table-column>
+
+          <!-- 动态工作量列 -->
+          <el-table-column
+            v-for="workloadColumn in getWorkloadColumns()"
+            :key="workloadColumn.key"
+            :label="workloadColumn.label"
+            align="center"
+            :show-overflow-tooltip="true" >
+            <template #default="scope">
+              {{ getWorkloadValue(scope.row, workloadColumn.identifier) }}
+            </template>
+          </el-table-column>
+        </el-table>
+      </div>
+
+      <div v-else class="text-center text-gray-500 py-4">
+        暂无平台井工作量数据
+      </div>
+    </ContentWrap>
+
+    <!-- 第四部分:审批意见 - 只在审批模式下显示 -->
+    <ContentWrap class="section-padding" v-if="isApprovalMode">
+      <el-form
+        ref="approvalFormRef"
+        :model="approvalForm"
+        style="margin-top: 1em"
+        label-width="200px"
+      >
+        <el-row>
+          <el-col :span="24">
+            <el-form-item label="审批意见" prop="opinion">
+              <el-input
+                v-model="approvalForm.opinion"
+                type="textarea"
+                :rows="4"
+                placeholder="请输入审批意见"
+                maxlength="500"
+                show-word-limit
+              />
+            </el-form-item>
+          </el-col>
+        </el-row>
+      </el-form>
+    </ContentWrap>
+
+    <!-- 操作按钮 -->
+    <ContentWrap class="section-padding" v-if="isEditMode">
+      <el-form>
+        <el-form-item style="float: right">
+          <el-button @click="submitForm" type="primary" :disabled="formLoading">
+            {{ t('common.save') }}
+          </el-button>
+          <el-button @click="close">{{ t('common.cancel') }}</el-button>
+        </el-form-item>
+      </el-form>
+    </ContentWrap>
+
+    <!-- 审批模式下的操作按钮 -->
+    <ContentWrap class="section-padding" v-if="isApprovalMode">
+      <el-form>
+        <el-form-item style="float: right">
+          <el-button @click="handleApprove('pass')" type="success">
+            审批通过
+          </el-button>
+          <el-button @click="handleApprove('reject')" type="danger">
+            审批驳回
+          </el-button>
+          <el-button @click="close">{{ t('common.close') }}</el-button>
+        </el-form-item>
+      </el-form>
+    </ContentWrap>
+
+    <!-- 详情模式下的操作按钮 - 只有关闭按钮 -->
+    <ContentWrap class="section-padding" v-if="isDetailMode">
+      <el-form>
+        <el-form-item style="float: right">
+          <el-button @click="close">{{ t('common.close') }}</el-button>
+        </el-form-item>
+      </el-form>
+    </ContentWrap>
+
+  </ContentWrap>
+
+  <!-- 设备选择对话框 -->
+  <el-dialog
+    v-model="deviceDialogVisible"
+    title="选择施工设备"
+    width="1000px"
+    :before-close="handleDeviceDialogClose"
+    class="device-select-dialog"
+  >
+    <div class="transfer-container">
+      <el-transfer
+        v-model="selectedDeviceIds"
+        :data="filteredDeviceList"
+        :titles="['可选设备', '已选设备']"
+        :props="{ key: 'id', label: 'deviceCode' }"
+        filterable
+        class="transfer-component"
+        @change="handleTransferChange"
+      >
+        <template #default="{ option }">
+          <el-tooltip
+            effect="dark"
+            placement="top"
+            :content="`${option.deviceCode || ''} - ${option.deviceName || ''}`"
+            :disabled="!option.deviceCode && !option.deviceName"
+            transition="fade-in-linear"
+          >
+          <span class="transfer-option-text">
+            {{ option.deviceCode }} - {{ option.deviceName }}
+          </span>
+          </el-tooltip>
+        </template>
+      </el-transfer>
+    </div>
+    <template #footer>
+    <span class="dialog-footer">
+      <el-button @click="handleDeviceDialogClose">取消</el-button>
+      <el-button type="primary" @click="confirmDeviceSelection">确定</el-button>
+    </span>
+    </template>
+  </el-dialog>
+
+</template>
+
+<script setup lang="ts">
+import { ref, reactive, computed, onMounted, nextTick, watch } from 'vue'
+import { useI18n } from '@/hooks/web/useI18n'
+import { useMessage } from '@/hooks/web/useMessage'
+import { useTagsViewStore } from '@/store/modules/tagsView'
+import { useRouter } from 'vue-router'
+import {DICT_TYPE, getDictLabel, getStrDictOptions} from '@/utils/dict'
+import { IotRdDailyReportApi } from '@/api/pms/iotrddailyreport'
+import { IotDailyReportAttrsApi } from '@/api/pms/iotdailyreportattrs'
+import * as DeptApi from '@/api/system/dept'
+import { useUserStore } from '@/store/modules/user'
+import dayjs from 'dayjs'
+import FileUpload from "@/components/UploadFile/src/FileUpload.vue";
+
+const { t } = useI18n()
+const message = useMessage()
+const { delView } = useTagsViewStore()
+const { push, currentRoute } = useRouter()
+const { params } = useRoute()
+const userStore = useUserStore()
+
+/** 填报日报 表单 */
+defineOptions({ name: 'DailyReportApprovalForm' })
+
+const formLoading = ref(false)
+const formRef = ref()
+const id = params.id // 瑞都日报id
+const mode = 'approval'
+// 日报数据
+const dailyReportData = ref<any>({})
+
+// 添加模式判断计算属性 此处 固定为 审批页面
+const isApprovalMode = computed(() => mode === 'approval')
+const isDetailMode = computed(() => mode === 'edit')
+const isEditMode = computed(() => mode === 'fill') // 默认为编辑模式
+
+// 只读模式判断:审批模式或详情模式都为只读
+const isReadonlyMode = computed(() => isApprovalMode.value || isDetailMode.value)
+
+// 在表单数据定义附近添加
+const platformWellPairs = ref<any[]>([]) // 存储各平台井的工作量数据
+const currentPlatformId = ref<number>() // 当前选中的平台井ID
+
+// 页面标题计算
+const pageTitle = computed(() => {
+  if (isApprovalMode.value) {
+    return dailyReportData.value.wellName && dailyReportData.value.constructionStartDate
+      ? `${dailyReportData.value.wellName} - ${formatDate(dailyReportData.value.constructionStartDate)} 日报审批`
+      : '日报审批'
+  } else if (isDetailMode.value) {
+    return dailyReportData.value.wellName && dailyReportData.value.constructionStartDate
+      ? `${dailyReportData.value.wellName} - ${formatDate(dailyReportData.value.constructionStartDate)} 日报详情`
+      : '日报详情'
+  } else {
+    return dailyReportData.value.wellName && dailyReportData.value.constructionStartDate
+      ? `${dailyReportData.value.wellName} - ${formatDate(dailyReportData.value.constructionStartDate)} 生产日报`
+      : '日报填报'
+  }
+})
+
+// 模式提示信息
+const modeNotice = computed(() => {
+  if (isApprovalMode.value) {
+    return '审批模式:所有字段均为只读'
+  } else if (isDetailMode.value) {
+    return '详情模式:所有字段均为只读'
+  }
+  return ''
+})
+
+// 动态属性相关变量
+const dynamicAttrs = ref<any[]>([]) // 存储动态属性列表
+
+// 添加设备选择相关变量
+const deviceDialogVisible = ref(false)
+const filteredDeviceList = ref<any[]>([])
+const selectedDeviceIds = ref<number[]>([])
+const deviceMap = ref<Record<number, any>>({})
+
+// 添加平台井相关响应式数据
+const platformOptions = ref<any[]>([]) // 平台井下拉选项
+const showPlatformField = ref(false) // 是否显示平台井字段
+
+// 计算属性:是否显示平台井字段
+const shouldShowPlatformField = computed(() => {
+  return dailyReportData.value.platformWell === 1
+})
+
+// 初始化平台井数据
+const initPlatformData = (reportData: any) => {
+  // 设置是否显示平台井字段
+  showPlatformField.value = reportData.platformWell === 1
+
+  // 设置平台井下拉选项
+  if (reportData.platforms && Array.isArray(reportData.platforms)) {
+    platformOptions.value = reportData.platforms
+
+    // 初始化 platformWellPairs,确保包含所有平台井的完整数据
+    if (reportData.platformWell === 1) {
+      // 初始化 platformWellPairs,包含所有平台井的完整数据
+      platformWellPairs.value = reportData.platforms.map((platform: any) => {
+        // 查找是否已有该平台井的数据
+        const existingData = reportData.platformWellPairs?.find((p: any) => p.taskId === platform.id)
+
+        // 确保 techniqueIds 是字符串数组格式
+        let techniqueIds = []
+        if (existingData && existingData.techniqueIds) {
+          techniqueIds = existingData.techniqueIds.map((id: any) => id.toString())
+        } else if (platform.techniqueIds) {
+          techniqueIds = platform.techniqueIds.map((id: any) => id.toString())
+        }
+
+        return existingData || {
+          taskId: platform.id,
+          reportId: platform.reportId, // 使用接口返回的 reportId
+          wellName: platform.wellName,
+          rdStatus: platform.rdStatus || '', // 初始为空
+          techniqueIds: techniqueIds, // 初始为空数组
+          extProperty: platform.extProperty || [] // 初始为空数组
+        }
+      })
+    }
+  } else {
+    platformOptions.value = []
+    platformWellPairs.value = []
+  }
+
+  // 设置默认选中的平台井
+  if (reportData.taskId && platformOptions.value.length > 0) {
+    // 查找与 taskId 匹配的平台井
+    const defaultPlatform = platformOptions.value.find(
+      (platform: any) => platform.id === reportData.taskId
+    )
+    if (defaultPlatform) {
+      formData.value.platformId = defaultPlatform.id
+      currentPlatformId.value = defaultPlatform.id
+
+      // 加载默认平台井的数据到表单
+      loadPlatformData(defaultPlatform.id)
+    }
+  }
+}
+
+// 添加审批表单相关变量
+const approvalFormRef = ref()
+const approvalForm = reactive({
+  opinion: '' // 审批意见
+})
+
+// 审批表单验证规则(可选,根据需求添加)
+const approvalFormRules = reactive({
+  opinion: [
+    { required: false, message: '请输入审批意见', trigger: 'blur' },
+    { min: 0, max: 500, message: '审批意见长度不能超过500个字符', trigger: 'blur' }
+  ]
+})
+
+// 添加文件上传组件的引用
+const fileUploadRef = ref()
+
+// 表单数据
+const formData = ref({
+  id: undefined,
+  deptId: undefined,
+  taskId: undefined,
+  platformWell: undefined,
+  companyId: undefined,
+  deptName: undefined,
+  constructionStartDate: undefined,
+  contractName: undefined,
+  projectDepartment: '',
+  costCenterId: undefined,
+  costCenter: '',
+  platformId: undefined, // 平台井ID
+  // 新增日报填报字段
+  timeRange: [ // 设置默认时间范围 8:00 - 8:00
+    dayjs().hour(8).minute(0).second(0).toDate(),
+    dayjs().hour(8).minute(0).second(0).toDate()
+  ],
+  startTime: undefined, // 开始时间
+  endTime: undefined, // 结束时间
+  rdStatus: '', // 施工状态
+  deviceIds: [] as number[], // 设备ID数组
+  techniqueIds: [], // 施工工艺
+  productionStatus: '', // 当日生产动态
+  nextPlan: '', // 下步工作计划
+  externalRental: '', // 外租设备
+  malfunction: '',    // 故障情况
+  faultDowntime: '',  // 故障误工
+  // 添加动态字段对象
+  dynamicFields: {} as Record<string, any>,
+  // 附件列表
+  attachments: [] as any[]
+})
+
+// 添加上传成功处理函数
+const handleUploadSuccess = (result: any) => {
+  console.log('上传成功:', result)
+
+  try {
+    // 检查响应是否成功
+    if (!result.response) {
+      message.error('上传响应数据异常')
+      return
+    }
+
+    if (result.response.code !== 0) {
+      message.error(result.response.msg || '文件上传失败')
+      return
+    }
+
+    const responseData = result.response.data
+
+    if (!responseData) {
+      message.error('上传数据为空')
+      return
+    }
+
+    // 处理返回的文件列表
+    if (responseData.files && Array.isArray(responseData.files) && responseData.files.length > 0) {
+      responseData.files.forEach((file: any) => {
+        if (!file.filePath) {
+          console.warn('文件缺少 filePath:', file)
+          return
+        }
+
+        // 根据后端返回的数据结构构建附件对象
+        const attachment = {
+          id: undefined,
+          category: 'daily_report',
+          bizId: formData.value.id,
+          type: 'attachment',
+          filename: file.name || '未知文件',
+          fileType: getFileType(file.name),
+          filePath: file.filePath, //使用正确的 filePath
+          fileSize: formatFileSize(file.size || 0),
+          remark: ''
+        }
+
+        // 添加到附件列表
+        if (!formData.value.attachments) {
+          formData.value.attachments = []
+        }
+        formData.value.attachments.push(attachment)
+      })
+
+      message.success(`成功上传 ${responseData.files.length} 个文件`)
+    } else {
+      console.warn('上传成功但没有返回文件信息')
+      message.warning('上传成功但未获取到文件信息')
+    }
+  } catch (error) {
+    console.error('处理上传结果时发生错误:', error)
+    message.error('处理上传结果失败')
+  }
+}
+
+// 删除附件
+const removeAttachment = (index: number) => {
+  if (formData.value.attachments && formData.value.attachments.length > index) {
+    formData.value.attachments.splice(index, 1)
+  }
+}
+
+// 计算属性:未施工设备名称
+const unSelectedDeviceNames = computed(() => {
+  const selectedDevices = dailyReportData.value.selectedDevices || []
+  const selectedDeviceIds = formData.value.deviceIds || []
+
+  if (selectedDevices.length === 0) {
+    return '无可用设备'
+  }
+
+  // 筛选出未选择的设备
+  const unselectedDevices = selectedDevices.filter((device: any) =>
+    !selectedDeviceIds.includes(device.id)
+  )
+
+  if (unselectedDevices.length === 0) {
+    return '所有设备都已施工'
+  }
+
+  // 提取设备名称并用逗号分隔
+  const deviceNames = unselectedDevices
+    .map((device: any) => device.deviceName || device.deviceCode || '未知设备')
+    .filter((name: string) => name !== '未知设备')
+
+  return deviceNames.join(', ') || '无未选择设备'
+})
+
+// 附件名称点击事件
+const inContent = async (attachment) => {
+  if (!attachment || !attachment.filePath) {
+    message.error('附件路径不存在')
+    return
+  }
+
+  try {
+    // 直接使用 attachment.filePath
+    const filePath = attachment.filePath
+    // 确保 filePath 是编码后的格式
+    const encodedPath = encodeURIComponent(Base64.encode(filePath))
+
+    // 打开预览窗口
+    window.open(`http://doc.deepoil.cc:8012/onlinePreview?url=${encodedPath}`)
+  } catch (error) {
+    console.error('预览附件失败:', error)
+    message.error('预览附件失败')
+  }
+}
+
+// 获取文件类型辅助函数
+const getFileType = (filename: string) => {
+  const ext = filename.split('.').pop()?.toLowerCase()
+  if (['jpg', 'jpeg', 'png', 'gif', 'bmp'].includes(ext || '')) {
+    return 'image'
+  } else if (['pdf'].includes(ext || '')) {
+    return 'pdf'
+  } else if (['doc', 'docx'].includes(ext || '')) {
+    return 'word'
+  } else if (['xls', 'xlsx'].includes(ext || '')) {
+    return 'excel'
+  } else {
+    return 'other'
+  }
+}
+
+// 格式化文件大小辅助函数
+const formatFileSize = (bytes: number) => {
+  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]
+}
+
+// 计算属性:格式化设备显示
+const formatDevicesForDisplay = computed(() => {
+  const deviceIds = formData.value.deviceIds
+  if (!deviceIds || deviceIds.length === 0) {
+    return '无设备'
+  }
+
+  const deviceNames = deviceIds
+    .map(id => deviceMap.value[id]?.deviceName)
+    .filter(name => name !== undefined && name !== '')
+
+  if (deviceNames.length === 0) return '无设备'
+
+  // 如果设备数量超过2个,显示前两个加省略号
+  /* if (deviceNames.length > 2) {
+    return `${deviceNames[0]}, ${deviceNames[1]}...`
+  } */
+
+  return deviceNames.join(', ')
+})
+
+// 计算属性:获取所有设备名称(用于tooltip)
+const getAllDeviceNamesForDisplay = computed(() => {
+  const deviceIds = formData.value.deviceIds
+  if (!deviceIds || deviceIds.length === 0) {
+    return '无设备'
+  }
+
+  const deviceNames = deviceIds
+    .map(id => deviceMap.value[id]?.deviceCode || '未知设备')
+    .filter(name => name !== '未知设备')
+
+  return deviceNames.join(', ') || '无有效设备'
+})
+
+// 打开设备选择对话框
+const openDeviceDialog = async () => {
+  if (!dailyReportData.value.deptId) {
+    message.error('请先加载项目信息')
+    return
+  }
+
+  try {
+    formLoading.value = true
+    selectedDeviceIds.value = [...(formData.value.deviceIds || [])]
+
+    // 直接从日报数据的 selectedDevices 中获取设备列表
+    const selectedDevices = dailyReportData.value.selectedDevices || []
+
+    // 更新设备映射表
+    const newDeviceMap = { ...deviceMap.value }
+    selectedDevices.forEach((device: any) => {
+      if (device.id) {
+        newDeviceMap[device.id] = device
+      }
+    })
+    deviceMap.value = newDeviceMap
+
+    filteredDeviceList.value = selectedDevices
+    deviceDialogVisible.value = true
+
+  } catch (error) {
+    console.error('获取设备列表失败:', error)
+    message.error('获取设备列表失败')
+  } finally {
+    formLoading.value = false
+  }
+}
+
+// 处理穿梭框变化
+const handleTransferChange = (value: number[], direction: string, movedKeys: number[]) => {
+  // 可以添加额外的处理逻辑
+}
+
+// 确认设备选择
+const confirmDeviceSelection = () => {
+  formData.value.deviceIds = [...selectedDeviceIds.value]
+  deviceDialogVisible.value = false
+  message.success(`已选择 ${selectedDeviceIds.value.length} 台设备`)
+}
+
+// 关闭设备选择对话框
+const handleDeviceDialogClose = () => {
+  deviceDialogVisible.value = false
+}
+
+// 初始化设备数据
+const initDeviceData = (reportData: any) => {
+  // 初始化设备ID
+  if (reportData.deviceIds && Array.isArray(reportData.deviceIds)) {
+    formData.value.deviceIds = [...reportData.deviceIds]
+  } else {
+    formData.value.deviceIds = []
+  }
+
+  // 初始化设备映射表(用于显示设备名称)
+  if (reportData.selectedDevices && Array.isArray(reportData.selectedDevices)) {
+    const newDeviceMap = { ...deviceMap.value }
+    reportData.selectedDevices.forEach((device: any) => {
+      if (device.id) {
+        newDeviceMap[device.id] = device
+      }
+    })
+    deviceMap.value = newDeviceMap
+  }
+}
+
+// 表单验证规则
+/* const formRules = reactive({
+  timeRange: [{ required: true, message: '时间节点不能为空', trigger: 'change' }],
+  rdStatus: [{ required: true, message: '施工状态不能为空', trigger: 'change' }],
+  techniqueIds: [{ required: true, message: '施工工艺不能为空', trigger: 'change' }],
+  productionStatus: [{ required: true, message: '当日生产动态不能为空', trigger: 'blur' }]
+}) */
+
+const formRules = computed(() => {
+  // 判断是否为虚拟项目
+  const isVirtualProject = dailyReportData.value.virtualProject === 'Y'
+
+  // 基础校验规则(时间节点、当日生产动态始终必填)
+  const rules = {
+    timeRange: [{ required: true, message: '时间节点不能为空', trigger: 'change' }],
+    productionStatus: [{ required: true, message: '当日生产动态不能为空', trigger: 'blur' }]
+  }
+
+  // 非虚拟项目时,添加施工状态、施工工艺的必填校验
+  if (!isVirtualProject) {
+    rules.rdStatus = [{ required: true, message: '施工状态不能为空', trigger: 'change' }]
+    rules.techniqueIds = [{ required: true, message: '施工工艺不能为空', trigger: 'change' }]
+  }
+
+  return rules
+})
+
+const queryParams = reactive({
+  deptId: undefined,
+  techniqueIds: [],
+})
+
+// 下拉选项
+const rdStatusOptions = getStrDictOptions(DICT_TYPE.PMS_PROJECT_RD_STATUS)   // 施工状态
+const techniqueOptions = getStrDictOptions(DICT_TYPE.PMS_PROJECT_RD_TECHNOLOGY) // 瑞都施工工艺
+
+// 计算属性:日报标题
+const dailyReportTitle = computed(() => {
+  if (!dailyReportData.value.wellName || !dailyReportData.value.constructionStartDate) {
+    return '日报填报'
+  }
+  const dateStr = formatDate(dailyReportData.value.constructionStartDate)
+  return `${dailyReportData.value.wellName} - ${dateStr} 生产日报`
+})
+
+// 日报审批:日报标题
+const dailyReportApprovalTitle = computed(() => {
+  if (!dailyReportData.value.wellName || !dailyReportData.value.constructionStartDate) {
+    return '日报审批'
+  }
+  const dateStr = formatDate(dailyReportData.value.constructionStartDate)
+  return `${dailyReportData.value.wellName} - ${dateStr} 日报审批`
+})
+
+// 计算属性:施工周期
+const constructionPeriod = computed(() => {
+  const start = dailyReportData.value.constructionStartDate
+  const end = dailyReportData.value.constructionEndDate
+  if (!start || !end) return 0
+
+  const startDate = dayjs(start)
+  const endDate = dayjs(end)
+  return endDate.diff(startDate, 'day')
+})
+
+// 日期格式化函数
+const formatDate = (timestamp: number) => {
+  if (!timestamp) return ''
+  return dayjs(timestamp).format('YYYY-MM-DD')
+}
+
+const close = () => {
+  delView(unref(currentRoute))
+  push({ name: 'FillDailyReport', params: {} })
+}
+
+/** 提交表单 */
+const emit = defineEmits(['success'])
+const submitForm = async () => {
+  // 验证表单
+  try {
+    await formRef.value.validate()
+  } catch (error) {
+    return
+  }
+
+  // 保存当前平台井的数据
+  if (currentPlatformId.value) {
+    saveCurrentPlatformData(currentPlatformId.value)
+  }
+
+  // 打印 platformWellPairs
+  console.log('platformWellPairs:', JSON.stringify(platformWellPairs.value, null, 2))
+
+  // 处理时间范围数据
+  if (formData.value.timeRange && formData.value.timeRange.length === 2) {
+    // 将时间范围转换为 LocalTime 格式的字符串
+    const startDate = dayjs(formData.value.timeRange[0])
+    const endDate = dayjs(formData.value.timeRange[1])
+
+    // 格式化为 HH:mm:ss 字符串,后端会自动转换为 LocalTime
+    formData.value.startTime = startDate.format('HH:mm:ss')
+    formData.value.endTime = endDate.format('HH:mm:ss')
+  }
+
+  // 构建动态属性 extProperty 数组
+  const extProperties = dynamicAttrs.value.map(attr => {
+    return {
+      name: attr.name,
+      sort: attr.sort,
+      unit: attr.unit,
+      actualValue: formData.value.dynamicFields[attr.identifier] || '', // 从 dynamicFields 中获取用户填写的值
+      dataType: attr.dataType,
+      maxValue: attr.maxValue,
+      minValue: attr.minValue,
+      required: attr.required,
+      accessMode: attr.accessMode,
+      identifier: attr.identifier,
+      defaultValue: attr.defaultValue
+    }
+  })
+
+  // 准备提交数据,包含动态字段
+  const baseSubmitData = {
+    ...formData.value,
+    // 将动态字段组装成 extProperty 数组
+    extProperty: extProperties,
+    deviceIds: formData.value.deviceIds, // 设备ID集合
+  }
+
+  // 删除不需要复制的字段
+  const { id: currentId, platformId, platformWell, taskId, rdStatus, techniqueIds, extProperty, ...baseData } = baseSubmitData
+
+  const submitDatas = []
+
+  if (dailyReportData.value.platformWell === 1 && platformWellPairs.value.length > 0) {
+    // 平台井模式:处理所有平台井数据
+    platformWellPairs.value.forEach(pair => {
+      // 复制基础数据
+      const platformData = { ...baseData }
+
+      // 设置平台井特定字段
+      platformData.id = pair.reportId // 使用 platformWellPairs 中的 reportId
+      platformData.platformId = pair.taskId // 使用 platformWellPairs 中的 taskId
+      platformData.rdStatus = pair.rdStatus || ''
+      platformData.techniqueIds = pair.techniqueIds || []
+      platformData.extProperty = pair.extProperty || []
+
+      // 处理附件:复制并修改 bizId 为当前 pair 的 reportId
+      platformData.attachments = (baseData.attachments || []).map(attachment => ({
+        ...attachment, // 深拷贝单个附件
+        bizId: pair.reportId // 替换 bizId 为当前平台井的 reportId
+      }))
+
+      // 重新构建 dynamicFields(如果需要)
+      const dynamicFields = {}
+      if (platformData.extProperty && platformData.extProperty.length > 0) {
+        platformData.extProperty.forEach(prop => {
+          if (prop.identifier) {
+            dynamicFields[prop.identifier] = prop.actualValue || ''
+          }
+        })
+      }
+      platformData.dynamicFields = dynamicFields
+
+      submitDatas.push(platformData)
+    })
+
+    console.log('平台井模式提交数据:', JSON.stringify(submitDatas, null, 2))
+  } else {
+    // 非平台井模式:只提交当前数据
+    submitDatas.push(baseSubmitData)
+  }
+
+  // 提交请求
+  formLoading.value = true
+  try {
+    // 调用更新接口
+    await IotRdDailyReportApi.saveBatch(submitDatas)
+    message.success(t('common.updateSuccess'))
+    close()
+    // 发送操作成功的事件
+    emit('success')
+  } catch (error) {
+    console.error('提交失败:', error)
+  } finally {
+    formLoading.value = false
+  }
+}
+
+/** 重置表单 */
+const resetForm = () => {
+  formRef.value?.resetFields()
+}
+
+// 初始化动态属性
+const initDynamicAttrs = (reportData: any) => {
+  if (reportData.dailyReportAttrs && reportData.dailyReportAttrs.length > 0) {
+    dynamicAttrs.value = reportData.dailyReportAttrs
+
+    // 初始化动态字段的值
+    const initialDynamicFields: Record<string, any> = {}
+
+    // 优先从 extProperty 中获取实际值(编辑时)
+    if (reportData.extProperty && reportData.extProperty.length > 0) {
+      reportData.extProperty.forEach((extProp: any) => {
+        if (extProp.identifier) {
+          initialDynamicFields[extProp.identifier] = extProp.actualValue || ''
+        }
+      })
+    }
+
+    reportData.dailyReportAttrs.forEach((attr: any) => {
+      if (!initialDynamicFields.hasOwnProperty(attr.identifier)) {
+        // 优先使用实际值,如果没有则使用默认值
+        const value = (attr.extProperty && attr.extProperty.actualValue !== undefined &&
+          attr.extProperty.actualValue !== null && attr.extProperty.actualValue !== '')
+          ? attr.extProperty.actualValue
+          : (attr.defaultValue || (attr.extProperty?.defaultValue || ''))
+
+        initialDynamicFields[attr.identifier] = value
+      }
+    })
+
+    formData.value.dynamicFields = initialDynamicFields
+  }
+}
+
+// 获取动态字段的验证规则
+const getDynamicAttrRules = (attr: any) => {
+  const rules = []
+  if (attr.required === 1) {
+    rules.push({
+      required: true,
+      message: `${attr.name}不能为空`,
+      trigger: 'blur'
+    })
+  }
+
+  // 数字类型验证
+  if (attr.dataType === 'double') {
+    rules.push({
+      validator: (rule: any, value: any, callback: any) => {
+        if (value === '' || value === null || value === undefined) {
+          callback()
+          return
+        }
+
+        const numValue = Number(value)
+        if (isNaN(numValue)) {
+          callback(new Error(`${attr.name}必须是数字`))
+        } else if (attr.minValue && numValue < Number(attr.minValue)) {
+          callback(new Error(`${attr.name}不能小于${attr.minValue}`))
+        } else if (attr.maxValue && numValue > Number(attr.maxValue)) {
+          callback(new Error(`${attr.name}不能大于${attr.maxValue}`))
+        } else {
+          callback()
+        }
+      },
+      trigger: 'blur'
+    })
+  }
+
+  return rules
+}
+
+// 更新动态属性(处理交集、新增和删除)
+const updateDynamicAttrs = async (newAttrs: any[], newTechniqueIds: string[], oldTechniqueIds?: string[]) => {
+  const oldAttrs = [...dynamicAttrs.value]
+  const oldDynamicFields = { ...formData.value.dynamicFields }
+
+  // 计算需要保留的字段(交集)
+  const commonAttrs = oldAttrs.filter(oldAttr =>
+    newAttrs.some(newAttr => newAttr.identifier === oldAttr.identifier)
+  )
+
+  // 计算需要新增的字段
+  const addedAttrs = newAttrs.filter(newAttr =>
+    !oldAttrs.some(oldAttr => oldAttr.identifier === newAttr.identifier)
+  )
+
+  // 计算需要删除的字段
+  const removedAttrs = oldAttrs.filter(oldAttr =>
+    !newAttrs.some(newAttr => newAttr.identifier === oldAttr.identifier)
+  )
+
+  // 构建新的动态属性数组
+  const updatedAttrs = [...commonAttrs, ...addedAttrs]
+
+  // 构建新的动态字段对象
+  const updatedDynamicFields = { ...oldDynamicFields }
+
+  // 移除已删除的字段
+  removedAttrs.forEach(attr => {
+    delete updatedDynamicFields[attr.identifier]
+  })
+
+  // 初始化新增字段的值
+  addedAttrs.forEach(attr => {
+    if (!updatedDynamicFields[attr.identifier]) {
+      // 如果有默认值使用默认值,否则为空
+      updatedDynamicFields[attr.identifier] = attr.defaultValue ||
+        (attr.extProperty?.defaultValue || '')
+    }
+  })
+
+  // 更新响应式数据
+  dynamicAttrs.value = updatedAttrs
+  formData.value.dynamicFields = updatedDynamicFields
+}
+
+// 加载动态属性
+const loadDynamicAttrs = async (newTechniqueIds: string[], oldTechniqueIds?: string[]) => {
+  try {
+    formLoading.value = true
+
+    const queryParams = {
+      techniqueIds: newTechniqueIds.join(',')
+    }
+
+    const response = await IotDailyReportAttrsApi.dailyReportAttrs(queryParams)
+    const newAttrs = response || []
+
+    // 处理动态属性更新
+    await updateDynamicAttrs(newAttrs, newTechniqueIds, oldTechniqueIds)
+
+  } catch (error) {
+    console.error('加载动态属性失败:', error)
+    message.error('加载动态属性失败')
+  } finally {
+    formLoading.value = false
+  }
+}
+
+// 在 watch 监听平台井选择变化的部分附近,添加施工工艺转换函数
+// 添加施工工艺数值到标签的转换函数
+const convertTechniqueIdsToLabels = (techniqueIds: number[]): string[] => {
+  if (!techniqueIds || !Array.isArray(techniqueIds)) {
+    return []
+  }
+
+  return techniqueIds.map(id => {
+    const dict = techniqueOptions.value.find(option => option.value === id.toString())
+    return dict ? dict.label : id.toString()
+  })
+}
+
+// 监听施工工艺变化
+watch(() => formData.value.techniqueIds, async (newTechniqueIds, oldTechniqueIds) => {
+  if (newTechniqueIds && newTechniqueIds.length > 0) {
+    await loadDynamicAttrs(newTechniqueIds, oldTechniqueIds)
+
+    // 动态属性加载完成后,更新当前平台井的 extProperty
+    if (currentPlatformId.value) {
+      updateCurrentPlatformExtProperty()
+    }
+  } else {
+    dynamicAttrs.value = []
+    formData.value.dynamicFields = {}
+
+    // 清空当前平台井的 extProperty
+    if (currentPlatformId.value) {
+      updateCurrentPlatformExtProperty()
+    }
+  }
+}, { deep: true })
+
+// 更新当前平台井的 extProperty
+const updateCurrentPlatformExtProperty = () => {
+  if (!currentPlatformId.value) return
+
+  const index = platformWellPairs.value.findIndex(item => item.taskId === currentPlatformId.value)
+  if (index !== -1) {
+    platformWellPairs.value[index].extProperty = getCurrentExtProperties()
+  }
+}
+
+// 监听平台井选择变化
+watch(() => formData.value.platformId, (newPlatformId, oldPlatformId) => {
+  if (newPlatformId && newPlatformId !== oldPlatformId) {
+    // 保存当前平台井的数据到 platformWellPairs
+    if (oldPlatformId) {
+      saveCurrentPlatformData(oldPlatformId)
+    }
+
+    // 加载新平台井的数据到表单
+    loadPlatformData(newPlatformId)
+    currentPlatformId.value = newPlatformId
+  }
+})
+
+// 监听动态字段变化,实时更新到 platformWellPairs
+watch(() => formData.value.dynamicFields, (newFields) => {
+  if (currentPlatformId.value) {
+    updateCurrentPlatformExtProperty()
+  }
+}, { deep: true })
+
+// 监听施工状态变化
+watch(() => formData.value.rdStatus, (newStatus) => {
+  if (currentPlatformId.value) {
+    const index = platformWellPairs.value.findIndex(item => item.taskId === currentPlatformId.value)
+    if (index !== -1) {
+      platformWellPairs.value[index].rdStatus = newStatus
+    }
+  }
+})
+
+// 保存当前平台井数据到 platformWellPairs
+const saveCurrentPlatformData = (platformId: number) => {
+  const index = platformWellPairs.value.findIndex(item => item.taskId === platformId)
+  if (index !== -1) {
+    platformWellPairs.value[index] = {
+      ...platformWellPairs.value[index],
+      rdStatus: formData.value.rdStatus,
+      techniqueIds: [...formData.value.techniqueIds],
+      extProperty: getCurrentExtProperties()
+    }
+  } else {
+    // 如果找不到对应的平台井,添加新的记录
+    const platform = platformOptions.value.find(p => p.id === platformId)
+    if (platform) {
+      platformWellPairs.value.push({
+        taskId: platformId,
+        reportId: undefined, // 新记录没有 reportId
+        wellName: platform.wellName,
+        rdStatus: formData.value.rdStatus,
+        techniqueIds: [...formData.value.techniqueIds],
+        extProperty: getCurrentExtProperties()
+      })
+    }
+  }
+}
+
+// 从 platformWellPairs 加载平台井数据到表单
+const loadPlatformData = (platformId: number) => {
+  const platformData = platformWellPairs.value.find(item => item.taskId === platformId)
+  if (platformData) {
+    // 更新表单字段
+    formData.value.rdStatus = platformData.rdStatus || ''
+    // formData.value.techniqueIds = platformData.techniqueIds ? [...platformData.techniqueIds] : []
+    // 将施工工艺数值转换为对应的标签
+    if (platformData.techniqueIds && Array.isArray(platformData.techniqueIds)) {
+      // 如果是数字数组,转换为字符串数组(与数据字典格式匹配)
+      formData.value.techniqueIds = platformData.techniqueIds.map(id => id.toString())
+    } else {
+      formData.value.techniqueIds = platformData.techniqueIds ? [...platformData.techniqueIds] : []
+    }
+
+    // 更新动态属性
+    if (platformData.extProperty && platformData.extProperty.length > 0) {
+      const dynamicFields: Record<string, any> = {}
+      platformData.extProperty.forEach((prop: any) => {
+        if (prop.identifier) {
+          dynamicFields[prop.identifier] = prop.actualValue || ''
+        }
+      })
+      formData.value.dynamicFields = dynamicFields
+    } else {
+      formData.value.dynamicFields = {}
+    }
+  } else {
+    // 如果没有找到数据,初始化默认值
+    formData.value.rdStatus = ''
+    formData.value.techniqueIds = []
+    formData.value.dynamicFields = {}
+  }
+}
+
+// 获取当前动态属性数据
+const getCurrentExtProperties = () => {
+  return dynamicAttrs.value.map(attr => {
+    return {
+      name: attr.name,
+      sort: attr.sort,
+      unit: attr.unit,
+      actualValue: formData.value.dynamicFields[attr.identifier] || '',
+      dataType: attr.dataType,
+      maxValue: attr.maxValue,
+      minValue: attr.minValue,
+      required: attr.required,
+      accessMode: attr.accessMode,
+      identifier: attr.identifier,
+      defaultValue: attr.defaultValue
+    }
+  })
+}
+
+// 初始化表单数据
+const initFormData = (reportData: any) => {
+  // 处理附件数据格式转换
+  const formattedAttachments = (reportData.attachments || []).map((attachment: any) => ({
+    id: attachment.id,
+    category: attachment.category?.toLowerCase() || 'daily_report',
+    bizId: attachment.bizId,
+    type: attachment.type?.toLowerCase() || 'attachment',
+    filename: attachment.filename,
+    fileType: attachment.fileType, // 使用辅助函数获取文件类型
+    filePath: attachment.filePath,
+    fileSize: attachment.fileSize,
+    remark: attachment.remark || ''
+  }))
+
+  // 确保 techniqueIds 是字符串数组格式
+  let techniqueIds = []
+  if (reportData.techniqueIds && Array.isArray(reportData.techniqueIds)) {
+    techniqueIds = reportData.techniqueIds.map((id: number) => id.toString())
+  }
+
+  formData.value = {
+    ...formData.value,
+    id: reportData.id,
+    deptId: reportData.deptId,
+    taskId: reportData.taskId,
+    platformWell: reportData.platformWell,
+    rdStatus: reportData.rdStatus || '',
+    techniqueIds: techniqueIds,
+    productionStatus: reportData.productionStatus || '',
+    nextPlan: reportData.nextPlan || '',
+    externalRental: reportData.externalRental || '',
+    malfunction: reportData.malfunction || '',
+    faultDowntime: reportData.faultDowntime || '',
+    startTime: reportData.startTime || undefined,
+    endTime: reportData.endTime || undefined,
+    companyId: reportData.companyId || '',
+    dynamicFields: {}, // 确保有初始值
+    // 初始化附件数据
+    attachments: formattedAttachments
+  }
+  queryParams.deptId = reportData.companyId
+  // 设置时间范围选择器
+  if (reportData.startTime && reportData.startTime[0] && reportData.endTime && reportData.endTime[0]) {
+    formData.value.timeRange = [
+      new Date(reportData.startTime[0]),
+      new Date(reportData.endTime[0])
+    ]
+  }
+
+  // 初始化平台井数据
+  initPlatformData(reportData)
+
+  // 初始化动态属性
+  initDynamicAttrs(reportData)
+
+  // 初始化设备数据
+  initDeviceData(reportData)
+
+  // 如果是平台井模式且有数据,初始化 platformWellPairs 中的第一个平台井数据
+  /* if (reportData.platformWell === 1 && formData.value.platformId) {
+    loadPlatformData(formData.value.platformId)
+  } */
+
+}
+
+onMounted(async () => {
+  formLoading.value = true
+  try {
+    // 加载当前登录人所属部门
+    const deptId = userStore.getUser.deptId
+    const dept = await DeptApi.getDept(deptId)
+
+    // 查询瑞都日报详情
+    if (id) {
+      const response = await IotRdDailyReportApi.getIotRdDailyReport(id)
+      dailyReportData.value = response || {}
+      initFormData(dailyReportData.value)
+    }
+  } catch (error) {
+    console.error('初始化数据失败:', error)
+    message.error('数据加载失败')
+  } finally {
+    formLoading.value = false
+  }
+})
+
+// 详细 审批 平台井 获取工作量列配置
+const getWorkloadColumns = () => {
+  if (!dailyReportData.value.platforms) return [];
+
+  const columns = [];
+  const addedIdentifiers = new Set();
+
+  dailyReportData.value.platforms.forEach(platform => {
+    if (platform.extProperty && Array.isArray(platform.extProperty)) {
+      platform.extProperty.forEach(extProp => {
+        if (!addedIdentifiers.has(extProp.identifier)) {
+          columns.push({
+            key: extProp.identifier,
+            identifier: extProp.identifier,
+            label: `${extProp.name}(${extProp.unit})`
+          });
+          addedIdentifiers.add(extProp.identifier);
+        }
+      });
+    }
+  });
+
+  return columns;
+};
+
+// 详情 审批 平台井 获取工作量值
+const getWorkloadValue = (platform, identifier) => {
+  if (!platform.extProperty) return '';
+  const prop = platform.extProperty.find(item => item.identifier === identifier);
+  return prop ? prop.actualValue || '' : '';
+};
+
+/** 审批操作 */
+const handleApprove = async (action: 'pass' | 'reject') => {
+  // 只有在审批模式下才执行审批操作
+  if (!isApprovalMode.value) {
+    message.warning('当前不是审批模式')
+    return
+  }
+  try {
+    // 验证审批表单(如果需要)
+    // await approvalFormRef.value.validate()
+
+    formLoading.value = true
+
+    // 处理时间范围数据
+    if (formData.value.timeRange && formData.value.timeRange.length === 2) {
+      // 将时间范围转换为 LocalTime 格式的字符串
+      const startDate = dayjs(formData.value.timeRange[0])
+      const endDate = dayjs(formData.value.timeRange[1])
+
+      // 格式化为 HH:mm:ss 字符串,后端会自动转换为 LocalTime
+      formData.value.startTime = startDate.format('HH:mm:ss')
+      formData.value.endTime = endDate.format('HH:mm:ss')
+    }
+
+    // 构建审批数据,包含审批意见
+    const approveData = {
+      ...formData.value,
+      id: Number(id),
+      opinion: approvalForm.opinion,
+      auditStatus: action === 'pass' ? 20 : 30
+    }
+
+    // 这里可以调用审批API
+    if (action === 'pass') {
+      // 审批通过逻辑
+      await IotRdDailyReportApi.approveRdDailyReport(approveData)
+      message.success('审批通过')
+    } else {
+      // 审批驳回逻辑
+      await IotRdDailyReportApi.approveRdDailyReport(approveData)
+      message.success('审批驳回')
+    }
+    close()
+  } catch (error) {
+    console.error('审批操作失败:', error)
+    message.error('审批操作失败')
+  } finally {
+    formLoading.value = false
+  }
+}
+
+</script>
+
+<style scoped>
+
+.info-table {
+  border: 1px solid #e0e0e0;
+  border-radius: 4px;
+  overflow: hidden;
+}
+
+.table-row {
+  display: flex;
+  border-bottom: 1px solid #e0e0e0;
+}
+
+.table-row:last-child {
+  border-bottom: none;
+}
+
+.table-cell {
+  flex: 1;
+  border-right: 1px solid #e0e0e0;
+  padding: 12px 8px;
+  min-height: 44px;
+  display: flex;
+  align-items: center;
+}
+
+.table-cell:last-child {
+  border-right: none;
+}
+
+.table-cell.full-width {
+  flex: 1;
+  border-right: none;
+}
+
+.cell-content {
+  display: flex;
+  align-items: center;
+  width: 100%;
+}
+
+.cell-label {
+  font-weight: 500;
+  /* 统一字体大小为 14px(Element 表单默认) */
+  font-size: 14px;
+  color: #606266;
+  min-width: 80px;
+  margin-right: 8px;
+  flex-shrink: 0;
+}
+
+.cell-value {
+  /* 统一字体大小为 14px(Element 输入框默认) */
+  font-size: 14px;
+  color: #303133;
+  /* 统一行高为 1.5(Element 组件默认行高) */
+  line-height: 1.5;
+  flex: 1;
+  word-break: break-all;
+}
+
+/* 响应式设计 */
+@media (max-width: 768px) {
+  .table-row {
+    flex-direction: column;
+  }
+
+  .table-cell {
+    border-right: none;
+    border-bottom: 1px solid #e0e0e0;
+  }
+
+  .table-cell:last-child {
+    border-bottom: none;
+  }
+}
+
+.daily-report-title {
+  text-align: center;
+  margin: 20px 0;
+  padding: 10px;
+  border-bottom: 2px solid #409eff;
+}
+
+.daily-report-title h2 {
+  margin: 0;
+  color: #303133;
+  font-size: 16px;
+  font-weight: bold;
+}
+
+/* 为第二、三部分增加左右留白 */
+.section-padding {
+  padding-left: 0px;
+  padding-right: 40px;
+}
+
+.project-info-section {
+  margin: 20px 0;
+  padding: 20px;
+  background-color: #f8f9fa;
+  border-radius: 4px;
+  border: 1px solid #e9ecef;
+}
+
+.info-row {
+  padding: 12px 0;
+  border-bottom: 1px solid #e9ecef;
+}
+
+.info-row:last-child {
+  border-bottom: none;
+}
+
+.info-label {
+  font-weight: bold;
+  color: #495057;
+  margin-right: 8px;
+}
+
+.info-value {
+  color: #212529;
+}
+
+:deep(.el-textarea .el-textarea__inner) {
+  min-height: 80px;
+}
+
+/* 确保表单label不换行 */
+:deep(.el-form-item__label) {
+  white-space: nowrap;
+  text-overflow: ellipsis;
+  overflow: hidden;
+}
+
+/* 甲方字段:单行显示+超出省略 */
+.single-line-ellipsis {
+  /* 强制文本单行显示 */
+  white-space: nowrap;
+  /* 超出容器部分隐藏 */
+  overflow: hidden;
+  /* 超出部分显示省略号 */
+  text-overflow: ellipsis;
+  /* 避免文本被截断(可选,根据需求调整) */
+  word-break: normal;
+}
+
+/* 设备配置字段:换行缩进(与首行对齐) */
+.indent-multiline {
+  /* 首行及换行后缩进 2em(与 label 宽度匹配,可根据需求调整) */
+  text-indent: 0em;
+  /* 允许长文本换行(覆盖原有 cell-value 的 break-all,确保中文换行正常) */
+  word-break: break-word;
+  /* 保证换行后文本正常显示(可选,清除可能的 nowrap 影响) */
+  white-space: normal;
+}
+
+/* 添加审批模式下的样式 */
+.approval-notice {
+  margin-top: 10px;
+}
+
+/* 审批模式下表单字段的只读样式 */
+:deep(.el-form-item.is-disabled .el-input__inner),
+:deep(.el-form-item.is-disabled .el-textarea__inner) {
+  background-color: #f5f7fa;
+  border-color: #e4e7ed;
+  color: #c0c4cc;
+  cursor: not-allowed;
+}
+
+:deep(.el-form-item.is-disabled .el-select .el-input__inner) {
+  background-color: #f5f7fa;
+  border-color: #e4e7ed;
+  color: #c0c4cc;
+  cursor: not-allowed;
+}
+
+:deep(.el-form-item.is-disabled .el-date-editor .el-input__inner) {
+  background-color: #f5f7fa;
+  border-color: #e4e7ed;
+  color: #c0c4cc;
+  cursor: not-allowed;
+}
+
+/* 只读模式下表单字段的样式 */
+:deep(.el-form-item.is-disabled .el-input__inner),
+:deep(.el-form-item.is-disabled .el-textarea__inner),
+:deep(.el-form-item.is-disabled .el-select .el-input__inner),
+:deep(.el-form-item.is-disabled .el-date-editor .el-input__inner) {
+  background-color: #f5f7fa;
+  border-color: #e4e7ed;
+  color: #606266; /* 保持文字可读性 */
+  cursor: not-allowed;
+}
+
+/* 详情模式下的特殊样式 */
+.detail-mode .cell-value {
+  color: #303133;
+  font-weight: normal;
+}
+
+/* 添加审批意见区域的样式 */
+.approval-opinion-section {
+  margin-top: 20px;
+  border-top: 2px solid #f0f0f0;
+  padding-top: 20px;
+}
+
+/* 审批意见文本域样式 */
+:deep(.approval-opinion .el-textarea__inner) {
+  min-height: 100px;
+  resize: vertical;
+}
+
+/* 审批意见标签样式 */
+:deep(.approval-opinion .el-form-item__label) {
+  font-weight: bold;
+  color: #606266;
+}
+
+/* 附件列表样式 */
+.attachment-list {
+  width: 100%;
+  margin-top: 5px;
+  border: 1px solid #e0e0e0;
+  border-radius: 4px;
+  padding: 10px;
+  background-color: #fafafa;
+  box-sizing: border-box;
+}
+
+.attachment-item {
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+  padding: 8px 12px;
+  border-bottom: 1px solid #f0f0f0;
+}
+
+.attachment-item:last-child {
+  border-bottom: none;
+}
+
+.attachment-name {
+  flex: 1;
+  color: #606266;
+  font-size: 11px;
+}
+
+.no-attachment {
+  color: #909399;
+  font-style: italic;
+  margin-top: 5px;
+  padding: 10px;
+}
+
+/* 附件名称链接样式 */
+.attachment-name {
+  color: #409eff;
+  text-decoration: underline;
+  cursor: pointer;
+}
+
+.attachment-name:hover {
+  color: #66b1ff;
+}
+
+/* 只读模式下的设备显示样式 */
+.device-display-readonly {
+  color: #606266;
+  font-size: 11px;
+  line-height: 1.5;
+  background-color: #f5f7fa;
+  padding: 8px 12px;
+  border-radius: 4px;
+  border: 1px solid #e4e7ed;
+  display: inline-block;
+  min-width: 200px;
+}
+
+.no-device {
+  margin-left: 10px;
+  color: #909399;
+  font-style: italic;
+}
+
+/* 设备选择对话框样式 */
+.transfer-container {
+  text-align: center;
+  padding: 0px;
+}
+
+.transfer-component {
+  width: 100%;
+  min-width: 600px;
+}
+
+:deep(.el-transfer-panel) {
+  width: 40% !important;
+}
+
+:deep(.el-transfer-panel__item) {
+  display: flex !important;
+  align-items: center !important;
+  height: 32px !important;
+  line-height: 32px !important;
+  padding: 0 8px !important;
+  margin: 0 !important;
+  white-space: nowrap;
+  overflow: hidden;
+  text-overflow: ellipsis;
+}
+
+.transfer-option-text {
+  display: inline-block;
+  max-width: 100%;
+}
+
+:deep(.el-transfer-panel__list) {
+  width: 100% !important;
+}
+
+.device-display-container {
+  /* 与其他文本域保持相同的宽度和样式 */
+  display: inline-block;
+  width: 100%; /* 减去按钮宽度 */
+  min-height: 32px;
+  line-height: 32px;
+  padding: 0 12px;
+  margin-left: 0px;
+  border-radius: 4px;
+  border: 1px solid #e4e7ed;
+  background-color: #fff;
+  font-size: 11px;
+  /* 文本溢出处理 */
+  white-space: nowrap;
+  overflow: hidden;
+  text-overflow: ellipsis;
+}
+
+/* 只读模式下的设备显示样式 */
+:deep(.is-disabled) .device-display-container {
+  background-color: #f5f7fa;
+  color: #606266;
+  cursor: not-allowed;
+}
+
+/* 附件容器样式调整 */
+.attachment-container {
+  /* 与其他文本域保持相同的宽度和边距 */
+  width: 100%;
+  margin-top: 10px;
+}
+
+/* 未选择设备字段的只读样式 */
+:deep(.unselected-device .el-textarea__inner) {
+  background-color: #f5f7fa;
+  border-color: #e4e7ed;
+  color: #909399;
+  cursor: not-allowed;
+  resize: none;
+}
+
+/* 平台井工作量区域专用样式 */
+.platform-workload-section {
+  padding-left: 0px;
+  padding-right: 0px; /* 去掉右侧间距 */
+}
+
+/* 表格样式优化 */
+.platform-workload-el-table {
+  width: 100%;
+}
+
+/* 表头不换行 */
+:deep(.platform-workload-el-table .el-table__header-wrapper th) {
+  white-space: nowrap;
+  text-overflow: ellipsis;
+  overflow: hidden;
+}
+
+/* 单元格内容不换行 */
+:deep(.platform-workload-el-table .el-table__body-wrapper td) {
+  white-space: nowrap;
+  text-overflow: ellipsis;
+  overflow: hidden;
+}
+
+/* 强制设置表头宽度为100% */
+:deep(.platform-workload-el-table .el-table__header) {
+  width: 100% !important;
+  min-width: 100% !important;
+}
+
+/* 强制设置表格主体宽度为100% */
+:deep(.platform-workload-el-table .el-table__body) {
+  width: 100% !important;
+  min-width: 100% !important;
+}
+
+/* 确保表格填满容器 */
+:deep(.platform-workload-el-table .el-table) {
+  width: 100% !important;
+}
+
+/* 表格容器填满父容器 */
+.platform-workload-table {
+  width: 100%;
+}
+
+</style>

+ 115 - 29
src/views/pms/iotrddailyreport/FillDailyReportForm.vue

@@ -35,7 +35,7 @@
           <div class="table-cell">
             <div class="cell-content">
               <span class="cell-label">井号:</span>
-              <span class="cell-value">{{ dailyReportData.wellName || dailyReportData.taskName || '-' }}</span>
+              <span class="cell-value">{{ displayWellName || dailyReportData.taskName || '-' }}</span>
             </div>
           </div>
         </div>
@@ -483,7 +483,7 @@
     </ContentWrap>
 
     <!-- 第四部分:审批意见 - 只在审批模式下显示 -->
-    <ContentWrap class="section-padding" v-if="isApprovalMode">
+    <ContentWrap class="section-padding" v-if="isApprovalMode || isEditMode || isDetailMode">
       <el-form
         ref="approvalFormRef"
         :model="approvalForm"
@@ -500,6 +500,8 @@
                 placeholder="请输入审批意见"
                 maxlength="500"
                 show-word-limit
+                :readonly="!isApprovalMode"
+                :disabled="!isApprovalMode"
               />
             </el-form-item>
           </el-col>
@@ -593,7 +595,7 @@ import { ref, reactive, computed, onMounted, nextTick, watch } from 'vue'
 import { useI18n } from '@/hooks/web/useI18n'
 import { useMessage } from '@/hooks/web/useMessage'
 import { useTagsViewStore } from '@/store/modules/tagsView'
-import { useRouter, useRoute } from 'vue-router'
+import { useRouter } from 'vue-router'
 import {DICT_TYPE, getDictLabel, getStrDictOptions} from '@/utils/dict'
 import { IotRdDailyReportApi } from '@/api/pms/iotrddailyreport'
 import { IotDailyReportAttrsApi } from '@/api/pms/iotdailyreportattrs'
@@ -631,19 +633,46 @@ const isReadonlyMode = computed(() => isApprovalMode.value || isDetailMode.value
 const platformWellPairs = ref<any[]>([]) // 存储各平台井的工作量数据
 const currentPlatformId = ref<number>() // 当前选中的平台井ID
 
+// 计算属性:显示井名(统一处理主井和平台井逻辑)
+const displayWellName = computed(() => {
+  // 如果是平台井模式且有平台井数据
+  if (dailyReportData.value.platformWell === 1 &&
+    dailyReportData.value.platforms &&
+    dailyReportData.value.platforms.length > 0) {
+
+    // 检查主井是否在平台井列表中
+    const isMainWellInPlatforms = dailyReportData.value.platforms.some(
+      (platform: any) => platform.id === dailyReportData.value.taskId
+    )
+
+    // 如果主井不在平台井列表中(说明主井已施工完成),使用第一个平台井的名称
+    if (!isMainWellInPlatforms) {
+      const firstPlatformWellName = dailyReportData.value.platforms[0].wellName
+      console.log(`主井已施工完成,井号显示使用平台井名称: ${firstPlatformWellName}`)
+      return firstPlatformWellName
+    }
+  }
+
+  // 其他情况使用原来的井名
+  return dailyReportData.value.wellName
+})
+
 // 页面标题计算
 const pageTitle = computed(() => {
+  const displayWellNameValue = displayWellName.value
+  const constructionDate = dailyReportData.value.constructionStartDate
+
   if (isApprovalMode.value) {
-    return dailyReportData.value.wellName && dailyReportData.value.constructionStartDate
-      ? `${dailyReportData.value.wellName} - ${formatDate(dailyReportData.value.constructionStartDate)} 日报审批`
+    return displayWellNameValue && constructionDate
+      ? `${displayWellNameValue} - ${formatDate(constructionDate)} 日报审批`
       : '日报审批'
   } else if (isDetailMode.value) {
-    return dailyReportData.value.wellName && dailyReportData.value.constructionStartDate
-      ? `${dailyReportData.value.wellName} - ${formatDate(dailyReportData.value.constructionStartDate)} 日报详情`
+    return displayWellNameValue && constructionDate
+      ? `${displayWellNameValue} - ${formatDate(constructionDate)} 日报详情`
       : '日报详情'
   } else {
-    return dailyReportData.value.wellName && dailyReportData.value.constructionStartDate
-      ? `${dailyReportData.value.wellName} - ${formatDate(dailyReportData.value.constructionStartDate)} 生产日报`
+    return displayWellNameValue && constructionDate
+      ? `${displayWellNameValue} - ${formatDate(constructionDate)} 生产日报`
       : '日报填报'
   }
 })
@@ -715,18 +744,33 @@ const initPlatformData = (reportData: any) => {
     platformWellPairs.value = []
   }
 
-  // 设置默认选中的平台井
-  if (reportData.taskId && platformOptions.value.length > 0) {
-    // 查找与 taskId 匹配的平台井
-    const defaultPlatform = platformOptions.value.find(
-      (platform: any) => platform.id === reportData.taskId
-    )
-    if (defaultPlatform) {
-      formData.value.platformId = defaultPlatform.id
-      currentPlatformId.value = defaultPlatform.id
+  // 设置默认选中的平台井 - 修改后的逻辑
+  if (platformOptions.value.length > 0) {
+    let selectedPlatform = null
+
+    // 首先尝试查找与 taskId 匹配的平台井
+    if (reportData.taskId) {
+      selectedPlatform = platformOptions.value.find(
+        (platform: any) => platform.id === reportData.taskId
+      )
+    }
+
+    // 如果没有找到匹配的平台井,选择第一个平台井
+    if (!selectedPlatform) {
+      selectedPlatform = platformOptions.value[0]
+    }
 
-      // 加载默认平台井的数据到表单
-      loadPlatformData(defaultPlatform.id)
+    // 设置选中的平台井
+    if (selectedPlatform) {
+      formData.value.platformId = selectedPlatform.id
+      currentPlatformId.value = selectedPlatform.id
+      // 加载平台井的数据到表单
+      loadPlatformData(selectedPlatform.id)
+
+      // 可选:在控制台输出提示信息
+      if (reportData.taskId && selectedPlatform.id !== reportData.taskId) {
+        console.log(`主井已施工完成,已自动选择第一个平台井: ${selectedPlatform.wellName}`)
+      }
     }
   }
 }
@@ -745,6 +789,18 @@ const approvalFormRules = reactive({
   ]
 })
 
+// 将时分秒数组转换为Date对象(基于constructionStartDate的日期)
+const parseTimeArrayToDate = (timeArray: number[], baseDate: number) => {
+  if (!Array.isArray(timeArray) || !baseDate) {
+    return null
+  }
+  const hour = timeArray[0] || 0
+  const minute = timeArray[1] || 0
+  const second = timeArray[2] || 0
+  // 基于日报日期(constructionStartDate)设置时分秒
+  return dayjs(baseDate).hour(hour).minute(minute).second(second).toDate()
+}
+
 // 添加文件上传组件的引用
 const fileUploadRef = ref()
 
@@ -762,8 +818,9 @@ const formData = ref({
   costCenterId: undefined,
   costCenter: '',
   platformId: undefined, // 平台井ID
-  // 新增日报填报字段
-  timeRange: [ // 设置默认时间范围 8:00 - 8:00
+  // 日报填报字段
+  timeRange: [
+    // 设置默认时间范围 8:00 - 8:00
     dayjs().hour(8).minute(0).second(0).toDate(),
     dayjs().hour(8).minute(0).second(0).toDate()
   ],
@@ -1032,11 +1089,30 @@ const initDeviceData = (reportData: any) => {
 }
 
 // 表单验证规则
-const formRules = reactive({
+/* const formRules = reactive({
   timeRange: [{ required: true, message: '时间节点不能为空', trigger: 'change' }],
   rdStatus: [{ required: true, message: '施工状态不能为空', trigger: 'change' }],
   techniqueIds: [{ required: true, message: '施工工艺不能为空', trigger: 'change' }],
   productionStatus: [{ required: true, message: '当日生产动态不能为空', trigger: 'blur' }]
+}) */
+
+const formRules = computed(() => {
+  // 判断是否为虚拟项目
+  const isVirtualProject = dailyReportData.value.virtualProject === 'Y'
+
+  // 基础校验规则(时间节点、当日生产动态始终必填)
+  const rules = {
+    timeRange: [{ required: true, message: '时间节点不能为空', trigger: 'change' }],
+    productionStatus: [{ required: true, message: '当日生产动态不能为空', trigger: 'blur' }]
+  }
+
+  // 非虚拟项目时,添加施工状态、施工工艺的必填校验
+  if (!isVirtualProject) {
+    rules.rdStatus = [{ required: true, message: '施工状态不能为空', trigger: 'change' }]
+    rules.techniqueIds = [{ required: true, message: '施工工艺不能为空', trigger: 'change' }]
+  }
+
+  return rules
 })
 
 const queryParams = reactive({
@@ -1140,10 +1216,12 @@ const submitForm = async () => {
     // 将动态字段组装成 extProperty 数组
     extProperty: extProperties,
     deviceIds: formData.value.deviceIds, // 设备ID集合
+    // 在填报模式下也提交审批意见字段
+    opinion: isEditMode.value ? approvalForm.opinion : undefined
   }
 
   // 删除不需要复制的字段
-  const { id: currentId, platformId, rdStatus, techniqueIds, extProperty, ...baseData } = baseSubmitData
+  const { id: currentId, platformId, platformWell, taskId, rdStatus, techniqueIds, extProperty, ...baseData } = baseSubmitData
 
   const submitDatas = []
 
@@ -1541,13 +1619,21 @@ const initFormData = (reportData: any) => {
     // 初始化附件数据
     attachments: formattedAttachments
   }
+
+  // 初始化审批意见数据
+  approvalForm.opinion = reportData.auditOpinion || reportData.opinion || ''
+
   queryParams.deptId = reportData.companyId
   // 设置时间范围选择器
-  if (reportData.startTime && reportData.startTime[0] && reportData.endTime && reportData.endTime[0]) {
-    formData.value.timeRange = [
-      new Date(reportData.startTime[0]),
-      new Date(reportData.endTime[0])
-    ]
+  if (reportData.startTime && Array.isArray(reportData.startTime) && reportData.endTime && Array.isArray(reportData.endTime)) {
+    // 基于日报的施工开始日期作为基准日期
+    const baseDate = reportData.constructionStartDate || Date.now()
+    const startTime = parseTimeArrayToDate(reportData.startTime, baseDate)
+    const endTime = parseTimeArrayToDate(reportData.endTime, baseDate)
+
+    if (startTime && endTime) {
+      formData.value.timeRange = [startTime, endTime]
+    }
   }
 
   // 初始化平台井数据

+ 26 - 26
src/views/pms/iotrddailyreport/fillDailyReport.vue

@@ -72,6 +72,27 @@
       <ContentWrap>
         <el-table v-loading="loading" :data="list" :stripe="true" :show-overflow-tooltip="true">
           <el-table-column label="主键id" align="center" prop="id" v-if="false"/>
+          <el-table-column label="操作" align="center" min-width="120px">
+            <template #default="scope">
+              <el-button
+                link
+                type="primary"
+                @click="openForm('fill', scope.row.id)"
+                v-hasPermi="['pms:iot-rd-daily-report:update']"
+                v-if="scope.row.status === 0"
+              >
+                填报
+              </el-button>
+              <el-button
+                link
+                type="success"
+                @click="handleDetail(scope.row.id)"
+                v-hasPermi="['pms:iot-rd-daily-report:query']"
+              >
+                查看
+              </el-button>
+            </template>
+          </el-table-column>
           <el-table-column
             label="创建时间"
             align="center"
@@ -79,16 +100,16 @@
             :formatter="dateFormatter"
             width="180px"
           />
-          <el-table-column label="施工队伍" align="center" prop="deptName" />
-          <el-table-column label="项目" align="center" prop="contractName" />
-          <el-table-column label="任务" align="center" prop="taskName" />
-          <el-table-column label="带班干部" align="center" prop="responsiblePersonNames" />
-          <el-table-column label="填报人" align="center" prop="submitterNames" />
           <el-table-column label="日报状态" align="center" prop="status">
             <template #default="scope">
               <dict-tag :type="DICT_TYPE.OPERATION_FILL_ORDER_STATUS" :value="scope.row.status" />
             </template>
           </el-table-column>
+          <el-table-column label="施工队伍" align="center" prop="deptName" />
+          <el-table-column label="项目" align="center" prop="contractName" />
+          <el-table-column label="任务" align="center" prop="taskName" />
+          <el-table-column label="带班干部" align="center" prop="responsiblePersonNames" />
+          <el-table-column label="填报人" align="center" prop="submitterNames" />
           <!--
           <el-table-column label="项目类别(钻井 修井 注氮 酸化压裂... )" align="center" prop="projectClassification" /> -->
           <!--
@@ -107,27 +128,6 @@
             :formatter="dateFormatter"
             width="180px"
           /> -->
-          <el-table-column label="操作" align="center" min-width="120px">
-            <template #default="scope">
-              <el-button
-                link
-                type="primary"
-                @click="openForm('fill', scope.row.id)"
-                v-hasPermi="['pms:iot-rd-daily-report:update']"
-                v-if="scope.row.status === 0"
-              >
-                填报
-              </el-button>
-              <el-button
-                link
-                type="success"
-                @click="handleDetail(scope.row.id)"
-                v-hasPermi="['pms:iot-rd-daily-report:query']"
-              >
-                查看
-              </el-button>
-            </template>
-          </el-table-column>
         </el-table>
         <!-- 分页 -->
         <Pagination

+ 79 - 23
src/views/pms/iotrddailyreport/index.vue

@@ -76,18 +76,20 @@
             label="创建时间"
             align="center"
             prop="createTime"
-            :formatter="dateFormatter"
+            :formatter="dateFormatter2"
             :width="columnWidths.createTime"
           />
           <el-table-column label="施工队伍" align="center" prop="deptName" :width="columnWidths.deptName"/>
-          <el-table-column label="项目" align="center" prop="contractName" :width="columnWidths.contractName"/>
           <el-table-column label="任务" align="center" prop="taskName" :width="columnWidths.taskName"/>
-          <el-table-column label="时间节点" align="center" prop="timeRange" :width="columnWidths.timeRange"/>
           <el-table-column :label="t('project.status')" align="center" prop="rdStatus" :width="columnWidths.rdStatus">
             <template #default="scope">
               <dict-tag :type="DICT_TYPE.PMS_PROJECT_RD_STATUS" :value="scope.row.rdStatus" />
             </template>
           </el-table-column>
+          <el-table-column label="项目" align="center" prop="contractName" :width="columnWidths.contractName" v-if="false"/>
+
+          <el-table-column label="时间节点" align="center" prop="timeRange" :width="columnWidths.timeRange" v-if="false"/>
+
           <!--
           <el-table-column label="项目类别(钻井 修井 注氮 酸化压裂... )" align="center" prop="projectClassification" />
           <el-table-column label="施工工艺" align="center" prop="techniqueIds" /> -->
@@ -103,26 +105,35 @@
           <el-table-column label="桥塞" align="center" prop="bridgePlug" :width="columnWidths.bridgePlug"/>
           <el-table-column label="水方量" align="center" prop="waterVolume" :width="columnWidths.waterVolume"/>
           <el-table-column label="时间H" align="center" prop="hourCount" :width="columnWidths.hourCount"/>
-          <!--
-          <el-table-column
-            label="施工开始日期"
-            align="center"
-            prop="constructionStartDate"
-            :formatter="dateFormatter"
-            :width="columnWidths.constructionStartDate"
-          />
-          <el-table-column
-            label="施工结束日期"
-            align="center"
-            prop="constructionEndDate"
-            :formatter="dateFormatter"
-            :width="columnWidths.constructionEndDate"
-          /> -->
-          <el-table-column label="当日生产动态" align="center" prop="productionStatus" :width="columnWidths.productionStatus"/>
-          <el-table-column label="下步工作计划" align="center" prop="nextPlan" :width="columnWidths.nextPlan"/>
+          <el-table-column label="当日生产动态" align="center" :width="columnWidths.productionStatus" fixed-width>
+            <template #default="scope">
+              <el-tooltip
+                effect="light"
+                :content="scope.row.productionStatus"
+                placement="top"
+                popper-class="long-text-tooltip"
+                :disabled="!scope.row.productionStatus || scope.row.productionStatus.length <= 30"
+              >
+                <span class="long-text">{{ formatLongText(scope.row.productionStatus) }}</span>
+              </el-tooltip>
+            </template>
+          </el-table-column>
+          <el-table-column label="下步工作计划" align="center" :width="columnWidths.nextPlan" fixed-width>
+            <template #default="scope">
+              <el-tooltip
+                effect="light"
+                :content="scope.row.nextPlan"
+                placement="top"
+                popper-class="long-text-tooltip"
+                :disabled="!scope.row.nextPlan || scope.row.nextPlan.length <= 30"
+              >
+                <span class="long-text">{{ formatLongText(scope.row.nextPlan) }}</span>
+              </el-tooltip>
+            </template>
+          </el-table-column>
           <el-table-column label="外租设备" align="center" prop="externalRental" :width="columnWidths.externalRental"/>
-          <el-table-column label="故障情况" align="center" prop="malfunction" :width="columnWidths.malfunction"/>
-          <el-table-column label="故障误工H" align="center" prop="faultDowntime" :width="columnWidths.faultDowntime"/>
+          <el-table-column label="故障情况" align="center" prop="malfunction" :width="columnWidths.malfunction" v-if="false"/>
+          <el-table-column label="故障误工H" align="center" prop="faultDowntime" :width="columnWidths.faultDowntime" v-if="false"/>
 
           <el-table-column label="操作" align="center" min-width="120px" fixed="right">
             <template #default="scope">
@@ -163,7 +174,7 @@
 </template>
 
 <script setup lang="ts">
-import { dateFormatter } from '@/utils/formatTime'
+import {dateFormatter, dateFormatter2} from '@/utils/formatTime'
 import download from '@/utils/download'
 import { IotRdDailyReportApi, IotRdDailyReportVO } from '@/api/pms/iotrddailyreport'
 import IotRdDailyReportForm from './IotRdDailyReportForm.vue'
@@ -266,6 +277,13 @@ const columnWidths = ref({
   operation: '120px'
 })
 
+// 添加长文本格式化函数
+const formatLongText = (text: string | null | undefined) => {
+  if (!text) return '-';
+  // 如果文本长度超过30个字符,显示前30个字符并添加省略号
+  return text.length > 30 ? text.substring(0, 30) + '...' : text;
+};
+
 // 计算文本宽度
 const getTextWidth = (text: string, fontSize = 14) => {
   const span = document.createElement('span');
@@ -295,6 +313,11 @@ const calculateColumnWidths = () => {
 
   // 计算各列宽度的函数
   const calculateColumnWidth = (key: string, label: string, getValue: Function) => {
+    // 如果是需要固定宽度的列,跳过计算
+    if (key === 'productionStatus' || key === 'nextPlan') {
+      return;
+    }
+
     const headerWidth = getTextWidth(label) + PADDING;
     let contentMaxWidth = MIN_WIDTH;
 
@@ -343,6 +366,10 @@ const calculateColumnWidths = () => {
   calculateColumnWidth('faultDowntime', '故障误工H', (row: any) => row.faultDowntime);
   calculateColumnWidth('createTime', '创建时间', (row: any) => dateFormatter(null, null, row.createTime));
 
+  // 为固定宽度的列设置固定值
+  newWidths.productionStatus = '200px';
+  newWidths.nextPlan = '200px';
+
   // 操作列固定宽度
   newWidths.operation = '120px';
   // id列固定宽度(虽然隐藏)
@@ -470,6 +497,9 @@ onMounted(() => {
   if (route.query.wellName) {
     queryParams.taskName = route.query.wellName as string
   }
+  if (route.query.taskId) {
+    queryParams.taskId = route.query.taskId as number
+  }
   getList()
   // 创建 ResizeObserver 监听表格容器尺寸变化
   if (tableContainerRef.value?.$el) {
@@ -518,4 +548,30 @@ white-space: nowrap;
 :deep(.el-table) {
 min-width: 100%;
 }
+
+/* 长文本样式 - 多行显示并添加省略号 */
+.long-text {
+  display: -webkit-box;
+  -webkit-line-clamp: 2;
+  -webkit-box-orient: vertical;
+  overflow: hidden;
+  text-overflow: ellipsis;
+  line-height: 1.5;
+  max-height: 3em; /* 两行文本的高度 */
+}
+/* 确保固定宽度列不参与自动调整 */
+:deep(.el-table__header-wrapper .el-table__cell.fixed-width),
+:deep(.el-table__body-wrapper .el-table__cell.fixed-width) {
+  flex-shrink: 0;
+  flex-grow: 0;
+}
+</style>
+
+<style>
+/* 长文本 tooltip 样式 - 保留换行符 */
+.long-text-tooltip {
+  white-space: pre-line;
+  max-width: 500px;
+  line-height: 1.5;
+}
 </style>

+ 58 - 11
src/views/pms/iotrddailyreport/statistics.vue

@@ -71,14 +71,20 @@
       <!-- 列表 -->
       <ContentWrap ref="tableContainerRef">
         <el-table ref="tableRef" v-loading="loading" :data="list" :stripe="true" :show-overflow-tooltip="true">
+          <el-table-column label="施工状态" align="center" prop="rdStatus" :width="columnWidths.rdStatus">
+            <template #default="scope">
+              <dict-tag :type="DICT_TYPE.PMS_PROJECT_RD_STATUS" :value="scope.row.rdStatus" />
+            </template>
+          </el-table-column>
+          <el-table-column label="施工周期(D)" align="center" prop="period" :width="columnWidths.projectDeptName"/>
           <el-table-column label="项目部" align="center" prop="projectDeptName" :width="columnWidths.projectDeptName"/>
           <el-table-column label="队伍" align="center" prop="deptName" :width="columnWidths.deptName"/>
-          <el-table-column label="甲方" align="center" prop="manufactureName" :width="columnWidths.manufactureName"/>
+
           <el-table-column label="井号" align="center" prop="wellName" :width="columnWidths.wellName">
             <template #default="scope">
               <el-link
                 type="primary"
-                @click="handleWellNameClick(scope.row.wellName)"
+                @click="handleWellNameClick(scope.row.taskId)"
                 :underline="false"
               >
                 {{ scope.row.wellName }}
@@ -103,7 +109,7 @@
               </template>
             </el-table-column>
           </el-table-column>
-
+          <el-table-column label="甲方" align="center" prop="manufactureName" :width="columnWidths.manufactureName"/>
           <!--
           <el-table-column label="操作" align="center" min-width="120px" fixed="right">
             <template #default="scope">
@@ -132,7 +138,7 @@
           :total="total"
           v-model:page="queryParams.pageNo"
           v-model:limit="queryParams.pageSize"
-          @pagination="getList"
+          @pagination="handlePagination"
         />
       </ContentWrap>
 
@@ -148,7 +154,7 @@ import { dateFormatter } from '@/utils/formatTime'
 import download from '@/utils/download'
 import { IotRdDailyReportApi, IotRdDailyReportVO } from '@/api/pms/iotrddailyreport'
 import IotRdDailyReportForm from './IotRdDailyReportForm.vue'
-import {DICT_TYPE} from "@/utils/dict";
+import {DICT_TYPE, getDictLabel} from "@/utils/dict";
 import { ref, reactive, onMounted, computed } from 'vue'
 import DeptTree2 from "@/views/pms/iotrhdailyreport/DeptTree2.vue";
 
@@ -159,7 +165,6 @@ const message = useMessage() // 消息弹窗
 const { t } = useI18n() // 国际化
 const { push } = useRouter() // 路由跳转
 const loading = ref(true) // 列表的加载中
-const list = ref<IotRdDailyReportVO[]>([]) // 列表的数据
 const total = ref(0) // 列表的总页数
 const queryParams = reactive({
   pageNo: 1,
@@ -211,6 +216,10 @@ const exportLoading = ref(false) // 导出的加载中
 
 const rootDeptId = ref(163)
 
+// 响应式数据
+const allList = ref<IotRdDailyReportVO[]>([]) // 存储所有数据
+const list = ref<IotRdDailyReportVO[]>([]) // 存储当前页数据
+
 // 表格引用
 const tableRef = ref()
 // 表格容器引用
@@ -239,6 +248,7 @@ const getWorkloadByUnit = (items, unit) => {
 // 列宽度配置
 const columnWidths = ref({
   id: '80px',
+  rdStatus: '120px', // 施工状态列默认宽度
   projectDeptName: '120px',
   contractName: '120px',
   deptName: '120px',
@@ -303,6 +313,12 @@ const calculateColumnWidths = () => {
     newWidths[key] = `${finalWidth}px`;
   };
 
+  // 计算施工状态列宽度(使用字典标签文本计算)
+  calculateColumnWidth('rdStatus', '施工状态', (row: any) => {
+    // 用字典标签(如"完工")而非原始编码(如"wg")计算宽度
+    return getDictLabel(DICT_TYPE.PMS_PROJECT_RD_STATUS, row.rdStatus) || row.rdStatus;
+  });
+
   // 计算各列宽度
   calculateColumnWidth('projectDeptName', '项目部', (row: any) => row.projectDeptName);
   calculateColumnWidth('deptName', '队伍', (row: any) => row.deptName);
@@ -330,8 +346,12 @@ const getList = async () => {
   loading.value = true
   try {
     const data = await IotRdDailyReportApi.statistics(queryParams)
-    list.value = data
-    // total.value = data.total
+    // 存储所有数据
+    allList.value = data
+    // 计算总条数
+    total.value = data.length
+    // 执行前端分页
+    handleFrontendPagination()
     // 获取数据后计算列宽
     nextTick(() => {
       calculateColumnWidths();
@@ -342,14 +362,15 @@ const getList = async () => {
 }
 
 /** 井号点击操作 */
-const handleWellNameClick = (wellName: string) => {
-  if (!wellName) return
+const handleWellNameClick = (taskId: number) => {
+  if (!taskId) return
 
   // 跳转到日报列表页面,传递井号参数
   push({
     name: 'IotRdDailyReport',
     query: {
-      wellName: wellName
+      // wellName: wellName
+      taskId: taskId
     }
   })
 }
@@ -364,6 +385,16 @@ const handleDeptNodeClick = async (row) => {
   await getList()
 }
 
+/** 前端分页处理 */
+const handleFrontendPagination = () => {
+  const { pageNo, pageSize } = queryParams
+  const startIndex = (pageNo - 1) * pageSize
+  const endIndex = startIndex + pageSize
+
+  // 对全部数据进行分页切片
+  list.value = allList.value.slice(startIndex, endIndex)
+}
+
 /** 搜索按钮操作 */
 const handleQuery = () => {
   queryParams.pageNo = 1
@@ -376,6 +407,14 @@ const resetQuery = () => {
   handleQuery()
 }
 
+/** 分页事件处理 */
+const handlePagination = (pagination: any) => {
+  queryParams.pageNo = pagination.page
+  queryParams.pageSize = pagination.limit
+  // 使用前端分页,不重新调用接口
+  handleFrontendPagination()
+}
+
 /** 添加/修改操作 */
 const formRef = ref()
 const openForm = (type: string, id?: number) => {
@@ -458,6 +497,14 @@ onUnmounted(() => {
   }
 })
 
+// 监听查询参数变化,实现前端分页
+watch(
+  [() => queryParams.pageNo, () => queryParams.pageSize],
+  () => {
+    handleFrontendPagination()
+  }
+)
+
 // 监听列表数据变化重新计算列宽
 watch(list, () => {
   nextTick(calculateColumnWidths)

+ 75 - 5
src/views/pms/iotrhdailyreport/index.vue

@@ -68,7 +68,7 @@
         </el-form>
       </ContentWrap>
 
-      <!-- 新增数据统计区域 -->
+      <!-- 数据统计区域 -->
       <ContentWrap class="mb-15px">
         <div class="statistics-container">
           <div class="stat-item" :style="{ color: totalColor }">
@@ -89,6 +89,14 @@
               {{ statistics.unFilled || '-' }}
             </span>
           </div>
+          <div class="stat-item" :style="{ color: '#0099CC' }">
+            <span>累计注水量(方):</span>
+            <span>{{ statistics.totalWaterInjection || '-' }}</span>
+          </div>
+          <div class="stat-item" :style="{ color: '#FF9900' }">
+            <span>累计注气量(万方):</span>
+            <span>{{ statistics.totalGasInjection || '-' }}</span>
+          </div>
         </div>
       </ContentWrap>
 
@@ -132,7 +140,7 @@
                 <dict-tag :type="DICT_TYPE.PMS_PROJECT_TASK_SCHEDULE" :value="scope.row.constructionStatus" />
               </template>
             </el-table-column>
-            <el-table-column label="搬迁安装天数" align="center" prop="relocationDays" :width="columnWidths.relocationDays"/>
+            <el-table-column label="搬迁安装天数" align="center" prop="relocationDays" :width="columnWidths.relocationDays" :formatter="relocationDaysFormatter"/>
             <el-table-column label="设计注气量(万方)" align="center" prop="designInjection" :width="columnWidths.designInjection"/>
             <el-table-column label="运行时效" align="center" prop="transitTime" :width="columnWidths.transitTime" :formatter="percentageFormatter"/>
             <el-table-column label="当日注气量(万方)" align="center" prop="dailyGasInjection"
@@ -291,8 +299,11 @@ const rootDeptId = ref(157)
 const statistics = ref({
   total: '-',
   filled: '-',
-  unFilled: '-'
+  unFilled: '-',
+  totalWaterInjection: '-', // 新增累计注水量
+  totalGasInjection: '-'    // 新增累计注气量
 })
+
 const totalColor = '#00DD99'
 const filledColor = '#0055BB'
 const unFilledColor = '#FF5500'
@@ -302,6 +313,12 @@ const tableRef = ref()
 // 表格容器引用
 const tableContainerRef = ref()
 
+// 工作量统计相关变量
+const workloadStatistics = ref({
+  totalWaterInjection: '-',
+  totalGasInjection: '-'
+})
+
 // 列宽度配置
 const columnWidths = ref({
   deptName: '120px',
@@ -431,6 +448,9 @@ const getList = async () => {
     // 获取统计数据
     await getStatistics()
 
+    // 获取工作量统计数据
+    await getWorkloadStatistics()
+
     // 获取数据后计算列宽
     nextTick(() => {
       calculateColumnWidths();
@@ -440,6 +460,15 @@ const getList = async () => {
   }
 }
 
+// 搬迁安装天数格式化函数
+const relocationDaysFormatter = (row: any, column: any, cellValue: any, index: number) => {
+  if (cellValue === null || cellValue === undefined || cellValue === '') return '';
+
+  const value = parseFloat(cellValue);
+  // 如果值为负数,显示0,否则显示原值
+  return value < 0 ? '0' : String(value);
+};
+
 // 注气量格式化函数(单位转换:方 -> 万方)
 const gasInjectionFormatter = (row: any, column: any, cellValue: any, index: number) => {
   if (cellValue === null || cellValue === undefined || cellValue === '') return '';
@@ -557,7 +586,13 @@ const calculateColumnWidths = () => {
     // 这里可以获取字典标签,简化处理使用值本身
     return String(row.constructionStatus || '');
   });
-  calculateColumnMinWidth('relocationDays', '搬迁安装天数', (row: any) => row.relocationDays);
+  // 修改搬迁安装天数的宽度计算,使用格式化后的值
+  calculateColumnMinWidth('relocationDays', '搬迁安装天数', (row: any) => {
+    const value = row.relocationDays;
+    if (value === null || value === undefined || value === '') return '';
+    const numValue = parseFloat(value);
+    return numValue < 0 ? '0' : String(numValue);
+  });
   calculateColumnMinWidth('designInjection', '设计注气量(万方)', (row: any) => row.designInjection);
   calculateColumnMinWidth('transitTime', '运行时效', (row: any) => row.transitTime);
   calculateColumnMinWidth('dailyGasInjection', '当日注气量(万方)', (row: any) => row.dailyGasInjection);
@@ -617,6 +652,33 @@ const calculateColumnWidths = () => {
   });
 };
 
+// 获取工作量统计数据的方法
+const getWorkloadStatistics = async () => {
+  // 重置工作量统计数据
+  statistics.value.totalWaterInjection = '-'
+  statistics.value.totalGasInjection = '-'
+
+  try {
+    const res = await IotRhDailyReportApi.totalWorkload(queryParams)
+
+    // 处理工作量统计数据
+    if (res) {
+      // 累计注水量直接显示,单位:方
+      statistics.value.totalWaterInjection = res.totalWaterInjection || '-'
+
+      // 累计注气量需要转换:方 -> 万方 (除以10000)
+      if (res.totalGasInjection) {
+        const gasInjection = parseFloat(res.totalGasInjection)
+        statistics.value.totalGasInjection = (gasInjection / 10000).toFixed(2)
+      } else {
+        statistics.value.totalGasInjection = '-'
+      }
+    }
+  } catch (error) {
+    console.error('获取工作量统计数据失败', error)
+  }
+}
+
 /** 搜索按钮操作 */
 const handleQuery = () => {
   queryParams.pageNo = 1
@@ -628,6 +690,8 @@ const resetQuery = () => {
   queryFormRef.value.resetFields()
   // 重置后需要重新获取统计数据
   getStatistics()
+  // 重新获取工作量统计数据
+  getWorkloadStatistics()
   handleQuery()
 }
 
@@ -828,7 +892,7 @@ watch(list, () => {
 .statistics-container {
   display: flex;
   justify-content: space-around;
-  padding: 15px 0;
+  padding: 10px 0;
 }
 
 .stat-item {
@@ -836,5 +900,11 @@ watch(list, () => {
   text-align: center;
   font-size: 16px;
   font-weight: 500;
+  min-width: 0; /* 防止内容溢出 */
+}
+
+/* 确保统计项内容不换行 */
+.stat-item span {
+  white-space: nowrap;
 }
 </style>

+ 2 - 0
src/views/pms/iotrydailyreport/index.vue

@@ -113,6 +113,8 @@
             <el-table-column label="完工井数" align="center" prop="completedWells" :width="columnWidths.completedWells"/>
             <el-table-column label="泥浆性能-密度(g/cm³)" align="center" prop="mudDensity" :width="columnWidths.mudDensity"/>
             <el-table-column label="泥浆性能-粘度(S)" align="center" prop="mudViscosity" :width="columnWidths.mudViscosity"/>
+            <el-table-column label="当日用电量(kWh)" align="center" prop="dailyPowerUsage" :width="columnWidths.mudViscosity"/>
+            <el-table-column label="当日油耗(吨)" align="center" prop="dailyFuel" :width="columnWidths.mudViscosity"/>
             <el-table-column
               label="施工开始日期"
               align="center"

+ 2 - 3
src/views/pms/iotrydailyreport/xjindex.vue

@@ -125,9 +125,8 @@
             <el-table-column label="井深(m)" align="center" prop="designWellDepth" :width="columnWidths.designWellDepth"/>
             <el-table-column label="套生段产管尺寸(mm)" align="center" prop="casingPipeSize" :width="columnWidths.casingPipeSize"/>
             <el-table-column label="井控级别" align="center" prop="wellControlLevel" :width="columnWidths.wellControlLevel"/>
-            <!--
-            <el-table-column label="泥浆性能-密度(g/cm³)" align="center" prop="mudDensity" :width="columnWidths.mudDensity"/>
-            <el-table-column label="泥浆性能-粘度(S)" align="center" prop="mudViscosity" :width="columnWidths.mudViscosity"/> -->
+            <el-table-column label="当日用电量(kWh)" align="center" prop="dailyPowerUsage" :width="columnWidths.mudViscosity"/>
+            <el-table-column label="当日油耗(吨)" align="center" prop="dailyFuel" :width="columnWidths.mudViscosity"/>
             <el-table-column
               label="施工开始日期"
               align="center"

+ 95 - 50
src/views/pms/stat/rdkb.vue

@@ -84,17 +84,18 @@
               <span class="text-base font-medium " style="color: #b6c8da">{{t('stat.deviceStatus')}}</span>
             </div>
           </template>
-          <div style="display:flex; align-items:center;min-height: 292px;">
-            <div ref="statusChartRef" style="width:100%; max-width:250px; height:250px;"></div>
-            <div class="text-[12px]" style="width:100%; display:flex; flex-wrap:wrap; justify-content:center; gap:8px; color:#fff;margin-top: -50px;">
-              <div v-for="item in legendData" :key="item.name" style="display:flex; align-items:center; gap:12px; padding:0; min-width:160px; justify-content:space-between;">
-                <div style="display:flex; align-items:center; gap:8px;">
-                  <span :style="{display:'inline-block', width:'12px', height:'12px', 'border-radius':'50%', background:item.color}"></span>
-                  <span>{{ item.name }}</span>
+          <div style="display:flex; align-items:center;  justify-content: center; min-height: 290px; flex-direction:column; gap:6px;">
+            <div ref="statusChartRef" style="width:100%; max-width:200px; height:170px;"></div>
+            <div class="text-[12px] h-[100px] w-[90%] flex flex-col justify-between items-center">
+              <div v-for="item in legendData" :key="item.name" class="flex">
+                <div class="flex items-center gap-1">
+                  <span class="status-legend-color" :style="{background: item.color}"></span>
+                  <span class="w-[100px] text-[#fff]">{{ item.name }}</span>
+                 
                 </div>
-                <div style="display:flex; align-items:center; gap:10px; color:#fff;">
-                  <span style="font-weight:700">{{ item.value }} 台</span>
-                  <span>{{ item.percent }}%</span>
+               <div class="flex items-center">
+                  <span class="text-[#fff] text-right w-12">{{ item.value }} 台</span>
+                  <span class="status-legend-percent text-right w-14">{{ item.percent }}%</span>
                 </div>
               </div>
             </div>
@@ -113,8 +114,8 @@
               :data="projectData"
               border
               @row-click="projectDataRowClick"
-              :header-cell-style="{color:'#fff'}"
-              :cell-style="{ color: '#fff', height: '65px' }"
+              :header-cell-style="{color:'#fff', 'background-color':'transparent',height:'58px'}"
+              :cell-style="{ color: '#fff', height: '58px' }"
               style="width:100%"
               
               >
@@ -142,7 +143,7 @@
    
     <el-row :gutter="16" class="mb-4">
       <!-- 备件更换情况部分保持不变 -->
-      <el-col :span="10" :xs="24">
+      <el-col :span="12" :xs="24">
         <el-card class="chart-card" shadow="never">
           <template #header>
             <div style="display: flex; flex-direction: row; justify-content: space-between">
@@ -195,8 +196,9 @@
               @row-click="handleRowClick"
               style="width: 100%; color: #4c4c4c;"
               :header-cell-style="{
-                'background-color': '#2196df',
+                'background-color': 'transparent',
                 'color': 'white',
+                'height':'56px',
                 'border-color': '#457794'
               }"
               :cell-style="{
@@ -236,7 +238,7 @@
         </el-card>
       </el-col>
       <!-- 月度工作量表 -->
-      <el-col :span="14" :xs="24">
+      <el-col :span="12" :xs="24">
         <el-card class="chart-card" shadow="never">
           <template #header>
             <div class="flex items-center justify-between">
@@ -250,32 +252,32 @@
               height="420px"
               :disabled-affix="true"
               style="width:100%"
-              :header-cell-style="{color:'#fff'}"
+              :header-cell-style="{color:'#fff', 'background-color':'transparent'}"
               :cell-style="{ color: '#fff' }"
               :summary-method="tableSummary"
              
               show-summary>
-              <el-table-column prop="month" label="月份" width="80" fixed="left"  align="center" />
+              <el-table-column prop="month" label="月份" width="50" fixed="left"  align="center" />
 
               <el-table-column label="2025年"  align="center">
-                <el-table-column prop="y2025_fractures" label="压裂井数"  align="center" width="110" />
-                <el-table-column prop="y2025_layers" label="压裂层数" width="110"  align="center" />
-                <el-table-column prop="y2025_pump_trips" label="泵车台次" width="110"  align="center" />
-                <el-table-column prop="y2025_oil_wells" label="连油井数" width="110"  align="center" />
+                <el-table-column prop="y2025_fractures" label="压裂井数"  align="center" min-width="50" />
+                <el-table-column prop="y2025_layers" label="压裂层数" min-width="50"  align="center" />
+                <el-table-column prop="y2025_pump_trips" label="泵车台次" min-width="50"  align="center" />
+                <el-table-column prop="y2025_oil_wells" label="连油井数" min-width="50"  align="center" />
               </el-table-column>
 
               <el-table-column label="2024年"  align="center">
-                <el-table-column prop="y2024_fractures" label="压裂井数" width="110"  align="center" />
-                <el-table-column prop="y2024_layers" label="压裂层数" width="110" align="center" />
-                <el-table-column prop="y2024_pump_trips" label="泵车台次" width="110"  align="center" />
-                <el-table-column prop="y2024_oil_wells" label="连油井数" width="110" align="center" />
+                <el-table-column prop="y2024_fractures" label="压裂井数" min-width="50"  align="center" />
+                <el-table-column prop="y2024_layers" label="压裂层数" min-width="50" align="center" />
+                <el-table-column prop="y2024_pump_trips" label="泵车台次" min-width="50"  align="center" />
+                <el-table-column prop="y2024_oil_wells" label="连油井数" min-width="50" align="center" />
               </el-table-column>
 
               <el-table-column label="同比增长量" align="center">
-                <el-table-column prop="diff_fractures" label="压裂井数" width="110" align="center" />
-                <el-table-column prop="diff_layers" label="压裂层数" width="110" align="center" />
-                <el-table-column prop="diff_pump_trips" label="泵车台次" width="110" align="center" />
-                <el-table-column prop="diff_oil_wells" label="连油井数" width="110" align="center" />
+                <el-table-column prop="diff_fractures" label="压裂井数" min-width="50" align="center" />
+                <el-table-column prop="diff_layers" label="压裂层数" min-width="50" align="center" />
+                <el-table-column prop="diff_pump_trips" label="泵车台次" min-width="50" align="center" />
+                <el-table-column prop="diff_oil_wells" label="连油井数" min-width="50" align="center" />
               </el-table-column>
             </el-table>
           </div>
@@ -297,7 +299,7 @@
         border
         style="width: 100%;"
         :header-cell-style="{
-        'background-color': 'rgba(0, 0, 0, 0.2)',
+        'background-color': 'transparent',
         'color': 'black',
         'border-color': '#457794'
       }"
@@ -349,7 +351,7 @@
             <el-table
               :data="domesticData"
               border
-               :header-cell-style="{color:'#fff'}"
+               :header-cell-style="{color:'#fff', 'background-color':'transparent'}"
               :cell-style="{ color: '#fff' }"
               style="width:100%"
               :summary-method="tableSummary"
@@ -383,7 +385,7 @@
             <el-table
               :data="iraqTableData"
               border
-              :header-cell-style="{color:'#fff'}"
+              :header-cell-style="{color:'#fff', 'background-color':'transparent'}"
               :cell-style="{ color: '#fff' }"
               style="width:100%"
               
@@ -418,7 +420,7 @@
             <el-table
               :data="libyaTableData"
               border
-              :header-cell-style="{color:'#fff'}"
+              :header-cell-style="{color:'#fff', 'background-color':'transparent'}"
               :cell-style="{ color: '#fff' }"
               :row-class-name="tableRowClass"
               style="width:100%"
@@ -534,8 +536,23 @@ const typeData = ref([])
 // 配色(与图表保持一致)
 const statusColors = ['#2ed3df', '#34d399', '#ff6b95', '#4aa3ff', '#f59e0b', '#ef4444', '#7dd3fc']
 
+/**
+ * 将后端返回的多种可能结构规范化为数组形式:
+ * - 如果已经是数组则直接使用
+ * - 如果包含 data 或 series 字段且为数组则优先使用
+ * - 否则把对象的键值对转换为 {name, value} 数组
+ */
+const normalizeTypeData = (val) => {
+  if (Array.isArray(val)) return val
+  if (!val || typeof val !== 'object') return []
+  if (Array.isArray(val.data)) return val.data
+  if (Array.isArray(val.series)) return val.series
+  // plain object with keys -> map to array
+  return Object.keys(val).map((k) => ({ name: k, value: val[k] }))
+}
+
 const legendData = computed(() => {
-  const arr = Array.isArray(typeData.value) ? typeData.value : []
+  const arr = normalizeTypeData(typeData.value)
   const total = arr.reduce((s, it) => s + (Number(it.value) || 0), 0)
   return arr.map((it, idx) => ({
     name: it.name,
@@ -1036,7 +1053,7 @@ const initDeviceStatusCharts = () => {
     // ignore
   }
   statusChartInstance = echarts.init(statusChartRef.value)
-  const data = Array.isArray(typeData.value) ? typeData.value : []
+  const data = normalizeTypeData(typeData.value)
   const option = {
     color: statusColors,
     tooltip: {
@@ -1047,8 +1064,8 @@ const initDeviceStatusCharts = () => {
       {
         name: '',
         type: 'pie',
-        radius: ['45%', '65%'],
-        center: ['50%', '36%'],
+        radius: ['38%', '58%'],
+        center: ['50%', '30%'],
         avoidLabelOverlap: false,
         label: { show: false },
         labelLine: { show: false },
@@ -1229,21 +1246,11 @@ onMounted(async () => {
 }
 
 
-::v-deep .el-table th {
-  background-color: #2196df !important;
-}
 
 ::v-deep .el-table__footer {
   color: #fff !important;
 }
-::v-deep .el-table__footer-wrapper {
-  color: #fff !important;
-  background-color: #42c5f9 !important;
-}
 
-::v-deep th.el-table-fixed-column--left {
-  background-color: #3fc1f7 !important;
-}
 
 
 
@@ -1251,9 +1258,7 @@ onMounted(async () => {
   color: #fff !important;
 }
 
-::v-deep td.el-table-fixed-column--left {
-  background-color: #3fc1f7 !important;
-}
+
 
 .summary {
   .el-col {
@@ -1385,4 +1390,44 @@ onMounted(async () => {
 .custom-table :deep .el-table__row {
   height: 50px !important;  /* 高度根据需求调整 */
 }
+
+/* 设备状态图例自适应样式 */
+.status-legend {
+  width: 100%;
+  display: flex;
+  flex-wrap: wrap;
+  justify-content: center;
+  gap: 8px;
+  padding: 6px 0;
+  box-sizing: border-box;
+  max-height: 90px; /* 限制高度,超出显示滚动 */
+  overflow-y: auto;
+}
+.status-legend-item {
+  display: flex;
+  align-items: center;
+  justify-content: space-between;
+  gap: 12px;
+  padding: 6px 10px;
+  min-width: 120px;
+  max-width: 100%;
+  box-sizing: border-box;
+}
+.status-legend-left { display:flex; align-items:center; gap:8px; min-width:0; }
+.status-legend-color { display:inline-block; width:12px; height:12px; border-radius:50%; flex:0 0 12px; }
+.status-legend-name {
+  max-width: calc(100% - 60px);
+  overflow: hidden;
+  text-overflow: ellipsis;
+  white-space: nowrap;
+  color: #fff;
+}
+.status-legend-right { display:flex; align-items:center; gap:8px; flex-shrink:0; }
+.status-legend-value { font-weight:700; color:#fff; }
+.status-legend-percent { color:#fff; }
+
+@media (max-width: 520px) {
+  .status-legend-item { min-width: 100%; }
+  .status-legend { justify-content: flex-start; max-height: none; overflow: visible; }
+}
 </style>

+ 2 - 0
types/env.d.ts

@@ -26,6 +26,8 @@ interface ImportMetaEnv {
   readonly VITE_SOURCEMAP: string
   readonly VITE_OUT_DIR: string
   readonly VITE_GOVIEW_URL: string
+  readonly VITE_DD_CORPID:string
+  readonly VITE_DD_CLIENTID:string
 }
 
 declare global {

+ 1 - 1
vite.config.ts

@@ -86,6 +86,6 @@ export default ({command, mode}: ConfigEnv): UserConfig => {
             }
         },
          // 排除 fullcalendar 相关包,避免依赖扫描
-        optimizeDeps: {include,  exclude: ['@fullcalendar/core', '@fullcalendar/common']}
+        optimizeDeps: {include,  exclude: ['@fullcalendar/core', '@fullcalendar/common', 'fsevents']}
     }
 }

Một số tệp đã không được hiển thị bởi vì quá nhiều tập tin thay đổi trong này khác