提交 8d534f1e authored 作者: coderBryanFu's avatar coderBryanFu

Merge branch 'pre' of http://8.140.26.4:10003/caijian/risk-monitor into fk-dev

流水线 #315 已通过 于阶段
in 1 分 37 秒
...@@ -1750,9 +1750,9 @@ ...@@ -1750,9 +1750,9 @@
} }
}, },
"node_modules/@rollup/rollup-android-arm-eabi": { "node_modules/@rollup/rollup-android-arm-eabi": {
"version": "4.50.2", "version": "4.60.1",
"resolved": "https://registry.npmmirror.com/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.50.2.tgz", "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.60.1.tgz",
"integrity": "sha512-uLN8NAiFVIRKX9ZQha8wy6UUs06UNSZ32xj6giK/rmMXAgKahwExvK6SsmgU5/brh4w/nSgj8e0k3c1HBQpa0A==", "integrity": "sha512-d6FinEBLdIiK+1uACUttJKfgZREXrF0Qc2SmLII7W2AD8FfiZ9Wjd+rD/iRuf5s5dWrr1GgwXCvPqOuDquOowA==",
"cpu": [ "cpu": [
"arm" "arm"
], ],
...@@ -1764,9 +1764,9 @@ ...@@ -1764,9 +1764,9 @@
] ]
}, },
"node_modules/@rollup/rollup-android-arm64": { "node_modules/@rollup/rollup-android-arm64": {
"version": "4.50.2", "version": "4.60.1",
"resolved": "https://registry.npmmirror.com/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.50.2.tgz", "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.60.1.tgz",
"integrity": "sha512-oEouqQk2/zxxj22PNcGSskya+3kV0ZKH+nQxuCCOGJ4oTXBdNTbv+f/E3c74cNLeMO1S5wVWacSws10TTSB77g==", "integrity": "sha512-YjG/EwIDvvYI1YvYbHvDz/BYHtkY4ygUIXHnTdLhG+hKIQFBiosfWiACWortsKPKU/+dUwQQCKQM3qrDe8c9BA==",
"cpu": [ "cpu": [
"arm64" "arm64"
], ],
...@@ -1778,9 +1778,9 @@ ...@@ -1778,9 +1778,9 @@
] ]
}, },
"node_modules/@rollup/rollup-darwin-arm64": { "node_modules/@rollup/rollup-darwin-arm64": {
"version": "4.50.2", "version": "4.60.1",
"resolved": "https://registry.npmmirror.com/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.50.2.tgz", "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.60.1.tgz",
"integrity": "sha512-OZuTVTpj3CDSIxmPgGH8en/XtirV5nfljHZ3wrNwvgkT5DQLhIKAeuFSiwtbMto6oVexV0k1F1zqURPKf5rI1Q==", "integrity": "sha512-mjCpF7GmkRtSJwon+Rq1N8+pI+8l7w5g9Z3vWj4T7abguC4Czwi3Yu/pFaLvA3TTeMVjnu3ctigusqWUfjZzvw==",
"cpu": [ "cpu": [
"arm64" "arm64"
], ],
...@@ -1792,9 +1792,9 @@ ...@@ -1792,9 +1792,9 @@
] ]
}, },
"node_modules/@rollup/rollup-darwin-x64": { "node_modules/@rollup/rollup-darwin-x64": {
"version": "4.50.2", "version": "4.60.1",
"resolved": "https://registry.npmmirror.com/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.50.2.tgz", "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.60.1.tgz",
"integrity": "sha512-Wa/Wn8RFkIkr1vy1k1PB//VYhLnlnn5eaJkfTQKivirOvzu5uVd2It01ukeQstMursuz7S1bU+8WW+1UPXpa8A==", "integrity": "sha512-haZ7hJ1JT4e9hqkoT9R/19XW2QKqjfJVv+i5AGg57S+nLk9lQnJ1F/eZloRO3o9Scy9CM3wQ9l+dkXtcBgN5Ew==",
"cpu": [ "cpu": [
"x64" "x64"
], ],
...@@ -1806,9 +1806,9 @@ ...@@ -1806,9 +1806,9 @@
] ]
}, },
"node_modules/@rollup/rollup-freebsd-arm64": { "node_modules/@rollup/rollup-freebsd-arm64": {
"version": "4.50.2", "version": "4.60.1",
"resolved": "https://registry.npmmirror.com/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.50.2.tgz", "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.60.1.tgz",
"integrity": "sha512-QkzxvH3kYN9J1w7D1A+yIMdI1pPekD+pWx7G5rXgnIlQ1TVYVC6hLl7SOV9pi5q9uIDF9AuIGkuzcbF7+fAhow==", "integrity": "sha512-czw90wpQq3ZsAVBlinZjAYTKduOjTywlG7fEeWKUA7oCmpA8xdTkxZZlwNJKWqILlq0wehoZcJYfBvOyhPTQ6w==",
"cpu": [ "cpu": [
"arm64" "arm64"
], ],
...@@ -1820,9 +1820,9 @@ ...@@ -1820,9 +1820,9 @@
] ]
}, },
"node_modules/@rollup/rollup-freebsd-x64": { "node_modules/@rollup/rollup-freebsd-x64": {
"version": "4.50.2", "version": "4.60.1",
"resolved": "https://registry.npmmirror.com/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.50.2.tgz", "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.60.1.tgz",
"integrity": "sha512-dkYXB0c2XAS3a3jmyDkX4Jk0m7gWLFzq1C3qUnJJ38AyxIF5G/dyS4N9B30nvFseCfgtCEdbYFhk0ChoCGxPog==", "integrity": "sha512-KVB2rqsxTHuBtfOeySEyzEOB7ltlB/ux38iu2rBQzkjbwRVlkhAGIEDiiYnO2kFOkJp+Z7pUXKyrRRFuFUKt+g==",
"cpu": [ "cpu": [
"x64" "x64"
], ],
...@@ -1834,9 +1834,9 @@ ...@@ -1834,9 +1834,9 @@
] ]
}, },
"node_modules/@rollup/rollup-linux-arm-gnueabihf": { "node_modules/@rollup/rollup-linux-arm-gnueabihf": {
"version": "4.50.2", "version": "4.60.1",
"resolved": "https://registry.npmmirror.com/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.50.2.tgz", "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.60.1.tgz",
"integrity": "sha512-9VlPY/BN3AgbukfVHAB8zNFWB/lKEuvzRo1NKev0Po8sYFKx0i+AQlCYftgEjcL43F2h9Ui1ZSdVBc4En/sP2w==", "integrity": "sha512-L+34Qqil+v5uC0zEubW7uByo78WOCIrBvci69E7sFASRl0X7b/MB6Cqd1lky/CtcSVTydWa2WZwFuWexjS5o6g==",
"cpu": [ "cpu": [
"arm" "arm"
], ],
...@@ -1848,9 +1848,9 @@ ...@@ -1848,9 +1848,9 @@
] ]
}, },
"node_modules/@rollup/rollup-linux-arm-musleabihf": { "node_modules/@rollup/rollup-linux-arm-musleabihf": {
"version": "4.50.2", "version": "4.60.1",
"resolved": "https://registry.npmmirror.com/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.50.2.tgz", "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.60.1.tgz",
"integrity": "sha512-+GdKWOvsifaYNlIVf07QYan1J5F141+vGm5/Y8b9uCZnG/nxoGqgCmR24mv0koIWWuqvFYnbURRqw1lv7IBINw==", "integrity": "sha512-n83O8rt4v34hgFzlkb1ycniJh7IR5RCIqt6mz1VRJD6pmhRi0CXdmfnLu9dIUS6buzh60IvACM842Ffb3xd6Gg==",
"cpu": [ "cpu": [
"arm" "arm"
], ],
...@@ -1862,9 +1862,9 @@ ...@@ -1862,9 +1862,9 @@
] ]
}, },
"node_modules/@rollup/rollup-linux-arm64-gnu": { "node_modules/@rollup/rollup-linux-arm64-gnu": {
"version": "4.50.2", "version": "4.60.1",
"resolved": "https://registry.npmmirror.com/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.50.2.tgz", "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.60.1.tgz",
"integrity": "sha512-df0Eou14ojtUdLQdPFnymEQteENwSJAdLf5KCDrmZNsy1c3YaCNaJvYsEUHnrg+/DLBH612/R0xd3dD03uz2dg==", "integrity": "sha512-Nql7sTeAzhTAja3QXeAI48+/+GjBJ+QmAH13snn0AJSNL50JsDqotyudHyMbO2RbJkskbMbFJfIJKWA6R1LCJQ==",
"cpu": [ "cpu": [
"arm64" "arm64"
], ],
...@@ -1876,9 +1876,9 @@ ...@@ -1876,9 +1876,9 @@
] ]
}, },
"node_modules/@rollup/rollup-linux-arm64-musl": { "node_modules/@rollup/rollup-linux-arm64-musl": {
"version": "4.50.2", "version": "4.60.1",
"resolved": "https://registry.npmmirror.com/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.50.2.tgz", "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.60.1.tgz",
"integrity": "sha512-iPeouV0UIDtz8j1YFR4OJ/zf7evjauqv7jQ/EFs0ClIyL+by++hiaDAfFipjOgyz6y6xbDvJuiU4HwpVMpRFDQ==", "integrity": "sha512-+pUymDhd0ys9GcKZPPWlFiZ67sTWV5UU6zOJat02M1+PiuSGDziyRuI/pPue3hoUwm2uGfxdL+trT6Z9rxnlMA==",
"cpu": [ "cpu": [
"arm64" "arm64"
], ],
...@@ -1890,9 +1890,23 @@ ...@@ -1890,9 +1890,23 @@
] ]
}, },
"node_modules/@rollup/rollup-linux-loong64-gnu": { "node_modules/@rollup/rollup-linux-loong64-gnu": {
"version": "4.50.2", "version": "4.60.1",
"resolved": "https://registry.npmmirror.com/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.50.2.tgz", "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.60.1.tgz",
"integrity": "sha512-OL6KaNvBopLlj5fTa5D5bau4W82f+1TyTZRr2BdnfsrnQnmdxh4okMxR2DcDkJuh4KeoQZVuvHvzuD/lyLn2Kw==", "integrity": "sha512-VSvgvQeIcsEvY4bKDHEDWcpW4Yw7BtlKG1GUT4FzBUlEKQK0rWHYBqQt6Fm2taXS+1bXvJT6kICu5ZwqKCnvlQ==",
"cpu": [
"loong64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
]
},
"node_modules/@rollup/rollup-linux-loong64-musl": {
"version": "4.60.1",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.60.1.tgz",
"integrity": "sha512-4LqhUomJqwe641gsPp6xLfhqWMbQV04KtPp7/dIp0nzPxAkNY1AbwL5W0MQpcalLYk07vaW9Kp1PBhdpZYYcEw==",
"cpu": [ "cpu": [
"loong64" "loong64"
], ],
...@@ -1904,9 +1918,23 @@ ...@@ -1904,9 +1918,23 @@
] ]
}, },
"node_modules/@rollup/rollup-linux-ppc64-gnu": { "node_modules/@rollup/rollup-linux-ppc64-gnu": {
"version": "4.50.2", "version": "4.60.1",
"resolved": "https://registry.npmmirror.com/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.50.2.tgz", "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.60.1.tgz",
"integrity": "sha512-I21VJl1w6z/K5OTRl6aS9DDsqezEZ/yKpbqlvfHbW0CEF5IL8ATBMuUx6/mp683rKTK8thjs/0BaNrZLXetLag==", "integrity": "sha512-tLQQ9aPvkBxOc/EUT6j3pyeMD6Hb8QF2BTBnCQWP/uu1lhc9AIrIjKnLYMEroIz/JvtGYgI9dF3AxHZNaEH0rw==",
"cpu": [
"ppc64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
]
},
"node_modules/@rollup/rollup-linux-ppc64-musl": {
"version": "4.60.1",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.60.1.tgz",
"integrity": "sha512-RMxFhJwc9fSXP6PqmAz4cbv3kAyvD1etJFjTx4ONqFP9DkTkXsAMU4v3Vyc5BgzC+anz7nS/9tp4obsKfqkDHg==",
"cpu": [ "cpu": [
"ppc64" "ppc64"
], ],
...@@ -1918,9 +1946,9 @@ ...@@ -1918,9 +1946,9 @@
] ]
}, },
"node_modules/@rollup/rollup-linux-riscv64-gnu": { "node_modules/@rollup/rollup-linux-riscv64-gnu": {
"version": "4.50.2", "version": "4.60.1",
"resolved": "https://registry.npmmirror.com/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.50.2.tgz", "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.60.1.tgz",
"integrity": "sha512-Hq6aQJT/qFFHrYMjS20nV+9SKrXL2lvFBENZoKfoTH2kKDOJqff5OSJr4x72ZaG/uUn+XmBnGhfr4lwMRrmqCQ==", "integrity": "sha512-QKgFl+Yc1eEk6MmOBfRHYF6lTxiiiV3/z/BRrbSiW2I7AFTXoBFvdMEyglohPj//2mZS4hDOqeB0H1ACh3sBbg==",
"cpu": [ "cpu": [
"riscv64" "riscv64"
], ],
...@@ -1932,9 +1960,9 @@ ...@@ -1932,9 +1960,9 @@
] ]
}, },
"node_modules/@rollup/rollup-linux-riscv64-musl": { "node_modules/@rollup/rollup-linux-riscv64-musl": {
"version": "4.50.2", "version": "4.60.1",
"resolved": "https://registry.npmmirror.com/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.50.2.tgz", "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.60.1.tgz",
"integrity": "sha512-82rBSEXRv5qtKyr0xZ/YMF531oj2AIpLZkeNYxmKNN6I2sVE9PGegN99tYDLK2fYHJITL1P2Lgb4ZXnv0PjQvw==", "integrity": "sha512-RAjXjP/8c6ZtzatZcA1RaQr6O1TRhzC+adn8YZDnChliZHviqIjmvFwHcxi4JKPSDAt6Uhf/7vqcBzQJy0PDJg==",
"cpu": [ "cpu": [
"riscv64" "riscv64"
], ],
...@@ -1946,9 +1974,9 @@ ...@@ -1946,9 +1974,9 @@
] ]
}, },
"node_modules/@rollup/rollup-linux-s390x-gnu": { "node_modules/@rollup/rollup-linux-s390x-gnu": {
"version": "4.50.2", "version": "4.60.1",
"resolved": "https://registry.npmmirror.com/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.50.2.tgz", "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.60.1.tgz",
"integrity": "sha512-4Q3S3Hy7pC6uaRo9gtXUTJ+EKo9AKs3BXKc2jYypEcMQ49gDPFU2P1ariX9SEtBzE5egIX6fSUmbmGazwBVF9w==", "integrity": "sha512-wcuocpaOlaL1COBYiA89O6yfjlp3RwKDeTIA0hM7OpmhR1Bjo9j31G1uQVpDlTvwxGn2nQs65fBFL5UFd76FcQ==",
"cpu": [ "cpu": [
"s390x" "s390x"
], ],
...@@ -1960,9 +1988,9 @@ ...@@ -1960,9 +1988,9 @@
] ]
}, },
"node_modules/@rollup/rollup-linux-x64-gnu": { "node_modules/@rollup/rollup-linux-x64-gnu": {
"version": "4.50.2", "version": "4.60.1",
"resolved": "https://registry.npmmirror.com/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.50.2.tgz", "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.60.1.tgz",
"integrity": "sha512-9Jie/At6qk70dNIcopcL4p+1UirusEtznpNtcq/u/C5cC4HBX7qSGsYIcG6bdxj15EYWhHiu02YvmdPzylIZlA==", "integrity": "sha512-77PpsFQUCOiZR9+LQEFg9GClyfkNXj1MP6wRnzYs0EeWbPcHs02AXu4xuUbM1zhwn3wqaizle3AEYg5aeoohhg==",
"cpu": [ "cpu": [
"x64" "x64"
], ],
...@@ -1974,9 +2002,9 @@ ...@@ -1974,9 +2002,9 @@
] ]
}, },
"node_modules/@rollup/rollup-linux-x64-musl": { "node_modules/@rollup/rollup-linux-x64-musl": {
"version": "4.50.2", "version": "4.60.1",
"resolved": "https://registry.npmmirror.com/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.50.2.tgz", "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.60.1.tgz",
"integrity": "sha512-HPNJwxPL3EmhzeAnsWQCM3DcoqOz3/IC6de9rWfGR8ZCuEHETi9km66bH/wG3YH0V3nyzyFEGUZeL5PKyy4xvw==", "integrity": "sha512-5cIATbk5vynAjqqmyBjlciMJl1+R/CwX9oLk/EyiFXDWd95KpHdrOJT//rnUl4cUcskrd0jCCw3wpZnhIHdD9w==",
"cpu": [ "cpu": [
"x64" "x64"
], ],
...@@ -1987,10 +2015,24 @@ ...@@ -1987,10 +2015,24 @@
"linux" "linux"
] ]
}, },
"node_modules/@rollup/rollup-openbsd-x64": {
"version": "4.60.1",
"resolved": "https://registry.npmjs.org/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.60.1.tgz",
"integrity": "sha512-cl0w09WsCi17mcmWqqglez9Gk8isgeWvoUZ3WiJFYSR3zjBQc2J5/ihSjpl+VLjPqjQ/1hJRcqBfLjssREQILw==",
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"openbsd"
]
},
"node_modules/@rollup/rollup-openharmony-arm64": { "node_modules/@rollup/rollup-openharmony-arm64": {
"version": "4.50.2", "version": "4.60.1",
"resolved": "https://registry.npmmirror.com/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.50.2.tgz", "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.60.1.tgz",
"integrity": "sha512-nMKvq6FRHSzYfKLHZ+cChowlEkR2lj/V0jYj9JnGUVPL2/mIeFGmVM2mLaFeNa5Jev7W7TovXqXIG2d39y1KYA==", "integrity": "sha512-4Cv23ZrONRbNtbZa37mLSueXUCtN7MXccChtKpUnQNgF010rjrjfHx3QxkS2PI7LqGT5xXyYs1a7LbzAwT0iCA==",
"cpu": [ "cpu": [
"arm64" "arm64"
], ],
...@@ -2002,9 +2044,9 @@ ...@@ -2002,9 +2044,9 @@
] ]
}, },
"node_modules/@rollup/rollup-win32-arm64-msvc": { "node_modules/@rollup/rollup-win32-arm64-msvc": {
"version": "4.50.2", "version": "4.60.1",
"resolved": "https://registry.npmmirror.com/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.50.2.tgz", "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.60.1.tgz",
"integrity": "sha512-eFUvvnTYEKeTyHEijQKz81bLrUQOXKZqECeiWH6tb8eXXbZk+CXSG2aFrig2BQ/pjiVRj36zysjgILkqarS2YA==", "integrity": "sha512-i1okWYkA4FJICtr7KpYzFpRTHgy5jdDbZiWfvny21iIKky5YExiDXP+zbXzm3dUcFpkEeYNHgQ5fuG236JPq0g==",
"cpu": [ "cpu": [
"arm64" "arm64"
], ],
...@@ -2016,9 +2058,9 @@ ...@@ -2016,9 +2058,9 @@
] ]
}, },
"node_modules/@rollup/rollup-win32-ia32-msvc": { "node_modules/@rollup/rollup-win32-ia32-msvc": {
"version": "4.50.2", "version": "4.60.1",
"resolved": "https://registry.npmmirror.com/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.50.2.tgz", "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.60.1.tgz",
"integrity": "sha512-cBaWmXqyfRhH8zmUxK3d3sAhEWLrtMjWBRwdMMHJIXSjvjLKvv49adxiEz+FJ8AP90apSDDBx2Tyd/WylV6ikA==", "integrity": "sha512-u09m3CuwLzShA0EYKMNiFgcjjzwqtUMLmuCJLeZWjjOYA3IT2Di09KaxGBTP9xVztWyIWjVdsB2E9goMjZvTQg==",
"cpu": [ "cpu": [
"ia32" "ia32"
], ],
...@@ -2029,10 +2071,24 @@ ...@@ -2029,10 +2071,24 @@
"win32" "win32"
] ]
}, },
"node_modules/@rollup/rollup-win32-x64-gnu": {
"version": "4.60.1",
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.60.1.tgz",
"integrity": "sha512-k+600V9Zl1CM7eZxJgMyTUzmrmhB/0XZnF4pRypKAlAgxmedUA+1v9R+XOFv56W4SlHEzfeMtzujLJD22Uz5zg==",
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"win32"
]
},
"node_modules/@rollup/rollup-win32-x64-msvc": { "node_modules/@rollup/rollup-win32-x64-msvc": {
"version": "4.50.2", "version": "4.60.1",
"resolved": "https://registry.npmmirror.com/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.50.2.tgz", "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.60.1.tgz",
"integrity": "sha512-APwKy6YUhvZaEoHyM+9xqmTpviEI+9eL7LoCH+aLcvWYHJ663qG5zx7WzWZY+a9qkg5JtzcMyJ9z0WtQBMDmgA==", "integrity": "sha512-lWMnixq/QzxyhTV6NjQJ4SFo1J6PvOX8vUx5Wb4bBPsEb+8xZ89Bz6kOXpfXj9ak9AHTQVQzlgzBEc1SyM27xQ==",
"cpu": [ "cpu": [
"x64" "x64"
], ],
...@@ -2551,9 +2607,9 @@ ...@@ -2551,9 +2607,9 @@
} }
}, },
"node_modules/anymatch/node_modules/picomatch": { "node_modules/anymatch/node_modules/picomatch": {
"version": "2.3.1", "version": "2.3.2",
"resolved": "https://registry.npmmirror.com/picomatch/-/picomatch-2.3.1.tgz", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz",
"integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"engines": { "engines": {
...@@ -2650,7 +2706,7 @@ ...@@ -2650,7 +2706,7 @@
}, },
"node_modules/asynckit": { "node_modules/asynckit": {
"version": "0.4.0", "version": "0.4.0",
"resolved": "https://registry.npmmirror.com/asynckit/-/asynckit-0.4.0.tgz", "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
"integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==",
"license": "MIT" "license": "MIT"
}, },
...@@ -2704,14 +2760,14 @@ ...@@ -2704,14 +2760,14 @@
} }
}, },
"node_modules/axios": { "node_modules/axios": {
"version": "1.12.2", "version": "1.14.0",
"resolved": "https://registry.npmmirror.com/axios/-/axios-1.12.2.tgz", "resolved": "https://registry.npmjs.org/axios/-/axios-1.14.0.tgz",
"integrity": "sha512-vMJzPewAlRyOgxV2dU0Cuz2O8zzzx9VYtbJOaBgXFeLc4IV/Eg50n4LowmehOOR61S8ZMpc2K5Sa7g6A4jfkUw==", "integrity": "sha512-3Y8yrqLSwjuzpXuZ0oIYZ/XGgLwUIBU3uLvbcpb0pidD9ctpShJd43KSlEEkVQg6DS0G9NKyzOvBfUtDKEyHvQ==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"follow-redirects": "^1.15.6", "follow-redirects": "^1.15.11",
"form-data": "^4.0.4", "form-data": "^4.0.5",
"proxy-from-env": "^1.1.0" "proxy-from-env": "^2.1.0"
} }
}, },
"node_modules/balanced-match": { "node_modules/balanced-match": {
...@@ -2795,9 +2851,9 @@ ...@@ -2795,9 +2851,9 @@
} }
}, },
"node_modules/brace-expansion": { "node_modules/brace-expansion": {
"version": "2.0.2", "version": "2.0.3",
"resolved": "https://registry.npmmirror.com/brace-expansion/-/brace-expansion-2.0.2.tgz", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.3.tgz",
"integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", "integrity": "sha512-MCV/fYJEbqx68aE58kv2cA/kiky1G8vux3OR6/jbS+jIMe/6fJWa0DTzJU7dqijOWYwHi1t29FlfYI9uytqlpA==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
...@@ -2873,7 +2929,7 @@ ...@@ -2873,7 +2929,7 @@
}, },
"node_modules/call-bind-apply-helpers": { "node_modules/call-bind-apply-helpers": {
"version": "1.0.2", "version": "1.0.2",
"resolved": "https://registry.npmmirror.com/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz",
"integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
...@@ -3073,7 +3129,7 @@ ...@@ -3073,7 +3129,7 @@
}, },
"node_modules/combined-stream": { "node_modules/combined-stream": {
"version": "1.0.8", "version": "1.0.8",
"resolved": "https://registry.npmmirror.com/combined-stream/-/combined-stream-1.0.8.tgz", "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
"integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
...@@ -3789,7 +3845,7 @@ ...@@ -3789,7 +3845,7 @@
}, },
"node_modules/delayed-stream": { "node_modules/delayed-stream": {
"version": "1.0.0", "version": "1.0.0",
"resolved": "https://registry.npmmirror.com/delayed-stream/-/delayed-stream-1.0.0.tgz", "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
"integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==",
"license": "MIT", "license": "MIT",
"engines": { "engines": {
...@@ -3832,9 +3888,9 @@ ...@@ -3832,9 +3888,9 @@
"license": "Apache-2.0" "license": "Apache-2.0"
}, },
"node_modules/diff": { "node_modules/diff": {
"version": "5.2.0", "version": "5.2.2",
"resolved": "https://registry.npmmirror.com/diff/-/diff-5.2.0.tgz", "resolved": "https://registry.npmjs.org/diff/-/diff-5.2.2.tgz",
"integrity": "sha512-uIFDxqpRZGZ6ThOk84hEfqWoHx2devRFvpTZcTHur85vImfaxUbTW9Ryh4CpCuDnToOP1CEtXKIgytHBPVff5A==", "integrity": "sha512-vtcDfH3TOjP8UekytvnHH1o1P4FcUdt4eQ1Y+Abap1tk/OB2MWQvcwS2ClCd1zuIhc3JKOx6p3kod8Vfys3E+A==",
"license": "BSD-3-Clause", "license": "BSD-3-Clause",
"engines": { "engines": {
"node": ">=0.3.1" "node": ">=0.3.1"
...@@ -3860,9 +3916,9 @@ ...@@ -3860,9 +3916,9 @@
"license": "MIT" "license": "MIT"
}, },
"node_modules/dompurify": { "node_modules/dompurify": {
"version": "3.3.0", "version": "3.3.3",
"resolved": "https://registry.npmmirror.com/dompurify/-/dompurify-3.3.0.tgz", "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.3.3.tgz",
"integrity": "sha512-r+f6MYR1gGN1eJv0TVQbhA7if/U7P87cdPl3HN5rikqaBSBxLiCb/b9O+2eG0cxz0ghyU+mU1QkbsOwERMYlWQ==", "integrity": "sha512-Oj6pzI2+RqBfFG+qOaOLbFXLQ90ARpcGG6UePL82bJLtdsa6CYJD7nmiU8MW9nQNOtCHV3lZ/Bzq1X0QYbBZCA==",
"license": "(MPL-2.0 OR Apache-2.0)", "license": "(MPL-2.0 OR Apache-2.0)",
"optionalDependencies": { "optionalDependencies": {
"@types/trusted-types": "^2.0.7" "@types/trusted-types": "^2.0.7"
...@@ -3870,7 +3926,7 @@ ...@@ -3870,7 +3926,7 @@
}, },
"node_modules/dunder-proto": { "node_modules/dunder-proto": {
"version": "1.0.1", "version": "1.0.1",
"resolved": "https://registry.npmmirror.com/dunder-proto/-/dunder-proto-1.0.1.tgz", "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz",
"integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
...@@ -3963,7 +4019,7 @@ ...@@ -3963,7 +4019,7 @@
}, },
"node_modules/es-define-property": { "node_modules/es-define-property": {
"version": "1.0.1", "version": "1.0.1",
"resolved": "https://registry.npmmirror.com/es-define-property/-/es-define-property-1.0.1.tgz", "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz",
"integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==",
"license": "MIT", "license": "MIT",
"engines": { "engines": {
...@@ -3972,7 +4028,7 @@ ...@@ -3972,7 +4028,7 @@
}, },
"node_modules/es-errors": { "node_modules/es-errors": {
"version": "1.3.0", "version": "1.3.0",
"resolved": "https://registry.npmmirror.com/es-errors/-/es-errors-1.3.0.tgz", "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz",
"integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==",
"license": "MIT", "license": "MIT",
"engines": { "engines": {
...@@ -3981,7 +4037,7 @@ ...@@ -3981,7 +4037,7 @@
}, },
"node_modules/es-object-atoms": { "node_modules/es-object-atoms": {
"version": "1.1.1", "version": "1.1.1",
"resolved": "https://registry.npmmirror.com/es-object-atoms/-/es-object-atoms-1.1.1.tgz", "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz",
"integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
...@@ -3993,7 +4049,7 @@ ...@@ -3993,7 +4049,7 @@
}, },
"node_modules/es-set-tostringtag": { "node_modules/es-set-tostringtag": {
"version": "2.1.0", "version": "2.1.0",
"resolved": "https://registry.npmmirror.com/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz", "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz",
"integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==", "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
...@@ -4304,9 +4360,9 @@ ...@@ -4304,9 +4360,9 @@
} }
}, },
"node_modules/form-data": { "node_modules/form-data": {
"version": "4.0.4", "version": "4.0.5",
"resolved": "https://registry.npmmirror.com/form-data/-/form-data-4.0.4.tgz", "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.5.tgz",
"integrity": "sha512-KrGhL9Q4zjj0kiUt5OO4Mr/A/jlI2jDYs5eHBpYHPcBEVSiipAvn2Ko2HnPe20rmcuuvMHNdZFp+4IlGTMF0Ow==", "integrity": "sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"asynckit": "^0.4.0", "asynckit": "^0.4.0",
...@@ -4391,7 +4447,7 @@ ...@@ -4391,7 +4447,7 @@
}, },
"node_modules/get-intrinsic": { "node_modules/get-intrinsic": {
"version": "1.3.0", "version": "1.3.0",
"resolved": "https://registry.npmmirror.com/get-intrinsic/-/get-intrinsic-1.3.0.tgz", "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz",
"integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
...@@ -4415,7 +4471,7 @@ ...@@ -4415,7 +4471,7 @@
}, },
"node_modules/get-proto": { "node_modules/get-proto": {
"version": "1.0.1", "version": "1.0.1",
"resolved": "https://registry.npmmirror.com/get-proto/-/get-proto-1.0.1.tgz", "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz",
"integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
...@@ -4486,9 +4542,9 @@ ...@@ -4486,9 +4542,9 @@
"license": "BSD" "license": "BSD"
}, },
"node_modules/glob/node_modules/brace-expansion": { "node_modules/glob/node_modules/brace-expansion": {
"version": "1.1.12", "version": "1.1.13",
"resolved": "https://registry.npmmirror.com/brace-expansion/-/brace-expansion-1.1.12.tgz", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.13.tgz",
"integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", "integrity": "sha512-9ZLprWS6EENmhEOpjCYW2c8VkmOvckIJZfkr7rBW6dObmfgJ/L1GpSYW5Hpo9lDz4D1+n0Ckz8rU7FwHDQiG/w==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"balanced-match": "^1.0.0", "balanced-match": "^1.0.0",
...@@ -4496,9 +4552,9 @@ ...@@ -4496,9 +4552,9 @@
} }
}, },
"node_modules/glob/node_modules/minimatch": { "node_modules/glob/node_modules/minimatch": {
"version": "3.1.2", "version": "3.1.5",
"resolved": "https://registry.npmmirror.com/minimatch/-/minimatch-3.1.2.tgz", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz",
"integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==",
"license": "ISC", "license": "ISC",
"dependencies": { "dependencies": {
"brace-expansion": "^1.1.7" "brace-expansion": "^1.1.7"
...@@ -4698,7 +4754,7 @@ ...@@ -4698,7 +4754,7 @@
}, },
"node_modules/gopd": { "node_modules/gopd": {
"version": "1.2.0", "version": "1.2.0",
"resolved": "https://registry.npmmirror.com/gopd/-/gopd-1.2.0.tgz", "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz",
"integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==",
"license": "MIT", "license": "MIT",
"engines": { "engines": {
...@@ -4748,7 +4804,7 @@ ...@@ -4748,7 +4804,7 @@
}, },
"node_modules/has-symbols": { "node_modules/has-symbols": {
"version": "1.1.0", "version": "1.1.0",
"resolved": "https://registry.npmmirror.com/has-symbols/-/has-symbols-1.1.0.tgz", "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz",
"integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==",
"license": "MIT", "license": "MIT",
"engines": { "engines": {
...@@ -4760,7 +4816,7 @@ ...@@ -4760,7 +4816,7 @@
}, },
"node_modules/has-tostringtag": { "node_modules/has-tostringtag": {
"version": "1.0.2", "version": "1.0.2",
"resolved": "https://registry.npmmirror.com/has-tostringtag/-/has-tostringtag-1.0.2.tgz", "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz",
"integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
...@@ -4904,9 +4960,9 @@ ...@@ -4904,9 +4960,9 @@
} }
}, },
"node_modules/immutable": { "node_modules/immutable": {
"version": "5.1.3", "version": "5.1.5",
"resolved": "https://registry.npmmirror.com/immutable/-/immutable-5.1.3.tgz", "resolved": "https://registry.npmjs.org/immutable/-/immutable-5.1.5.tgz",
"integrity": "sha512-+chQdDfvscSF1SJqv2gn4SRO2ZyS3xL3r7IW/wWEEzrzLisnOlKiQu5ytC/BVNcS15C39WT2Hg/bjKjDMcu+zg==", "integrity": "sha512-t7xcm2siw+hlUM68I+UEOK+z84RzmN59as9DZ7P1l0994DKUWV7UXBMQZVxaoMSRQ+PBZbHCOoBt7a2wxOMt+A==",
"dev": true, "dev": true,
"license": "MIT" "license": "MIT"
}, },
...@@ -5141,9 +5197,9 @@ ...@@ -5141,9 +5197,9 @@
"license": "MIT" "license": "MIT"
}, },
"node_modules/js-yaml": { "node_modules/js-yaml": {
"version": "3.14.1", "version": "3.14.2",
"resolved": "https://registry.npmmirror.com/js-yaml/-/js-yaml-3.14.1.tgz", "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.2.tgz",
"integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", "integrity": "sha512-PMSmkqxr106Xa156c2M265Z+FTrPl+oxd/rgOQy2tijQeK5TxQ43psO1ZCwhVOSdnn+RzkzlRz/eY4BgJBYVpg==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"argparse": "^1.0.7", "argparse": "^1.0.7",
...@@ -5275,15 +5331,15 @@ ...@@ -5275,15 +5331,15 @@
} }
}, },
"node_modules/lodash": { "node_modules/lodash": {
"version": "4.17.21", "version": "4.18.1",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.18.1.tgz",
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", "integrity": "sha512-dMInicTPVE8d1e5otfwmmjlxkZoUpiVLwyeTdUsi/Caj/gfzzblBcCE5sRHV/AsjuCmxWrte2TNGSYuCeCq+0Q==",
"license": "MIT" "license": "MIT"
}, },
"node_modules/lodash-es": { "node_modules/lodash-es": {
"version": "4.17.21", "version": "4.18.1",
"resolved": "https://registry.npmmirror.com/lodash-es/-/lodash-es-4.17.21.tgz", "resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.18.1.tgz",
"integrity": "sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==", "integrity": "sha512-J8xewKD/Gk22OZbhpOVSwcs60zhd95ESDwezOFuA3/099925PdHJ7OFHNTGtajL3AlZkykD32HykiMo+BIBI8A==",
"license": "MIT" "license": "MIT"
}, },
"node_modules/lodash-unified": { "node_modules/lodash-unified": {
...@@ -5328,9 +5384,9 @@ ...@@ -5328,9 +5384,9 @@
} }
}, },
"node_modules/markdown-it": { "node_modules/markdown-it": {
"version": "14.1.0", "version": "14.1.1",
"resolved": "https://registry.npmmirror.com/markdown-it/-/markdown-it-14.1.0.tgz", "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-14.1.1.tgz",
"integrity": "sha512-a54IwgWPaeBCAAsv13YgmALOF1elABB08FxO9i+r4VFk5Vl4pKokRPeX8u5TCgSsPi6ec1otfLjdOpVcgbpshg==", "integrity": "sha512-BuU2qnTti9YKgK5N+IeMubp14ZUKUUw7yeJbkjtosvHiP0AZ5c8IAgEMk79D0eC8F23r4Ac/q8cAIFdm2FtyoA==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"argparse": "^2.0.1", "argparse": "^2.0.1",
...@@ -5403,7 +5459,7 @@ ...@@ -5403,7 +5459,7 @@
}, },
"node_modules/math-intrinsics": { "node_modules/math-intrinsics": {
"version": "1.1.0", "version": "1.1.0",
"resolved": "https://registry.npmmirror.com/math-intrinsics/-/math-intrinsics-1.1.0.tgz", "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz",
"integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==",
"license": "MIT", "license": "MIT",
"engines": { "engines": {
...@@ -5953,9 +6009,9 @@ ...@@ -5953,9 +6009,9 @@
} }
}, },
"node_modules/micromatch/node_modules/picomatch": { "node_modules/micromatch/node_modules/picomatch": {
"version": "2.3.1", "version": "2.3.2",
"resolved": "https://registry.npmmirror.com/picomatch/-/picomatch-2.3.1.tgz", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz",
"integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"engines": { "engines": {
...@@ -5967,7 +6023,7 @@ ...@@ -5967,7 +6023,7 @@
}, },
"node_modules/mime-db": { "node_modules/mime-db": {
"version": "1.52.0", "version": "1.52.0",
"resolved": "https://registry.npmmirror.com/mime-db/-/mime-db-1.52.0.tgz", "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
"integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==",
"license": "MIT", "license": "MIT",
"engines": { "engines": {
...@@ -5976,7 +6032,7 @@ ...@@ -5976,7 +6032,7 @@
}, },
"node_modules/mime-types": { "node_modules/mime-types": {
"version": "2.1.35", "version": "2.1.35",
"resolved": "https://registry.npmmirror.com/mime-types/-/mime-types-2.1.35.tgz", "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz",
"integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
...@@ -5987,13 +6043,13 @@ ...@@ -5987,13 +6043,13 @@
} }
}, },
"node_modules/minimatch": { "node_modules/minimatch": {
"version": "9.0.5", "version": "9.0.9",
"resolved": "https://registry.npmmirror.com/minimatch/-/minimatch-9.0.5.tgz", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.9.tgz",
"integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", "integrity": "sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==",
"dev": true, "dev": true,
"license": "ISC", "license": "ISC",
"dependencies": { "dependencies": {
"brace-expansion": "^2.0.1" "brace-expansion": "^2.0.2"
}, },
"engines": { "engines": {
"node": ">=16 || 14 >=14.17" "node": ">=16 || 14 >=14.17"
...@@ -6406,9 +6462,9 @@ ...@@ -6406,9 +6462,9 @@
"license": "ISC" "license": "ISC"
}, },
"node_modules/picomatch": { "node_modules/picomatch": {
"version": "4.0.3", "version": "4.0.4",
"resolved": "https://registry.npmmirror.com/picomatch/-/picomatch-4.0.3.tgz", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz",
"integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"engines": { "engines": {
...@@ -6664,10 +6720,13 @@ ...@@ -6664,10 +6720,13 @@
} }
}, },
"node_modules/proxy-from-env": { "node_modules/proxy-from-env": {
"version": "1.1.0", "version": "2.1.0",
"resolved": "https://registry.npmmirror.com/proxy-from-env/-/proxy-from-env-1.1.0.tgz", "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-2.1.0.tgz",
"integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==", "integrity": "sha512-cJ+oHTW1VAEa8cJslgmUZrc+sjRKgAKl3Zyse6+PV38hZe/V6Z14TbCuXcan9F9ghlz4QrFr2c92TNF82UkYHA==",
"license": "MIT" "license": "MIT",
"engines": {
"node": ">=10"
}
}, },
"node_modules/punycode.js": { "node_modules/punycode.js": {
"version": "2.3.1", "version": "2.3.1",
...@@ -6750,9 +6809,9 @@ ...@@ -6750,9 +6809,9 @@
} }
}, },
"node_modules/readdirp/node_modules/picomatch": { "node_modules/readdirp/node_modules/picomatch": {
"version": "2.3.1", "version": "2.3.2",
"resolved": "https://registry.npmmirror.com/picomatch/-/picomatch-2.3.1.tgz", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz",
"integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"engines": { "engines": {
...@@ -6900,9 +6959,9 @@ ...@@ -6900,9 +6959,9 @@
"license": "Unlicense" "license": "Unlicense"
}, },
"node_modules/rollup": { "node_modules/rollup": {
"version": "4.50.2", "version": "4.60.1",
"resolved": "https://registry.npmmirror.com/rollup/-/rollup-4.50.2.tgz", "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.60.1.tgz",
"integrity": "sha512-BgLRGy7tNS9H66aIMASq1qSYbAAJV6Z6WR4QYTvj5FgF15rZ/ympT1uixHXwzbZUBDbkvqUI1KR0fH1FhMaQ9w==", "integrity": "sha512-VmtB2rFU/GroZ4oL8+ZqXgSA38O6GR8KSIvWmEFv63pQ0G6KaBH9s07PO8XTXP4vI+3UJUEypOfjkGfmSBBR0w==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
...@@ -6916,27 +6975,31 @@ ...@@ -6916,27 +6975,31 @@
"npm": ">=8.0.0" "npm": ">=8.0.0"
}, },
"optionalDependencies": { "optionalDependencies": {
"@rollup/rollup-android-arm-eabi": "4.50.2", "@rollup/rollup-android-arm-eabi": "4.60.1",
"@rollup/rollup-android-arm64": "4.50.2", "@rollup/rollup-android-arm64": "4.60.1",
"@rollup/rollup-darwin-arm64": "4.50.2", "@rollup/rollup-darwin-arm64": "4.60.1",
"@rollup/rollup-darwin-x64": "4.50.2", "@rollup/rollup-darwin-x64": "4.60.1",
"@rollup/rollup-freebsd-arm64": "4.50.2", "@rollup/rollup-freebsd-arm64": "4.60.1",
"@rollup/rollup-freebsd-x64": "4.50.2", "@rollup/rollup-freebsd-x64": "4.60.1",
"@rollup/rollup-linux-arm-gnueabihf": "4.50.2", "@rollup/rollup-linux-arm-gnueabihf": "4.60.1",
"@rollup/rollup-linux-arm-musleabihf": "4.50.2", "@rollup/rollup-linux-arm-musleabihf": "4.60.1",
"@rollup/rollup-linux-arm64-gnu": "4.50.2", "@rollup/rollup-linux-arm64-gnu": "4.60.1",
"@rollup/rollup-linux-arm64-musl": "4.50.2", "@rollup/rollup-linux-arm64-musl": "4.60.1",
"@rollup/rollup-linux-loong64-gnu": "4.50.2", "@rollup/rollup-linux-loong64-gnu": "4.60.1",
"@rollup/rollup-linux-ppc64-gnu": "4.50.2", "@rollup/rollup-linux-loong64-musl": "4.60.1",
"@rollup/rollup-linux-riscv64-gnu": "4.50.2", "@rollup/rollup-linux-ppc64-gnu": "4.60.1",
"@rollup/rollup-linux-riscv64-musl": "4.50.2", "@rollup/rollup-linux-ppc64-musl": "4.60.1",
"@rollup/rollup-linux-s390x-gnu": "4.50.2", "@rollup/rollup-linux-riscv64-gnu": "4.60.1",
"@rollup/rollup-linux-x64-gnu": "4.50.2", "@rollup/rollup-linux-riscv64-musl": "4.60.1",
"@rollup/rollup-linux-x64-musl": "4.50.2", "@rollup/rollup-linux-s390x-gnu": "4.60.1",
"@rollup/rollup-openharmony-arm64": "4.50.2", "@rollup/rollup-linux-x64-gnu": "4.60.1",
"@rollup/rollup-win32-arm64-msvc": "4.50.2", "@rollup/rollup-linux-x64-musl": "4.60.1",
"@rollup/rollup-win32-ia32-msvc": "4.50.2", "@rollup/rollup-openbsd-x64": "4.60.1",
"@rollup/rollup-win32-x64-msvc": "4.50.2", "@rollup/rollup-openharmony-arm64": "4.60.1",
"@rollup/rollup-win32-arm64-msvc": "4.60.1",
"@rollup/rollup-win32-ia32-msvc": "4.60.1",
"@rollup/rollup-win32-x64-gnu": "4.60.1",
"@rollup/rollup-win32-x64-msvc": "4.60.1",
"fsevents": "~2.3.2" "fsevents": "~2.3.2"
} }
}, },
...@@ -8066,9 +8129,9 @@ ...@@ -8066,9 +8129,9 @@
} }
}, },
"node_modules/vite": { "node_modules/vite": {
"version": "5.4.20", "version": "5.4.21",
"resolved": "https://registry.npmmirror.com/vite/-/vite-5.4.20.tgz", "resolved": "https://registry.npmjs.org/vite/-/vite-5.4.21.tgz",
"integrity": "sha512-j3lYzGC3P+B5Yfy/pfKNgVEg4+UtcIJcVRt2cDjIOmhLourAqPqf8P7acgxeiSgUB7E3p2P8/3gNIgDLpwzs4g==", "integrity": "sha512-o5a9xKjbtuhY6Bi5S3+HvbRERmouabWbyUcpXXUA1u+GNUKoROi9byOJ8M0nHbHYHkYICiMlqxkg1KkYmm25Sw==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
...@@ -8214,9 +8277,9 @@ ...@@ -8214,9 +8277,9 @@
"license": "MIT" "license": "MIT"
}, },
"node_modules/yaml": { "node_modules/yaml": {
"version": "2.8.2", "version": "2.8.3",
"resolved": "https://registry.npmmirror.com/yaml/-/yaml-2.8.2.tgz", "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.8.3.tgz",
"integrity": "sha512-mplynKqc1C2hTVYxd0PU2xQAc22TI1vShAYGksCCfxbn/dFwnHTNi1bvYsBTkhdUNtGIf5xNOg938rrSSYvS9A==", "integrity": "sha512-AvbaCLOO2Otw/lW5bmh9d/WEdcDFdQp2Z2ZUH3pX9U2ihyUY0nvLv7J6TrWowklRGPYbB/IuIMfYgxaCPg5Bpg==",
"dev": true, "dev": true,
"license": "ISC", "license": "ISC",
"bin": { "bin": {
......
...@@ -178,7 +178,7 @@ export function getSearchBlurb(params) { ...@@ -178,7 +178,7 @@ export function getSearchBlurb(params) {
}) })
} }
// 获取相关事件getRelatedEvents // 获取相关事件
export function getRelatedEvents(params) { export function getRelatedEvents(params) {
return request({ return request({
method: 'GET', method: 'GET',
...@@ -186,8 +186,16 @@ export function getRelatedEvents(params) { ...@@ -186,8 +186,16 @@ export function getRelatedEvents(params) {
params params
}) })
} }
// 获取相关行政举措
export function getSearchAOMeasures(params) {
return request({
method: 'GET',
url: `/api/marketsearchDetails/getSearchAOMeasures`,
params
})
}
// 获取事件脉络 getSearchContext // 获取事件脉络
export function getSearchContext(params) { export function getSearchContext(params) {
return request({ return request({
method: 'GET', method: 'GET',
......
...@@ -126,11 +126,25 @@ export function getAreaType() { ...@@ -126,11 +126,25 @@ export function getAreaType() {
}) })
} }
/**
* 资助项目列表:领域、年份用逗号拼接为一个查询参数(arealist=1,2,3&yearlist=2025,2024)
*/
function normalizeProjectListQueryParams(params) {
const next = { ...(params || {}) }
if (Array.isArray(next.arealist)) {
next.arealist = next.arealist.filter((v) => v !== undefined && v !== null && v !== "").join(",")
}
if (Array.isArray(next.yearlist)) {
next.yearlist = next.yearlist.filter((v) => v !== undefined && v !== null && v !== "").join(",")
}
return next
}
//资助体系v2.0:资助项目列表分页 //资助体系v2.0:资助项目列表分页
export function getProjectListNew(params) { export function getProjectListNew(params) {
return request({ return request({
method: 'GET', method: 'GET',
url: `/api/fund/getProjectListNew`, url: `/api/fund/getProjectListNew`,
params params: normalizeProjectListQueryParams(params)
}) })
} }
<template>
<div class="layout-container">
<div class="layout-main">
<div class="layout-main-center">
<div class="report-header">
<div class="report-title">政令原文</div>
<el-switch v-model="isHighlight" @change="handleHighlight" />
<div class="switch-label switch-label-left">高亮实体</div>
<el-switch v-model="isTranslate" @change="handleTranslate" />
<div class="switch-label">译文显示</div>
<div class="btn" @click="emits('download')">
<div class="icon icon-gap-4">
<img src="./assets/icons/download.png" alt="" />
</div>
<div class="text">下载</div>
</div>
<div class="btn" @click="handleFindWord('open')">
<div class="icon icon-gap-6">
<img src="./assets/icons/search.png" alt="" />
</div>
<div class="text">查找</div>
</div>
<div class="find-word-box" v-if="findWordBox">
<div class="find-word-input">
<el-input v-model="findWordTxt" placeholder="查找原文内容" @input="handleUpdateWord" />
</div>
<div class="find-word-limit">{{ findWordNum }}/{{ findWordMax }}</div>
<div class="find-word-icon" @click="handleFindWord('last')">
<el-icon><ArrowUp /></el-icon>
</div>
<div class="find-word-icon" @click="handleFindWord('next')">
<el-icon><ArrowDown /></el-icon>
</div>
<div class="find-word-icon" @click="handleFindWord('close')">
<el-icon><Close /></el-icon>
</div>
</div>
</div>
<div :class="['report-main', {'is-highlight': isHighlight}]">
<div v-if="!formatData.length" class="no-content">暂无数据</div>
<el-scrollbar v-else height="100%">
<div v-for="(item, index) in formatData" :key="index" class="content-row">
<div class="content-en" :class="{ 'only-show': !isTranslate }">
<template v-for="(node, num) in item.contentEn" :key="num">
<el-icon v-if="node.icon && isHighlight" color="#508fd4" size="14"><Search /></el-icon>
<span v-else-if="node.point" class="find-light-point"></span>
<span v-else-if="node.fill" :class="node.class" @click="handleHighLight(node)">{{ node.txt }}</span>
<span v-else :class="node.class">{{ node.txt }}</span>
</template>
</div>
<div class="content-ch" v-if="isTranslate">
<template v-for="(node, num) in item.contentCh" :key="num">
<el-icon v-if="node.icon && isHighlight" color="#508fd4" size="14"><Search /></el-icon>
<span v-else-if="node.point" class="find-light-point"></span>
<span v-else-if="node.fill" :class="node.class" @click="handleHighLight(node)">{{ node.txt }}</span>
<span v-else :class="node.class">{{ node.txt }}</span>
</template>
</div>
</div>
</el-scrollbar>
</div>
</div>
</div>
</div>
</template>
<script setup>
import { nextTick, ref } from "vue";
import { debounce } from "lodash";
import { extractTextEntity } from "@/api/intelligent";
const emits = defineEmits(["download"]);
const isHighlight = ref(true); // 是否高亮实体
const isTranslate = ref(true); // 是否显示译文
const handleTranslate = () => {
if (findWordTxt.value?.trim()) handleUpdateWord()
}
const findWordTxt = ref("");
const findWordBox = ref(false);
const findWordNum = ref(0);
const findWordMax = ref(0);
const formatData = ref([])
const handleUpdateWord = debounce(() => {
findWordNum.value = 0;
findWordMax.value = 0;
formatData.value = originData.map(item => {
return {
contentEn: onHighlightedText(item.contentEn, keywordEn),
contentCh: isTranslate.value ? onHighlightedText(item.contentCh, keywordCh) : [],
}
})
if (findWordMax.value) {
findWordNum.value = 1;
nextTick(updateActiveHighlight)
}
}, 300);
function handleFindWord(event) {
switch (event) {
case "open":
findWordBox.value = true;
break;
case "last":
if (findWordMax.value > 1) {
findWordNum.value = findWordNum.value === 1 ? findWordMax.value : findWordNum.value - 1;
updateActiveHighlight();
}
break;
case "next":
if (findWordMax.value > 1) {
findWordNum.value = findWordNum.value === findWordMax.value ? 1 : findWordNum.value + 1;
updateActiveHighlight();
}
break;
case "close":
findWordBox.value = false;
findWordTxt.value = "";
handleUpdateWord();
break;
}
}
const updateActiveHighlight = () => {
if (!findWordNum.value) return
const spans = document.querySelectorAll("span.find-light-point");
spans.forEach((span, index) => {
if (index + 1 === findWordNum.value) span.scrollIntoView({});
});
}
// 政令原文信息
let originData = []
let keywordCh = []
let keywordEn = []
const setOriginalData = (data) => {
originData = []
let num = Math.max(data.content.length, data.contentEn.length)
for (let i = 0; i < num; i++) {
let obj = {
contentCh: data.content[i] || "",
contentEn: data.contentEn[i] || "",
}
originData.push(obj);
}
let allEn = ""
let allCh = ""
formatData.value = originData.map(item => {
allEn += item.contentEn + "。"
allCh += item.contentCh + "。"
return {
contentEn: [{txt: item.contentEn, class: ""}],
contentCh: [{txt: item.contentCh, class: ""}]
}
})
extractTextEntity(allEn || "").then(res => {
if (res?.result?.length) keywordEn = res.result || []
originData.forEach((item, index) => {
formatData.value[index].contentEn = onHighlightedText(item.contentEn, keywordEn);
})
})
extractTextEntity(allCh || "").then(res => {
if (res?.result?.length) keywordCh = res.result || []
if (isTranslate.value) {
originData.forEach((item, index) => {
formatData.value[index].contentCh = onHighlightedText(item.contentCh, keywordCh);
})
}
})
}
defineExpose({ setOriginalData })
// 文本分割
const onHighlightedText = (text, nounList) => {
if (text === "") return []
// 获取区间(合并相邻/重叠),并自动过滤空关键词
const getIntervals = (str, keywords) => {
const intervals = [];
for (const kw of keywords) {
if (!kw) continue; // 跳过空字符串,防止无限循环
let idx = 0;
while ((idx = str.indexOf(kw, idx)) !== -1) {
intervals.push({ start: idx, end: idx + kw.length });
idx += kw.length;
}
}
if (!intervals.length) return [];
intervals.sort((a, b) => a.start - b.start);
const merged = [intervals[0]];
for (let i = 1; i < intervals.length; i++) {
const prev = merged[merged.length - 1];
const curr = intervals[i];
if (curr.start <= prev.end) {
prev.end = Math.max(prev.end, curr.end);
} else {
merged.push(curr);
}
}
return merged;
};
// 处理空搜索文本
let textTrim = findWordTxt.value.trim() || "";
const searchIntervals = textTrim ? getIntervals(text, [textTrim]) : [];
const nounIntervals = getIntervals(text, nounList.map(n => n.text_span));
// 收集分割点
const points = new Set([0, text.length]);
[...searchIntervals, ...nounIntervals].forEach(({ start, end }) => {
points.add(start);
points.add(end);
});
const sortedPoints = Array.from(points).sort((a, b) => a - b);
const list = [];
for (let i = 0; i < sortedPoints.length - 1; i++) {
const start = sortedPoints[i];
const end = sortedPoints[i + 1];
if (start === end) continue;
const fragment = text.slice(start, end);
const findLight = searchIntervals.some(s => start >= s.start && end <= s.end);
const highLight = nounIntervals.some(n => start >= n.start && end <= n.end);
const classes = [];
if (findLight) classes.push("find-light");
if (highLight) classes.push("high-light");
const textItem = { txt: fragment, class: classes.join(" ") };
if (highLight) {
const nounInterval = nounIntervals.find(n => start >= n.start && end <= n.end);
if (nounInterval) {
textItem.fill = text.slice(nounInterval.start, nounInterval.end);
}
}
list.push(textItem);
// 实体区间结束后添加图标
const iconAdded = new Set();
for (const nounInterval of nounIntervals) {
const key = `${nounInterval.start}-${nounInterval.end}`;
if (end === nounInterval.end && !iconAdded.has(key)) {
list.push({ icon: true, class: "" });
iconAdded.add(key);
break;
}
}
// 搜索区间结束后添加锚点
const pointAdded = new Set();
for (const searchInterval of searchIntervals) {
const key = `${searchInterval.start}-${searchInterval.end}`;
if (end === searchInterval.end && !pointAdded.has(key)) {
findWordMax.value++;
list.push({ point: true, class: "" });
pointAdded.add(key);
break;
}
}
}
return list;
};
// 点击高亮实体
import { useGotoSearchResults } from "@/router/modules/comprehensiveSearch";
const gotoSearchResults = useGotoSearchResults();
const handleHighLight = (node) => {
gotoSearchResults(node.fill, '')
}
</script>
<style lang="scss" scoped>
.is-highlight .high-light {
color: var(--color-primary-100);
cursor: pointer;
}
.find-light {
background-color: #ffff00;
}
.layout-container {
width: 100%;
height: 100%;
background-color: #f7f8f9;
.layout-main {
height: 100%;
display: flex;
flex-direction: column;
align-items: center;
.layout-main-center {
width: 1600px;
background-color: white;
padding: 0 60px;
flex: auto;
height: 100%;
min-height: 0;
display: flex;
flex-direction: column;
.report-header {
height: 80px;
display: flex;
align-items: center;
border-bottom: solid 1px rgba(234, 236, 238, 1);
margin: 0 20px 10px;
position: relative;
.find-word-box {
position: absolute;
top: -50px;
right: 0px;
width: 430px;
height: 60px;
border: 1px solid rgba(230, 231, 232, 1);
background-color: white;
border-radius: 6px;
display: flex;
align-items: center;
.find-word-input {
flex: auto;
}
.find-word-limit {
border-right: solid 1px rgba(230, 231, 232, 1);
color: #5f656c;
padding-right: 16px;
}
.find-word-icon {
padding: 10px 12px;
margin: 0 2px;
cursor: pointer;
}
}
.report-title {
color: rgba(59, 65, 75, 1);
font-family: Microsoft YaHei;
font-size: 20px;
line-height: 20px;
font-weight: 700;
flex: 1;
}
.btn {
margin-left: 10px;
width: 88px;
height: 32px;
box-sizing: border-box;
border: 1px solid rgba(230, 231, 232, 1);
border-radius: 6px;
background: rgba(255, 255, 255, 1);
display: flex;
justify-content: center;
align-items: center;
cursor: pointer;
.text {
height: 24px;
color: rgba(95, 101, 108, 1);
font-family: Microsoft YaHei;
font-style: Regular;
font-size: 14px;
font-weight: 400;
line-height: 24px;
letter-spacing: 0px;
text-align: left;
}
.icon {
width: 16px;
height: 16px;
font-size: 0px;
img {
width: 100%;
height: 100%;
}
}
.icon-gap-4 {
margin-right: 4px;
}
.icon-gap-6 {
margin-right: 6px;
}
}
}
.report-main {
flex: auto;
height: 20px;
padding: 10px 0;
:deep(.el-scrollbar) {
height: 100%;
}
.no-content {
height: 100%;
display: flex;
align-items: center;
justify-content: center;
color: rgba(59, 65, 75, 1);
font-family: Microsoft YaHei;
font-style: Regular;
font-size: 20px;
font-weight: 400;
}
.content-row {
display: flex;
width: 100%;
padding: 0 20px;
min-height: 100px;
gap: 80px;
.content-en,
.content-ch {
width: 50%;
flex: auto;
padding-bottom: 40px;
box-sizing: border-box;
font-size: 16px;
line-height: 1.8;
color: #3b414b;
font-family: Microsoft YaHei;
text-align: justify;
white-space: pre-wrap;
}
.only-show {
padding-bottom: 10px;
}
}
}
}
}
}
.switch-label {
margin-left: 6px;
}
.switch-label-left {
margin-right: 10px;
}
:deep(.el-scrollbar__bar.is-vertical) {
right: 0px;
width: 4px;
background: transparent;
border-radius: 2px;
& > div {
background: #c5c7c9;
opacity: 1;
}
& > div:hover {
background: #505357;
}
}
</style>
...@@ -70,7 +70,9 @@ router.beforeEach((to, from, next) => { ...@@ -70,7 +70,9 @@ router.beforeEach((to, from, next) => {
if (to.meta.dynamicTitle) { if (to.meta.dynamicTitle) {
console.log('to', to); console.log('to', to);
const storageKey = to.meta.titleStorageKey || "curTabName"; const storageKey = to.meta.titleStorageKey || "curTabName";
document.title = window.sessionStorage.getItem(storageKey) || to.meta.title; // 新开页签时 sessionStorage 不共享,优先用 query 带过来的 title/name
const queryTitle = (to.query && (to.query.title || to.query.name)) ? String(to.query.title || to.query.name) : "";
document.title = queryTitle || window.sessionStorage.getItem(storageKey) || to.meta.title;
} else { } else {
document.title = to.meta.title document.title = to.meta.title
......
...@@ -88,7 +88,8 @@ const decreeRoutes = [ ...@@ -88,7 +88,8 @@ const decreeRoutes = [
component: Institution, component: Institution,
meta: { meta: {
title: "行政机构主页", title: "行政机构主页",
dynamicTitle: true dynamicTitle: true,
titleStorageKey: "institutionTabName"
} }
}, },
{ {
......
// Bill layout & visual tokens
// 统一用于 bill 板块布局改造,后续可并入全局设计变量体系
// spacing
$bill-space-8: 8px;
$bill-space-12: 12px;
$bill-space-16: 16px;
$bill-space-24: 24px;
$bill-space-30: 30px;
// layout
$bill-column-gap: 16px;
$bill-left-column-width: 1064px;
$bill-right-column-width: 520px;
// typography
$bill-title-font-size: 16px;
$bill-title-font-weight: 600;
$bill-body-font-size: 14px;
$bill-body-font-weight: 400;
// surface
$bill-panel-radius: 8px;
$bill-panel-border-color: #e8ecf3;
$bill-panel-shadow: 0 2px 8px rgba(15, 35, 95, 0.06);
$bill-panel-bg: #ffffff;
// text & color
$bill-text-primary: #1f2a44;
$bill-text-secondary: #5b6b88;
$bill-text-muted: #8b97ad;
$bill-color-accent: #2f66ff;
$bill-color-success: #19be6b;
$bill-color-warning: #ff9f43;
$bill-color-danger: #f56c6c;
# Bill 板块布局统一改造计划
> 目标:统一 `@src/views/bill` 下页面布局与视觉风格,解决“底部 30px 留白不稳定”问题,并沉淀可复用布局组件,便于后续新会话直接接续执行。
## 1. 背景与问题
当前 `bill` 板块存在以下共性问题:
1. 页面布局实现不统一(外层滚动、内层滚动、固定高度混用)。
2. 多数页面为“左右两列 + 多卡片”结构,但容器命名、间距、宽高策略不一致。
3. `30px` 底部留白在不同页面生效机制不同,容易出现:
- 某页不生效
- 增加占位后挤压布局
- Header(Tab/操作按钮)受影响
4. 样式硬编码较多(固定宽高、局部 margin/padding),复用性低。
## 2. 总体改造策略
采用“**分层统一 + 渐进迁移**”策略,避免一次性大改风险:
- **第一层:板块承载层统一**
- 统一滚动、内容宽度、底部安全留白机制。
- **第二层:页面布局骨架统一**
- 抽象“页面壳 + 双列布局 + 卡片容器”组件。
- **第三层:业务页迁移**
- 先迁移典型页,再批量替换。
## 3. 分阶段计划
### 阶段 A:基线确认与止血(进行中)
- 修复当前试错引入的结构问题(例如模板闭合错误、布局挤压)。
- 保证关键页面可用:
- `background`
- `processAnalysis`
- `introdoction`
### 阶段 B:新增通用布局组件(进行中)
#### 完成备注(2026-04-02)
- [x] 第一步已完成并通过验收:完成布局组件目录与基础文件脚手架
- `src/views/bill/components/layout/BillPageShell.vue`
- `src/views/bill/components/layout/BillTwoColumn.vue`
- `src/views/bill/components/layout/BillPanel.vue`
- `src/views/bill/components/layout/index.js`
- [x] 第二步已完成并通过验收:实现 `BillPageShell` 滚动容器与底部 `30px` 安全留白机制
- [x] 第三步已完成并通过验收:实现 `BillTwoColumn` 统一双列布局(1064/520 + gap 16 + 响应式堆叠)
- [x] 第四步已完成并通过验收:实现 `BillPanel` 统一卡片结构与基础样式(header/body/footer + 可配置边框/圆角/阴影)
- [x] 第五步已完成并通过验收:`bill-tokens.scss` 接入 `BillPageShell/BillTwoColumn/BillPanel` 并替换关键样式硬编码
- [x] 第六步已完成并通过验收:试点页 `background/index.vue` 已迁移到统一布局骨架(`BillPageShell + BillTwoColumn`
- [x] 第六步修正项(验收反馈已落实):
- 修正 1:移除 `.right-panel``margin-left/margin-right`,避免右列偏移与原样式不一致
- 修正 2:`BillPageShell` 不再使用内部滚动容器;页面滚动回到外层 `layout-main`,确保 Header 与内容一起滚动
- [x] 第七步已完成并通过验收:`introdoction/index.vue` 迁移到统一布局骨架(`BillPageShell + BillTwoColumn`
- [x] 第七步修正项(验收反馈已落实):
- 修正 1:移除 `.introduction-wrap-right``margin-left/margin-right`,消除右列偏移
- 修正 2:在 `.introduction-wrap-content` 增加 `margin-bottom: 30px`,确保外层滚动时可见底部留白
- [x] 第八步已完成并通过验收:`template/index.vue` 迁移到统一布局骨架(`BillPageShell + BillTwoColumn`
- [x] 第八步注意点(已沉淀):
- 删除 `page-bottom-gap` 占位节点,避免与统一留白策略重复
- 在双列容器 `.content-row` 增加 `margin-bottom: 30px`,适配“外层 `layout-main` 滚动”模式
- 迁移后需检查未使用变量并清理,避免 lint 噪音影响后续页面迁移
- [x] 第九步已完成并通过验收:`deepDig/processOverview/index.vue` 迁移到统一页面壳(`BillPageShell`
- [x] 第九步注意点(已沉淀):
- 保留页面内部横向滚动容器(`.main`),仅替换页面根壳,避免时间轴布局回归风险
- 删除 `page-bottom-gap`,改用页面容器底部留白(`margin-bottom: 30px`)适配外层滚动
- [x] 第十步已完成并通过验收:`deepDig/processAnalysis/index.vue` 迁移到统一页面壳(`BillPageShell`
- [x] 第十步注意点(已沉淀):
- 保持原双列业务结构与内部滚动策略不变,仅替换页面根壳
- 页面底部留白统一为容器 `margin-bottom: 30px`,与外层 `layout-main` 滚动机制一致
新增组件建议放在:`src/views/bill/components/layout/`
#### 计划新增组件索引
1. `src/views/bill/components/layout/BillPageShell.vue`
- 作用:统一页面根容器、内容区、底部留白(30px)机制。
2. `src/views/bill/components/layout/BillTwoColumn.vue`
- 作用:统一左右列布局(默认 1064 / 520)、列间距、响应式策略。
3. `src/views/bill/components/layout/BillPanel.vue`
- 作用:统一卡片容器(header/body/footer)结构、间距、基础样式。
4. `src/views/bill/components/layout/index.js`
- 作用:导出布局组件,便于页面统一引入。
> 可选(后续):
> - `BillPanelGroup.vue`(同列多卡片统一间距)
> - `BillPageSection.vue`(统一页面内 section 标题与辅助动作区)
### 阶段 C:样式 Token 统一(计划)
新增:`src/styles/bill-tokens.scss`(或接入现有变量体系)
- 间距:`8/12/16/24/30`
- 列间距:`16`
- 标题字号/字重
- 卡片边框、阴影、圆角
- 统一颜色 token(主文字、次文字、强调色)
### 阶段 D:页面迁移(计划)
按“先典型、后批量”执行:
1. 试点页(先迁移)
- `background/index.vue`(典型双列 + 卡片 + 多交互)
2. 法案概况组
- `introdoction/index.vue`
- `template/index.vue`
- `background/index.vue`
3. 深度挖掘组
- `deepDig/processOverview/index.vue`
- `deepDig/processAnalysis/index.vue`
- `deepDig/poliContribution/index.vue`
4. 影响分析组
- `influence/industry/index.vue`
- `influence/scientificResearch/index.vue`
- `influence/index.vue`(承载层)
### 阶段 E:收口与回归(计划)
- 清理临时样式补丁(历史试错 `gap/margin-bottom` 等)。
- 回归检查:
1. 所有页面底部留白可见
2. 无横向滚动条
3. Header 不丢失
4. 双列不挤压
## 4. 现有页面索引(改造范围)
### 4.1 板块承载与导航层
- `src/views/bill/billLayout/index.vue`
- `src/views/bill/billLayout/components/BillHeader.vue`
- `src/views/bill/index.vue`
- `src/views/bill/deepDig/index.vue`
- `src/views/bill/influence/index.vue`
### 4.2 法案概况(Bill)
- `src/views/bill/introdoction/index.vue`
- `src/views/bill/background/index.vue`
- `src/views/bill/template/index.vue`
- `src/views/bill/billOriginalText/index.vue`
### 4.3 深度挖掘(DeepDig)
- `src/views/bill/deepDig/processOverview/index.vue`
- `src/views/bill/deepDig/processAnalysis/index.vue`
- `src/views/bill/deepDig/poliContribution/index.vue`
### 4.4 影响分析(Influence)
- `src/views/bill/influence/industry/index.vue`
- `src/views/bill/influence/scientificResearch/index.vue`
- `src/views/bill/influence/ProgressForecast/index.vue`
### 4.5 其他相关页面
- `src/views/bill/relevantCircumstance/index.vue`
- `src/views/bill/versionCompare/index.vue`
- `src/views/bill/billHome/index.vue`
## 5. 迁移原则(执行时必须遵守)
1. 不改变业务逻辑(API、状态、路由行为)
2. 先替换布局骨架,再替换样式细节
3. 每次只迁移少量页面,保证可回滚
4. 对“固定高度 + 内部滚动”页面优先保守改造
5. 若页面是横向 flex 主体,禁止直接插入会改变横向布局的占位节点
## 6. 验收标准
1. `@bill` 目标页面滚动到底统一可见 `30px` 留白
2. 页面核心布局(左右列、卡片)不变形
3. `BillHeader` 的 Tab 与功能按钮稳定显示
4. 不新增横向滚动条
5. 关键路由刷新后视觉一致
## 7. 新会话接续建议
新会话可直接按以下顺序继续:
1. 先读取本文件:
- `src/views/bill/BILL_LAYOUT_UNIFICATION_PLAN.md`
2. 先完成组件脚手架:
- `BillPageShell.vue`
- `BillTwoColumn.vue`
- `BillPanel.vue`
3. 首个迁移页:
- `src/views/bill/background/index.vue`
4. 迁移完成后逐页扩展到 `introdoction/template/processOverview/processAnalysis`
---
最后更新:2026-04-02
<template> <template>
<div class="background-wrap"> <BillPageShell class="background-page">
<BillTwoColumn class="background-content" :stack-on-narrow="false">
<template #left>
<div class="background-wrap-left"> <div class="background-wrap-left">
<AnalysisBox class="left-box left-box--background" title="立法背景" :showAllBtn="false" :devTip="true"> <AnalysisBox class="left-box left-box--background" title="立法背景" :showAllBtn="false" :devTip="true">
<template #header-btn> <template #header-btn>
...@@ -22,8 +24,13 @@ ...@@ -22,8 +24,13 @@
<div class="info"> <div class="info">
{{ totalText }} {{ totalText }}
</div> </div>
<el-pagination background layout="prev, pager, next" :total="total" v-model:current-page="currentPage" <el-pagination
@current-change="handleGetBillBackground" /> background
layout="prev, pager, next"
:total="total"
v-model:current-page="currentPage"
@current-change="handleGetBillBackground"
/>
</div> </div>
</div> </div>
</AnalysisBox> </AnalysisBox>
...@@ -47,6 +54,9 @@ ...@@ -47,6 +54,9 @@
</div> </div>
</AnalysisBox> </AnalysisBox>
</div> </div>
</template>
<template #right>
<AnalysisBox class="right-panel" title="议员相关性分析" :showAllBtn="false" :devTip="true"> <AnalysisBox class="right-panel" title="议员相关性分析" :showAllBtn="false" :devTip="true">
<template #header-btn> <template #header-btn>
<div class="header-btn-box"> <div class="header-btn-box">
...@@ -83,8 +93,7 @@ ...@@ -83,8 +93,7 @@
</el-icon> </el-icon>
</div> </div>
<div class="right-box1-main-bottom"> <div class="right-box1-main-bottom">
<WordCloudMap :data="wordCloudData" :selectedName="selectedIndustryName" shape="circle" <WordCloudMap :data="wordCloudData" :selectedName="selectedIndustryName" shape="circle" @wordClick="handleWordClick" />
@wordClick="handleWordClick" />
</div> </div>
</div> </div>
<div class="right-box2"> <div class="right-box2">
...@@ -111,7 +120,9 @@ ...@@ -111,7 +120,9 @@
</div> </div>
</div> </div>
</AnalysisBox> </AnalysisBox>
</div> </template>
</BillTwoColumn>
</BillPageShell>
</template> </template>
<script setup> <script setup>
...@@ -119,6 +130,7 @@ import { computed, onMounted, ref } from "vue"; ...@@ -119,6 +130,7 @@ import { computed, onMounted, ref } from "vue";
import { useRoute, useRouter } from "vue-router"; import { useRoute, useRouter } from "vue-router";
import WordCloudMap from "./WordCloudMap.vue"; import WordCloudMap from "./WordCloudMap.vue";
import CommonPrompt from "../commonPrompt/index.vue"; import CommonPrompt from "../commonPrompt/index.vue";
import { BillPageShell, BillTwoColumn } from "../components/layout";
import userIcon from "./assets/icons/user-icon.png"; import userIcon from "./assets/icons/user-icon.png";
import userIcon1 from "./assets/icons/user-icon1.png"; import userIcon1 from "./assets/icons/user-icon1.png";
import userIcon2 from "./assets/icons/user-icon2.png"; import userIcon2 from "./assets/icons/user-icon2.png";
...@@ -400,16 +412,31 @@ onMounted(() => { ...@@ -400,16 +412,31 @@ onMounted(() => {
} }
} }
.background-wrap { .background-page {
width: 100%; width: 100%;
height: 100%; height: 100%;
box-sizing: border-box; box-sizing: border-box;
display: flex; }
.background-content {
width: 100%;
height: auto;
box-sizing: border-box;
align-items: flex-start; align-items: flex-start;
:deep(.bill-two-column__left) {
width: 1064px;
}
:deep(.bill-two-column__right) {
width: 520px;
margin-right: 18px;
}
.background-wrap-left { .background-wrap-left {
width: 1064px; width: 1064px;
margin-top: 16px; margin-top: 16px;
margin-bottom: 30px;
.left-box { .left-box {
width: 1064px; width: 1064px;
...@@ -600,9 +627,8 @@ onMounted(() => { ...@@ -600,9 +627,8 @@ onMounted(() => {
} }
} }
.right-panel { .right-panel {
margin-right: 18px;
margin-left: 16px;
margin-top: 16px; margin-top: 16px;
width: 520px; width: 520px;
max-height: 824px; max-height: 824px;
......
...@@ -61,7 +61,7 @@ ...@@ -61,7 +61,7 @@
</div> </div>
<div class="right-box-bottom" v-if="showActions"> <div class="right-box-bottom" v-if="showActions">
<div class="btn2" @click="emit('open-analysis', 'forsee')"> <div class="btn2" v-if="showForsee" @click="emit('open-analysis', 'forsee')">
<div class="icon"> <div class="icon">
<img :src="btnIconForsee" alt="" /> <img :src="btnIconForsee" alt="" />
</div> </div>
...@@ -108,6 +108,10 @@ const props = defineProps({ ...@@ -108,6 +108,10 @@ const props = defineProps({
showActions: { showActions: {
type: Boolean, type: Boolean,
default: true default: true
},
showForsee: {
type: Boolean,
default: true
} }
}); });
...@@ -154,9 +158,7 @@ const emit = defineEmits(["tab-click", "open-analysis"]); ...@@ -154,9 +158,7 @@ const emit = defineEmits(["tab-click", "open-analysis"]);
} }
.header-main { .header-main {
position: sticky; position: relative;
top: 0;
z-index: 1000;
width: 100%; width: 100%;
background-color: #fff; background-color: #fff;
box-shadow: 0px 4px 10px 0px rgba(0, 0, 0, 0.05); box-shadow: 0px 4px 10px 0px rgba(0, 0, 0, 0.05);
......
...@@ -4,7 +4,8 @@ ...@@ -4,7 +4,8 @@
<div class="layout-main"> <div class="layout-main">
<BillHeader :billInfo="billInfoGlobal" :defaultLogo="USALogo" :tabs="mainHeaderBtnList" <BillHeader :billInfo="billInfoGlobal" :defaultLogo="USALogo" :tabs="mainHeaderBtnList"
:activeTitle="activeTitle" :showTabs="showHeaderTabs" :showActions="showHeaderActions" :activeTitle="activeTitle" :showTabs="showHeaderTabs" :showActions="showHeaderActions"
@tab-click="handleClickMainHeaderBtn" @open-analysis="handleAnalysisClick" /> :showForsee="showForseeAction" @tab-click="handleClickMainHeaderBtn"
@open-analysis="handleAnalysisClick" />
<div class="layout-main-center"> <div class="layout-main-center">
<router-view /> <router-view />
...@@ -14,10 +15,10 @@ ...@@ -14,10 +15,10 @@
</template> </template>
<script setup> <script setup>
import { ref, onMounted, watch } from "vue"; import { ref, onMounted, watch, computed } from "vue";
import router from "@/router"; import router from "@/router";
import { useRoute } from "vue-router"; import { useRoute } from "vue-router";
import { getBillInfoGlobal } from "@/api/bill"; import { getBillInfoGlobal, getBillInfo } from "@/api/bill";
import BillHeader from "./components/BillHeader.vue"; import BillHeader from "./components/BillHeader.vue";
const route = useRoute(); const route = useRoute();
...@@ -77,6 +78,25 @@ const activeTitle = ref("法案概况"); ...@@ -77,6 +78,25 @@ const activeTitle = ref("法案概况");
const showHeaderTabs = ref(true); const showHeaderTabs = ref(true);
const showHeaderActions = ref(true); const showHeaderActions = ref(true);
const billBasicInfo = ref({});
const getBillBasicInfoFn = async () => {
const billId = route.query.billId;
if (!billId) return;
try {
const res = await getBillInfo({ id: billId });
billBasicInfo.value = res?.data || {};
} catch (error) {
console.error(error);
billBasicInfo.value = {};
}
};
const showForseeAction = computed(() => {
const stageList = Array.isArray(billBasicInfo.value?.stageList) ? billBasicInfo.value.stageList : [];
const latestStage = stageList.length ? String(stageList[stageList.length - 1] || "").trim() : "";
return !latestStage.includes("完成立法");
});
const getActiveTitleByRoutePath = path => { const getActiveTitleByRoutePath = path => {
if (path.startsWith("/billLayout/deepDig")) return "深度挖掘"; if (path.startsWith("/billLayout/deepDig")) return "深度挖掘";
if (path.startsWith("/billLayout/influence")) return "影响分析"; if (path.startsWith("/billLayout/influence")) return "影响分析";
...@@ -132,6 +152,7 @@ const handleAnalysisClick = analysisType => { ...@@ -132,6 +152,7 @@ const handleAnalysisClick = analysisType => {
onMounted(() => { onMounted(() => {
getBillInfoGlobalFn(); getBillInfoGlobalFn();
getBillBasicInfoFn();
// 以当前路由为准,避免 sessionStorage 造成高亮错乱 // 以当前路由为准,避免 sessionStorage 造成高亮错乱
syncHeaderStateFromRoute(); syncHeaderStateFromRoute();
// 兜底:如果未来出现未知路由且有缓存,再用缓存 // 兜底:如果未来出现未知路由且有缓存,再用缓存
...@@ -143,6 +164,14 @@ watch( ...@@ -143,6 +164,14 @@ watch(
() => route.path, () => route.path,
() => { () => {
syncHeaderStateFromRoute(); syncHeaderStateFromRoute();
}
);
watch(
() => route.query.billId,
() => {
getBillInfoGlobalFn();
getBillBasicInfoFn();
}, },
{ immediate: true } { immediate: true }
); );
...@@ -160,12 +189,12 @@ watch( ...@@ -160,12 +189,12 @@ watch(
width: 100%; width: 100%;
height: 100vh; height: 100vh;
overflow-y: auto; overflow-y: auto;
overflow-x: hidden;
.layout-main-center { .layout-main-center {
// height: calc(100% - 137px);
width: 1600px; width: 1600px;
max-width: 100%;
margin: 0 auto; margin: 0 auto;
padding-bottom: 20px;
} }
} }
} }
......
<template>
<div class="bill-page-shell" :class="shellClass" :style="shellStyle">
<div class="bill-page-shell__content" :class="contentClass">
<slot />
</div>
</div>
</template>
<script>
const BILL_DEFAULT_BOTTOM_SAFE_SPACE = 30
export default {
name: 'BillPageShell',
props: {
bottomSafeSpace: {
type: Number,
default: BILL_DEFAULT_BOTTOM_SAFE_SPACE
},
shellClass: {
type: [String, Array, Object],
default: ''
},
contentClass: {
type: [String, Array, Object],
default: ''
}
},
computed: {
shellStyle() {
return {
paddingBottom: `${this.bottomSafeSpace}px`
}
}
}
}
</script>
<style scoped lang="scss">
@import '@/styles/bill-tokens.scss';
.bill-page-shell {
width: 100%;
min-height: 0;
box-sizing: border-box;
}
.bill-page-shell__content {
width: 100%;
color: $bill-text-primary;
}
</style>
<template>
<section class="bill-panel" :class="panelClass" :style="panelStyle">
<header
v-if="$slots.header"
class="bill-panel__header"
:class="headerClass"
:style="sectionStyle"
>
<slot name="header" />
</header>
<div class="bill-panel__body" :class="bodyClass" :style="sectionStyle">
<slot />
</div>
<footer
v-if="$slots.footer"
class="bill-panel__footer"
:class="footerClass"
:style="sectionStyle"
>
<slot name="footer" />
</footer>
</section>
</template>
<script>
const BILL_DEFAULT_PANEL_PADDING = 16
const BILL_DEFAULT_PANEL_RADIUS = 8
export default {
name: 'BillPanel',
props: {
panelClass: {
type: [String, Array, Object],
default: ''
},
headerClass: {
type: [String, Array, Object],
default: ''
},
bodyClass: {
type: [String, Array, Object],
default: ''
},
footerClass: {
type: [String, Array, Object],
default: ''
},
padding: {
type: Number,
default: BILL_DEFAULT_PANEL_PADDING
},
borderRadius: {
type: Number,
default: BILL_DEFAULT_PANEL_RADIUS
},
bordered: {
type: Boolean,
default: true
},
shadow: {
type: Boolean,
default: false
},
background: {
type: String,
default: '#fff'
}
},
computed: {
panelStyle() {
return {
background: this.background,
borderRadius: `${this.borderRadius}px`,
border: this.bordered ? '1px solid #e8ecf3' : 'none',
boxShadow: this.shadow ? '0 2px 8px rgba(15, 35, 95, 0.06)' : 'none'
}
},
sectionStyle() {
return {
padding: `${this.padding}px`
}
}
}
}
</script>
<style scoped lang="scss">
@import '@/styles/bill-tokens.scss';
.bill-panel {
width: 100%;
box-sizing: border-box;
color: $bill-text-primary;
}
.bill-panel__header,
.bill-panel__body,
.bill-panel__footer {
width: 100%;
box-sizing: border-box;
}
.bill-panel__header {
padding-bottom: $bill-space-12;
}
.bill-panel__footer {
padding-top: $bill-space-12;
}
.bill-panel__header:empty,
.bill-panel__footer:empty {
display: none;
}
</style>
<template>
<div class="bill-two-column" :class="wrapperClass" :style="wrapperStyle">
<div class="bill-two-column__left" :style="leftStyle">
<slot name="left" />
</div>
<div class="bill-two-column__right" :style="rightStyle">
<slot name="right" />
</div>
</div>
</template>
<script>
const BILL_DEFAULT_LEFT_WIDTH = 1064
const BILL_DEFAULT_RIGHT_WIDTH = 520
const BILL_DEFAULT_COLUMN_GAP = 16
const BILL_DEFAULT_MIN_STACK_WIDTH = 1660
export default {
name: 'BillTwoColumn',
props: {
leftWidth: {
type: Number,
default: BILL_DEFAULT_LEFT_WIDTH
},
rightWidth: {
type: Number,
default: BILL_DEFAULT_RIGHT_WIDTH
},
gap: {
type: Number,
default: BILL_DEFAULT_COLUMN_GAP
},
minStackWidth: {
type: Number,
default: BILL_DEFAULT_MIN_STACK_WIDTH
},
stackOnNarrow: {
type: Boolean,
default: true
},
wrapperClass: {
type: [String, Array, Object],
default: ''
}
},
computed: {
shouldStack() {
if (!this.stackOnNarrow || typeof window === 'undefined') {
return false
}
return window.innerWidth < this.minStackWidth
},
wrapperStyle() {
if (this.shouldStack) {
return {
display: 'flex',
flexDirection: 'column',
gap: `${this.gap}px`
}
}
return {
display: 'grid',
gridTemplateColumns: `${this.leftWidth}px ${this.rightWidth}px`,
columnGap: `${this.gap}px`,
alignItems: 'start'
}
},
leftStyle() {
if (this.shouldStack) {
return {
width: '100%'
}
}
return {
minWidth: '0'
}
},
rightStyle() {
if (this.shouldStack) {
return {
width: '100%'
}
}
return {
minWidth: '0'
}
}
}
}
</script>
<style scoped lang="scss">
@import '@/styles/bill-tokens.scss';
.bill-two-column {
width: 100%;
min-width: 0;
color: $bill-text-primary;
}
.bill-two-column__left,
.bill-two-column__right {
min-width: 0;
}
</style>
import BillPageShell from './BillPageShell.vue'
import BillTwoColumn from './BillTwoColumn.vue'
import BillPanel from './BillPanel.vue'
export {
BillPageShell,
BillTwoColumn,
BillPanel
}
<template> <template>
<div class="wrap"> <BillPageShell class="wrap">
<div class="left"> <div class="left">
<div class="box1"> <div class="box1">
<!-- <div class="box-header"> <!-- <div class="box-header">
...@@ -31,7 +31,7 @@ ...@@ -31,7 +31,7 @@
</div> </div>
</div> </div>
</div> --> </div> -->
<AnalysisBox title="典型阶段耗时"> <AnalysisBox title="典型阶段耗时分析">
<div class="analysis-ai-wrapper analysis-ai-wrapper--box1"> <div class="analysis-ai-wrapper analysis-ai-wrapper--box1">
<div class="box1-main" :class="{ 'box1-main--full': !timeFooterText }"> <div class="box1-main" :class="{ 'box1-main--full': !timeFooterText }">
<div class="box1-main-center" id="chart1"></div> <div class="box1-main-center" id="chart1"></div>
...@@ -48,7 +48,7 @@ ...@@ -48,7 +48,7 @@
</div> </div>
</div> </div>
<div v-if="!aiPaneVisible.box1" class="analysis-ai-tip-row"> <div v-if="!aiPaneVisible.box1" class="analysis-ai-tip-row">
<TipTab class="analysis-ai-tip" /> <TipTab class="analysis-ai-tip" :text="'与历史同类法案的典型阶段耗时对比分析,数据来源:美国国会官网'"/>
<AiButton class="analysis-ai-tip-action" @mouseenter="handleShowAiPane('box1')" /> <AiButton class="analysis-ai-tip-action" @mouseenter="handleShowAiPane('box1')" />
</div> </div>
<div v-if="aiPaneVisible.box1" class="analysis-ai-pane" @mouseleave="handleHideAiPane('box1')"> <div v-if="aiPaneVisible.box1" class="analysis-ai-pane" @mouseleave="handleHideAiPane('box1')">
...@@ -105,7 +105,7 @@ ...@@ -105,7 +105,7 @@
</div> </div>
</div> </div>
<div v-if="!aiPaneVisible.box2" class="analysis-ai-tip-row"> <div v-if="!aiPaneVisible.box2" class="analysis-ai-tip-row">
<TipTab class="analysis-ai-tip" /> <TipTab class="analysis-ai-tip" :text="'与历史同类法案的修正案次数对比分析,数据来源:美国国会官网'"/>
<AiButton class="analysis-ai-tip-action" @mouseenter="handleShowAiPane('box2')" /> <AiButton class="analysis-ai-tip-action" @mouseenter="handleShowAiPane('box2')" />
</div> </div>
<div v-if="aiPaneVisible.box2" class="analysis-ai-pane" @mouseleave="handleHideAiPane('box2')"> <div v-if="aiPaneVisible.box2" class="analysis-ai-pane" @mouseleave="handleHideAiPane('box2')">
...@@ -716,7 +716,7 @@ ...@@ -716,7 +716,7 @@
</AnalysisBox> </AnalysisBox>
</div> </div>
</div> </div>
</div> </BillPageShell>
</template> </template>
<script setup> <script setup>
...@@ -728,6 +728,7 @@ import { getChartAnalysis } from "@/api/aiAnalysis/index"; ...@@ -728,6 +728,7 @@ import { getChartAnalysis } from "@/api/aiAnalysis/index";
import TipTab from "@/components/base/TipTab/index.vue"; import TipTab from "@/components/base/TipTab/index.vue";
import AiButton from "@/components/base/Ai/AiButton/index.vue"; import AiButton from "@/components/base/Ai/AiButton/index.vue";
import AiPane from "@/components/base/Ai/AiPane/index.vue"; import AiPane from "@/components/base/Ai/AiPane/index.vue";
import { BillPageShell } from "../../components/layout";
import icon1 from "./assets/images/icon1.png"; import icon1 from "./assets/images/icon1.png";
import icon2 from "./assets/images/icon2.png"; import icon2 from "./assets/images/icon2.png";
...@@ -1160,7 +1161,7 @@ onMounted(async () => { ...@@ -1160,7 +1161,7 @@ onMounted(async () => {
min: "最小次数", min: "最小次数",
current: "该法案修正案数量" current: "该法案修正案数量"
}; };
let chart2 = getBoxPlotChcart(chartData2.value, "", countLabels); let chart2 = getBoxPlotChcart(chartData2.value, "", countLabels);
setChart(chart2, "chart2"); setChart(chart2, "chart2");
}); });
</script> </script>
...@@ -1168,6 +1169,8 @@ onMounted(async () => { ...@@ -1168,6 +1169,8 @@ onMounted(async () => {
<style lang="scss" scoped> <style lang="scss" scoped>
.wrap { .wrap {
display: flex; display: flex;
margin-bottom: 30px;
.box-header { .box-header {
height: 56px; height: 56px;
......
<template> <template>
<div class="process-overview-wrap"> <BillPageShell class="process-overview-wrap">
<AnalysisBox title="流程概要" :showAllBtn="false"> <AnalysisBox title="流程概要" :showAllBtn="false">
<div class="main"> <div class="main">
<div class="left" :style="{ width: boardWidth + 'px' }"> <div class="left" :style="{ width: boardWidth + 'px' }">
...@@ -194,7 +194,7 @@ ...@@ -194,7 +194,7 @@
:position="dialogPos" :position="dialogPos"
@close="handleClickDetail(false)" @close="handleClickDetail(false)"
/> />
</div> </BillPageShell>
</template> </template>
<script setup> <script setup>
...@@ -202,6 +202,7 @@ import { ref, onMounted, computed, nextTick } from "vue"; ...@@ -202,6 +202,7 @@ import { ref, onMounted, computed, nextTick } from "vue";
import { getBillDyqkSummary } from "@/api/bill"; import { getBillDyqkSummary } from "@/api/bill";
import CommonPrompt from "../../commonPrompt/index.vue"; import CommonPrompt from "../../commonPrompt/index.vue";
import ProcessOverviewDetailDialog from "../../ProcessOverviewDetailDialog.vue"; import ProcessOverviewDetailDialog from "../../ProcessOverviewDetailDialog.vue";
import { BillPageShell } from "../../components/layout";
const actionList = ref([]); const actionList = ref([]);
const isShowDetailDialog = ref(false); const isShowDetailDialog = ref(false);
...@@ -499,6 +500,7 @@ const updateRightTop = () => { ...@@ -499,6 +500,7 @@ const updateRightTop = () => {
width: 1600px; width: 1600px;
height: 848px; height: 848px;
margin-top: 16px; margin-top: 16px;
margin-bottom: 30px;
position: relative; position: relative;
.main { .main {
...@@ -799,20 +801,13 @@ const updateRightTop = () => { ...@@ -799,20 +801,13 @@ const updateRightTop = () => {
.text { .text {
width: 240px; width: 240px;
max-width: 100%;
color: rgb(59, 65, 75); color: rgb(59, 65, 75);
font-size: 16px; font-size: 16px;
line-height: 24px; line-height: 24px;
display: -webkit-box; white-space: nowrap;
line-clamp: 2;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
overflow: hidden; overflow: hidden;
text-overflow: ellipsis; text-overflow: ellipsis;
height: 48px;
}
:deep(.text-ellipsis) {
white-space: normal !important;
} }
} }
} }
......
<template> <template>
<div class="introduction-wrap"> <BillPageShell class="introduction-wrap">
<WarningPane v-if="riskSignal" class="risk-signal-pane-top" :warnningLevel="riskSignal.riskLevel" <WarningPane v-if="riskSignal" class="risk-signal-pane-top" :warnningLevel="riskSignal.riskLevel"
:warnningContent="riskSignal.riskContent" /> :warnningContent="riskSignal.riskContent" />
<div class="introduction-wrap-content"> <BillTwoColumn class="introduction-wrap-content" :stack-on-narrow="false">
<template #left>
<div class="introduction-wrap-left"> <div class="introduction-wrap-left">
<div class="introduction-wrap-left-box1"> <div class="introduction-wrap-left-box1">
...@@ -70,6 +71,8 @@ ...@@ -70,6 +71,8 @@
</AnalysisBox> </AnalysisBox>
</div> </div>
</div> </div>
</template>
<template #right>
<div class="introduction-wrap-right"> <div class="introduction-wrap-right">
<AnalysisBox title="提出人" :showAllBtn="false"> <AnalysisBox title="提出人" :showAllBtn="false">
<div class="introduction-wrap-right-main"> <div class="introduction-wrap-right-main">
...@@ -141,8 +144,9 @@ ...@@ -141,8 +144,9 @@
</div> </div>
</AnalysisBox> </AnalysisBox>
</div> </div>
</div> </template>
</div> </BillTwoColumn>
</BillPageShell>
</template> </template>
<script setup> <script setup>
...@@ -151,6 +155,7 @@ import { useRoute, useRouter } from "vue-router"; ...@@ -151,6 +155,7 @@ import { useRoute, useRouter } from "vue-router";
import WordCloudMap from "./WordCloudMap.vue"; import WordCloudMap from "./WordCloudMap.vue";
import STimeline from "./STimeline.vue"; import STimeline from "./STimeline.vue";
import WarningPane from "@/components/base/WarningPane/index.vue"; import WarningPane from "@/components/base/WarningPane/index.vue";
import { BillPageShell, BillTwoColumn } from "../components/layout";
import { getBillInfo, getBillPerson, getBillEvent, getBillDyqk } from "@/api/bill"; import { getBillInfo, getBillPerson, getBillEvent, getBillDyqk } from "@/api/bill";
import { getPersonSummaryInfo } from "@/api/common/index"; import { getPersonSummaryInfo } from "@/api/common/index";
import defaultAvatar from "../assets/images/default-icon1.png"; import defaultAvatar from "../assets/images/default-icon1.png";
...@@ -338,6 +343,14 @@ onMounted(() => { ...@@ -338,6 +343,14 @@ onMounted(() => {
height: auto; height: auto;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
box-sizing: border-box;
.page-bottom-gap {
height: 30px;
width: 100%;
flex-shrink: 0;
pointer-events: none;
}
.progress-header-btns { .progress-header-btns {
display: flex; display: flex;
...@@ -432,6 +445,7 @@ onMounted(() => { ...@@ -432,6 +445,7 @@ onMounted(() => {
.introduction-wrap-content { .introduction-wrap-content {
display: flex; display: flex;
margin-bottom: 30px;
} }
.introduction-wrap-left { .introduction-wrap-left {
...@@ -497,7 +511,6 @@ onMounted(() => { ...@@ -497,7 +511,6 @@ onMounted(() => {
flex-wrap: wrap; flex-wrap: wrap;
align-items: center; align-items: center;
width: 700px; width: 700px;
min-height: 40px;
gap: 8px; gap: 8px;
.right1-item { .right1-item {
...@@ -769,8 +782,6 @@ onMounted(() => { ...@@ -769,8 +782,6 @@ onMounted(() => {
.introduction-wrap-right { .introduction-wrap-right {
margin-top: 16px; margin-top: 16px;
margin-left: 16px;
margin-right: 18px;
width: 520px; width: 520px;
height: 845px; height: 845px;
......
<template> <template>
<div class="temp-wrap"> <BillPageShell class="temp-wrap">
<div class="tools-row"> <div class="tools-row">
<div class="tools-row-left"> <div class="tools-row-left">
<el-select v-model="curBill" placeholder="请选择版本" @change="handleChangeBill" <el-select v-model="curBill" placeholder="请选择版本" @change="handleChangeBill"
...@@ -39,7 +39,8 @@ ...@@ -39,7 +39,8 @@
</div> </div>
</div> </div>
</div> </div>
<div class="content-row"> <BillTwoColumn class="content-row" :left-width="520" :right-width="1064" :stack-on-narrow="false">
<template #left>
<div class="side"> <div class="side">
<div class="side-box side-box-domain"> <div class="side-box side-box-domain">
<AnalysisBox title="涉及领域" width="520px" height="415px" v-loading="domainLoading"> <AnalysisBox title="涉及领域" width="520px" height="415px" v-loading="domainLoading">
...@@ -94,6 +95,8 @@ ...@@ -94,6 +95,8 @@
</AnalysisBox> </AnalysisBox>
</div> </div>
</div> </div>
</template>
<template #right>
<div class="terms"> <div class="terms">
<div class="terms-switch"> <div class="terms-switch">
<span class="terms-switch-label">高亮实体</span> <span class="terms-switch-label">高亮实体</span>
...@@ -103,6 +106,10 @@ ...@@ -103,6 +106,10 @@
active-text="开" active-text="开"
inactive-text="关" inactive-text="关"
/> />
<span v-if="termsEntityLoading" class="terms-entity-loading">
<el-icon class="is-loading"><Loading /></el-icon>
实体识别中(剩余 {{ termsEntityPendingCount }} 条)
</span>
<span class="terms-switch-divider"></span> <span class="terms-switch-divider"></span>
<span class="terms-switch-label">显示原文</span> <span class="terms-switch-label">显示原文</span>
<el-switch <el-switch
...@@ -112,7 +119,7 @@ ...@@ -112,7 +119,7 @@
inactive-text="关" inactive-text="关"
/> />
</div> </div>
<AnalysisBox title="主要条款" :showAllBtn="false" v-loading="termsLoading"> <AnalysisBox title="主要条款" :showAllBtn="false" height="auto" v-loading="termsLoading">
<div class="left-main"> <div class="left-main">
<div class="left-main-item" v-for="(term, index) in displayTermsList" :key="getTermKey(term, index)"> <div class="left-main-item" v-for="(term, index) in displayTermsList" :key="getTermKey(term, index)">
<div class="term-body"> <div class="term-body">
...@@ -120,11 +127,23 @@ ...@@ -120,11 +127,23 @@
<div class="term-main"> <div class="term-main">
<div class="term-row term-row-cn"> <div class="term-row term-row-cn">
<div class="term-no-cn">{{ term.tkxh }}条.</div> <div class="term-no-cn">{{ term.tkxh }}条.</div>
<div class="term-content-cn" v-html="getTermContentHtml(term, 'cn')"></div> <div class="term-content-cn">
<IntelligentEntityText
:text="term?.fynr || ''"
:entities="termsHighlight ? getTermEntities(term, 'cn') : []"
@on-entity-click="e => gotoSearchResults(e.text_span, '')"
/>
</div>
</div> </div>
<div class="term-row term-row-en" v-if="termsShowOriginal"> <div class="term-row term-row-en" v-if="termsShowOriginal">
<div class="term-no-en">Sec.{{ term.tkxh }}</div> <div class="term-no-en">Sec.{{ term.tkxh }}</div>
<div class="term-content-en" v-html="getTermContentHtml(term, 'en')"></div> <div class="term-content-en">
<IntelligentEntityText
:text="term?.ywnr || ''"
:entities="termsHighlight ? getTermEntities(term, 'en') : []"
@on-entity-click="e => gotoSearchResults(e.text_span, '')"
/>
</div>
</div> </div>
</div> </div>
</div> </div>
...@@ -145,15 +164,16 @@ ...@@ -145,15 +164,16 @@
</div> </div>
</AnalysisBox> </AnalysisBox>
</div> </div>
</div> </template>
</div> </BillTwoColumn>
</BillPageShell>
</template> </template>
<script setup> <script setup>
import { ref, onMounted, onBeforeUnmount, computed, watch } from "vue"; import { ref, onMounted, onBeforeUnmount, computed, watch } from "vue";
import { useRoute, onBeforeRouteLeave } from "vue-router"; import { useRoute, onBeforeRouteLeave } from "vue-router";
import * as echarts from "echarts"; import * as echarts from "echarts";
import { Search } from "@element-plus/icons-vue"; import { Search, Loading } from "@element-plus/icons-vue";
import getPieChart from "./utils/piechart"; import getPieChart from "./utils/piechart";
import { getBillContentId, getBillContentTk, getBillContentXzfs, getBillHyly } from "@/api/bill"; import { getBillContentId, getBillContentTk, getBillContentXzfs, getBillHyly } from "@/api/bill";
import { getChartAnalysis } from "@/api/aiAnalysis/index"; import { getChartAnalysis } from "@/api/aiAnalysis/index";
...@@ -162,9 +182,12 @@ import AiButton from "@/components/base/Ai/AiButton/index.vue"; ...@@ -162,9 +182,12 @@ import AiButton from "@/components/base/Ai/AiButton/index.vue";
import AiPane from "@/components/base/Ai/AiPane/index.vue"; import AiPane from "@/components/base/Ai/AiPane/index.vue";
import { MUTICHARTCOLORS } from "@/common/constant"; import { MUTICHARTCOLORS } from "@/common/constant";
import { extractTextEntity } from "@/api/intelligent/index"; import { extractTextEntity } from "@/api/intelligent/index";
import { useGotoSearchResults } from "@/router/modules/comprehensiveSearch";
import IntelligentEntityText from "@/components/base/texts/IntelligentEntityText.vue";
import { BillPageShell, BillTwoColumn } from "../components/layout";
const route = useRoute(); const route = useRoute();
const gotoSearchResults = useGotoSearchResults();
const pageAbortController = new AbortController(); const pageAbortController = new AbortController();
const isRequestCanceled = error => { const isRequestCanceled = error => {
...@@ -186,6 +209,8 @@ const stopCurrentPageRequests = () => { ...@@ -186,6 +209,8 @@ const stopCurrentPageRequests = () => {
hylyRequestToken.value += 1; hylyRequestToken.value += 1;
entityRequestToken.value += 1; entityRequestToken.value += 1;
termsLoading.value = false; termsLoading.value = false;
termsEntityLoading.value = false;
termsEntityPendingCount.value = 0;
limitLoading.value = false; limitLoading.value = false;
domainLoading.value = false; domainLoading.value = false;
aiPaneLoading.value = { domain: false, limit: false }; aiPaneLoading.value = { domain: false, limit: false };
...@@ -214,16 +239,8 @@ const termsShowOriginal = ref(true); ...@@ -214,16 +239,8 @@ const termsShowOriginal = ref(true);
const entityRequestToken = ref(0); const entityRequestToken = ref(0);
const termEntityCache = ref(new Map()); const termEntityCache = ref(new Map());
const termsEntityLoading = ref(false);
const escapeHtml = value => { const termsEntityPendingCount = ref(0);
const str = String(value ?? "");
return str
.replace(/&/g, "&amp;")
.replace(/</g, "&lt;")
.replace(/>/g, "&gt;")
.replace(/"/g, "&quot;")
.replace(/'/g, "&#39;");
};
const normalizeEntities = entities => { const normalizeEntities = entities => {
const list = Array.isArray(entities) ? entities : []; const list = Array.isArray(entities) ? entities : [];
...@@ -237,69 +254,23 @@ const normalizeEntities = entities => { ...@@ -237,69 +254,23 @@ const normalizeEntities = entities => {
.filter(item => item.text_span); .filter(item => item.text_span);
}; };
const getEntityRanges = (text, entities) => {
const ranges = [];
const rawText = String(text ?? "");
if (!rawText) return ranges;
const list = normalizeEntities(entities).sort((a, b) => b.text_span.length - a.text_span.length);
for (const ent of list) {
let startIndex = 0;
while (startIndex < rawText.length) {
const idx = rawText.indexOf(ent.text_span, startIndex);
if (idx === -1) break;
ranges.push({ start: idx, end: idx + ent.text_span.length, ent });
startIndex = idx + ent.text_span.length;
}
}
ranges.sort((a, b) => a.start - b.start || b.end - a.end);
const merged = [];
let lastEnd = 0;
for (const r of ranges) {
if (r.start < lastEnd) continue;
merged.push(r);
lastEnd = r.end;
}
return merged;
};
const buildHighlightedHtml = (text, entities, enableHighlight) => {
const rawText = String(text ?? "");
if (!rawText) return "";
const safeText = escapeHtml(rawText).replace(/\n/g, "<br />");
if (!enableHighlight) return safeText;
const ranges = getEntityRanges(rawText, entities);
if (!ranges.length) return safeText;
let html = "";
let cursor = 0;
for (const r of ranges) {
if (cursor < r.start) {
html += escapeHtml(rawText.slice(cursor, r.start));
}
const spanText = rawText.slice(r.start, r.end);
const type = escapeHtml(r.ent?.type ?? "");
html += `<span class="term-entity" data-entity-type="${type}">${escapeHtml(spanText)}</span>`;
cursor = r.end;
}
if (cursor < rawText.length) {
html += escapeHtml(rawText.slice(cursor));
}
return html.replace(/\n/g, "<br />");
};
const getTermEntityKey = (term, lang) => { const getTermEntityKey = (term, lang) => {
const baseKey = getTermKey(term, -1); const baseKey = getTermKey(term, -1);
return `${baseKey}__${lang}`; return `${baseKey}__${lang}`;
}; };
const ensureEntitiesForTerms = async terms => { const ensureEntitiesForTerms = async terms => {
if (!termsHighlight.value) return; if (!termsHighlight.value) {
termsEntityLoading.value = false;
termsEntityPendingCount.value = 0;
return;
}
const list = Array.isArray(terms) ? terms : []; const list = Array.isArray(terms) ? terms : [];
if (!list.length) return; if (!list.length) {
termsEntityLoading.value = false;
termsEntityPendingCount.value = 0;
return;
}
const currentToken = ++entityRequestToken.value; const currentToken = ++entityRequestToken.value;
...@@ -314,30 +285,40 @@ const ensureEntitiesForTerms = async terms => { ...@@ -314,30 +285,40 @@ const ensureEntitiesForTerms = async terms => {
tasks.push({ key: enKey, text: term.ywnr }); tasks.push({ key: enKey, text: term.ywnr });
} }
} }
if (!tasks.length) return; if (!tasks.length) {
termsEntityLoading.value = false;
termsEntityPendingCount.value = 0;
return;
}
termsEntityLoading.value = true;
termsEntityPendingCount.value = tasks.length;
const fetchOne = async item => {
try { try {
const results = await Promise.all(
tasks.map(async item => {
const res = await extractTextEntity(item.text, { signal: getPageSignal() }); const res = await extractTextEntity(item.text, { signal: getPageSignal() });
const entities = normalizeEntities(res?.result ?? res?.data?.result ?? res?.data ?? res);
return { key: item.key, entities };
})
);
if (currentToken !== entityRequestToken.value) return; if (currentToken !== entityRequestToken.value) return;
for (const r of results) { const entities = normalizeEntities(res?.result ?? res?.data?.result ?? res?.data ?? res);
termEntityCache.value.set(r.key, r.entities); const nextCache = new Map(termEntityCache.value);
} nextCache.set(item.key, entities);
termEntityCache.value = nextCache;
} catch (error) { } catch (error) {
if (currentToken !== entityRequestToken.value) return; if (currentToken !== entityRequestToken.value) return;
} finally {
if (currentToken !== entityRequestToken.value) return;
termsEntityPendingCount.value = Math.max(0, termsEntityPendingCount.value - 1);
if (termsEntityPendingCount.value === 0) {
termsEntityLoading.value = false;
}
} }
};
await Promise.all(tasks.map(item => fetchOne(item)));
}; };
const getTermContentHtml = (term, lang) => { const getTermEntities = (term, lang) => {
const raw = lang === "en" ? term?.ywnr : term?.fynr;
const key = getTermEntityKey(term, lang); const key = getTermEntityKey(term, lang);
const entities = termEntityCache.value.get(key) || []; return termEntityCache.value.get(key) || [];
return buildHighlightedHtml(raw, entities, termsHighlight.value);
}; };
const tkRequestToken = ref(0); const tkRequestToken = ref(0);
...@@ -347,10 +328,6 @@ const hylyRequestToken = ref(0); ...@@ -347,10 +328,6 @@ const hylyRequestToken = ref(0);
const mainTermsList = ref([]); const mainTermsList = ref([]);
const domainFooterText = ref(""); const domainFooterText = ref("");
const limitFooterText = ref(""); const limitFooterText = ref("");
const btnActiveIndex = ref(1);
const handleSelectBtn = index => {
btnActiveIndex.value = index;
};
const getTermKey = (term, index) => { const getTermKey = (term, index) => {
return term?.ywid ?? term?.id ?? term?.tkxh ?? index; return term?.ywid ?? term?.id ?? term?.tkxh ?? index;
...@@ -576,7 +553,16 @@ const handleChangeCheckbox = val => { ...@@ -576,7 +553,16 @@ const handleChangeCheckbox = val => {
handleGetBillHyly(); handleGetBillHyly();
}; };
/** 法案布局主区域可滚动容器(.layout-main)滚回顶部 */
const scrollBillLayoutMainToTop = () => {
const mainEl = document.querySelector(".layout-main");
if (mainEl) {
mainEl.scrollTo({ top: 0, behavior: "smooth" });
}
};
const handleCurrentChange = val => { const handleCurrentChange = val => {
scrollBillLayoutMainToTop();
currentPage.value = val; currentPage.value = val;
handleGetBillContentTk(checkedValue.value ? "Y" : "N"); handleGetBillContentTk(checkedValue.value ? "Y" : "N");
}; };
...@@ -925,8 +911,11 @@ onBeforeUnmount(() => { ...@@ -925,8 +911,11 @@ onBeforeUnmount(() => {
.content-row { .content-row {
display: flex; display: flex;
align-items: flex-start;
margin-bottom: 30px;
} }
.box-header { .box-header {
display: flex; display: flex;
position: relative; position: relative;
...@@ -988,9 +977,7 @@ onBeforeUnmount(() => { ...@@ -988,9 +977,7 @@ onBeforeUnmount(() => {
.terms { .terms {
margin-top: 16px; margin-top: 16px;
margin-left: 16px;
width: 1064px; width: 1064px;
height: 1232px;
position: relative; position: relative;
.terms-switch { .terms-switch {
...@@ -1007,6 +994,14 @@ onBeforeUnmount(() => { ...@@ -1007,6 +994,14 @@ onBeforeUnmount(() => {
color: var(--text-primary-65-color); color: var(--text-primary-65-color);
} }
.terms-entity-loading {
display: inline-flex;
align-items: center;
gap: 4px;
font-size: 12px;
color: var(--text-primary-65-color);
}
.terms-switch-divider { .terms-switch-divider {
display: inline-block; display: inline-block;
width: 1px; width: 1px;
...@@ -1022,17 +1017,21 @@ onBeforeUnmount(() => { ...@@ -1022,17 +1017,21 @@ onBeforeUnmount(() => {
} }
} }
:deep(.analysis-box-wrapper) {
height: auto;
}
:deep(.wrapper-main) { :deep(.wrapper-main) {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
height: calc(100% - 45px); height: auto;
gap:16px; min-height: 0;
overflow: visible;
gap: 16px;
} }
.left-main { .left-main {
flex: 1; flex: 0 0 auto;
min-height: 0;
overflow-y: auto;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
gap: 12px; gap: 12px;
...@@ -1112,12 +1111,12 @@ onBeforeUnmount(() => { ...@@ -1112,12 +1111,12 @@ onBeforeUnmount(() => {
line-height: 24px; line-height: 24px;
color: var(--text-primary-80-color); color: var(--text-primary-80-color);
:deep(.term-entity) { :deep(.entity-link) {
display: inline; color: var(--color-primary-100);
padding: 0 2px; }
border-radius: 4px;
background: rgba(255, 213, 79, 0.35); :deep(.entity-link:hover) {
box-shadow: inset 0 0 0 1px rgba(255, 193, 7, 0.25); cursor: pointer;
} }
} }
...@@ -1128,12 +1127,12 @@ onBeforeUnmount(() => { ...@@ -1128,12 +1127,12 @@ onBeforeUnmount(() => {
line-height: 24px; line-height: 24px;
color: var(--text-primary-65-color); color: var(--text-primary-65-color);
:deep(.term-entity) { :deep(.entity-link) {
display: inline; color: var(--color-primary-100);
padding: 0 2px; }
border-radius: 4px;
background: rgba(255, 213, 79, 0.28); :deep(.entity-link:hover) {
box-shadow: inset 0 0 0 1px rgba(255, 193, 7, 0.2); cursor: pointer;
} }
} }
...@@ -1196,6 +1195,7 @@ onBeforeUnmount(() => { ...@@ -1196,6 +1195,7 @@ onBeforeUnmount(() => {
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
padding-left: 20px;
} }
.overview-tip-action { .overview-tip-action {
......
...@@ -26,7 +26,7 @@ ...@@ -26,7 +26,7 @@
</div> </div>
<div class="layout-main-center"> <div class="layout-main-center">
<BaseDecreeOriginal :report-data="reportData" @download="handleDownload" /> <newOriginal ref="refNewOriginal" @download="handleDownload"></newOriginal>
</div> </div>
</div> </div>
</div> </div>
...@@ -38,7 +38,7 @@ import { useRoute } from "vue-router"; ...@@ -38,7 +38,7 @@ import { useRoute } from "vue-router";
import { ElMessage } from "element-plus"; import { ElMessage } from "element-plus";
import { getDecreeSummary } from "@/api/decree/introduction"; import { getDecreeSummary } from "@/api/decree/introduction";
import { getDecreeReport } from "@/api/decree/introduction"; import { getDecreeReport } from "@/api/decree/introduction";
import BaseDecreeOriginal from "@/components/base/DecreeOriginal/index.vue"; import newOriginal from "@/components/base/DecreeOriginal/newOriginal.vue";
const route = useRoute(); const route = useRoute();
let pdfUrl = ""; let pdfUrl = "";
...@@ -98,26 +98,16 @@ const handleGetSummary = async () => { ...@@ -98,26 +98,16 @@ const handleGetSummary = async () => {
}; };
// 获取报告原文 - 修改为获取分段数组 // 获取报告原文 - 修改为获取分段数组
const reportData = ref([]); const refNewOriginal = ref(null);
const handleGetReport = async () => { const handleGetReport = async () => {
try { try {
const res = await getDecreeReport({id: route.query.id}); const res = await getDecreeReport({id: route.query.id});
console.log("报告原文", res); console.log("报告原文", res);
if (res.code === 200 && res.data) { if (res.code === 200) {
pdfUrl = res.data.pdfUrl; pdfUrl = res.data.pdfUrl;
const originData = []; refNewOriginal.value.setOriginalData({...res.data});
let num = Math.max(res.data.content.length, res.data.contentEn.length)
for (let i = 0; i < num; i++) {
let obj = {
content: res.data.content[i] || "",
contentEn: res.data.contentEn[i] || "",
num: i + 1,
}
originData.push(obj);
} }
reportData.value = JSON.parse(JSON.stringify(originData)); } catch (error) {}
}
} catch (error) { }
}; };
onMounted(() => { onMounted(() => {
......
<template> <template>
<AnalysisBox :title="props.title" :showAllBtn="false" height="auto"> <AnalysisBox :title="props.title" :showAllBtn="false" height="auto">
<div class="box-main"> <div class="box-main">
<el-empty v-if="!props.listData?.length" description="暂无数据" :image-size="200" />
<div v-for="(item, index) in props.listData" :key="index" class="box-item"> <div v-for="(item, index) in props.listData" :key="index" class="box-item">
<div class="item-tag">行政令</div> <div class="item-tag" :class="getClassName(item)">{{ item.TYPE }}</div>
<div class="item-right"> <div class="item-right" @click="onNavigateTo(item)">
<div class="item-head"> <div class="item-head">
<div class="item-name one-line-ellipsis">{{ item.name }}</div> <div class="item-name one-line-ellipsis text-click-hover">{{ item.NAME }}</div>
<div class="item-time">{{ item.time }}</div> <div class="item-time">{{ item.DATE }}</div>
</div> </div>
<div class="item-text one-line-ellipsis">{{ item.text }}</div> <div class="item-text one-line-ellipsis">{{ item.SUMMARY }}</div>
</div> </div>
</div> </div>
</div> </div>
...@@ -16,6 +17,8 @@ ...@@ -16,6 +17,8 @@
</template> </template>
<script setup lang="ts" name="RelatedEvent"> <script setup lang="ts" name="RelatedEvent">
import router from "@/router";
import { useGotoNewsDetail } from '@/router/modules/news';
const props = defineProps({ const props = defineProps({
listData: { listData: {
...@@ -28,6 +31,43 @@ const props = defineProps({ ...@@ -28,6 +31,43 @@ const props = defineProps({
} }
}) })
const getClassName = (item: any) => {
switch (item.TYPE) {
case "行政令":
return "theme1"
case "新闻":
return "theme2"
case "法案":
return "theme3"
default:
return "theme1"
}
}
// 跳转相关事件
const gotoNewsDetail = useGotoNewsDetail()
const onNavigateTo = (item: any) => {
switch (item.TYPE) {
case "行政令":
let route1 = router.resolve({
path: "/decreeLayout",
query: { id: item.ID }
});
window.open(route1.href, "_blank");
break;
case "新闻":
gotoNewsDetail(item.ID)
break;
case "法案":
let route2 = router.resolve({
path: "/billLayout",
query: { billId: item.ID }
});
window.open(route2.href, "_blank");
break;
}
}
</script> </script>
<style scoped lang="scss"> <style scoped lang="scss">
...@@ -47,10 +87,9 @@ const props = defineProps({ ...@@ -47,10 +87,9 @@ const props = defineProps({
text-align: center; text-align: center;
margin-right: 16px; margin-right: 16px;
margin-top: 7px; margin-top: 7px;
color: var(--color-yellow-100);
background-color: var(--color-yellow-10);
} }
.item-right { .item-right {
cursor: pointer;
width: 20px; width: 20px;
flex: auto; flex: auto;
line-height: 30px; line-height: 30px;
...@@ -77,4 +116,17 @@ const props = defineProps({ ...@@ -77,4 +116,17 @@ const props = defineProps({
border-bottom: 1px solid var(--bg-black-5); border-bottom: 1px solid var(--bg-black-5);
} }
} }
.theme1 {
background-color: var(--color-yellow-10);
color: var(--color-yellow-100);
}
.theme2 {
background-color: var(--color-green-10);
color: var(--color-green-100);
}
.theme3 {
background-color: var(--color-orange-10);
color: var(--color-orange-100);
}
</style> </style>
\ No newline at end of file
<template>
<AnalysisBox :title="props.title" :showAllBtn="false" height="auto">
<div class="box-main">
<el-empty v-if="!props.listData?.length" description="暂无数据" :image-size="100" />
<div v-for="(item, index) in props.listData" :key="index" class="box-item">
<div class="item-icon">
<img src="@/views/marketAccessRestrictions/singleCaseLayout/assets/images/icon_affiche.png" alt="">
</div>
<div class="item-right">
<div class="item-time">{{ item.time }}</div>
<div class="item-text">{{ item.content }}</div>
</div>
</div>
</div>
</AnalysisBox>
</template>
<script setup lang="ts" name="SurveyAffiche">
const props = defineProps({
listData: {
type: Array as any,
default: () => ([])
},
title: {
type: String,
default: ""
}
})
</script>
<style scoped lang="scss">
.box-main {
padding: 0 16px 16px;
.box-item {
border-top: 1px solid var(--bg-black-5);
padding: 6px;
display: flex;
.item-icon {
width: 15px;
height: 15px;
font-size: 0px;
margin-right: 16px;
margin-top: 7px;
img {
width: 100%;
height: 100%;
}
}
.item-right {
width: 20px;
flex: auto;
font-family: Source Han Sans CN;
font-size: 16px;
line-height: 30px;
.item-time {
font-weight: bold;
color: var(--text-primary-80-color);
}
.item-text {
color: var(--text-primary-65-color);
}
}
}
.box-item:last-child {
border-bottom: 1px solid var(--bg-black-5);
}
}
</style>
\ No newline at end of file
<template> <template>
<div class="view-box"> <div class="view-box">
<el-empty v-if="!props.surveyList?.length" description="当前条件下暂无数据" :image-size="200" /> <el-empty v-if="!props.surveyList?.length" description="暂无数据" :image-size="100" />
<div class="timeline-item" v-for="(item, index) in props.surveyList" :key="item.searchid" @click="onNavigateToDetail(item)"> <div class="timeline-item" v-for="(item, index) in props.surveyList" :key="item.searchid" @click="onNavigateToDetail(item)">
<div class="timeline-date"> <div class="timeline-date">
<div class="date-text">{{ item.searchdatezh.slice(0,4) }}</div> <div class="date-text">{{ item.searchdatezh.slice(0,4) }}</div>
...@@ -16,14 +16,12 @@ ...@@ -16,14 +16,12 @@
<div class="timeline-content-card"> <div class="timeline-content-card">
<div class="item-head"> <div class="item-head">
<div :class="`item-tag tag-${item.sortcode}`">{{ item.sortcode }}</div> <div :class="`item-tag tag-${item.sortcode}`">{{ item.sortcode }}</div>
<div class="item-name">{{ item.searchname }}</div> <div class="item-name one-line-ellipsis">{{ item.searchname }}</div>
<div class="item-state"> <div class="item-state">
<span class="dot"></span> {{ item.casestatus }} <span class="dot"></span> {{ item.casestatus }}
</div> </div>
</div> </div>
<div class="card-body"> <div class="card-body">{{ item.content }}</div>
{{ item.content }}
</div>
<div class="card-footer"> <div class="card-footer">
<div class="footer-left-tags"> <div class="footer-left-tags">
<AreaTag v-for="(name, num) in item.searchArea" :key="num" :tagName="name"></AreaTag> <AreaTag v-for="(name, num) in item.searchArea" :key="num" :tagName="name"></AreaTag>
...@@ -129,7 +127,7 @@ const onNavigateToDetail = item => { ...@@ -129,7 +127,7 @@ const onNavigateToDetail = item => {
.timeline-content-card { .timeline-content-card {
width: 20px; width: 20px;
flex: auto; flex: auto;
padding: 2px 16px 0; padding: 4px 16px 0;
margin-bottom: 30px; margin-bottom: 30px;
&:hover .item-head .item-name { &:hover .item-head .item-name {
......
...@@ -145,7 +145,7 @@ ...@@ -145,7 +145,7 @@
<div class="box-header-right"> <div class="box-header-right">
<el-select v-model="box6SelectedYear" @change="handleChangeBox6Year" placeholder="选择时间" <el-select v-model="box6SelectedYear" @change="handleChangeBox6Year" placeholder="选择时间"
style="width: 120px"> style="width: 120px">
<el-option v-for="item in box6YearList" :key="item.value" :label="item.label" :value="item.value" /> <el-option v-for="item in box7YearList" :key="item.value" :label="item.label" :value="item.value" />
</el-select> </el-select>
</div> </div>
</template> </template>
...@@ -168,12 +168,12 @@ ...@@ -168,12 +168,12 @@
<template #header-right> <template #header-right>
<div class="box-header-right"> <div class="box-header-right">
<div class="box7-header-right-select-box"> <div class="box7-header-right-select-box">
<el-select v-model="box7SelectedSurvey" @change="handleChangeBox7Survey" placeholder="选择调查" <el-select v-model="box7SelectedSurvey" @change="handleBox7()" placeholder="选择调查"
style="width: 120px"> style="width: 120px">
<el-option v-for="item in box7SurveyList" :key="item.value" :label="item.label" <el-option v-for="item in box8SurveyList" :key="item.value" :label="item.label"
:value="item.value" /> :value="item.value" />
</el-select> </el-select>
<el-select v-model="box7SelectedYear" @change="handleChangeBox7Year" placeholder="选择时间" <el-select v-model="box7SelectedYear" @change="handleBox7()" placeholder="选择时间"
style="width: 120px"> style="width: 120px">
<el-option v-for="item in box7YearList" :key="item.value" :label="item.label" <el-option v-for="item in box7YearList" :key="item.value" :label="item.label"
:value="item.value" /> :value="item.value" />
...@@ -197,7 +197,7 @@ ...@@ -197,7 +197,7 @@
</template> </template>
<template #header-right> <template #header-right>
<div class="box-header-right"> <div class="box-header-right">
<el-select v-model="box8SelectedSurvey" @change="handleChangeBox8Survey" placeholder="选择调查" <el-select v-model="box8SelectedSurvey" @change="handleBox8()" placeholder="选择调查"
style="width: 120px"> style="width: 120px">
<el-option v-for="item in box8SurveyList" :key="item.value" :label="item.label" <el-option v-for="item in box8SurveyList" :key="item.value" :label="item.label"
:value="item.value" /> :value="item.value" />
...@@ -216,8 +216,7 @@ ...@@ -216,8 +216,7 @@
<div class="home-main-footer"> <div class="home-main-footer">
<DivideHeader id="position4" class="divide-header" :titleText="'资源库'"></DivideHeader> <DivideHeader id="position4" class="divide-header" :titleText="'资源库'"></DivideHeader>
<div class="home-main-footer-header"> <div class="home-main-footer-header">
<SourceTabList :sourceTabList="categoryList" :activeSouceTabId="activeCateId" @clickTab="handleClickCate"> <SourceTabList :sourceTabList="categoryList" :activeSouceTabId="activeCateId" @clickTab="handleClickCate"></SourceTabList>
</SourceTabList>
<div class="select-box"> <div class="select-box">
<el-select v-model="isSort" placeholder="发布时间" style="width: 166px" @change="handlePxChange"> <el-select v-model="isSort" placeholder="发布时间" style="width: 166px" @change="handlePxChange">
<template #prefix> <template #prefix>
...@@ -232,60 +231,52 @@ ...@@ -232,60 +231,52 @@
</div> </div>
<div class="home-main-footer-main"> <div class="home-main-footer-main">
<div class="left"> <div class="left">
<div class="left-box1"> <!-- 科技领域 -->
<div class="left-box1-header"> <div class="check-box">
<div class="icon"></div> <div class="check-head">
<div class="title">{{ "发布时间" }}</div> <div class="head-name">{{ "科技领域" }}</div>
</div> </div>
<div class="left-box1-main"> <el-checkbox-group class="check-list" v-model="checkedAreaList" @change="handleCheckedAreasChange">
<el-checkbox-group class="checkbox-group" v-model="checkedSurveyYears" <el-checkbox class="check-item" v-for="item in surveyAreaList" :key="item.id" :label="item.id">
@change="handleChangeCheckedSurveyYears"> {{ item.name }}
<el-checkbox class="filter-checkbox" label="全部时间"> 全部时间 </el-checkbox>
<el-checkbox v-for="year in surveyYearList" :key="year.id" :label="year.id" class="filter-checkbox">
{{ year.name }}
</el-checkbox> </el-checkbox>
</el-checkbox-group> </el-checkbox-group>
</div> </div>
<!-- 发布时间 -->
<div class="check-box">
<div class="check-head">
<div class="head-name">{{ "发布时间" }}</div>
</div> </div>
<div class="left-box2"> <div class="left-main">
<div class="left-box2-header"> <el-checkbox-group class="check-list" v-model="checkedYearList" @change="handleCheckedYearsChange">
<div class="icon"></div> <el-checkbox class="check-item" v-for="item in surveyYearList" :key="item.id" :label="item.id">
<div class="title">{{ "科技领域" }}</div> {{ item.name }}
</div>
<div class="left-box2-main">
<el-checkbox-group class="checkbox-group" v-model="checkedAreaList" @change="handleChangeCheckedAreas">
<el-checkbox class="filter-checkbox" label="全部领域"> 全部领域 </el-checkbox>
<el-checkbox v-for="area in areaList" :key="area.id" :label="area.id" class="filter-checkbox">
{{ area.name }}
</el-checkbox> </el-checkbox>
</el-checkbox-group> </el-checkbox-group>
</div> </div>
</div> </div>
<div class="left-box2"> <!-- 发布机构 -->
<div class="left-box2-header"> <div class="check-box">
<div class="icon"></div> <div class="check-head">
<div class="title">{{ "发布机构" }}</div> <div class="head-name">{{ "发布机构" }}</div>
</div> </div>
<div class="left-box2-main"> <div class="left-main">
<el-checkbox-group class="checkbox-group" v-model="checkedInsList" @change="handleChangeCheckedIns"> <el-checkbox-group class="check-list" v-model="checkedOrgList" @change="handleChangeCheckedIns">
<el-checkbox class="filter-checkbox" label="全部机构"> 全部机构 </el-checkbox> <el-checkbox class="check-item" v-for="item in surveyOrgList" :key="item.id" :label="item.id">
<el-checkbox v-for="area in insList" :key="area.id" :label="area.id" class="filter-checkbox"> {{ item.name }}
{{ area.name }}
</el-checkbox> </el-checkbox>
</el-checkbox-group> </el-checkbox-group>
</div> </div>
</div> </div>
<div class="left-box2"> <!-- 受调查国家/地区 -->
<div class="left-box2-header"> <div class="check-box">
<div class="icon"></div> <div class="check-head">
<div class="title">{{ "受调查国家/地区" }}</div> <div class="head-name">{{ "受调查国家/地区" }}</div>
</div> </div>
<div class="left-box2-main"> <div class="left-main">
<el-checkbox-group class="checkbox-group" v-model="checkedCountryList" <el-checkbox-group class="check-list" v-model="checkedCountryList" @change="handleCheckedCountriesChange">
@change="handleChangeCheckedCountry"> <el-checkbox class="check-item" v-for="item in surveyCountryList" :key="item.id" :label="item.id">
<el-checkbox class="filter-checkbox" label="全部"> 全部 </el-checkbox> {{ item.name }}
<el-checkbox v-for="area in countryList" :key="area.id" :label="area.id" class="filter-checkbox">
{{ area.name }}
</el-checkbox> </el-checkbox>
</el-checkbox-group> </el-checkbox-group>
</div> </div>
...@@ -316,7 +307,7 @@ ...@@ -316,7 +307,7 @@
</template> </template>
<script setup> <script setup>
import { onMounted, ref, nextTick } from "vue"; import { onMounted, ref, nextTick, reactive } from "vue";
import LeftBtn from "@/components/base/pageBtn/LeftBtn.vue"; import LeftBtn from "@/components/base/pageBtn/LeftBtn.vue";
import RightBtn from "@/components/base/pageBtn/RightBtn.vue"; import RightBtn from "@/components/base/pageBtn/RightBtn.vue";
...@@ -347,8 +338,6 @@ import { ...@@ -347,8 +338,6 @@ import {
getSearchResult, getSearchResult,
getSearchAllOrg, getSearchAllOrg,
getSearchAllCountry, getSearchAllCountry,
getStatAreaCompanyList,
getCompanyPlace
} from "@/api/marketAccessRestrictions/index"; } from "@/api/marketAccessRestrictions/index";
import { getRiskSignal, getNews, getRemarks } from "@/api/common/index"; import { getRiskSignal, getNews, getRemarks } from "@/api/common/index";
import { ElMessage } from "element-plus"; import { ElMessage } from "element-plus";
...@@ -379,21 +368,6 @@ const handleToPosi = id => { ...@@ -379,21 +368,6 @@ const handleToPosi = id => {
} }
}; };
const formatDate = (dateStr, dateType) => {
if (!dateStr) return "";
const date = new Date(dateStr);
if (isNaN(date.getTime())) return dateStr;
const year = date.getFullYear();
const month = date.getMonth() + 1;
const day = date.getDate();
if (dateType === 'year') {
return year
} else {
return `${month.toString().padStart(2, "0")}月${day.toString().padStart(2, "0")}日`
}
// return `${year}年${month.toString().padStart(2, "0")}月${day.toString().padStart(2, "0")}日`;
}
let containerRef = ref(null); let containerRef = ref(null);
// 首页分类 // 首页分类
const sortInfo = ref([{}]); const sortInfo = ref([{}]);
...@@ -726,32 +700,6 @@ const handleBox5 = async () => { ...@@ -726,32 +700,6 @@ const handleBox5 = async () => {
// 制裁领域分布 // 制裁领域分布
const box6SelectedYear = ref("2025"); const box6SelectedYear = ref("2025");
const box6YearList = ref([
{
label: "2025",
value: "2025"
},
{
label: "2024",
value: "2024"
},
{
label: "2023",
value: "2023"
},
{
label: "2022",
value: "2022"
},
{
label: "2021",
value: "2021"
},
{
label: "2020",
value: "2020"
}
]);
const handleChangeBox6Year = () => { const handleChangeBox6Year = () => {
handleBox6(); handleBox6();
}; };
...@@ -846,59 +794,18 @@ const handleBox6 = async () => { ...@@ -846,59 +794,18 @@ const handleBox6 = async () => {
}; };
// 受调查国家分布 // 受调查国家分布
const box7SurveyList = ref([
{
label: "337调查",
value: "337"
},
{
label: "301调查",
value: "301"
},
{
label: "232调查",
value: "232"
}
]);
const box7SelectedSurvey = ref("337"); const box7SelectedSurvey = ref("337");
const box7YearList = ref([ const box7YearList = ref([
{ { label: "2025", value: "2025" },
label: "2025", { label: "2024", value: "2024" },
value: "2025" { label: "2023", value: "2023" },
}, { label: "2022", value: "2022" },
{ { label: "2021", value: "2021" },
label: "2024", { label: "2020", value: "2020" },
value: "2024"
},
{
label: "2023",
value: "2023"
},
{
label: "2022",
value: "2022"
},
{
label: "2021",
value: "2021"
},
{
label: "2020",
value: "2020"
}
]); ]);
const box7SelectedYear = ref("2025"); const box7SelectedYear = ref("2025");
const box7Data = reactive({
const handleChangeBox7Survey = () => { title: [],
handleBox7();
};
const handleChangeBox7Year = () => {
handleBox7();
};
const box7Data = ref({
title: [
],
data: [] data: []
}); });
...@@ -911,13 +818,13 @@ const handleGetBox7Data = async () => { ...@@ -911,13 +818,13 @@ const handleGetBox7Data = async () => {
const res = await getSearchCountry(params); const res = await getSearchCountry(params);
console.log("受调查国家分布", res); console.log("受调查国家分布", res);
if (res.code === 200 && res.data) { if (res.code === 200 && res.data) {
box7Data.value.title = res.data.map(item => { box7Data.title = res.data.map(item => {
return { return {
name: item.COUNTRY, name: item.COUNTRY,
img: item.COUNTRYIMAGE img: item.COUNTRYIMAGE
}; };
}); });
box7Data.value.data = res.data.map(item => { box7Data.data = res.data.map(item => {
return item.NUM; return item.NUM;
}); });
} }
...@@ -928,35 +835,21 @@ const handleGetBox7Data = async () => { ...@@ -928,35 +835,21 @@ const handleGetBox7Data = async () => {
const handleBox7 = async () => { const handleBox7 = async () => {
await handleGetBox7Data(); await handleGetBox7Data();
const box7Chart = getBarChart(box7Data.value.title, box7Data.value.data); const box7Chart = getBarChart(box7Data.title, box7Data.data);
setChart(box7Chart, "box7Chart"); setChart(box7Chart, "box7Chart");
}; };
const box8SurveyList = ref([ const box8SurveyList = ref([
{ { label: "337调查", value: "337" },
label: "337调查", { label: "301调查", value: "301" },
value: "337" { label: "232调查", value: "232" },
},
{
label: "301调查",
value: "301"
},
{
label: "232调查",
value: "232"
}
]); ]);
const box8SelectedSurvey = ref("337");
// 调查结果分布 // 调查结果分布
const box8Data = ref([ const box8SelectedSurvey = ref("337");
]); const box8Data = ref([]);
const handleGetBox8Data = async () => { const handleGetBox8Data = async () => {
const params = {
// searchId: '',
sortCode: box8SelectedSurvey.value
};
try { try {
const res = await getSearchResult(params); const res = await getSearchResult({sortCode: box8SelectedSurvey.value});
console.log("调查结果分布", res); console.log("调查结果分布", res);
if (res.code === 200 && res.data) { if (res.code === 200 && res.data) {
box8Data.value = res.data.map(item => { box8Data.value = res.data.map(item => {
...@@ -968,23 +861,16 @@ const handleGetBox8Data = async () => { ...@@ -968,23 +861,16 @@ const handleGetBox8Data = async () => {
} else { } else {
box8Data.value = [] box8Data.value = []
} }
} catch (error) { } catch (error) {
console.error(error); console.error(error);
} }
}; };
const handleBox8 = async () => { const handleBox8 = async () => {
await handleGetBox8Data() await handleGetBox8Data()
const box8Chart = getPieChart(box8Data.value); const box8Chart = getPieChart(box8Data.value);
setChart(box8Chart, "box8Chart"); setChart(box8Chart, "box8Chart");
} }
const handleChangeBox8Survey = () => {
handleBox8();
};
// 资源库 // 资源库
const pageSize = ref(10); const pageSize = ref(10);
const currentPage = ref(1); const currentPage = ref(1);
...@@ -992,234 +878,132 @@ const totalDiscussNum = ref(0); ...@@ -992,234 +878,132 @@ const totalDiscussNum = ref(0);
const handleCurrentChange = page => { const handleCurrentChange = page => {
handleToPosi("position4") handleToPosi("position4")
currentPage.value = page; currentPage.value = page;
handleGetSurveyList(); handleFetchSurveyList();
}; };
const categoryList = ref([ const categoryList = ref([
{ { name: "全部调查", id: "" },
name: "全部调查", { name: "337调查", id: "337" },
id: "" { name: "301调查", id: "301" },
}, { name: "232调查", id: "232" },
{
name: "301调查",
id: "301"
},
{
name: "232调查",
id: "232"
},
{
name: "337调查",
id: "337"
}
]); ]);
const activeCateId = ref(""); const activeCateId = ref("");
const handleClickCate = item => { const handleClickCate = item => {
activeCateId.value = item.id; activeCateId.value = item.id;
handleGetInsList() currentPage.value = 1;
handleGetSurveyList(); handleFetchSurveyList();
}; };
const releaseTimeList = ref([ const releaseTimeList = ref([
{ { label: "按发布时间倒序", value: true },
label: "按发布时间倒序", { label: "按发布时间升序", value: false }
value: true
},
{
label: "按发布时间升序",
value: false
}
]); ]);
const isSort = ref(true);
const isSort = ref(true); // true 倒序 false 升序 const handlePxChange = () => {
// const handleSwithSort = () => { currentPage.value = 1;
// isSort.value = !isSort.value; handleFetchSurveyList();
// };
const handlePxChange = val => {
handleGetSurveyList()
}; };
const surveyYearList = ref([ const surveyYearList = ref([
{ { name: "全部时间", id: "" },
name: "2025年", { name: "2025年", id: "2025" },
id: "2025" { name: "2024年", id: "2024" },
}, { name: "2023年", id: "2023" },
{ { name: "2022年", id: "2022" },
name: "2024年", { name: "2021年", id: "2021" }
id: "2024"
},
{
name: "2023年",
id: "2023"
},
{
name: "2022年",
id: "2022"
},
{
name: "2021年",
id: "2021"
}
]); ]);
const checkedSurveyYears = ref(['全部时间']); const checkedYearList = ref(['']);
const handleChangeCheckedSurveyYears = (val) => { const handleCheckedYearsChange = event => {
if (val.includes("全部时间") && val.length > 1) { if (event.length && event[event.length-1] !== "") {
if (val[val.length - 1] === "全部时间") { checkedYearList.value = event.filter(item => item !== "");
checkedSurveyYears.value = ["全部时间"];
} else { } else {
checkedSurveyYears.value = val.filter(item => item !== "全部时间"); checkedYearList.value = [""];
}
} else if (val.length === 0) {
checkedSurveyYears.value = ["全部时间"];
} }
handleGetSurveyList(); currentPage.value = 1;
handleFetchSurveyList();
}; };
const areaList = ref([ // 科技领域过滤
]); const surveyAreaList = ref([]);
const checkedAreaList = ref(['全部领域']); const checkedAreaList = ref(['']);
const handleGetAreaList = async () => { const handleGetSearchAllArea = async () => {
try { try {
const res = await getHylyList(); const res = await getHylyList();
console.log("行业领域列表", res); if (res.code === 200) {
if (res.code === 200 && res.data) { surveyAreaList.value = res.data.map(item => ({ name: item.name, id: item.id }));
areaList.value = res.data.map(item => {
return {
name: item.name,
id: item.id
};
});
console.log("areaList", areaList.value);
} }
} catch (error) { } } catch (error) {}
surveyAreaList.value.unshift({ name: "全部领域", id: "" });
}; };
const handleCheckedAreasChange = event => {
const handleChangeCheckedAreas = (val) => { if (event.length && event[event.length-1] !== "") {
// console.log('val',val); checkedAreaList.value = event.filter(item => item !== "");
if (val.includes("全部领域") && val.length > 1) {
if (val[val.length - 1] === "全部领域") {
checkedAreaList.value = ["全部领域"];
} else { } else {
checkedAreaList.value = val.filter(item => item !== "全部领域"); checkedAreaList.value = [""];
} }
} else if (val.length === 0) { currentPage.value = 1;
checkedAreaList.value = ["全部领域"]; handleFetchSurveyList();
}
handleGetSurveyList();
}; };
// 发布机构 // 发布机构过滤
const insList = ref([ const surveyOrgList = ref([]);
{ const checkedOrgList = ref(['']);
name: "商务部",
id: "54"
},
{
name: "国际贸易委员会",
id: "262"
},
{
name: "贸易代表办公室",
id: "491"
}
]);
const checkedInsList = ref(['全部机构']);
const handleGetInsList = async () => { const handleGetInsList = async () => {
// const params = {
// sortCode: activeCateId.value
// }
try { try {
const res = await getSearchAllOrg() const res = await getSearchAllOrg()
console.log('发布机构', res); if (res.code === 200) {
if (res.code === 200 && res.data) { surveyOrgList.value = res.data.map(item => ({ name: item.ORGNAME, id: item.ORGID }))
insList.value = res.data.map(item => {
return {
name: item.ORGNAME,
id: item.ORGID
}
})
// checkedInsList.value = [insList.value[0].id]
}
} catch (error) {
} }
} catch (error) {}
surveyOrgList.value.unshift({ name: "全部机构", id: "" });
} }
const handleChangeCheckedIns = (event) => {
if (event.length && event[event.length-1] !== "") {
const handleChangeCheckedIns = (val) => { checkedOrgList.value = event.filter(item => item !== "");
// console.log(checkedAreaList.value);
if (val.includes("全部机构") && val.length > 1) {
if (val[val.length - 1] === "全部机构") {
checkedInsList.value = ["全部机构"];
} else { } else {
checkedInsList.value = val.filter(item => item !== "全部机构"); checkedOrgList.value = [""];
}
} else if (val.length === 0) {
checkedInsList.value = ["全部机构"];
} }
handleGetSurveyList(); currentPage.value = 1;
handleFetchSurveyList();
}; };
// 受调查国家/地区 // 受调查国家/地区
const countryList = ref([ const surveyCountryList = ref([]);
]); const checkedCountryList = ref(['']);
const checkedCountryList = ref(['全部']);
const handleGetAllSearchCountry = async () => { const handleGetAllSearchCountry = async () => {
try { try {
const res = await getSearchAllCountry() const res = await getSearchAllCountry()
console.log('受调查国家/地区', res); if (res.code === 200) {
if (res.code && res.data) { surveyCountryList.value = res.data.map(item => ({ name: item.COUNTRYNAME, id: item.COUNTRYID }))
countryList.value = res.data.map(item => {
return {
name: item.COUNTRYNAME,
id: item.COUNTRYID
}
})
// checkedCountryList.value = [countryList.value[0].id]
}
} catch (error) {
} }
} catch (error) {}
surveyCountryList.value.unshift({ name: "全部", id: "" });
} }
handleGetAllSearchCountry() const handleCheckedCountriesChange = event => {
const handleChangeCheckedCountry = (val) => { if (event.length && event[event.length-1] !== "") {
if (val.includes("全部") && val.length > 1) { checkedCountryList.value = event.filter(item => item !== "");
if (val[val.length - 1] === "全部") {
checkedCountryList.value = ["全部"];
} else { } else {
checkedCountryList.value = val.filter(item => item !== "全部"); checkedCountryList.value = [""];
}
} else if (val.length === 0) {
checkedCountryList.value = ["全部"];
} }
handleGetSurveyList(); currentPage.value = 1;
handleFetchSurveyList();
}; };
const surveyInfoList = ref([]); const surveyInfoList = ref([]);
const handleGetSurveyList = async () => { const handleFetchSurveyList = async () => {
const params = { const params = {
currentPage: currentPage.value - 1, currentPage: currentPage.value - 1,
pageSize: pageSize.value, pageSize: pageSize.value,
sortCode: activeCateId.value ? activeCateId.value : null, sortCode: activeCateId.value || null,
publishYear: checkedSurveyYears.value[0] === '全部时间' ? null : checkedSurveyYears.value.toString(), publishYear: checkedYearList.value.join(',') || null,
Area: checkedAreaList.value[0] === '全部领域' ? null : checkedAreaList.value.toString(), Area: checkedAreaList.value.join(',') || null,
publishOrg: checkedInsList.value[0] === '全部机构' ? null : checkedInsList.value.toString(), publishOrg: checkedOrgList.value.join(',') || null,
searchCountry: checkedCountryList.value[0] === '全部' ? null : checkedCountryList.value.toString(), searchCountry: checkedCountryList.value.join(',') || null,
sortField: "date", sortField: "date",
sortOrder: isSort.value ? "desc" : "asc" sortOrder: isSort.value ? "desc" : "asc"
}; };
// console.log(params);
try { try {
const res = await getSurveyList(params); const res = await getSurveyList(params);
console.log("调查列表", res); console.log("调查列表", res);
...@@ -1254,9 +1038,10 @@ onMounted(async () => { ...@@ -1254,9 +1038,10 @@ onMounted(async () => {
handleBox6(); handleBox6();
handleBox7(); handleBox7();
handleBox8(); handleBox8();
await handleGetInsList() handleGetAllSearchCountry()
await handleGetAreaList(); handleGetInsList()
handleGetSurveyList(); handleGetSearchAllArea();
handleFetchSurveyList();
}); });
</script> </script>
...@@ -2293,67 +2078,44 @@ onMounted(async () => { ...@@ -2293,67 +2078,44 @@ onMounted(async () => {
box-shadow: 0px 0px 15px 0px rgba(60, 87, 126, 0.2); box-shadow: 0px 0px 15px 0px rgba(60, 87, 126, 0.2);
background: rgba(255, 255, 255, 1); background: rgba(255, 255, 255, 1);
.left-box1 { .check-box {
margin-top: 17px; margin-top: 18px;
.check-head {
// height: 220px; position: relative;
.left-box1-header { margin-bottom: 12px;
display: flex; &::before {
content: "";
.icon { position: absolute;
top: 0px;
left: 0px;
width: 8px; width: 8px;
height: 16px; height: 100%;
margin-top: 4px; background: var(--color-primary-100);
border-radius: 2px 2px 0 0; border-radius: 0 2px 2px 0;
background: var(--color-main-active);
} }
.head-name {
.title { margin-left: 25px;
height: 2px; color: var(--color-primary-100);
margin-left: 17px;
color: var(--color-main-active);
font-family: Source Han Sans CN;
font-size: 16px; font-size: 16px;
font-weight: 700; line-height: 16px;
line-height: 24px; font-family: Source Han Sans CN;
} font-weight: bold;
}
.left-box1-main {
margin-top: 10px;
padding-left: 20px;
}
} }
.left-box2 {
margin-top: 17px;
// height: 260px;
.left-box2-header {
display: flex;
.icon {
width: 8px;
height: 16px;
margin-top: 4px;
border-radius: 2px 2px 0 0;
background: var(--color-main-active);
} }
.check-list {
.title { padding: 0 10px 0 25px;
height: 2px; display: grid;
margin-left: 17px; grid-template-columns: repeat(2, 1fr);
color: var(--color-main-active); grid-gap: 0 12px;
.check-item {
width: 100%;
height: 32px;
:deep(.el-checkbox__label) {
font-family: Source Han Sans CN; font-family: Source Han Sans CN;
font-size: 16px; font-size: 16px;
font-weight: 700; color: var(--text-primary-65-color);
line-height: 24px;
} }
} }
.left-box2-main {
margin-top: 10px;
padding-left: 20px;
} }
} }
} }
......
...@@ -32,39 +32,26 @@ ...@@ -32,39 +32,26 @@
<div class="wrapper-main"> <div class="wrapper-main">
<div class="left"> <div class="left">
<!-- 科技领域 --> <!-- 科技领域 -->
<div class="left-box"> <div class="check-box">
<div class="left-header"> <div class="check-head">
<div class="icon"></div> <div class="head-name">{{ "科技领域" }}</div>
<div class="title">{{ "科技领域" }}</div>
</div> </div>
<div class="left-main"> <el-checkbox-group class="check-list" v-model="checkedAreaList" @change="handleCheckedAreasChange">
<el-checkbox-group class="checkbox-group" v-model="checkedAreaList" @change="handleCheckedAreasChange"> <el-checkbox class="check-item" v-for="item in surveyAreaList" :key="item.id" :label="item.id">
<el-checkbox class="filter-checkbox" label="全部领域"> 全部领域 </el-checkbox> {{ item.name }}
<el-checkbox v-for="area in surveyAreaList" :key="area.id" :label="area.id" class="filter-checkbox">
{{ area.name }}
</el-checkbox> </el-checkbox>
</el-checkbox-group> </el-checkbox-group>
</div> </div>
</div>
<!-- 发布时间 --> <!-- 发布时间 -->
<div class="left-box"> <div class="check-box">
<div class="left-header"> <div class="check-head">
<div class="icon"></div> <div class="head-name">{{ "发布时间" }}</div>
<div class="title">{{ "发布时间" }}</div>
</div> </div>
<div class="left-main"> <div class="left-main">
<el-checkbox-group class="checkbox-group" v-model="checkedSurveyYears" @change="handleCheckedYearsChange"> <el-checkbox-group class="check-list" v-model="checkedYearList" @change="handleCheckedYearsChange">
<el-checkbox class="filter-checkbox" label="全部时间"> 全部时间 </el-checkbox> <el-checkbox class="check-item" v-for="item in surveyYearList" :key="item.id" :label="item.id">
<el-checkbox v-for="year in displayedYearList" :key="year.id" :label="year.id" class="filter-checkbox"> {{ item.name }}
{{ year.name }}
</el-checkbox> </el-checkbox>
<div v-if="surveyYearList.length > 6" class="expand-btn" @click="isYearExpanded = !isYearExpanded">
{{ isYearExpanded ? "收起" : "更早" }}
<el-icon>
<ArrowUp v-if="isYearExpanded" />
<ArrowDown v-else />
</el-icon>
</div>
</el-checkbox-group> </el-checkbox-group>
</div> </div>
</div> </div>
...@@ -98,8 +85,8 @@ ...@@ -98,8 +85,8 @@
</template> </template>
<script setup> <script setup>
import { ref, onMounted, watch, computed } from "vue"; import { ref, onMounted, watch } from "vue";
import { Search, ArrowDown, ArrowUp } from "@element-plus/icons-vue"; import { Search } from "@element-plus/icons-vue";
import { getSearchAllArea, getSearchAllYear, getSurveyList } from "@/api/marketAccessRestrictions"; import { getSearchAllArea, getSearchAllYear, getSurveyList } from "@/api/marketAccessRestrictions";
import SurveyHistory from "@/views/marketAccessRestrictions/com/SurveyHistory.vue" import SurveyHistory from "@/views/marketAccessRestrictions/com/SurveyHistory.vue"
...@@ -116,42 +103,49 @@ const handleSwithSort = () => { ...@@ -116,42 +103,49 @@ const handleSwithSort = () => {
// 科技领域过滤 // 科技领域过滤
const surveyAreaList = ref([]); const surveyAreaList = ref([]);
const checkedAreaList = ref([]); const checkedAreaList = ref(['']);
const checkAllAreas = ref(true); const handleGetSearchAllArea = async () => {
const isIndeterminateAreas = ref(false); try {
const res = await getSearchAllArea({ sortCode: "232" });
const handleCheckAllAreasChange = val => { if (res.code === 200) {
checkedAreaList.value = val ? surveyAreaList.value.map(a => a.id) : []; surveyAreaList.value = res.data.map(item => ({ name: item.AREANAME, id: item.AREACODE }));
isIndeterminateAreas.value = false; }
} catch (error) {}
surveyAreaList.value.unshift({ name: "全部领域", id: "" });
}; };
const handleCheckedAreasChange = event => {
const handleCheckedAreasChange = value => { if (event.length && event[event.length-1] !== "") {
const checkedCount = value.length; checkedAreaList.value = event.filter(item => item !== "");
checkAllAreas.value = checkedCount === surveyAreaList.value.length; } else {
isIndeterminateAreas.value = checkedCount > 0 && checkedCount < surveyAreaList.value.length; checkedAreaList.value = [""];
}
currentPage.value = 1;
handleFetchSurveyList();
}; };
// 发布时间过滤 // 发布时间过滤
const surveyYearList = ref([]); const surveyYearList = ref([]);
const checkedSurveyYears = ref([]); const checkedYearList = ref(['']);
const checkAllYears = ref(true); const handleGetSearchAllYear = async () => {
const isIndeterminateYears = ref(false); try {
const isYearExpanded = ref(false); const res = await getSearchAllYear({ sortCode: "232" });
if (res.code === 200) {
const displayedYearList = computed(() => { let allYear = res.data.sort((a, b) => (b-a));
if (isYearExpanded.value) return surveyYearList.value; let beforeYear = allYear.slice(6).join(',');
return surveyYearList.value.slice(0, 6); surveyYearList.value = allYear.slice(0, 6).map(item => ({ name: item + "年", id: item }));
}); if (beforeYear) surveyYearList.value.push({ name: "更早", id: beforeYear });
}
const handleCheckAllYearsChange = val => { } catch (error) {}
checkedSurveyYears.value = val ? surveyYearList.value.map(y => y.id) : []; surveyYearList.value.unshift({ name: "全部时间", id: "" });
isIndeterminateYears.value = false;
}; };
const handleCheckedYearsChange = event => {
const handleCheckedYearsChange = value => { if (event.length && event[event.length-1] !== "") {
const checkedCount = value.length; checkedYearList.value = event.filter(item => item !== "");
checkAllYears.value = checkedCount === surveyYearList.value.length; } else {
isIndeterminateYears.value = checkedCount > 0 && checkedCount < surveyYearList.value.length; checkedYearList.value = [""];
}
currentPage.value = 1;
handleFetchSurveyList();
}; };
// 数据列表 // 数据列表
...@@ -169,8 +163,8 @@ const handleFetchSurveyList = async () => { ...@@ -169,8 +163,8 @@ const handleFetchSurveyList = async () => {
currentPage: currentPage.value - 1, currentPage: currentPage.value - 1,
pageSize: pageSize.value, pageSize: pageSize.value,
sortCode: "232", sortCode: "232",
publishYear: checkAllYears.value ? "" : checkedSurveyYears.value.toString(), publishYear: checkedYearList.value.join(',') || null,
Area: checkAllAreas.value ? "" : checkedAreaList.value.toString(), Area: checkedAreaList.value.join(',') || null,
caseStatus: filterStage.value, caseStatus: filterStage.value,
keywords: searchText.value, keywords: searchText.value,
sortField: "date", sortField: "date",
...@@ -199,39 +193,12 @@ const handleSearch = () => { ...@@ -199,39 +193,12 @@ const handleSearch = () => {
}; };
// 监听过滤条件 // 监听过滤条件
watch([checkedSurveyYears, checkedAreaList, isSort, filterStage, filterParty, filterReason], () => { watch([isSort, filterStage, filterParty, filterReason], () => {
if (isInitializing.value) return; if (isInitializing.value) return;
currentPage.value = 1; currentPage.value = 1;
handleFetchSurveyList(); handleFetchSurveyList();
}); });
const handleGetSearchAllArea = async () => {
try {
const res = await getSearchAllArea({ sortCode: "232" });
if (res.code === 200 && res.data) {
surveyAreaList.value = res.data.map(item => ({
name: item.AREANAME,
id: item.AREACODE
}));
handleCheckAllAreasChange(true);
}
} catch (error) {}
};
const handleGetSearchAllYear = async () => {
try {
const res = await getSearchAllYear({ sortCode: "232" });
if (res.code === 200 && res.data) {
const sortedYears = res.data.sort((a, b) => b - a);
surveyYearList.value = sortedYears.map(item => ({
name: item + "年",
id: item
}));
handleCheckAllYearsChange(true);
}
} catch (error) {}
};
onMounted(async () => { onMounted(async () => {
await Promise.all([handleGetSearchAllArea(), handleGetSearchAllYear()]); await Promise.all([handleGetSearchAllArea(), handleGetSearchAllYear()]);
isInitializing.value = false; isInitializing.value = false;
...@@ -306,58 +273,50 @@ onMounted(async () => { ...@@ -306,58 +273,50 @@ onMounted(async () => {
.left { .left {
width: 360px; width: 360px;
min-height: 560px; min-height: 300px;
height: fit-content; height: fit-content;
padding-bottom: 20px; padding-bottom: 20px;
border-radius: 10px; border-radius: 10px;
box-shadow: 0px 0px 15px 0px rgba(60, 87, 126, 0.2); box-shadow: 0px 0px 15px 0px rgba(60, 87, 126, 0.2);
background: #fff; background: #fff;
.left-box { .check-box {
margin-top: 17px; margin-top: 18px;
.check-head {
.left-header { position: relative;
display: flex; margin-bottom: 12px;
align-items: center; &::before {
content: "";
.icon { position: absolute;
top: 0px;
left: 0px;
width: 8px; width: 8px;
height: 16px; height: 100%;
background: var(--color-main-active); background: var(--color-primary-100);
border-radius: 0 2px 2px 0; border-radius: 0 2px 2px 0;
} }
.head-name {
.title { margin-left: 25px;
margin-left: 17px; color: var(--color-primary-100);
color: var(--color-main-active);
font-size: 16px; font-size: 16px;
font-weight: 700; line-height: 16px;
} font-family: Source Han Sans CN;
font-weight: bold;
} }
} }
.check-list {
.checkbox-group { padding: 0 10px 0 25px;
padding: 10px 0 0 25px; display: grid;
.filter-checkbox { grid-template-columns: repeat(2, 1fr);
width: 130px; grid-gap: 0 12px;
margin-bottom: 8px; .check-item {
width: 100%;
height: 32px; height: 32px;
:deep(.el-checkbox__label) { :deep(.el-checkbox__label) {
font-family: Source Han Sans CN;
font-size: 16px; font-size: 16px;
color: #5f656c; color: var(--text-primary-65-color);
}
} }
.expand-btn {
color: var(--color-main-active);
font-size: 14px;
cursor: pointer;
display: flex;
align-items: center;
margin-top: 4px;
.el-icon {
margin-left: 4px;
} }
} }
} }
......
...@@ -21,39 +21,26 @@ ...@@ -21,39 +21,26 @@
<div class="wrapper-main"> <div class="wrapper-main">
<div class="left"> <div class="left">
<!-- 科技领域 --> <!-- 科技领域 -->
<div class="left-box"> <div class="check-box">
<div class="left-header"> <div class="check-head">
<div class="icon"></div> <div class="head-name">{{ "科技领域" }}</div>
<div class="title">{{ "科技领域" }}</div>
</div> </div>
<div class="left-main"> <el-checkbox-group class="check-list" v-model="checkedAreaList" @change="handleCheckedAreasChange">
<el-checkbox-group class="checkbox-group" v-model="checkedAreaList" @change="handleCheckedAreasChange"> <el-checkbox class="check-item" v-for="item in surveyAreaList" :key="item.id" :label="item.id">
<el-checkbox class="filter-checkbox" label="全部领域"> 全部领域 </el-checkbox> {{ item.name }}
<el-checkbox v-for="area in surveyAreaList" :key="area.id" :label="area.id" class="filter-checkbox">
{{ area.name }}
</el-checkbox> </el-checkbox>
</el-checkbox-group> </el-checkbox-group>
</div> </div>
</div>
<!-- 发布时间 --> <!-- 发布时间 -->
<div class="left-box"> <div class="check-box">
<div class="left-header"> <div class="check-head">
<div class="icon"></div> <div class="head-name">{{ "发布时间" }}</div>
<div class="title">{{ "发布时间" }}</div>
</div> </div>
<div class="left-main"> <div class="left-main">
<el-checkbox-group class="checkbox-group" v-model="checkedSurveyYears" @change="handleCheckedYearsChange"> <el-checkbox-group class="check-list" v-model="checkedYearList" @change="handleCheckedYearsChange">
<el-checkbox class="filter-checkbox" label="全部时间"> 全部时间 </el-checkbox> <el-checkbox class="check-item" v-for="item in surveyYearList" :key="item.id" :label="item.id">
<el-checkbox v-for="year in displayedYearList" :key="year.id" :label="year.id" class="filter-checkbox"> {{ item.name }}
{{ year.name }}
</el-checkbox> </el-checkbox>
<div v-if="surveyYearList.length > 6" class="expand-btn" @click="isYearExpanded = !isYearExpanded">
{{ isYearExpanded ? "收起" : "更早" }}
<el-icon>
<ArrowUp v-if="isYearExpanded" />
<ArrowDown v-else />
</el-icon>
</div>
</el-checkbox-group> </el-checkbox-group>
</div> </div>
</div> </div>
...@@ -78,8 +65,8 @@ ...@@ -78,8 +65,8 @@
</template> </template>
<script setup> <script setup>
import { ref, onMounted, watch, computed } from "vue"; import { ref, onMounted, watch } from "vue";
import { Search, ArrowDown, ArrowUp } from "@element-plus/icons-vue"; import { Search } from "@element-plus/icons-vue";
import { getSearchAllArea, getSearchAllYear, getSurveyList } from "@/api/marketAccessRestrictions"; import { getSearchAllArea, getSearchAllYear, getSurveyList } from "@/api/marketAccessRestrictions";
import SurveyHistory from "@/views/marketAccessRestrictions/com/SurveyHistory.vue" import SurveyHistory from "@/views/marketAccessRestrictions/com/SurveyHistory.vue"
...@@ -88,46 +75,51 @@ const handleSwithSort = () => { ...@@ -88,46 +75,51 @@ const handleSwithSort = () => {
isSort.value = !isSort.value; isSort.value = !isSort.value;
}; };
const surveyYearList = ref([]); // 科技领域过滤
const checkedSurveyYears = ref([]); const surveyAreaList = ref([]);
const isYearExpanded = ref(false); const checkedAreaList = ref(['']);
const handleGetSearchAllArea = async () => {
const displayedYearList = computed(() => { try {
if (isYearExpanded.value) { const res = await getSearchAllArea({ sortCode: "301" });
return surveyYearList.value; if (res.code === 200) {
surveyAreaList.value = res.data.map(item => ({ name: item.AREANAME, id: item.AREACODE }));
} }
return surveyYearList.value.slice(0, 6); } catch (error) {}
}); surveyAreaList.value.unshift({ name: "全部领域", id: "" });
const checkAllYears = ref(false);
const isIndeterminateYears = ref(false);
const handleCheckAllYearsChange = (val) => {
checkedSurveyYears.value = val ? surveyYearList.value.map(y => y.id) : [];
isIndeterminateYears.value = false;
}; };
const handleCheckedAreasChange = event => {
const handleCheckedYearsChange = (value) => { if (event.length && event[event.length-1] !== "") {
const checkedCount = value.length; checkedAreaList.value = event.filter(item => item !== "");
checkAllYears.value = checkedCount === surveyYearList.value.length; } else {
isIndeterminateYears.value = checkedCount > 0 && checkedCount < surveyYearList.value.length; checkedAreaList.value = [""];
}
currentPage.value = 1;
handleFetchSurveyList();
}; };
const surveyAreaList = ref([]); // 发布时间过滤
const checkedAreaList = ref([]); const surveyYearList = ref([]);
const checkedYearList = ref(['']);
const checkAllAreas = ref(false); const handleGetSearchAllYear = async () => {
const isIndeterminateAreas = ref(false); try {
const res = await getSearchAllYear({ sortCode: "301" });
const handleCheckAllAreasChange = (val) => { if (res.code === 200) {
checkedAreaList.value = val ? surveyAreaList.value.map(a => a.id) : []; let allYear = res.data.sort((a, b) => (b-a));
isIndeterminateAreas.value = false; let beforeYear = allYear.slice(6).join(',');
surveyYearList.value = allYear.slice(0, 6).map(item => ({ name: item + "年", id: item }));
if (beforeYear) surveyYearList.value.push({ name: "更早", id: beforeYear });
}
} catch (error) {}
surveyYearList.value.unshift({ name: "全部时间", id: "" });
}; };
const handleCheckedYearsChange = event => {
const handleCheckedAreasChange = (value) => { if (event.length && event[event.length-1] !== "") {
const checkedCount = value.length; checkedYearList.value = event.filter(item => item !== "");
checkAllAreas.value = checkedCount === surveyAreaList.value.length; } else {
isIndeterminateAreas.value = checkedCount > 0 && checkedCount < surveyAreaList.value.length; checkedYearList.value = [""];
}
currentPage.value = 1;
handleFetchSurveyList();
}; };
const totalDiscussNum = ref(0); const totalDiscussNum = ref(0);
...@@ -145,8 +137,8 @@ const handleFetchSurveyList = async () => { ...@@ -145,8 +137,8 @@ const handleFetchSurveyList = async () => {
currentPage: currentPage.value - 1, currentPage: currentPage.value - 1,
pageSize: pageSize.value, pageSize: pageSize.value,
sortCode: "301", sortCode: "301",
publishYear: checkAllYears.value ? "" : checkedSurveyYears.value.toString(), publishYear: checkedYearList.value.join(',') || null,
Area: checkAllAreas.value ? "" : checkedAreaList.value.toString(), Area: checkedAreaList.value.join(',') || null,
// keywords: searchText.value, // keywords: searchText.value,
sortField: "date", sortField: "date",
sortOrder: isSort.value ? "asc" : "desc" sortOrder: isSort.value ? "asc" : "desc"
...@@ -173,60 +165,11 @@ const handleSearch = () => { ...@@ -173,60 +165,11 @@ const handleSearch = () => {
handleFetchSurveyList(); handleFetchSurveyList();
}; };
watch( watch([isSort], () => {
[checkedSurveyYears, checkedAreaList, isSort],
() => {
if (isInitializing.value) return; if (isInitializing.value) return;
currentPage.value = 1; currentPage.value = 1;
handleFetchSurveyList(); handleFetchSurveyList();
}, });
{
deep: true
}
);
const handleGetSearchAllArea = async () => {
try {
const res = await getSearchAllArea({
sortCode: '301'
});
if(res.code === 200 && res.data) {
surveyAreaList.value = res.data.map(item => {
return {
name: item.AREANAME,
id: item.AREACODE
};
});
// 默认选中全部
checkAllAreas.value = true;
handleCheckAllAreasChange(true);
}
} catch (error) {
}
}
const handleGetSearchAllYear = async () => {
try {
const res = await getSearchAllYear({
sortCode: '301'
});
if(res.code === 200 && res.data) {
// 排序并格式化
const sortedYears = res.data.sort((a, b) => b - a);
surveyYearList.value = sortedYears.map(item => {
return {
name: item + '年',
id: item
};
});
// 默认选中全部
checkAllYears.value = true;
handleCheckAllYearsChange(true);
}
} catch (error) {
}
}
onMounted(async () => { onMounted(async () => {
await Promise.all([handleGetSearchAllArea(), handleGetSearchAllYear()]); await Promise.all([handleGetSearchAllArea(), handleGetSearchAllYear()]);
...@@ -309,59 +252,51 @@ onMounted(async () => { ...@@ -309,59 +252,51 @@ onMounted(async () => {
.left { .left {
width: 360px; width: 360px;
min-height: 560px; min-height: 300px;
height: fit-content; height: fit-content;
padding-bottom: 20px; padding-bottom: 20px;
border-radius: 10px; border-radius: 10px;
box-shadow: 0px 0px 15px 0px rgba(60, 87, 126, 0.2); box-shadow: 0px 0px 15px 0px rgba(60, 87, 126, 0.2);
background: #fff; background: #fff;
.left-box { .check-box {
margin-top: 17px; margin-top: 18px;
.check-head {
.left-header { position: relative;
display: flex; margin-bottom: 12px;
align-items: center; &::before {
content: "";
.icon { position: absolute;
top: 0px;
left: 0px;
width: 8px; width: 8px;
height: 16px; height: 100%;
background: var(--color-main-active); background: var(--color-primary-100);
border-radius: 0 2px 2px 0; border-radius: 0 2px 2px 0;
} }
.head-name {
.title { margin-left: 25px;
margin-left: 17px; color: var(--color-primary-100);
color: var(--color-main-active);
font-size: 16px; font-size: 16px;
font-weight: 700; line-height: 16px;
} font-family: Source Han Sans CN;
font-weight: bold;
} }
} }
.check-list {
.checkbox-group { padding: 0 10px 0 25px;
padding: 10px 0 0 25px; display: grid;
.filter-checkbox { grid-template-columns: repeat(2, 1fr);
width: 130px; grid-gap: 0 12px;
margin-bottom: 8px; .check-item {
width: 100%;
height: 32px; height: 32px;
:deep(.el-checkbox__label) { :deep(.el-checkbox__label) {
font-family: Source Han Sans CN;
font-size: 16px; font-size: 16px;
color: #5f656c; color: var(--text-primary-65-color);
} }
} }
.expand-btn {
color: var(--color-main-active);
font-size: 14px;
cursor: pointer;
display: flex;
align-items: center;
margin-top: 4px;
.el-icon {
margin-left: 4px;
}
} }
} }
} }
......
...@@ -33,54 +33,38 @@ ...@@ -33,54 +33,38 @@
<div class="wrapper-main"> <div class="wrapper-main">
<div class="left"> <div class="left">
<!-- 科技领域 --> <!-- 科技领域 -->
<div class="left-box"> <div class="check-box">
<div class="left-header"> <div class="check-head">
<div class="icon"></div> <div class="head-name">{{ "科技领域" }}</div>
<div class="title">{{ "科技领域" }}</div>
</div> </div>
<div class="left-main"> <el-checkbox-group class="check-list" v-model="checkedAreaList" @change="handleCheckedAreasChange">
<el-checkbox-group class="checkbox-group" v-model="checkedAreaList" @change="handleCheckedAreasChange"> <el-checkbox class="check-item" v-for="item in surveyAreaList" :key="item.id" :label="item.id">
<el-checkbox class="filter-checkbox" label="全部领域"> 全部领域 </el-checkbox> {{ item.name }}
<el-checkbox v-for="area in surveyAreaList" :key="area.id" :label="area.id" class="filter-checkbox">
{{ area.name }}
</el-checkbox> </el-checkbox>
</el-checkbox-group> </el-checkbox-group>
</div> </div>
</div>
<!-- 发布时间 --> <!-- 发布时间 -->
<div class="left-box"> <div class="check-box">
<div class="left-header"> <div class="check-head">
<div class="icon"></div> <div class="head-name">{{ "发布时间" }}</div>
<div class="title">{{ "发布时间" }}</div>
</div> </div>
<div class="left-main"> <div class="left-main">
<el-checkbox-group class="checkbox-group" v-model="checkedSurveyYears" @change="handleCheckedYearsChange"> <el-checkbox-group class="check-list" v-model="checkedYearList" @change="handleCheckedYearsChange">
<el-checkbox class="filter-checkbox" label="全部时间"> 全部时间 </el-checkbox> <el-checkbox class="check-item" v-for="item in surveyYearList" :key="item.id" :label="item.id">
<el-checkbox v-for="year in displayedYearList" :key="year.id" :label="year.id" class="filter-checkbox"> {{ item.name }}
{{ year.name }}
</el-checkbox> </el-checkbox>
<div v-if="surveyYearList.length > 6" class="expand-btn" @click="isYearExpanded = !isYearExpanded">
{{ isYearExpanded ? "收起" : "更早" }}
<el-icon>
<ArrowUp v-if="isYearExpanded" />
<ArrowDown v-else />
</el-icon>
</div>
</el-checkbox-group> </el-checkbox-group>
</div> </div>
</div> </div>
<!-- 受调查国家/地区 --> <!-- 受调查国家/地区 -->
<div class="left-box"> <div class="check-box">
<div class="left-header"> <div class="check-head">
<div class="icon"></div> <div class="head-name">{{ "受调查国家/地区" }}</div>
<div class="title">{{ "受调查国家/地区" }}</div>
</div> </div>
<div class="left-main"> <div class="left-main">
<el-checkbox-group class="checkbox-group" v-model="checkedCountryList" <el-checkbox-group class="check-list" v-model="checkedCountryList" @change="handleCheckedCountriesChange">
@change="handleCheckedCountriesChange"> <el-checkbox class="check-item" v-for="item in surveyCountryList" :key="item.id" :label="item.id">
<el-checkbox class="filter-checkbox" label="全部"> 全部 </el-checkbox> {{ item.name }}
<el-checkbox v-for="area in surveyCountryList" :key="area.id" :label="area.id" class="filter-checkbox">
{{ area.name }}
</el-checkbox> </el-checkbox>
</el-checkbox-group> </el-checkbox-group>
</div> </div>
...@@ -103,8 +87,8 @@ ...@@ -103,8 +87,8 @@
</template> </template>
<script setup> <script setup>
import { ref, onMounted, watch, computed } from "vue"; import { ref, onMounted, watch } from "vue";
import { Search, ArrowDown, ArrowUp } from "@element-plus/icons-vue"; import { Search } from "@element-plus/icons-vue";
import { getSearchAllArea, getSearchAllYear, getSurveyList, getSearchAllCountry } from "@/api/marketAccessRestrictions"; import { getSearchAllArea, getSearchAllYear, getSurveyList, getSearchAllCountry } from "@/api/marketAccessRestrictions";
import AnalysisBox from "@/components/base/boxBackground/analysisBox.vue" import AnalysisBox from "@/components/base/boxBackground/analysisBox.vue"
...@@ -131,61 +115,71 @@ const releaseTimeList = ref([ ...@@ -131,61 +115,71 @@ const releaseTimeList = ref([
// 科技领域过滤 // 科技领域过滤
const surveyAreaList = ref([]); const surveyAreaList = ref([]);
const checkedAreaList = ref(['全部领域']); const checkedAreaList = ref(['']);
const handleGetSearchAllArea = async () => {
const handleCheckedAreasChange = val => { try {
if (val.includes("全部领域") && val.length > 1) { const res = await getSearchAllArea({ sortCode: "337" });
if (val[val.length - 1] === "全部领域") { if (res.code === 200) {
checkedAreaList.value = ["全部领域"]; surveyAreaList.value = res.data.map(item => ({ name: item.AREANAME, id: item.AREACODE }));
} else {
checkedAreaList.value = val.filter(item => item !== "全部领域");
} }
} else if (val.length === 0) { } catch (error) {}
checkedAreaList.value = ["全部领域"]; surveyAreaList.value.unshift({ name: "全部领域", id: "" });
};
const handleCheckedAreasChange = event => {
if (event.length && event[event.length-1] !== "") {
checkedAreaList.value = event.filter(item => item !== "");
} else {
checkedAreaList.value = [""];
} }
currentPage.value = 1;
handleFetchSurveyList();
}; };
// 发布时间过滤 // 发布时间过滤
const surveyYearList = ref([]); const surveyYearList = ref([]);
const checkedSurveyYears = ref(['全部时间']); const checkedYearList = ref(['']);
const handleGetSearchAllYear = async () => {
const isYearExpanded = ref(false); try {
const res = await getSearchAllYear({ sortCode: "337" });
const displayedYearList = computed(() => { if (res.code === 200) {
if (isYearExpanded.value) return surveyYearList.value; let allYear = res.data.sort((a, b) => (b-a));
return surveyYearList.value.slice(0, 6); let beforeYear = allYear.slice(6).join(',');
}); surveyYearList.value = allYear.slice(0, 6).map(item => ({ name: item + "年", id: item }));
if (beforeYear) surveyYearList.value.push({ name: "更早", id: beforeYear });
const handleCheckedYearsChange = value => {
// const checkedCount = value.length;
// checkAllYears.value = checkedCount === surveyYearList.value.length;
// isIndeterminateYears.value = checkedCount > 0 && checkedCount < surveyYearList.value.length;
if (val.includes("全部时间") && val.length > 1) {
if (val[val.length - 1] === "全部时间") {
checkedSurveyYears.value = ["全部时间"];
} else {
checkedSurveyYears.value = val.filter(item => item !== "全部时间");
} }
} else if (val.length === 0) { } catch (error) {}
checkedSurveyYears.value = ["全部时间"]; surveyYearList.value.unshift({ name: "全部时间", id: "" });
};
const handleCheckedYearsChange = event => {
if (event.length && event[event.length-1] !== "") {
checkedYearList.value = event.filter(item => item !== "");
} else {
checkedYearList.value = [""];
} }
currentPage.value = 1;
handleFetchSurveyList();
}; };
// 受调查国家/地区过滤 // 受调查国家/地区过滤
const surveyCountryList = ref([]); const surveyCountryList = ref([]);
const checkedCountryList = ref(['全部']); const checkedCountryList = ref(['']);
const handleGetSearchAllCountry = async () => {
try {
const handleCheckedCountriesChange = val => { const res = await getSearchAllCountry();
if (val.includes("全部") && val.length > 1) { if (res.code === 200) {
if (val[val.length - 1] === "全部") { surveyCountryList.value = res.data.map(item => ({ name: item.COUNTRYNAME, id: item.COUNTRYID }));
checkedCountryList.value = ["全部"];
} else {
checkedCountryList.value = val.filter(item => item !== "全部");
} }
} else if (val.length === 0) { } catch (error) {}
checkedCountryList.value = ["全部"]; surveyCountryList.value.unshift({ name: "全部", id: "" });
};
const handleCheckedCountriesChange = event => {
if (event.length && event[event.length-1] !== "") {
checkedCountryList.value = event.filter(item => item !== "");
} else {
checkedCountryList.value = [""];
} }
currentPage.value = 1;
handleFetchSurveyList();
}; };
// 数据列表 // 数据列表
...@@ -203,9 +197,9 @@ const handleFetchSurveyList = async () => { ...@@ -203,9 +197,9 @@ const handleFetchSurveyList = async () => {
currentPage: currentPage.value - 1, currentPage: currentPage.value - 1,
pageSize: pageSize.value, pageSize: pageSize.value,
sortCode: "337", sortCode: "337",
publishYear: checkedSurveyYears.value[0] === '全部时间' ? null : checkedSurveyYears.value.toString(), publishYear: checkedYearList.value.join(',') || null,
Area: checkedAreaList.value[0] === '全部领域' ? null : checkedAreaList.value.toString(), Area: checkedAreaList.value.join(',') || null,
searchCountry: checkedCountryList.value[0] === '全部' ? null : checkedCountryList.value.toString(), searchCountry: checkedCountryList.value.join(',') || null,
caseStatus: filterStage.value ? filterStage.value : null, caseStatus: filterStage.value ? filterStage.value : null,
keywords: searchText.value ? searchText.value : null, keywords: searchText.value ? searchText.value : null,
sortField: "date", sortField: "date",
...@@ -234,52 +228,11 @@ const handleSearch = () => { ...@@ -234,52 +228,11 @@ const handleSearch = () => {
}; };
// 监听过滤条件 // 监听过滤条件
watch( watch([isSort, filterStage, filterParty, filterReason], () => {
[checkedSurveyYears, checkedAreaList, checkedCountryList, isSort, filterStage, filterParty, filterReason],
() => {
if (isInitializing.value) return; if (isInitializing.value) return;
currentPage.value = 1; currentPage.value = 1;
handleFetchSurveyList(); handleFetchSurveyList();
} });
);
const handleGetSearchAllArea = async () => {
try {
const res = await getSearchAllArea({ sortCode: "337" });
if (res.code === 200 && res.data) {
surveyAreaList.value = res.data.map(item => ({
name: item.AREANAME,
id: item.AREACODE
}));
handleCheckAllAreasChange(true);
}
} catch (error) { }
};
const handleGetSearchAllYear = async () => {
try {
const res = await getSearchAllYear({ sortCode: "337" });
if (res.code === 200 && res.data) {
const sortedYears = res.data.sort((a, b) => b - a);
surveyYearList.value = sortedYears.map(item => ({
name: item + "年",
id: item
}));
}
} catch (error) { }
};
const handleGetSearchAllCountry = async () => {
try {
const res = await getSearchAllCountry();
if (res.code === 200 && res.data) {
surveyCountryList.value = res.data.map(item => ({
name: item.COUNTRYNAME,
id: item.COUNTRYID
}));
}
} catch (error) { }
};
onMounted(async () => { onMounted(async () => {
await Promise.all([handleGetSearchAllArea(), handleGetSearchAllYear(), handleGetSearchAllCountry()]); await Promise.all([handleGetSearchAllArea(), handleGetSearchAllYear(), handleGetSearchAllCountry()]);
...@@ -360,58 +313,50 @@ onMounted(async () => { ...@@ -360,58 +313,50 @@ onMounted(async () => {
.left { .left {
width: 360px; width: 360px;
min-height: 560px; min-height: 300px;
height: fit-content; height: fit-content;
padding-bottom: 20px; padding-bottom: 20px;
border-radius: 10px; border-radius: 10px;
box-shadow: 0px 0px 15px 0px rgba(60, 87, 126, 0.2); box-shadow: 0px 0px 15px 0px rgba(60, 87, 126, 0.2);
background: #fff; background: #fff;
.left-box { .check-box {
margin-top: 17px; margin-top: 18px;
.check-head {
.left-header { position: relative;
display: flex; margin-bottom: 12px;
align-items: center; &::before {
content: "";
.icon { position: absolute;
top: 0px;
left: 0px;
width: 8px; width: 8px;
height: 16px; height: 100%;
background: var(--color-main-active); background: var(--color-primary-100);
border-radius: 0 2px 2px 0; border-radius: 0 2px 2px 0;
} }
.head-name {
.title { margin-left: 25px;
margin-left: 17px; color: var(--color-primary-100);
color: var(--color-main-active);
font-size: 16px; font-size: 16px;
font-weight: 700; line-height: 16px;
} font-family: Source Han Sans CN;
font-weight: bold;
} }
} }
.check-list {
.checkbox-group { padding: 0 10px 0 25px;
padding: 10px 0 0 25px; display: grid;
.filter-checkbox { grid-template-columns: repeat(2, 1fr);
width: 130px; grid-gap: 0 12px;
margin-bottom: 8px; .check-item {
width: 100%;
height: 32px; height: 32px;
:deep(.el-checkbox__label) { :deep(.el-checkbox__label) {
font-family: Source Han Sans CN;
font-size: 16px; font-size: 16px;
color: #5f656c; color: var(--text-primary-65-color);
}
} }
.expand-btn {
color: var(--color-main-active);
font-size: 14px;
cursor: pointer;
display: flex;
align-items: center;
margin-top: 4px;
.el-icon {
margin-left: 4px;
} }
} }
} }
......
...@@ -100,7 +100,12 @@ ...@@ -100,7 +100,12 @@
<script setup> <script setup>
import { ref, onMounted } from "vue"; import { ref, onMounted } from "vue";
import { useRoute } from "vue-router"; import { useRoute } from "vue-router";
import { getSearchBlurb, getSearchContext, getSearchConclusion } from "@/api/marketAccessRestrictions"; import {
getSearchBlurb,
getSearchContext,
getSearchConclusion,
getRelatedEvents,
} from "@/api/marketAccessRestrictions";
import RelatedEvent from "@/views/marketAccessRestrictions/com/RelatedEvent.vue"; import RelatedEvent from "@/views/marketAccessRestrictions/com/RelatedEvent.vue";
import SurveyConclusion from "@/views/marketAccessRestrictions/com/SurveyConclusion.vue"; import SurveyConclusion from "@/views/marketAccessRestrictions/com/SurveyConclusion.vue";
...@@ -181,26 +186,21 @@ const handleGetSearchConclusion = async () => { ...@@ -181,26 +186,21 @@ const handleGetSearchConclusion = async () => {
}; };
// 相关行政举措 // 相关行政举措
const eventList = ref([ const eventList = ref([])
{ const handleGetRelatedEvents = async () => {
name: "某些特定外国制造的半导体器件及其下游产品和组件;委员会最终裁定未违反第337条的通知;调查终止", try {
text: "特此通知,2025 年 2 月 18 日,根据 1930 年《关税法》第 337 条(经修订)已代表爱尔兰 Longitude Licensing Ltd.和爱尔", const res = await getRelatedEvents({
time: "2025年4月15日" searchId: route.query.searchId
}, });
{ if(res.code === 200) eventList.value = res.data || [];
name: "某些特定外国制造的半导体器件及其下游产品和组件;委员会最终裁定未违反第337条的通知;调查终止", } catch (error) {
text: "特此通知,2025 年 2 月 18 日,根据 1930 年《关税法》第 337 条(经修订)已代表爱尔兰 Longitude Licensing Ltd.和爱尔", console.error("获取相关行政举措失败", error);
time: "2025年4月15日" }
}, };
{
name: "某些特定外国制造的半导体器件及其下游产品和组件;委员会最终裁定未违反第337条的通知;调查终止",
text: "特此通知,2025 年 2 月 18 日,根据 1930 年《关税法》第 337 条(经修订)已代表爱尔兰 Longitude Licensing Ltd.和爱尔",
time: "2025年4月15日"
},
])
onMounted(() => { onMounted(() => {
handleGetSearchBlurb(); handleGetSearchBlurb();
handleGetRelatedEvents();
handleGetSearchContext(); handleGetSearchContext();
handleGetSearchConclusion(); handleGetSearchConclusion();
}); });
......
<template> <template>
<div class="wrapper"> <div class="wrapper">
<div class="left"> <div class="left">
<div class="box1" v-loading="leftLoading"> <AnalysisBox title="基本信息" :showAllBtn="false" height="auto">
<div class="box-header">
<div class="header-left"></div>
<div class="title">基本信息</div>
<div class="header-right">
<div class="icon">
<img src="@/assets/icons/box-header-icon3.png" alt="" />
</div>
</div>
</div>
<div class="box1-main"> <div class="box1-main">
<div class="box1-item"> <div class="box1-item">
<div class="box1-item-left">{{ "启动时间:" }}</div> <div class="box1-item-left">{{ "启动时间:" }}</div>
...@@ -34,14 +25,8 @@ ...@@ -34,14 +25,8 @@
<div class="box1-item"> <div class="box1-item">
<div class="box1-item-left">{{ "调查领域:" }}</div> <div class="box1-item-left">{{ "调查领域:" }}</div>
<div class="box1-item-right2"> <div class="box1-item-right2">
<div <AreaTag v-for="(item, num) in surveyAreaList" :key="num" :tagName="item.name"></AreaTag>
class="tag" <div v-if="!surveyAreaList?.length">-</div>
:class="{ tag1: tag.type === 1, tag2: tag.type === 2 }"
v-for="(tag, index) in surveyAreaList"
:key="index"
>
{{ tag.name }}
</div>
</div> </div>
</div> </div>
<div class="box1-item"> <div class="box1-item">
...@@ -68,50 +53,22 @@ ...@@ -68,50 +53,22 @@
</div> </div>
</div> </div>
</div> </div>
</div> </AnalysisBox>
<div class="box2" v-loading="leftLoading"> <SurveyAffiche title="调查公告" :listData="box2Data"></SurveyAffiche>
<div class="box-header">
<div class="header-left"></div>
<div class="title">调查公告</div>
<div class="header-right">
<div class="icon">
<img src="@/assets/icons/box-header-icon3.png" alt="" />
</div>
</div>
</div>
<div class="box2-main">
<div class="box2-item" v-for="(item, index) in box2Data" :key="index">
<div class="box2-item-left">
<img src="./assets/images/box2-icon.png" alt="" />
</div>
<div class="box2-item-right">
<div class="time">{{ item.time }}</div>
<div class="content">{{ item.content }}</div>
</div>
</div>
</div>
</div>
</div> </div>
<div class="right"> <div class="right">
<div class="box3" v-loading="box3Loading"> <AnalysisBox :showAllBtn="false" height="auto">
<div class="box-header"> <template #custom-title>
<div class="btn-box"> <div class="btn-box">
<div <div class="btn"
class="btn"
:class="{ btnActive: box3BtnActive === item }" :class="{ btnActive: box3BtnActive === item }"
v-for="(item, index) in box3BtnList" v-for="(item, index) in box3BtnList" :key="index"
:key="index"
@click="handleClickBox3Btn(item)" @click="handleClickBox3Btn(item)"
> >
{{ item }} {{ item }}
</div> </div>
</div> </div>
<div class="header-right"> </template>
<div class="icon">
<img src="@/assets/icons/box-header-icon3.png" alt="" />
</div>
</div>
</div>
<div class="box3-main"> <div class="box3-main">
<div class="box3-main1" v-if="box3BtnActive === '事件脉络'"> <div class="box3-main1" v-if="box3BtnActive === '事件脉络'">
<div class="box3-main1-item" v-for="(item, index) in box3Data1" :key="index"> <div class="box3-main1-item" v-for="(item, index) in box3Data1" :key="index">
...@@ -123,10 +80,10 @@ ...@@ -123,10 +80,10 @@
</div> </div>
<div class="right"> <div class="right">
<div class="header"> <div class="header">
<div class="time">{{ item.time }}</div> <div class="time">{{ item.CONTTIME }}</div>
<div class="title">{{ item.title }}</div> <div class="title">{{ item.CONTNODE }}</div>
</div> </div>
<div class="content">{{ item.content }}</div> <div class="content">{{ item.CONTDESC }}</div>
</div> </div>
</div> </div>
</div> </div>
...@@ -151,60 +108,27 @@ ...@@ -151,60 +108,27 @@
</div> </div>
</div> </div>
</div> </div>
</div> </AnalysisBox>
<div class="box4" v-loading="box4Loading"> <RelatedEvent title="相关事件" :listData="eventList"></RelatedEvent>
<div class="box-header">
<div class="header-left"></div>
<div class="title">相关事件</div>
<div class="header-right">
<div class="icon">
<img src="@/assets/icons/box-header-icon3.png" alt="" />
</div>
</div>
</div>
<div class="box4-main">
<div class="box4-main-item" v-for="(item, index) in box4Data" :key="index">
<div class="item-left">
<div class="item-left-tag" :class="{
tag1: item.tag.type == '新闻',
tag2: item.tag.type == '行政令',
tag3: item.tag.type == '法案',
}">
{{ item.tag.name }}
</div>
</div>
<div class="item-right">
<div class="item-right-header">
<div class="item-right-title">{{ item.title }}</div>
<div class="item-right-time">
{{ item.time }}
</div>
</div>
<div class="item-right-content">{{ item.content }}</div>
</div>
</div>
</div>
</div>
</div> </div>
</div> </div>
</template> </template>
<script setup> <script setup>
import { ref, onMounted } from "vue"; import { ref, onMounted } from "vue";
import { useRoute } from "vue-router"; import { useRoute } from "vue-router";
import { getSearchBlurb, getRelatedEvents, getSearchContext, getSearchMeasures } from "@/api/marketAccessRestrictions"; import {
getSearchBlurb,
getRelatedEvents,
getSearchContext,
getSearchMeasures,
} from "@/api/marketAccessRestrictions";
import RelatedEvent from "@/views/marketAccessRestrictions/com/RelatedEvent.vue";
import SurveyAffiche from "@/views/marketAccessRestrictions/com/SurveyAffiche.vue";
const route = useRoute(); const route = useRoute();
const leftLoading = ref(false);
const box3Loading = ref(false);
const box4Loading = ref(false);
const baseInfo = ref({}); const baseInfo = ref({});
const surveyAreaList = ref([]); const surveyAreaList = ref([]);
const box2Data = ref([]);
const box3Data1 = ref([]);
const box3Data2 = ref([]);
const box4Data = ref([]);
const box3BtnList = ref(["事件脉络", "报复性措施"]); const box3BtnList = ref(["事件脉络", "报复性措施"]);
const box3BtnActive = ref("事件脉络"); const box3BtnActive = ref("事件脉络");
...@@ -213,8 +137,8 @@ const handleClickBox3Btn = btn => { ...@@ -213,8 +137,8 @@ const handleClickBox3Btn = btn => {
box3BtnActive.value = btn; box3BtnActive.value = btn;
}; };
const box2Data = ref([]);
const handleGetSearchBlurb = async () => { const handleGetSearchBlurb = async () => {
leftLoading.value = true;
try { try {
const res = await getSearchBlurb({ const res = await getSearchBlurb({
searchId: route.query.searchId, searchId: route.query.searchId,
...@@ -234,89 +158,43 @@ const handleGetSearchBlurb = async () => { ...@@ -234,89 +158,43 @@ const handleGetSearchBlurb = async () => {
// 调查公告 // 调查公告
if (data.progress) { if (data.progress) {
box2Data.value = data.progress.map(p => ({ box2Data.value = data.progress.map(p => ({ time: p.PROGRESSDATE, content: p.PROGRESSSTAGE }));
time: p.PROGRESSDATE,
content: p.PROGRESSSTAGE
}));
// 事件脉络
box3Data1.value = data.progress.map(p => ({
time: p.PROGRESSDATE,
title: p.PROGRESSSTAGE,
content: ""
}));
}
// 报复性措施
if (data.SORTMEASURE) {
box3Data2.value = [
{
title: "报复性措施",
data: [{ content: data.SORTMEASURE }]
}
];
} }
} }
} catch (error) { } catch (error) {
console.error("获取调查详情失败", error); console.error("获取调查详情失败", error);
} finally {
leftLoading.value = false;
} }
}; };
// 相关事件
const eventList = ref([]);
const handleGetRelatedEvents = async () => { const handleGetRelatedEvents = async () => {
box4Loading.value = true;
try { try {
const res = await getRelatedEvents({ const res = await getRelatedEvents({
searchId: route.query.searchId searchId: route.query.searchId
}); });
if(res.code === 200 && res.data) { if(res.code === 200) eventList.value = res.data || [];
box4Data.value = res.data.map(item => ({
title: item.NAME,
content: item.SUMMARY,
time: item.DATE,
tag: {
type: item.TYPE,
name: item.TYPE
}
}));
}
} catch (error) { } catch (error) {
console.error("获取相关事件失败", error); console.error("获取相关事件失败", error);
} finally {
box4Loading.value = false;
} }
}; };
// 事件脉络
const box3Data1 = ref([]);
const handleGetSearchContext = async () => { const handleGetSearchContext = async () => {
box3Loading.value = true;
try { try {
const res = await getSearchContext({ const res = await getSearchContext({ searchId: route.query.searchId });
searchId: route.query.searchId console.log('事件脉络', res.data)
}); if(res.code === 200) box3Data1.value = res.data;
if(res.code === 200 && res.data) {
console.log(res.data)
box3Data1.value = res.data.map(item => ({
time: item.CONTTIME,
title: item.CONTNODE,
content: item.CONTDESC
}));
}
} catch (error) { } catch (error) {
console.error("获取事件脉络失败", error); console.error("获取事件脉络失败", error);
} finally {
box3Loading.value = false;
} }
} }
// 报复性措施
const box3Data2 = ref([]);
const handleGetSearchMeasures = async () => { const handleGetSearchMeasures = async () => {
// box3Loading is shared with Context for now if they are called together
// or we can just set it true here as well
box3Loading.value = true;
try { try {
const res = await getSearchMeasures({ const res = await getSearchMeasures({ searchId: route.query.searchId });
searchId: route.query.searchId
});
if(res.code === 200 && res.data) { if(res.code === 200 && res.data) {
box3Data2.value = res.data.map(item => ({ box3Data2.value = res.data.map(item => ({
title: item.TITLE, title: item.TITLE,
...@@ -325,8 +203,6 @@ const handleGetSearchMeasures = async () => { ...@@ -325,8 +203,6 @@ const handleGetSearchMeasures = async () => {
} }
} catch (error) { } catch (error) {
console.error("获取报复性措施失败", error); console.error("获取报复性措施失败", error);
} finally {
box3Loading.value = false;
} }
}; };
onMounted(() => { onMounted(() => {
...@@ -342,88 +218,24 @@ onMounted(() => { ...@@ -342,88 +218,24 @@ onMounted(() => {
width: 1600px; width: 1600px;
margin: 20px auto; margin: 20px auto;
display: flex; display: flex;
.box-header { .left {
height: 56px; width: 520px;
display: flex;
position: relative;
.header-left {
margin-top: 20px;
width: 8px;
height: 16px;
border-radius: 0 4px 4px 0;
background: var(--color-main-active);
}
.title {
margin-left: 14px;
margin-top: 16px;
height: 24px;
line-height: 24px;
color: var(--color-main-active);
font-family: Microsoft YaHei;
font-size: 18px;
font-weight: 700;
}
.btn-box {
position: absolute;
top: 17px;
left: 36px;
display: flex; display: flex;
gap: 20px; flex-direction: column;
height: 26px; gap: 16px;
.btn {
height: 26px;
padding: 0 8px;
box-sizing: border-box;
border: 1px solid rgba(230, 231, 232, 1);
border-radius: 4px;
background: rgba(255, 255, 255, 1);
color: rgba(59, 65, 75, 1);
font-family: Microsoft YaHei;
font-style: Regular;
font-size: 18px;
font-weight: 400;
line-height: 24px;
letter-spacing: 0px;
text-align: left;
cursor: pointer;
}
.btnActive {
color: var(--color-main-active);
border: 1px solid var(--color-main-active);
font-weight: bold;
background: rgba(231, 243, 255, 1);
}
} }
.header-right { .right {
position: absolute; width: 20px;
top: 14px; flex: auto;
right: 12px;
display: flex; display: flex;
justify-content: flex-end; flex-direction: column;
gap: 4px; gap: 16px;
.icon { margin-left: 16px;
width: 28px;
height: 28px;
img {
width: 100%;
height: 100%;
}
}
}
} }
.left { }
width: 520px;
margin-bottom: 20px; .box1-main {
.box1 { padding: 0 22px;
margin-top: 16px;
width: 520px;
height: 561px;
border-radius: 10px;
box-shadow: 0px 0px 15px 0px rgba(60, 87, 126, 0.2);
background: rgba(255, 255, 255, 1);
.box1-main {
margin-top: 6px;
margin-left: 22px;
.box1-item { .box1-item {
display: flex; display: flex;
margin-bottom: 16px; margin-bottom: 16px;
...@@ -470,33 +282,9 @@ onMounted(() => { ...@@ -470,33 +282,9 @@ onMounted(() => {
} }
} }
.box1-item-right2 { .box1-item-right2 {
margin-top: 2px;
height: 24px;
display: flex; display: flex;
flex-wrap: wrap;
gap: 8px; gap: 8px;
.tag {
height: 24px;
padding: 0 8px;
box-sizing: border-box;
border-radius: 4px;
text-align: center;
line-height: 24px;
}
.tag1 {
color: rgba(19, 168, 168, 1);
border: 1px solid rgba(135, 232, 222, 1);
background: rgba(230, 255, 251, 1);
}
.tag2 {
color: rgba(22, 119, 255, 1);
border: 1px solid rgba(145, 202, 255, 1);
background: rgba(230, 244, 255, 1);
}
.tag3 {
color: rgba(114, 46, 209, 1);
border: 1px solid rgba(211, 173, 247, 1);
background: rgba(249, 240, 255, 1);
}
} }
.box1-item-right3 { .box1-item-right3 {
width: 346px; width: 346px;
...@@ -512,86 +300,44 @@ onMounted(() => { ...@@ -512,86 +300,44 @@ onMounted(() => {
width: 346px; width: 346px;
} }
} }
} }
}
.box2 { .btn-box {
width: 520px;
height: 815px;
margin-top: 16px;
border-radius: 10px;
box-shadow: 0px 0px 15px 0px rgba(60, 87, 126, 0.2);
background: rgba(255, 255, 255, 1);
.box2-main {
height: 749px;
border-top: 1px solid rgba(234, 236, 238, 1);
.box2-item {
width: 483px;
// height: 108px;
margin: 0 auto;
display: flex; display: flex;
gap: 16px; align-items: center;
padding: 12px 8px 8px 8px;
border-bottom: 1px solid rgba(234, 236, 238, 1);
.box2-item-left {
margin-top: 4px;
width: 15px;
height: 15px;
img {
width: 100%;
height: 100%; height: 100%;
} gap: 20px;
} .btn {
.box2-item-right { height: 26px;
.time { padding: 0 8px;
height: 24px; box-sizing: border-box;
border: 1px solid rgba(230, 231, 232, 1);
border-radius: 4px;
background: rgba(255, 255, 255, 1);
color: rgba(59, 65, 75, 1); color: rgba(59, 65, 75, 1);
font-family: Microsoft YaHei; font-family: Microsoft YaHei;
font-style: Bold;
font-size: 16px;
font-weight: 700;
line-height: 24px;
letter-spacing: 1px;
text-align: left;
}
.content {
width: 435px;
// height: 60px;
margin-top: 4px;
color: rgba(95, 101, 108, 1);
font-family: Microsoft YaHei;
font-style: Regular; font-style: Regular;
font-size: 16px; font-size: 18px;
font-weight: 400; font-weight: 400;
line-height: 30px; line-height: 24px;
letter-spacing: 0px; letter-spacing: 0px;
text-align: justify; text-align: left;
} cursor: pointer;
}
}
}
} }
.btnActive {
color: var(--color-main-active);
border: 1px solid var(--color-main-active);
font-weight: bold;
background: rgba(231, 243, 255, 1);
} }
.right { }
width: 1064px; .box3-main {
margin-left: 16px;
.box3 {
margin-top: 16px;
width: 1064px;
// height: 410px;
border-radius: 10px;
box-shadow: 0px 0px 15px 0px rgba(60, 87, 126, 0.2);
background: rgba(255, 255, 255, 1);
.box3-main {
margin-top: 8px;
margin: 10px 0;
border-top: 1px solid rgba(234, 236, 238, 1); border-top: 1px solid rgba(234, 236, 238, 1);
padding: 15px 20px; padding: 15px 20px;
.box3-main1 { .box3-main1 {
.box3-main1-item { .box3-main1-item {
// height: 140px;
margin-bottom: 20px; margin-bottom: 20px;
display: flex; display: flex;
.left { .left {
width: 10px; width: 10px;
.point { .point {
...@@ -646,7 +392,7 @@ onMounted(() => { ...@@ -646,7 +392,7 @@ onMounted(() => {
} }
.box3-main2 { .box3-main2 {
.box3-main2-item { .box3-main2-item {
margin-top: 16px; margin-bottom: 16px;
.box3-main2-item-header { .box3-main2-item-header {
width: 1020px; width: 1020px;
height: 48px; height: 48px;
...@@ -712,107 +458,6 @@ onMounted(() => { ...@@ -712,107 +458,6 @@ onMounted(() => {
} }
} }
} }
}
}
.box4 {
margin-top: 16px;
margin-bottom: 35px;
width: 1064px;
// height: 714px;
border-radius: 10px;
box-shadow: 0px 0px 15px 0px rgba(60, 87, 126, 0.2);
background: rgba(255, 255, 255, 1);
padding-bottom: 18px;
.box4-main {
width: 1014px;
margin: 10px auto;
.box4-main-item {
width: 1014px;
padding: 11px 0;
display: flex;
border-bottom: 1px solid rgba(234, 236, 238, 1);
.item-left {
width: 90px;
display: flex;
.item-left-tag {
width: 80px;
height: 28px;
padding: 0px 8px;
border-radius: 20px;
font-family: Microsoft YaHei;
font-size: 16px;
font-weight: 400;
line-height: 24px;
letter-spacing: 0px;
text-align: center;
padding: 0 8px;
}
.tag1 {
color: rgba(19, 168, 168, 1);
border: 1px solid rgba(135, 232, 222, 1);
background: rgba(230, 255, 251, 1);
}
.tag2 {
color: rgba(22, 119, 255, 1);
border: 1px solid rgba(145, 202, 255, 1);
background: rgba(230, 244, 255, 1);
}
.tag3 {
color: rgba(114, 46, 209, 1);
border: 1px solid rgba(211, 173, 247, 1);
background: rgba(249, 240, 255, 1);
}
}
.item-right {
width: 924px;
.item-right-header {
width: 924px;
display: flex;
justify-content: space-between;
.item-right-title {
width: 800px;
height: 24px;
color: rgba(59, 65, 75, 1);
font-family: Microsoft YaHei;
font-size: 16px;
font-weight: 700;
line-height: 24px;
letter-spacing: 0px;
text-align: left;
}
.item-right-time {
width: 124px;
height: 24px;
color: rgba(95, 101, 108, 1);
font-family: Microsoft YaHei;
font-size: 16px;
font-weight: 400;
line-height: 24px;
letter-spacing: 0px;
text-align: left;
}
}
.item-right-content {
margin-top: 4px;
width: 928px;
height: 30px;
color: rgba(95, 101, 108, 1);
font-family: Microsoft YaHei;
font-size: 16px;
font-weight: 400;
line-height: 30px;
letter-spacing: 0px;
text-align: justify;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
}
}
}
}
}
} }
:deep(.el-timeline-item) { :deep(.el-timeline-item) {
......
...@@ -30,37 +30,13 @@ ...@@ -30,37 +30,13 @@
<div class="box1-item"> <div class="box1-item">
<div class="box1-item-left">{{ "调查领域:" }}</div> <div class="box1-item-left">{{ "调查领域:" }}</div>
<div class="box1-item-right1"> <div class="box1-item-right1">
<div class="tag" v-for="(item, index) in baseInfo.areaData" :key="index">{{ item }}</div> <AreaTag v-for="(item, num) in baseInfo.areaData" :key="num" :tagName="item"></AreaTag>
<div v-if="!baseInfo.areaData || !baseInfo.areaData.length">-</div> <div v-if="!baseInfo.areaData?.length">-</div>
</div>
</div>
<div class="box1-item">
<div class="box1-item-left">{{ "案件进展:" }}</div>
<div class="box1-item-right2">
<div class="box1-item-right2-item" v-for="(item, index) in processList" :key="index">
<div class="icon">
<img src="./assets/images/icon1.png" alt="" />
</div>
<div class="time">{{ item.time }}</div>
<div class="title">{{ item.title }}</div>
</div>
</div>
</div>
</div>
</AnalysisBox>
<AnalysisBox title="调查公告" :showAllBtn="false" height="auto">
<div class="box4-main">
<div v-for="(item, index) in afficheList" :key="index" class="box4-item">
<div class="item-icon">
<img src="@/views/marketAccessRestrictions/singleCaseLayout/assets/images/icon_affiche.png" alt="">
</div>
<div class="item-right">
<div class="item-time">{{ item.time }}</div>
<div class="item-text">{{ item.text }}</div>
</div> </div>
</div> </div>
</div> </div>
</AnalysisBox> </AnalysisBox>
<SurveyAffiche title="调查公告" :listData="processList"></SurveyAffiche>
</div> </div>
<div class="right"> <div class="right">
<AnalysisBox title="原告信息" :showAllBtn="false" height="auto"> <AnalysisBox title="原告信息" :showAllBtn="false" height="auto">
...@@ -99,19 +75,20 @@ ...@@ -99,19 +75,20 @@
<script setup> <script setup>
import { ref, onMounted } from "vue"; import { ref, onMounted } from "vue";
import { useRoute } from "vue-router"; import { useRoute } from "vue-router";
import { getSearchBlurb } from "@/api/marketAccessRestrictions"; import { getSearchBlurb , getRelatedEvents} from "@/api/marketAccessRestrictions";
import AiTips from "@/views/marketAccessRestrictions/com/AiTips.vue"; import AiTips from "@/views/marketAccessRestrictions/com/AiTips.vue";
import RelatedEvent from "@/views/marketAccessRestrictions/com/RelatedEvent.vue"; import RelatedEvent from "@/views/marketAccessRestrictions/com/RelatedEvent.vue";
import SurveyAffiche from "@/views/marketAccessRestrictions/com/SurveyAffiche.vue";
const tips = `Pantech是韩国的一家通信设备公司,曾经是手机制造商,但现在可能已转型为专利持有实体。这类公司常被称为"非执业实体"(NPE)或"专利断言实体"(PAE),通过专利授权和诉讼获取收益。这些企业曾经是行业龙头,但因科技和市场形态巨变,加上自身改革步伐缓慢,经营状况每况愈下。卖掉实体业务部门后,留下来的是高达几万件的专利。` const tips = `Pantech是韩国的一家通信设备公司,曾经是手机制造商,但现在可能已转型为专利持有实体。这类公司常被称为"非执业实体"(NPE)或"专利断言实体"(PAE),通过专利授权和诉讼获取收益。这些企业曾经是行业龙头,但因科技和市场形态巨变,加上自身改革步伐缓慢,经营状况每况愈下。卖掉实体业务部门后,留下来的是高达几万件的专利。`
const route = useRoute(); const route = useRoute();
const loading = ref(false); const loading = ref(false);
const baseInfo = ref({}); const baseInfo = ref({});
const processList = ref([]);
const caseList = ref([]); const caseList = ref([]);
// 调查概况 // 调查概况
const processList = ref([]);
const handleGetSearchBlurb = async () => { const handleGetSearchBlurb = async () => {
loading.value = true; loading.value = true;
try { try {
...@@ -126,10 +103,7 @@ const handleGetSearchBlurb = async () => { ...@@ -126,10 +103,7 @@ const handleGetSearchBlurb = async () => {
// 案件进展 // 案件进展
if (data.progress) { if (data.progress) {
processList.value = data.progress.map(p => ({ processList.value = data.progress.map(p => ({ time: p.PROGRESSDATE, content: p.PROGRESSSTAGE }));
time: p.PROGRESSDATE,
title: p.PROGRESSSTAGE
}));
} }
// 被告信息分组 // 被告信息分组
...@@ -157,51 +131,22 @@ const handleGetSearchBlurb = async () => { ...@@ -157,51 +131,22 @@ const handleGetSearchBlurb = async () => {
loading.value = false; loading.value = false;
}; };
// 调查公告
const afficheList = ref([
{
time: "2025-03-30",
text: "美国ITC正式对外国制造的半导体器件及其下游产品和组件启动337调查"
},
{
time: "2025-03-30",
text: "美国ITC正式对外国制造的半导体器件及其下游产品和组件启动337调查"
},
{
time: "2025-03-30",
text: "美国ITC正式对外国制造的半导体器件及其下游产品和组件启动337调查"
},
{
time: "2025-03-30",
text: "美国ITC正式对外国制造的半导体器件及其下游产品和组件启动337调查"
},
{
time: "2025-03-30",
text: "美国ITC正式对外国制造的半导体器件及其下游产品和组件启动337调查"
},
]);
// 相关事件 // 相关事件
const eventList = ref([ const eventList = ref([])
{ const handleGetRelatedEvents = async () => {
name: "某些特定外国制造的半导体器件及其下游产品和组件;委员会最终裁定未违反第337条的通知;调查终止", try {
text: "特此通知,2025 年 2 月 18 日,根据 1930 年《关税法》第 337 条(经修订)已代表爱尔兰 Longitude Licensing Ltd.和爱尔", const res = await getRelatedEvents({
time: "2025年4月15日" searchId: route.query.searchId
}, });
{ if(res.code === 200) eventList.value = res.data || [];
name: "某些特定外国制造的半导体器件及其下游产品和组件;委员会最终裁定未违反第337条的通知;调查终止", } catch (error) {
text: "特此通知,2025 年 2 月 18 日,根据 1930 年《关税法》第 337 条(经修订)已代表爱尔兰 Longitude Licensing Ltd.和爱尔", console.error("获取相关事件失败", error);
time: "2025年4月15日" }
}, };
{
name: "某些特定外国制造的半导体器件及其下游产品和组件;委员会最终裁定未违反第337条的通知;调查终止",
text: "特此通知,2025 年 2 月 18 日,根据 1930 年《关税法》第 337 条(经修订)已代表爱尔兰 Longitude Licensing Ltd.和爱尔",
time: "2025年4月15日"
},
])
onMounted(() => { onMounted(() => {
handleGetSearchBlurb(); handleGetSearchBlurb();
handleGetRelatedEvents()
}); });
</script> </script>
...@@ -346,59 +291,6 @@ onMounted(() => { ...@@ -346,59 +291,6 @@ onMounted(() => {
display: flex; display: flex;
flex-wrap: wrap; flex-wrap: wrap;
gap: 8px; gap: 8px;
.tag {
margin-top: 3px;
margin-bottom: 3px;
height: 24px;
box-sizing: border-box;
border: 1px solid rgba(135, 232, 222, 1);
border-radius: 4px;
background: rgba(230, 255, 251, 1);
line-height: 24px;
text-align: center;
padding: 0 8px;
color: rgba(19, 168, 168, 1);
font-family: Microsoft YaHei;
font-size: 14px;
font-weight: 400;
}
}
.box1-item-right2 {
.box1-item-right2-item {
width: 332px;
height: 36px;
display: flex;
.icon {
width: 10px;
height: 10px;
margin-left: 17px;
margin-top: 10px;
img {
width: 100%;
height: 100%;
}
}
.time {
height: 24px;
margin-left: 16px;
margin-top: 6px;
color: var(--color-main-active);
font-family: Microsoft YaHei;
font-size: 16px;
font-weight: 700;
line-height: 24px;
}
.title {
height: 24px;
margin-left: 16px;
margin-top: 6px;
color: var(--color-main-active);
font-family: Microsoft YaHei;
font-size: 16px;
font-weight: 400;
line-height: 24px;
}
}
} }
} }
} }
...@@ -513,41 +405,4 @@ onMounted(() => { ...@@ -513,41 +405,4 @@ onMounted(() => {
} }
} }
} }
.box4-main {
padding: 0 16px 16px;
.box4-item {
border-top: 1px solid var(--bg-black-5);
padding: 6px;
display: flex;
.item-icon {
width: 15px;
height: 15px;
font-size: 0px;
margin-right: 16px;
margin-top: 7px;
img {
width: 100%;
height: 100%;
}
}
.item-right {
width: 20px;
flex: auto;
font-family: Source Han Sans CN;
font-size: 16px;
line-height: 30px;
.item-time {
font-weight: bold;
color: var(--text-primary-80-color);
}
.item-text {
color: var(--text-primary-65-color);
}
}
}
.box4-item:last-child {
border-bottom: 1px solid var(--bg-black-5);
}
}
</style> </style>
...@@ -23,8 +23,8 @@ ...@@ -23,8 +23,8 @@
</div> </div>
</div> --> </div> -->
<NewsList :newsList="leftList" @more-click="handleToMoreNews" img="newsImage" title="newsTitle" <NewsList :newsList="leftList" @more-click="handleToMoreNews" img="newsImage" title="newsTitle"
content="newsContent" from="from" /> content="newsContent" from="from" @item-click="item => gotoNewsDetail(item.newsId)" />
<MessageBubble :messageList="rightList" @more-click="handleToSocialDetail" source="orgName" content="remarks" <MessageBubble :messageList="rightList" @person-click="handleToSocialDetail" source="orgName" content="remarks"
name="personName" imageUrl="personImage"> name="personName" imageUrl="personImage">
</MessageBubble> </MessageBubble>
<!-- <div class="right-box"> <!-- <div class="right-box">
...@@ -56,6 +56,7 @@ ...@@ -56,6 +56,7 @@
import NewsList from "@/components/base/newsList/index.vue"; import NewsList from "@/components/base/newsList/index.vue";
import { ref, onMounted } from "vue"; import { ref, onMounted } from "vue";
import { useGotoNewsDetail } from "@/router/modules/news";
import { import {
getSocialMediaInfo, getNews getSocialMediaInfo, getNews
} from "@/api/scientificFunding/overview"; } from "@/api/scientificFunding/overview";
...@@ -171,15 +172,19 @@ const handleToMoreNews = () => { ...@@ -171,15 +172,19 @@ const handleToMoreNews = () => {
}; };
// 查看社交媒体详情 // 查看社交媒体详情
const handleToSocialDetail = item => { const handleToSocialDetail = item => {
const personId = item?.personId || item?.id;
if (!personId) return;
const route = router.resolve({ const route = router.resolve({
path: "/characterPage", path: "/characterPage",
query: { query: {
personId: item.id personId
} }
}); });
window.open(route.href, "_blank"); window.open(route.href, "_blank");
}; };
const gotoNewsDetail = useGotoNewsDetail();
onMounted(async () => { onMounted(async () => {
handleNews() handleNews()
handleSocialMediaInfo() handleSocialMediaInfo()
......
...@@ -21,23 +21,30 @@ ...@@ -21,23 +21,30 @@
<div class="left-center-main-ul"> <div class="left-center-main-ul">
<ul> <ul>
<li> <li>
<img src="./assets/icon-black.png" alt="" class="li-img" />
<span class="ul-title">投资主体:</span> <span class="ul-title">投资主体:</span>
<span class="ul-content">美国国家科学基金会</span> <span class="ul-content">美国国家科学基金会</span>
</li> </li>
<li> <li>
<img src="./assets/icon-black.png" alt="" class="li-img" />
<span class="ul-title">发布日期:</span> <span class="ul-title">发布日期:</span>
<span class="ul-content">{{ itemData.publicationDate }}</span> <span class="ul-content">{{ itemData.publicationDate }}</span>
</li> </li>
<li> <li>
<img src="./assets/icon-black.png" alt="" class="li-img" />
<span class="ul-title">资助经费:</span> <span class="ul-title">资助经费:</span>
<span class="ul-content">{{ itemData.amount }}</span> <span class="ul-content">{{ itemData.amount }}</span>
</li> </li>
<li> <li>
<img src="./assets/icon-black.png" alt="" class="li-img" />
<span class="ul-title">涉及领域:</span> <span class="ul-title">涉及领域:</span>
<span class="ul-pie cl1" v-for="value in itemData.toOrgNameList">{{ value }}</span> <span class="ul-pie cl1">
<AreaTag v-for="(val, idx) in itemData.areaList" :key="idx" :tagName="val" />
</span>
</li> </li>
<li> <li>
<img src="./assets/icon-black.png" alt="" class="li-img" />
<span class="ul-title">资助对象:</span> <span class="ul-title">资助对象:</span>
<span class="ul-content">{{ itemData.fromOrgNameList.join(',') }}</span> <span class="ul-content">{{ itemData.fromOrgNameList.join(',') }}</span>
</li> </li>
...@@ -97,42 +104,7 @@ import { ...@@ -97,42 +104,7 @@ import {
import router from "@/router"; import router from "@/router";
const list = ref([ const list = ref([
{
id: 1,
title: "特别重大",
content: "NSF宣布新的“新兴技术体验式学习”计划资...",
time: "一天前"
},
{
id: 2,
title: "一般风险",
content: "美国NASA公布NIAC计划2025年度第一轮资助",
time: "一天前"
},
{
id: 3,
title: "特别重大",
content: "美国NASA公布“早期创新计划”2026年资助...",
time: "一天前"
},
{
id: 4,
title: "重大风险",
content: '美国NIH冻结多所顶尖大学资金引发广泛争议"',
time: "一天前"
},
{
id: 5,
title: "重大风险",
content: "美国NIH终止哥伦比亚大学研究项目拨款引发...",
time: "一天前"
},
{
id: 6,
title: "特别重大",
content: "美国DARPA资助可调控生物功能微系统技术开发",
time: "一天前"
}
]); ]);
//// 获取风险信号 //// 获取风险信号
...@@ -286,7 +258,7 @@ onMounted(async () => { ...@@ -286,7 +258,7 @@ onMounted(async () => {
height: 175px; height: 175px;
.left-center-main-title { .left-center-main-title {
margin-left: 19px; margin-left: 22px;
margin-bottom: 17px; margin-bottom: 17px;
font-size: 20px; font-size: 20px;
font-weight: 700; font-weight: 700;
...@@ -305,6 +277,20 @@ onMounted(async () => { ...@@ -305,6 +277,20 @@ onMounted(async () => {
width: 100%; width: 100%;
height: 24px; height: 24px;
margin-bottom: 12px; margin-bottom: 12px;
display: flex;
.li-img {
width: 4px;
height: 4px;
margin-right: 18px;
margin-top: 10px;
img {
width: 100%;
height: 100%;
display: block;
}
}
.ul-title { .ul-title {
display: inline-block; display: inline-block;
...@@ -326,19 +312,14 @@ onMounted(async () => { ...@@ -326,19 +312,14 @@ onMounted(async () => {
} }
.ul-pie { .ul-pie {
display: inline-block; display: flex;
gap: 8px;
box-sizing: border-box; box-sizing: border-box;
padding: 2px 8px; flex-direction: row;
border: 1px solid;
border-radius: 4px;
margin-right: 8px; margin-right: 8px;
} }
.cl1 {
border-color: rgba(186, 224, 255, 1);
background-color: rgba(230, 244, 255, 1);
color: rgba(22, 119, 255, 1);
}
.cl2 { .cl2 {
border-color: rgba(255, 163, 158, 1); border-color: rgba(255, 163, 158, 1);
......
...@@ -5,20 +5,34 @@ ...@@ -5,20 +5,34 @@
<div class="left-title"> <div class="left-title">
<img src="./assets/icon01.png" alt="" /> <img src="./assets/icon01.png" alt="" />
<div class="tit">资助领域分布情况</div> <div class="tit">资助领域分布情况</div>
<div :class="radio1 === true ? 'btn-select' : 'btn'" style=" right:250px;" @click="changeradio1()"> <div :class="radio1 === true ? 'btn-select' : 'btn'" style=" right:250px;" @click="setRadio1(true)">
资助经费 资助经费
</div> </div>
<div :class="radio1 === false ? 'btn-select' : 'btn'" style=" right: 150px;" @click="changeradio1()"> <div :class="radio1 === false ? 'btn-select' : 'btn'" style=" right: 150px;" @click="setRadio1(false)">
资助项目 资助项目
</div> </div>
<el-select v-model="value1" placeholder="Select" class="select" style=" right: 31px;"> <el-select v-model="value1" placeholder="Select" class="select" style=" right: 31px;"
@change="handleLeft1YearChange">
<el-option v-for="item in options1" :key="item.value" :label="item.label" :value="item.value" /> <el-option v-for="item in options1" :key="item.value" :label="item.label" :value="item.value" />
</el-select> </el-select>
</div> </div>
<div class="left-main"> <div class="left-main">
<div class="left-main-echarts" ref="leftChartRef" v-show="radio1 === true">资助经费</div> <div class="left-main-echarts" ref="leftChartRef" v-show="radio1 === true"></div>
<div class="left-main-echarts" ref="leftChartRef1" v-show="radio1 === false">资助项目</div> <div class="left-main-echarts" ref="leftChartRef1" v-show="radio1 === false"></div>
<el-empty v-show="!hasLeft1ChartData && !isLeft1Loading" class="datasub-el-empty" description="暂无数据"
:image-size="100" />
<div class="source" v-show="hasLeft1ChartData">
<TipTab :text="'资助领域分布情况,数据来源:美国国会官网'" />
</div>
<div class="chart-box" v-show="hasLeft1ChartData">
<div class="btn-box" v-if="!isShowAiContentLeft1" @mouseenter="handleSwitchAiLeft1(true)">
<AiButton />
</div>
<div class="content-box" v-else @mouseleave="handleSwitchAiLeft1(false)">
<AiPane :aiContent="aiContentLeft1" />
</div>
</div>
</div> </div>
</div> </div>
<div class="left"> <div class="left">
...@@ -31,6 +45,18 @@ ...@@ -31,6 +45,18 @@
</div> </div>
<div class="left-main1"> <div class="left-main1">
<div class="left-sankey-echarts" ref="leftSankeyRef"></div> <div class="left-sankey-echarts" ref="leftSankeyRef"></div>
<el-empty v-show="!hasLeft2ChartData" class="datasub-el-empty" description="暂无数据" :image-size="100" />
<div class="source" v-show="hasLeft2ChartData">
<TipTab :text="'机构资助领域情况,数据来源:美国国会官网'" />
</div>
<div class="chart-box" v-show="hasLeft2ChartData">
<div class="btn-box" v-if="!isShowAiContentLeft2" @mouseenter="handleSwitchAiLeft2(true)">
<AiButton />
</div>
<div class="content-box" v-else @mouseleave="handleSwitchAiLeft2(false)">
<AiPane :aiContent="aiContentLeft2" />
</div>
</div>
</div> </div>
</div> </div>
</div> </div>
...@@ -39,33 +65,58 @@ ...@@ -39,33 +65,58 @@
<div class="right-title"> <div class="right-title">
<img src="./assets/icon02.png" alt="" /> <img src="./assets/icon02.png" alt="" />
<div class="tit">资助经费变化情况</div> <div class="tit">资助经费变化情况</div>
<div :class="radio2 === true ? 'btn-select' : 'btn'" style=" right:250px;" @click="changeradio2()"> <div :class="radio2 === true ? 'btn-select' : 'btn'" style=" right:250px;" @click="setRadio2(true)">
资助经费 资助经费
</div> </div>
<div :class="radio2 === false ? 'btn-select' : 'btn'" style=" right: 150px;" @click="changeradio2()"> <div :class="radio2 === false ? 'btn-select' : 'btn'" style=" right: 150px;" @click="setRadio2(false)">
资助项目 资助项目
</div> </div>
<el-select v-model="value" placeholder="Select" class="select"> <el-select v-model="value" placeholder="Select" class="select" @change="handleRight1RangeChange">
<el-option v-for="item in options" :key="item.value" :label="item.label" :value="item.value" /> <el-option v-for="item in options" :key="item.value" :label="item.label" :value="item.value" />
</el-select> </el-select>
</div> </div>
<div class="right-main"> <div class="right-main">
<div class="right-main-echarts" ref="rightChartRef" v-show="radio2 === true"></div> <div class="right-main-echarts" ref="rightChartRef" v-show="radio2 === true"></div>
<div class="right-main-echarts" ref="rightChartRef1" v-show="radio2 === false"></div> <div class="right-main-echarts" ref="rightChartRef1" v-show="radio2 === false"></div>
<div class="right-main-tit">亿美元</div> <div class="right-main-tit" v-show="hasRight1ChartData">亿美元</div>
<el-empty v-show="!hasRight1ChartData && !isRight1Loading" class="datasub-el-empty" description="暂无数据"
:image-size="100" />
<div class="source" v-show="hasRight1ChartData">
<TipTab :text="'资助经费变化情况,数据来源:美国国会官网'" />
</div>
<div class="chart-box" v-show="hasRight1ChartData">
<div class="btn-box" v-if="!isShowAiContentRight1" @mouseenter="handleSwitchAiRight1(true)">
<AiButton />
</div>
<div class="content-box" v-else @mouseleave="handleSwitchAiRight1(false)">
<AiPane :aiContent="aiContentRight1" />
</div>
</div>
</div> </div>
</div> </div>
<div class="right"> <div class="right">
<div class="right-title"> <div class="right-title">
<img src="./assets/icon04.png" alt="" /> <img src="./assets/icon04.png" alt="" />
<div class="tit">项目资助强度分布</div> <div class="tit">项目资助强度分布</div>
<el-select v-model="value3" placeholder="Select" class="select"> <el-select v-model="value3" placeholder="Select" class="select" @change="handleRight2YearChange">
<el-option v-for="item in options1" :key="item.value" :label="item.label" :value="item.value" /> <el-option v-for="item in options1" :key="item.value" :label="item.label" :value="item.value" />
</el-select> </el-select>
</div> </div>
<div class="right-main1"> <div class="right-main1">
<div class="right-boxplot-echarts" ref="boxplotChartRef"></div> <div class="right-boxplot-echarts" ref="boxplotChartRef"></div>
<div class="right-main1-tit">单位:亿美元</div> <div class="right-main1-tit" v-show="hasRight2ChartData">单位:亿美元</div>
<el-empty v-show="!hasRight2ChartData" class="datasub-el-empty" description="暂无数据" :image-size="100" />
<div class="source" v-show="hasRight2ChartData">
<TipTab :text="'项目资助强度分布,数据来源:美国国会官网'" />
</div>
<div class="chart-box" v-show="hasRight2ChartData">
<div class="btn-box" v-if="!isShowAiContentRight2" @mouseenter="handleSwitchAiRight2(true)">
<AiButton />
</div>
<div class="content-box" v-else @mouseleave="handleSwitchAiRight2(false)">
<AiPane :aiContent="aiContentRight2" />
</div>
</div>
</div> </div>
</div> </div>
</div> </div>
...@@ -73,13 +124,31 @@ ...@@ -73,13 +124,31 @@
</template> </template>
<script setup> <script setup>
import { ref, onMounted, onBeforeUnmount, nextTick } from "vue"; import { ref, onMounted, onBeforeUnmount, nextTick, computed } from "vue";
import { getChartAnalysis } from "@/api/aiAnalysis";
import AiButton from "@/components/base/Ai/AiButton/index.vue";
import AiPane from "@/components/base/Ai/AiPane/index.vue";
import TipTab from "@/views/thinkTank/TipTab/index.vue";
import { import {
findFundField, findCountryProjectAreaList, getCountryFundingChange, getCountryFundProjectChange, getOrgFundsArea, getOrgFundStrength findFundField, findCountryProjectAreaList, getCountryFundingChange, getCountryFundProjectChange, getOrgFundsArea, getOrgFundStrength
} from "@/api/scientificFunding/overview"; } from "@/api/scientificFunding/overview";
import * as echarts from "echarts"; import * as echarts from "echarts";
const isNonEmptyArray = (v) => Array.isArray(v) && v.length > 0;
// 兼容后端多种返回结构:[] / {data:[]} / {content:[]} 等
const extractArrayData = (res) => {
const d = res?.data;
if (Array.isArray(d)) return d;
if (Array.isArray(d?.data)) return d.data;
if (Array.isArray(d?.content)) return d.content;
if (Array.isArray(d?.list)) return d.list;
return [];
};
const isSuccessCode = (res) => Number(res?.code) === 200;
const value = ref(10); const value = ref(10);
...@@ -107,54 +176,153 @@ const options1 = [ ...@@ -107,54 +176,153 @@ const options1 = [
label: "2024年" label: "2024年"
} }
]; ];
//获取当前时间x年前的日期 const normalizeYearParam = (val) => {
function getDateYearsAgo(years) { const y = Number(val);
// 获取当前日期 return Number.isFinite(y) ? y : val;
const currentDate = new Date(); };
// 计算指定年数之前的日期
const pastDate = new Date(currentDate.getFullYear() - years, currentDate.getMonth(), currentDate.getDate()); /** 资助经费变化情况:固定时间窗起点 */
// 格式化日期为 "YYYY-MM-DD" 的形式 const buildStartDateByRange = (rangeYears) => {
const year = pastDate.getFullYear(); const n = Number(rangeYears);
const month = String(pastDate.getMonth() + 1).padStart(2, "0"); // 月份从0开始,需要加1 if (n === 10) return "2015-01-01";
const day = String(pastDate.getDate()).padStart(2, "0"); if (n === 5) return "2020-01-01";
return `${year}-${month}-${day}`; // 兜底:保持原逻辑的“年初”
} const y = new Date().getFullYear() - (Number.isFinite(n) ? n : 0);
return `${y}-01-01`;
};
const radio1 = ref(true) const radio1 = ref(true)
const changeradio1 = () => { const setRadio1 = (val) => {
radio1.value = !radio1.value if (radio1.value === val) return;
} radio1.value = val;
// 切换模式:先清空当前模式数据与图表,再按当前年份重新拉数
if (val) {
left1RawFund.value = [];
if (leftChart) {
leftChart.dispose();
leftChart = null;
}
} else {
left1RawProject.value = [];
if (leftChart1) {
leftChart1.dispose();
leftChart1 = null;
}
}
handleLeft1YearChange();
// 切换显示后强制当前图表 resize,确保 canvas 尺寸稳定
nextTick(() => {
if (radio1.value) {
if (leftChart) leftChart.resize();
} else {
if (leftChart1) leftChart1.resize();
}
});
};
const value1 = ref(2025); const value1 = ref(2025);
const leftChartRef = ref(null); const leftChartRef = ref(null);
const leftChartRef1 = ref(null); const leftChartRef1 = ref(null);
const left1RawFund = ref([]);
const left1RawProject = ref([]);
const left1FundLoading = ref(false);
const left1ProjLoading = ref(false);
const hasLeft1ChartData = computed(() => {
return radio1.value ? isNonEmptyArray(left1RawFund.value) : isNonEmptyArray(left1RawProject.value);
});
const isLeft1Loading = computed(() => (radio1.value ? left1FundLoading.value : left1ProjLoading.value));
let left1FundReqSeq = 0;
let left1ProjReqSeq = 0;
const handleLeft1YearChange = () => {
// 根据当前“资助经费/资助项目”切换状态请求对应接口
if (radio1.value) {
handleGetFundField();
} else {
handleFindCountryProjectAreaList();
}
};
// 资助体系v2.0:资助领域分布情况:资助经费 // 资助体系v2.0:资助领域分布情况:资助经费
const handleGetFundField = async () => { const handleGetFundField = async () => {
const seq = ++left1FundReqSeq;
left1FundLoading.value = true;
try { try {
let params = { let params = {
year: value1.value year: normalizeYearParam(value1.value)
} }
const res = await findFundField(params); const res = await findFundField(params);
if (seq !== left1FundReqSeq) return;
console.log("资助领域分布情况", res); console.log("资助领域分布情况", res);
if (res.code === 200 && res.data) { if (isSuccessCode(res)) {
initLeftDonut(res.data, true) const list = extractArrayData(res);
left1RawFund.value = list;
if (list.length) {
await nextTick();
initLeftDonut(list, true)
} else if (leftChart) {
leftChart.dispose();
leftChart = null;
}
} else {
left1RawFund.value = [];
if (leftChart) {
leftChart.dispose();
leftChart = null;
}
} }
} catch (error) { } catch (error) {
if (seq !== left1FundReqSeq) return;
console.error("获取资助领域分布情况error", error); console.error("获取资助领域分布情况error", error);
left1RawFund.value = [];
if (leftChart) {
leftChart.dispose();
leftChart = null;
}
} finally {
if (seq === left1FundReqSeq) {
left1FundLoading.value = false;
}
} }
}; };
//资助体系v2.0:资助领域分布情况:资助项目 //资助体系v2.0:资助领域分布情况:资助项目
const handleFindCountryProjectAreaList = async () => { const handleFindCountryProjectAreaList = async () => {
const seq = ++left1ProjReqSeq;
left1ProjLoading.value = true;
try { try {
let params = { let params = {
year: value1.value year: normalizeYearParam(value1.value)
} }
const res = await findCountryProjectAreaList(params); const res = await findCountryProjectAreaList(params);
if (seq !== left1ProjReqSeq) return;
console.log("资助领域分布情况", res); console.log("资助领域分布情况", res);
if (res.code === 200 && res.data) { if (isSuccessCode(res)) {
initLeftDonut(res.data, false) const list = extractArrayData(res);
left1RawProject.value = list;
if (list.length) {
await nextTick();
initLeftDonut(list, false)
} else if (leftChart1) {
leftChart1.dispose();
leftChart1 = null;
}
} else {
left1RawProject.value = [];
if (leftChart1) {
leftChart1.dispose();
leftChart1 = null;
}
} }
} catch (error) { } catch (error) {
if (seq !== left1ProjReqSeq) return;
console.error("获取资助领域分布情况error", error); console.error("获取资助领域分布情况error", error);
left1RawProject.value = [];
if (leftChart1) {
leftChart1.dispose();
leftChart1 = null;
}
} finally {
if (seq === left1ProjReqSeq) {
left1ProjLoading.value = false;
}
} }
}; };
// 资助领域分布情况 // 资助领域分布情况
...@@ -208,68 +376,179 @@ const initLeftDonut = (rawData, show) => { ...@@ -208,68 +376,179 @@ const initLeftDonut = (rawData, show) => {
}; };
if (show == true) { if (show == true) {
if (leftChart) leftChart.dispose();
leftChart = echarts.init(leftChartRef.value); leftChart = echarts.init(leftChartRef.value);
leftChart.setOption(option); leftChart.setOption(option);
nextTick(() => leftChart && leftChart.resize());
} else { } else {
if (leftChart1) leftChart1.dispose();
leftChart1 = echarts.init(leftChartRef1.value); leftChart1 = echarts.init(leftChartRef1.value);
leftChart1.setOption(option); leftChart1.setOption(option);
nextTick(() => leftChart1 && leftChart1.resize());
} }
}; };
const rightChartRef = ref(null); const rightChartRef = ref(null);
const rightChartRef1 = ref(null); const rightChartRef1 = ref(null);
const right1RawFund = ref([]);
const right1RawProject = ref([]);
const right1FundLoading = ref(false);
const right1ProjLoading = ref(false);
const hasRight1ChartData = computed(() => {
return radio2.value ? isNonEmptyArray(right1RawFund.value) : isNonEmptyArray(right1RawProject.value);
});
const isRight1Loading = computed(() => (radio2.value ? right1FundLoading.value : right1ProjLoading.value));
const radio2 = ref(true) const radio2 = ref(true)
const changeradio2 = () => { const handleRight1RangeChange = () => {
radio2.value ? handlegetCountryFundingChange() : handlegetCountryFundProjectChange() // 根据当前“资助经费/资助项目”切换状态请求对应接口
radio2.value = !radio2.value if (radio2.value) {
} handlegetCountryFundingChange();
} else {
handlegetCountryFundProjectChange();
}
};
const setRadio2 = (val) => {
if (radio2.value === val) return;
radio2.value = val;
// 切换模式:先清空当前模式数据与图表,再按当前时间窗重新拉数
if (val) {
right1RawFund.value = [];
if (rightChart) {
rightChart.dispose();
rightChart = null;
}
} else {
right1RawProject.value = [];
if (rightChart1) {
rightChart1.dispose();
rightChart1 = null;
}
}
handleRight1RangeChange();
// 切换显示后强制当前图表 resize,确保 canvas 尺寸稳定
nextTick(() => {
if (radio2.value) {
if (rightChart) rightChart.resize();
} else {
if (rightChart1) rightChart1.resize();
}
});
};
// 资助体系v2.0:资助经费变化情况:资助经费 // 资助体系v2.0:资助经费变化情况:资助经费
const handlegetCountryFundingChange = async () => { const handlegetCountryFundingChange = async () => {
try { try {
right1FundLoading.value = true;
let params = { let params = {
startDate: getDateYearsAgo(value.value) startDate: buildStartDateByRange(value.value)
} }
const res = await getCountryFundingChange(params); const res = await getCountryFundingChange(params);
console.log("资助经费变化情况", res); console.log("资助经费变化情况", res);
if (res.code === 200 && res.data) { if (isSuccessCode(res)) {
initRightLine(res.data, true) const list = extractArrayData(res);
right1RawFund.value = list;
if (list.length) {
await nextTick();
initRightLine(list, true)
} else if (rightChart) {
rightChart.dispose();
rightChart = null;
}
} else {
right1RawFund.value = [];
if (rightChart) {
rightChart.dispose();
rightChart = null;
}
} }
} catch (error) { } catch (error) {
console.error("获取资助经费变化情况error", error); console.error("获取资助经费变化情况error", error);
right1RawFund.value = [];
if (rightChart) {
rightChart.dispose();
rightChart = null;
}
} finally {
right1FundLoading.value = false;
} }
}; };
//资助体系v2.0:资助经费变化情况:资助项目 //资助体系v2.0:资助经费变化情况:资助项目
const handlegetCountryFundProjectChange = async () => { const handlegetCountryFundProjectChange = async () => {
try { try {
right1ProjLoading.value = true;
let params = { let params = {
startDate: getDateYearsAgo(value.value) startDate: buildStartDateByRange(value.value)
} }
const res = await getCountryFundProjectChange(params); const res = await getCountryFundProjectChange(params);
console.log("资助项目变化情况", res); console.log("资助项目变化情况", res);
if (res.code === 200 && res.data) { if (isSuccessCode(res)) {
initRightLine(res.data) const list = extractArrayData(res);
right1RawProject.value = list;
if (list.length) {
await nextTick();
initRightLine(list)
} else if (rightChart1) {
rightChart1.dispose();
rightChart1 = null;
}
} else {
right1RawProject.value = [];
if (rightChart1) {
rightChart1.dispose();
rightChart1 = null;
}
} }
} catch (error) { } catch (error) {
console.error("获取资助项目变化情况error", error); console.error("获取资助项目变化情况error", error);
right1RawProject.value = [];
if (rightChart1) {
rightChart1.dispose();
rightChart1 = null;
}
} finally {
right1ProjLoading.value = false;
} }
}; };
//项目资助强度分布 //项目资助强度分布
const value3 = ref(2025); const value3 = ref(2025);
const boxplotChartRef = ref(null); const boxplotChartRef = ref(null);
const right2RawStrength = ref([]);
const hasRight2ChartData = computed(() => isNonEmptyArray(right2RawStrength.value));
const handleRight2YearChange = () => {
handlegetOrgFundStrength();
};
const handlegetOrgFundStrength = async () => { const handlegetOrgFundStrength = async () => {
try { try {
let params = { let params = {
year: value3.value year: normalizeYearParam(value3.value)
} }
const res = await getOrgFundStrength(params); const res = await getOrgFundStrength(params);
console.log("项目资助强度分布", res); console.log("项目资助强度分布", res);
if (res.code === 200 && res.data) { if (isSuccessCode(res)) {
initBoxPlot(res.data) const list = extractArrayData(res);
right2RawStrength.value = list;
if (list.length) {
await nextTick();
initBoxPlot(list)
} else if (boxplotChart) {
boxplotChart.dispose();
boxplotChart = null;
}
} else {
right2RawStrength.value = [];
if (boxplotChart) {
boxplotChart.dispose();
boxplotChart = null;
}
} }
} catch (error) { } catch (error) {
console.error("获取项目资助强度分布error", error); console.error("获取项目资助强度分布error", error);
right2RawStrength.value = [];
if (boxplotChart) {
boxplotChart.dispose();
boxplotChart = null;
}
} }
}; };
//项目资助强度分布 //项目资助强度分布
...@@ -420,11 +699,152 @@ const initBoxPlot = (data) => { ...@@ -420,11 +699,152 @@ const initBoxPlot = (data) => {
let leftChart; let leftChart;
let leftChart1; let leftChart1;
// let rightChart; let rightChart;
// let rightChart1; let rightChart1;
let leftSankey; let leftSankey;
let boxplotChart; let boxplotChart;
// ------- AI 解读(刷新后默认展开,行为对齐智库概览) -------
const isShowAiContentLeft1 = ref(true);
const isShowAiContentLeft2 = ref(true);
const isShowAiContentRight1 = ref(true);
const isShowAiContentRight2 = ref(true);
const aiContentLeft1 = ref("");
const aiContentLeft2 = ref("");
const aiContentRight1 = ref("");
const aiContentRight2 = ref("");
const isAiLoadingLeft1 = ref(false);
const isAiLoadingLeft2 = ref(false);
const isAiLoadingRight1 = ref(false);
const isAiLoadingRight2 = ref(false);
const appendAiInterpretationChunk = (targetRef, chunk, loadingText = "解读生成中…") => {
if (!chunk) return;
const current = String(targetRef.value || "");
const base = current === loadingText ? "" : current;
targetRef.value = base + String(chunk);
};
const getInterpretationTextFromChartResponse = (res) => {
const list = res?.data;
const first = Array.isArray(list) ? list[0] : null;
return (
first?.["解读"] ||
first?.["interpretation"] ||
first?.["analysis"] ||
first?.["content"] ||
""
);
};
const fetchChartInterpretationOnce = async (payload, targetRef, loadingRef) => {
if (loadingRef.value) return;
const hasValidContent =
targetRef.value &&
targetRef.value !== "解读生成中…" &&
targetRef.value !== "解读加载失败" &&
targetRef.value !== "暂无图表数据";
if (hasValidContent) return;
loadingRef.value = true;
targetRef.value = "解读生成中…";
try {
const res = await getChartAnalysis(
{ text: JSON.stringify(payload) },
{
onChunk: (chunk) => appendAiInterpretationChunk(targetRef, chunk)
}
);
const text = getInterpretationTextFromChartResponse(res);
targetRef.value = text || targetRef.value || "未返回有效解读内容";
} catch (e) {
console.error("图表解读请求失败", e);
targetRef.value = "解读加载失败";
} finally {
loadingRef.value = false;
}
};
const buildPayloadLeft1 = () => {
const raw = radio1.value ? left1RawFund.value : left1RawProject.value;
if (!Array.isArray(raw) || raw.length === 0) return null;
return {
type: "分布图",
name: radio1.value ? "资助领域分布情况-资助经费" : "资助领域分布情况-资助项目",
data: raw
};
};
const buildPayloadLeft2 = () => {
const raw = left2RawSankey.value;
if (!Array.isArray(raw) || raw.length === 0) return null;
return {
type: "桑基图",
name: "机构资助领域情况",
data: raw
};
};
const buildPayloadRight1 = () => {
const raw = radio2.value ? right1RawFund.value : right1RawProject.value;
if (!Array.isArray(raw) || raw.length === 0) return null;
return {
type: "折线图",
name: radio2.value ? "资助经费变化情况-资助经费" : "资助经费变化情况-资助项目",
data: raw
};
};
const buildPayloadRight2 = () => {
const raw = right2RawStrength.value;
if (!Array.isArray(raw) || raw.length === 0) return null;
return {
type: "箱线图",
name: "项目资助强度分布",
data: raw
};
};
const handleSwitchAiLeft1 = async (val) => {
isShowAiContentLeft1.value = val;
if (!val) return;
const payload = buildPayloadLeft1();
if (!payload) {
aiContentLeft1.value = "暂无图表数据";
return;
}
await fetchChartInterpretationOnce(payload, aiContentLeft1, isAiLoadingLeft1);
};
const handleSwitchAiLeft2 = async (val) => {
isShowAiContentLeft2.value = val;
if (!val) return;
const payload = buildPayloadLeft2();
if (!payload) {
aiContentLeft2.value = "暂无图表数据";
return;
}
await fetchChartInterpretationOnce(payload, aiContentLeft2, isAiLoadingLeft2);
};
const handleSwitchAiRight1 = async (val) => {
isShowAiContentRight1.value = val;
if (!val) return;
const payload = buildPayloadRight1();
if (!payload) {
aiContentRight1.value = "暂无图表数据";
return;
}
await fetchChartInterpretationOnce(payload, aiContentRight1, isAiLoadingRight1);
};
const handleSwitchAiRight2 = async (val) => {
isShowAiContentRight2.value = val;
if (!val) return;
const payload = buildPayloadRight2();
if (!payload) {
aiContentRight2.value = "暂无图表数据";
return;
}
await fetchChartInterpretationOnce(payload, aiContentRight2, isAiLoadingRight2);
};
//资助经费变化情况 //资助经费变化情况
...@@ -463,8 +883,10 @@ const initRightLine = (data, show) => { ...@@ -463,8 +883,10 @@ const initRightLine = (data, show) => {
name: orgName, name: orgName,
type: "line", type: "line",
data: values, data: values,
symbol: "none", smooth: true,
showSymbol: false, symbol: "emptyCircle",
showSymbol: true,
symbolSize: 6,
endLabel: { endLabel: {
show: true, show: true,
formatter: orgName, // 只显示 orgName formatter: orgName, // 只显示 orgName
...@@ -522,30 +944,55 @@ const initRightLine = (data, show) => { ...@@ -522,30 +944,55 @@ const initRightLine = (data, show) => {
}; };
if (show == true) { if (show == true) {
let rightChart = echarts.init(rightChartRef.value); if (rightChart) rightChart.dispose();
rightChart = echarts.init(rightChartRef.value);
rightChart.setOption(option); rightChart.setOption(option);
nextTick(() => rightChart && rightChart.resize());
} else { } else {
let rightChart1 = echarts.init(rightChartRef1.value); if (rightChart1) rightChart1.dispose();
rightChart1 = echarts.init(rightChartRef1.value);
rightChart1.setOption(option); rightChart1.setOption(option);
nextTick(() => rightChart1 && rightChart1.resize());
} }
}; };
const leftSankeyRef = ref(null); const leftSankeyRef = ref(null);
const value2 = ref(2025); const value2 = ref(2025);
const left2RawSankey = ref([]);
const hasLeft2ChartData = computed(() => isNonEmptyArray(left2RawSankey.value));
// 机构资助领域情况 // 机构资助领域情况
const handleGetOrgFundsArea = async () => { const handleGetOrgFundsArea = async () => {
try { try {
let params = { let params = {
year: value2.value year: normalizeYearParam(value2.value)
} }
const res = await getOrgFundsArea(params); const res = await getOrgFundsArea(params);
console.log("机构资助领域情况", res); console.log("机构资助领域情况", res);
if (res.code === 200 && res.data) { if (isSuccessCode(res)) {
initLeftSankey(res.data) const list = extractArrayData(res);
left2RawSankey.value = list;
if (list.length) {
await nextTick();
initLeftSankey(list)
} else if (leftSankey) {
leftSankey.dispose();
leftSankey = null;
}
} else {
left2RawSankey.value = [];
if (leftSankey) {
leftSankey.dispose();
leftSankey = null;
}
} }
} catch (error) { } catch (error) {
console.error("获取机构资助领域情况error", error); console.error("获取机构资助领域情况error", error);
left2RawSankey.value = [];
if (leftSankey) {
leftSankey.dispose();
leftSankey = null;
}
} }
}; };
//机构资助领域情况 //机构资助领域情况
...@@ -638,6 +1085,7 @@ const initLeftSankey = (data) => { ...@@ -638,6 +1085,7 @@ const initLeftSankey = (data) => {
}; };
leftSankey.setOption(option); leftSankey.setOption(option);
nextTick(() => leftSankey && leftSankey.resize());
}; };
...@@ -650,13 +1098,21 @@ const initLeftSankey = (data) => { ...@@ -650,13 +1098,21 @@ const initLeftSankey = (data) => {
// }; // };
onMounted(() => { onMounted(() => {
handleGetFundField() // 刷新后 AiPane 默认展开:先给出“解读生成中…”占位,再在数据到位后触发解读请求
handleFindCountryProjectAreaList() aiContentLeft1.value = "解读生成中…";
handlegetCountryFundingChange() aiContentLeft2.value = "解读生成中…";
handlegetCountryFundProjectChange() aiContentRight1.value = "解读生成中…";
handleGetOrgFundsArea() aiContentRight2.value = "解读生成中…";
handlegetOrgFundStrength()
// 先拉数据;每块数据到位后立即触发一次 AI 解读(不必等其它块完成)
void handleGetFundField().then(() => handleSwitchAiLeft1(true));
void handleFindCountryProjectAreaList();
void handlegetCountryFundingChange().then(() => handleSwitchAiRight1(true));
void handlegetCountryFundProjectChange();
void handleGetOrgFundsArea().then(() => handleSwitchAiLeft2(true));
void handlegetOrgFundStrength().then(() => handleSwitchAiRight2(true));
}); });
// onBeforeUnmount(() => { // onBeforeUnmount(() => {
// window.removeEventListener("resize", handleResize); // window.removeEventListener("resize", handleResize);
...@@ -746,18 +1202,24 @@ onMounted(() => { ...@@ -746,18 +1202,24 @@ onMounted(() => {
.left-main { .left-main {
width: 792px; width: 792px;
height: 412px; height: 412px;
padding: 52px 60px 78px 61px; box-sizing: border-box;
/* 对齐智库概览-数据总览内边距 */
padding: 24px 24px 65px 24px;
position: relative;
.left-main-echarts { .left-main-echarts {
width: 780px; width: 100%;
height: 350px; height: 100%;
} }
} }
.left-main1 { .left-main1 {
width: 792px; width: 792px;
height: 412px; height: 412px;
padding: 30px 30px 30px 30px; box-sizing: border-box;
/* 对齐智库概览-数据总览内边距 */
padding: 24px 24px 65px 24px;
position: relative;
.left-sankey-echarts { .left-sankey-echarts {
width: 100%; width: 100%;
...@@ -825,14 +1287,16 @@ onMounted(() => { ...@@ -825,14 +1287,16 @@ onMounted(() => {
.right-main { .right-main {
width: 792px; width: 792px;
height: 421px; height: 412px;
padding: 40px 5px 30px 22px; box-sizing: border-box;
/* 对齐智库概览-数据总览内边距 */
padding: 24px 24px 65px 24px;
position: relative; position: relative;
.right-main-echarts { .right-main-echarts {
/* 矢量 476 */ /* 矢量 476 */
width: 780px; width: 100%;
height: 350px; height: 100%;
} }
.right-main-tit { .right-main-tit {
...@@ -849,15 +1313,16 @@ onMounted(() => { ...@@ -849,15 +1313,16 @@ onMounted(() => {
.right-main1 { .right-main1 {
width: 792px; width: 792px;
height: 421px; height: 412px;
padding: 20px 20px; /* 对齐智库概览-数据总览内边距 */
padding: 24px 24px 65px 24px;
position: relative; position: relative;
box-sizing: border-box; box-sizing: border-box;
.right-boxplot-echarts { .right-boxplot-echarts {
width: 100%; width: 100%;
height: 100%; height: 323px;
min-height: 300px;
} }
.right-main1-tit { .right-main1-tit {
...@@ -876,6 +1341,50 @@ onMounted(() => { ...@@ -876,6 +1341,50 @@ onMounted(() => {
} }
} }
/* 数据总览内:TipTab 与 AI 解读(尽量复用智库概览的定位) */
.source {
position: absolute;
left: 24px;
bottom: 21px;
z-index: 2;
}
.chart-box {
position: absolute;
right: 0px;
bottom: 18px;
width: 74px;
height: 28px;
z-index: 3;
.btn-box {
width: 74px;
height: 28px;
}
.content-box {
width: 792px;
position: absolute;
right: 0;
bottom: -18px;
}
}
.datasub-el-empty {
position: absolute;
inset: 0;
display: flex;
align-items: center;
justify-content: center;
padding: 0;
margin: 0;
z-index: 5;
:deep(.el-empty__description) {
margin-top: 8px;
}
}
.btn { .btn {
position: absolute; position: absolute;
top: 11px; top: 11px;
......
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
{{ item.orgName }} {{ item.orgName }}
</div> </div>
</div> </div>
<div class="select-box"> <div class="reslib-sort-box">
<div class="paixu-btn" @click="handleSwithSort()"> <div class="paixu-btn" @click="handleSwithSort()">
<div class="icon1"> <div class="icon1">
<img v-if="sort" src="@/assets/icons/shengxu1.png" alt="" /> <img v-if="sort" src="@/assets/icons/shengxu1.png" alt="" />
...@@ -21,42 +21,41 @@ ...@@ -21,42 +21,41 @@
</div> </div>
<div class="main"> <div class="main">
<div class="left"> <div class="left">
<div class="left-ti1"></div> <div class="select-box">
<div class="left-ti2"></div> <div class="header">
<!-- <div class="left-title">项目经费</div> <div class="icon"></div>
<div class="left-content"> <div class="title">科技领域</div>
<div v-for="(item, i) in dataList" :key="item.id" class="left-item">
<input type="checkbox" checked />{{ item.name }}
</div> </div>
</div> --> <div class="select-main">
<div class="left-title cl1">涉及领域</div> <el-checkbox-group class="checkbox-group" :model-value="selectedAreaListModel"
<div class="left-content"> @change="handleAreaGroupChange">
<el-checkbox v-model="checkAll" :indeterminate="isIndeterminate" class="all-checkbox" <el-checkbox class="filter-checkbox all-checkbox" :label="RESOURCE_FILTER_ALL_AREA">
@change="handleCheckAllChange"> {{ RESOURCE_FILTER_ALL_AREA }}
全部领域
</el-checkbox> </el-checkbox>
<el-checkbox v-for="research in areaList" :key="research.id" v-model="selectedAreaList" :label="research.id" <el-checkbox v-for="research in areaList" :key="research.id" class="filter-checkbox" :label="research.id">
@change="handleCheckedAreaChange()" class="filter-checkbox">
{{ research.name }} {{ research.name }}
</el-checkbox> </el-checkbox>
<!-- <div v-for="(item, i) in areaList" :key="item.id" class="left-item"> </el-checkbox-group>
<input type="checkbox" :checked="i === 0" />{{ item.name }} </div>
</div> -->
</div> </div>
<div class="left-title cl1">发布时间</div> <div class="select-box">
<div class="left-content"> <div class="header">
<el-checkbox v-model="checkAllTime" class="all-checkbox" :indeterminate="isIndeterminateTime" <div class="icon"></div>
@change="handleCheckAllChangeTime"> <div class="title">发布时间</div>
全部时间 </div>
<div class="select-main">
<el-checkbox-group class="checkbox-group" :model-value="selectedPubTimeListModel"
@change="handleTimeGroupChange">
<el-checkbox class="filter-checkbox all-checkbox" :label="RESOURCE_FILTER_ALL_TIME">
{{ RESOURCE_FILTER_ALL_TIME }}
</el-checkbox> </el-checkbox>
<el-checkbox-group v-model="selectedPubTimeList"> <el-checkbox v-for="time in pubTimeList" :key="time.id" class="filter-checkbox" :label="time.id">
<el-checkbox v-for="time in pubTimeList" :key="time.id" :label="time.id" class="filter-checkbox"
@change="handleCheckedAreaChangeTime()">
{{ time.name }} {{ time.name }}
</el-checkbox> </el-checkbox>
</el-checkbox-group> </el-checkbox-group>
</div> </div>
</div> </div>
</div>
<div class="right"> <div class="right">
<div class="right-title"> <div class="right-title">
<img src="./assets/icon01.png" alt="" /> <img src="./assets/icon01.png" alt="" />
...@@ -68,29 +67,22 @@ ...@@ -68,29 +67,22 @@
<div class="right-item-title">{{ item.projectName }}</div> <div class="right-item-title">{{ item.projectName }}</div>
<div class="right-item-content">{{ item.abstractContent }}</div> <div class="right-item-content">{{ item.abstractContent }}</div>
<div class="right-item-pie"> <div class="right-item-pie">
<div v-for="(pie, i) in item.areaList" :key="i" class="right-item-pie-item" :class="{
cl1: pie === '新材料', <AreaTag v-for="(val, idx) in item.areaList" :key="idx" :tagName="val" />
cl2: pie === '人工智能',
cl3: pie === '量子科技',
cl4: pie === '能源',
cl5: pie === '生物科技',
cl6: pie === '航空航天'
}">
{{ pie }}
</div>
</div> </div>
<div class="right-item-time">{{ item.publicationDate }}</div> <div class="right-item-time">{{ item.publicationDate }}</div>
<div class="right-item-money" <div class="right-item-money"
:style="{ color: item.amount <= 1000 ? 'rgba(232, 189, 11, 1)' : item.amount <= 10000 ? 'rgba(255, 149, 77, 1)' : 'rgba(206, 79, 81, 1)' }"> :style="{ color: item.amount <= 1000 ? 'rgba(232, 189, 11, 1)' : item.amount <= 10000 ? 'rgba(255, 149, 77, 1)' : 'rgba(206, 79, 81, 1)' }">
{{ '$' + item.amount + '万' }}</div> {{ '$' + item.amount + '万' }}</div>
</div> </div>
<div class="page"> <div class="page">
<div class="count">{{ total }}</div> <div class="count">{{ total }}</div>
<el-pagination v-model:current-page="currentPage" :page-size="pageSize" :total="total" <el-pagination v-model:current-page="currentPage" :page-size="pageSize" :total="total"
layout="prev, pager, next" background @current-change="handlePageChange" /> layout="prev, pager, next" background @current-change="handlePageChange" />
</div> </div>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
...@@ -101,49 +93,35 @@ import { ref, onMounted } from "vue"; ...@@ -101,49 +93,35 @@ import { ref, onMounted } from "vue";
import { import {
getProjectListNew, geFundSourceOrg, getAreaType getProjectListNew, geFundSourceOrg, getAreaType
} from "@/api/scientificFunding/overview"; } from "@/api/scientificFunding/overview";
import {
RESOURCE_FILTER_ALL_AREA,
RESOURCE_FILTER_ALL_TIME,
RESOURCE_FILTER_EARLIER,
normalizeExclusiveAllOption,
stripAllAreaForRequest,
stripAllTimeForRequest,
isSelectionCoveringAllOptions,
expandEarlierNumericYears
} from "@/views/thinkTank/utils/resourceLibraryFilters";
/** 领域字典与接口 arealist 使用数字 id(1、2、3…) */
const normalizeAreaId = (id) => {
const n = Number(id);
return Number.isFinite(n) ? n : id;
};
/** 请求用:仅保留合法整数领域 id */
const toAreaIdListForRequest = (ids) => {
const list = Array.isArray(ids) ? ids : [];
return list
.map((id) => normalizeAreaId(id))
.filter((id) => typeof id === "number" && Number.isInteger(id));
};
const navList = ref([]); const navList = ref([]);
const activeItem = ref(""); const activeItem = ref("");
const areaList = ref([ const areaList = ref([]);
{
id: 1,
name: "全部领域"
},
{
id: 2,
name: "人工智能"
},
{
id: 3,
name: "集成电路"
},
{
id: 4,
name: "通信网络"
},
{
id: 5,
name: "量子科技"
},
{
id: 6,
name: "能源"
},
{
id: 7,
name: "生物科技"
},
{
id: 8,
name: "航空航天"
},
{
id: 9,
name: "海洋"
}
]);
// 来源机构列表 // 来源机构列表
...@@ -160,99 +138,97 @@ const handleGeFundSourceOrg = async () => { ...@@ -160,99 +138,97 @@ const handleGeFundSourceOrg = async () => {
} }
}; };
const checkAll = ref(false); const selectedAreaListModel = ref([RESOURCE_FILTER_ALL_AREA]);
const isIndeterminate = ref(true); const selectedPubTimeListModel = ref([RESOURCE_FILTER_ALL_TIME]);
const selectedAreaList = ref([]);
const handleAreaGroupChange = (val) => {
const handleCheckAllChange = val => { selectedAreaListModel.value = normalizeExclusiveAllOption(val, RESOURCE_FILTER_ALL_AREA).map((item) =>
// console.log(val, "handleCheckAllChange"); item === RESOURCE_FILTER_ALL_AREA ? item : normalizeAreaId(item)
if (val) { );
isIndeterminate.value = false;
selectedAreaList.value.length !== areaList.value.length
? (selectedAreaList.value = areaList.value.map(obj => obj.id))
: "";
} else {
selectedAreaList.value = [];
}
// selectedAreaList.value = val ? areaList : []
// isIndeterminate.value = false
handleGetProjectListNew(); handleGetProjectListNew();
}; };
const handleCheckedAreaChange = () => {
// console.log(selectedAreaList.value, "handleCheckedAreaChange"); const handleTimeGroupChange = (val) => {
console.log(selectedAreaList.value, "当前选中的领域"); selectedPubTimeListModel.value = normalizeExclusiveAllOption(val, RESOURCE_FILTER_ALL_TIME);
selectedAreaList.value.length !== areaList.value.length
? (isIndeterminate.value = true)
: ((checkAll.value = true), (isIndeterminate.value = false));
handleGetProjectListNew(); handleGetProjectListNew();
}; };
const pubTimeList = ref([ const pubTimeList = ref([
{ {
id: 2025, id: 2025,
name: "2025" name: "2025"
}, },
{ {
id: 2024, id: 2024,
name: "2024" name: "2024"
}, },
{ {
id: 2023, id: 2023,
name: "2023" name: "2023"
}, },
{ {
id: 2022, id: 2022,
name: "2022" name: "2022"
}, },
{ {
id: 2021, id: 2021,
name: "2021" name: "2021年"
},
{
id: RESOURCE_FILTER_EARLIER,
name: RESOURCE_FILTER_EARLIER
} }
// {
// id: "更早时间",
// name: "更早时间"
// }
]); ]);
const selectedPubTimeList = ref([""]);
const checkAllTime = ref(false); /** 选择「全部时间」时,yearlist 传 2000~2025 逐年 */
const isIndeterminateTime = ref(true); const YEAR_ALL_RANGE_START = 2000;
const YEAR_ALL_RANGE_END = 2025;
const buildYearlistForRequest = (selectedTimeModel) => {
const strippedTime = stripAllTimeForRequest(selectedTimeModel);
// 仅勾选「全部时间」、未选具体年份时,传 2000~2025 逐年
if (strippedTime.length === 0) {
const out = [];
for (let y = YEAR_ALL_RANGE_START; y <= YEAR_ALL_RANGE_END; y += 1) {
out.push(String(y));
}
return out;
}
const hasEarlier = strippedTime.includes(RESOURCE_FILTER_EARLIER);
const numericOnly = strippedTime.filter((id) => id !== RESOURCE_FILTER_EARLIER);
const strippedNums = numericOnly
.map((id) => Number(id))
.filter((n) => Number.isInteger(n));
// 勾选「更早」:展开为 2000~2020,并与已选数字年合并(可与其他年份同时选)
if (hasEarlier) {
const yearsSet = new Set(expandEarlierNumericYears());
strippedNums.forEach((n) => yearsSet.add(n));
return [...yearsSet]
.sort((a, b) => a - b)
.map((n) => String(n));
}
return strippedNums.map((n) => String(n));
};
const sort = ref(false); const sort = ref(false);
const handleSwithSort = () => { const handleSwithSort = () => {
sort.value = !sort.value; sort.value = !sort.value;
handleGetProjectListNew(); handleGetProjectListNew();
}; };
const handleCheckAllChangeTime = val => {
// console.log(val, "handleCheckAllChange");
if (val) {
isIndeterminateTime.value = false;
selectedPubTimeList.value.length !== pubTimeList.value.length
? (selectedPubTimeList.value = pubTimeList.value.map(obj => obj.id))
: "";
} else {
selectedPubTimeList.value = [];
}
// selectedAreaList.value = val ? areaList : []
// isIndeterminate.value = false
handleGetProjectListNew();
};
const handleCheckedAreaChangeTime = () => {
// console.log(selectedAreaList.value, "handleCheckedAreaChange");
console.log(selectedPubTimeList.value, "当前选中的时间");
selectedPubTimeList.value.length !== pubTimeList.value.length
? (isIndeterminateTime.value = true)
: ((checkAllTime.value = true), (isIndeterminateTime.value = false));
handleGetProjectListNew();
};
// 获取行业领域列表 // 获取行业领域列表
const handleGetAreaType = async () => { const handleGetAreaType = async () => {
try { try {
const res = await getAreaType(); const res = await getAreaType();
console.log("获取行业领域列表", res); console.log("获取行业领域列表", res);
if (res.code === 200 && res.data) { if (res.code === 200 && res.data) {
areaList.value = res.data areaList.value = res.data.map((row) => ({
...row,
id: normalizeAreaId(row.id)
}));
} }
} catch (error) { } catch (error) {
console.error("获取行业领域列表error", error); console.error("获取行业领域列表error", error);
...@@ -270,11 +246,22 @@ const handlePageChange = p => { ...@@ -270,11 +246,22 @@ const handlePageChange = p => {
// 资助体系v2.0:资助项目列表分页 // 资助体系v2.0:资助项目列表分页
const handleGetProjectListNew = async () => { const handleGetProjectListNew = async () => {
try { try {
const strippedArea = toAreaIdListForRequest(
stripAllAreaForRequest(selectedAreaListModel.value)
);
const allAreaIds = toAreaIdListForRequest(areaList.value.map((obj) => obj.id));
const arealist =
strippedArea.length === 0 || isSelectionCoveringAllOptions(strippedArea, allAreaIds)
? allAreaIds
: strippedArea;
const yearlist = buildYearlistForRequest(selectedPubTimeListModel.value);
let params = { let params = {
arealist: selectedAreaList.value, arealist,
currentPage: currentPage.value, currentPage: currentPage.value,
pageSize: 10, pageSize: 10,
yearlist: selectedPubTimeList.value.map(item => item.toString().trim()).filter(item => item !== ""), yearlist,
funSort: sort.value ? 'desc' : 'asc', funSort: sort.value ? 'desc' : 'asc',
orgId: activeItem.value orgId: activeItem.value
} }
...@@ -305,11 +292,10 @@ onMounted(async () => { ...@@ -305,11 +292,10 @@ onMounted(async () => {
.reslib-page { .reslib-page {
width: 1600px; width: 1600px;
height: 1565px;
position: relative;
.select-box { position: relative;
.reslib-sort-box {
width: 128px; width: 128px;
position: absolute; position: absolute;
top: 7px; top: 7px;
...@@ -370,15 +356,15 @@ onMounted(async () => { ...@@ -370,15 +356,15 @@ onMounted(async () => {
} }
.nav { .nav {
width: calc(100% - 100px);
height: 42px; height: 42px;
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: space-between;
margin-bottom: 34px; margin-bottom: 34px;
.nav-item { .nav-item {
width: 100%;
text-align: center; text-align: center;
cursor: pointer; cursor: pointer;
padding: 8px 20px; padding: 8px 20px;
...@@ -397,133 +383,85 @@ onMounted(async () => { ...@@ -397,133 +383,85 @@ onMounted(async () => {
} }
} }
.select {
width: 128px;
position: absolute;
top: 7px;
right: 0px;
}
.main { .main {
width: 1600px; width: 1600px;
height: 1489px;
display: flex; display: flex;
margin-bottom: 100px;
.left { .left {
width: 300px; width: 360px;
margin-right: 16px; margin-right: 16px;
height: 100%;
padding-bottom: 24px;
box-sizing: border-box;
border: 1px solid rgba(234, 236, 238, 1);
border-radius: 10px; border-radius: 10px;
background-color: #fff; box-shadow: 0px 0px 20px 0px rgba(94, 95, 95, 0.1);
box-shadow: 0px 0px 20px 0px rgba(25, 69, 130, 0.1); background: rgba(255, 255, 255, 1);
position: relative; position: relative;
.left-ti1 { .select-box {
width: 8px; margin-top: 16px;
height: 16px;
background-color: rgb(5, 95, 194);
border-top-right-radius: 3px;
border-bottom-right-radius: 3px;
position: absolute;
top: 17px;
left: 0px;
}
.left-ti2 { .header {
display: flex;
gap: 17px;
.icon {
margin-top: 4px;
width: 8px; width: 8px;
height: 16px; height: 16px;
background-color: rgb(5, 95, 194); background: var(--color-main-active);
border-top-right-radius: 3px; border-radius: 0 4px 4px 0;
border-bottom-right-radius: 3px;
position: absolute;
top: 207px;
left: 0px;
} }
.left-title { .title {
margin-left: 25px; height: 24px;
color: rgb(5, 95, 194); color: var(--color-main-active);
font-family: "Source Han Sans CN";
font-size: 16px; font-size: 16px;
font-weight: 700; font-weight: 700;
font-family: "Microsoft YaHei";
line-height: 24px; line-height: 24px;
margin-top: 13px; letter-spacing: 1px;
text-align: left;
}
} }
.left-content { .select-main {
width: 253px; margin-left: 24px;
// height: 132px; margin-top: 12px;
margin-left: 25px;
margin-top: 13px;
display: flex;
flex-wrap: wrap;
/* 允许内容换行 */
justify-content: space-between;
/* 两端对齐 */
.left-item {
white-space: nowrap;
/* 保持在一行内 */
overflow: hidden;
/* 隐藏超出部分 */
text-overflow: ellipsis;
/* 超出部分显示省略号 */
width: calc(50% - 8px);
/* 每个选项占一半宽度,减去间距 */
height: 30px;
margin-bottom: 4px;
font-size: 16px;
font-weight: 400;
font-family: "Microsoft YaHei";
line-height: 24px;
color: rgb(95, 101, 108);
input[type="checkbox"] { .checkbox-group {
-webkit-appearance: none; display: grid;
appearance: none; grid-template-columns: repeat(2, 160px);
width: 14px; gap: 8px 4px;
height: 14px;
margin-right: 8px;
border: 1px solid rgb(200, 204, 210);
border-radius: 4px;
background-color: #fff;
vertical-align: middle;
}
input[type="checkbox"]:checked { :deep(.all-checkbox) {
background-color: rgb(5, 95, 194); width: 160px;
border-top-right-radius: 3px; height: 24px;
border-bottom-right-radius: 3px; margin: 0;
margin-right: 17px;
} }
input[type="checkbox"]:checked::after { :deep(.filter-checkbox) {
content: ""; width: 160px;
display: block; height: 24px;
width: 4px; margin-right: 0 !important;
height: 8px;
margin: 1px auto 0;
border: 2px solid #fff;
border-top: none;
border-left: none;
transform: rotate(45deg);
} }
} }
} }
.cl1 {
margin-top: 21px;
} }
} }
.right { .right {
width: 1284px; width: 1224px;
height: 1489px;
border-radius: 10px; border-radius: 10px;
background-color: #fff; background-color: #fff;
box-shadow: 0px 0px 20px 0px rgba(25, 69, 130, 0.1); box-shadow: 0px 0px 20px 0px rgba(25, 69, 130, 0.1);
.right-title { .right-title {
width: 1284px; width: 1224px;
height: 48px; height: 48px;
border-bottom: 1px solid rgb(235, 238, 242); border-bottom: 1px solid rgb(235, 238, 242);
position: relative; position: relative;
...@@ -550,13 +488,13 @@ onMounted(async () => { ...@@ -550,13 +488,13 @@ onMounted(async () => {
} }
.right-main { .right-main {
width: 1284px; width: 1224px;
height: 1441px;
padding: 19px 34px 20px 29px; padding: 19px 34px 20px 29px;
position: relative; position: relative;
.right-item { .right-item {
width: 1221px; width: 1161px;
height: 124px; height: 124px;
border-bottom: 1px solid rgb(234, 236, 238); border-bottom: 1px solid rgb(234, 236, 238);
margin-bottom: 8px; margin-bottom: 8px;
...@@ -588,7 +526,7 @@ onMounted(async () => { ...@@ -588,7 +526,7 @@ onMounted(async () => {
/* 隐藏超出部分 */ /* 隐藏超出部分 */
text-overflow: ellipsis; text-overflow: ellipsis;
/* 超出部分显示省略号 */ /* 超出部分显示省略号 */
width: 90%; width: 1112px;
/* 设置一个固定的宽度或百分比 */ /* 设置一个固定的宽度或百分比 */
position: absolute; position: absolute;
top: 44px; top: 44px;
...@@ -605,6 +543,7 @@ onMounted(async () => { ...@@ -605,6 +543,7 @@ onMounted(async () => {
top: 76px; top: 76px;
left: 56px; left: 56px;
display: flex; display: flex;
gap: 8px;
.right-item-pie-item { .right-item-pie-item {
padding: 2px 8px; padding: 2px 8px;
...@@ -677,15 +616,16 @@ onMounted(async () => { ...@@ -677,15 +616,16 @@ onMounted(async () => {
} }
.page { .page {
width: 1221px; width: 1161px;
height: 40px; height: 40px;
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: space-between; justify-content: space-between;
position: absolute;
bottom: 20px;
left: 20px; margin-top: 29px;
padding-left: 11px;
.count { .count {
font-size: 16px; font-size: 16px;
...@@ -749,7 +689,10 @@ onMounted(async () => { ...@@ -749,7 +689,10 @@ onMounted(async () => {
background-color: #fff; background-color: #fff;
} }
} }
} }
} }
} }
} }
......
...@@ -14,14 +14,8 @@ ...@@ -14,14 +14,8 @@
<div class="main-content" ref="containerRef"> <div class="main-content" ref="containerRef">
<div class="home-top-bg"></div> <div class="home-top-bg"></div>
<!-- 搜索栏部分 --> <!-- 搜索栏部分 -->
<SearchContainer <SearchContainer style="margin-bottom: 48px; height: fit-content" v-if="containerRef" :countInfo="countInfo"
style="margin-bottom: 48px; height: fit-content" placeholder="搜索科研资助实体、资助记录" :containerRef="containerRef" areaName="" />
v-if="containerRef"
:countInfo="countInfo"
placeholder="搜索科研资助实体、资助记录"
:containerRef="containerRef"
areaName=""
/>
<!-- <div class="search"> --> <!-- <div class="search"> -->
<!-- <div class="search-main"> <!-- <div class="search-main">
...@@ -78,7 +72,8 @@ ...@@ -78,7 +72,8 @@
<!-- </div> --> <!-- </div> -->
<!-- 6个数据 --> <!-- 6个数据 -->
<div class="data"> <div class="data">
<div v-for="(item, index) in dataList" :key="item.id" class="data-item"> <div v-for="(item, index) in dataList" :key="item.orgId || item.id" class="data-item"
@click="handleClickOrg(item)">
<img v-if="item.logoUrl && /\\.(jpe?g|png)$/i.test(item.logoUrl)" :src="item.logoUrl" alt="" /> <img v-if="item.logoUrl && /\\.(jpe?g|png)$/i.test(item.logoUrl)" :src="item.logoUrl" alt="" />
<img v-else src="./assets/images/nullcorpimg.png" alt="" /> <img v-else src="./assets/images/nullcorpimg.png" alt="" />
<div class="data-text-item"> <div class="data-text-item">
...@@ -91,28 +86,28 @@ ...@@ -91,28 +86,28 @@
</div> </div>
<!-- 最新动态 --> <!-- 最新动态 -->
<div class="newdata" id="position1"> <div class="newdata" id="position1">
<com-title title="最新动态" /> <com-title title="最新动态" style="width: 1600px;" />
<div class="newdata-main"> <div class="newdata-main">
<newData /> <newData />
</div> </div>
</div> </div>
<!-- 资讯要问 --> <!-- 资讯要问 -->
<div class="ask" id="position2"> <div class="ask" id="position2">
<com-title title="资讯要闻" /> <com-title title="资讯要闻" style="width: 1600px;" />
<div class="ask-main"> <div class="ask-main">
<askPage /> <askPage />
</div> </div>
</div> </div>
<!-- 数据总览 --> <!-- 数据总览 -->
<div class="datasub" id="position3"> <div class="datasub" id="position3">
<com-title title="数据总览" /> <com-title title="数据总览" style="width: 1600px;" />
<div class="datasub-main"> <div class="datasub-main">
<dataSub /> <dataSub />
</div> </div>
</div> </div>
<!-- 资源库 --> <!-- 资源库 -->
<div class="reslib" id="position4"> <div class="reslib" id="position4">
<com-title title="资源库" /> <com-title title="资源库" style="width: 1600px;" />
<div class="reslib-main"> <div class="reslib-main">
<resLib /> <resLib />
</div> </div>
...@@ -170,6 +165,21 @@ const handleBackHome = () => { ...@@ -170,6 +165,21 @@ const handleBackHome = () => {
path: "/overview" path: "/overview"
}); });
}; };
// 点击机构卡片跳转机构详情
const handleClickOrg = (item) => {
const orgId = item?.orgId;
if (!orgId) return;
// Institution 路由开启了 dynamicTitle,这里提前写入标题,避免沿用上一次的“白宫”等旧值
const title = item?.orgName || "";
window.sessionStorage.setItem("institutionTabName", title);
window.sessionStorage.setItem("curTabName", title);
const route = router.resolve({
path: "/institution",
query: { id: orgId, name: title }
});
window.open(route.href, "_blank");
};
// 固定数据 // 固定数据
const dataList = ref([ const dataList = ref([
{ {
...@@ -576,12 +586,12 @@ onMounted(async () => { ...@@ -576,12 +586,12 @@ onMounted(async () => {
.reslib { .reslib {
width: 1600px; width: 1600px;
height: 1633px;
margin: 0 auto 0px auto; margin: 0 auto 0px auto;
.reslib-main { .reslib-main {
width: 1600px; width: 1600px;
height: 1565px;
margin-top: 26px; margin-top: 26px;
} }
} }
......
...@@ -399,7 +399,8 @@ const reportAuthors = computed(() => { ...@@ -399,7 +399,8 @@ const reportAuthors = computed(() => {
// 点击报告作者头像,跳转到人物主页 // 点击报告作者头像,跳转到人物主页
// 与核心研究人员逻辑一致:核心依赖 personId,本页面依赖作者的 id(作为 personId 传入) // 与核心研究人员逻辑一致:核心依赖 personId,本页面依赖作者的 id(作为 personId 传入)
const handleClickReportAuthor = async (author) => { const handleClickReportAuthor = async (author) => {
const personId = author?.id;
const personId = author?.personId;
if (!personId) return; if (!personId) return;
......
...@@ -96,6 +96,7 @@ ...@@ -96,6 +96,7 @@
</div> </div>
<div class="divider" v-if="index !== hearingData.length - 1"></div> <div class="divider" v-if="index !== hearingData.length - 1"></div>
</div> </div>
</div> </div>
</div> </div>
<div class="right-footer"> <div class="right-footer">
...@@ -107,6 +108,7 @@ ...@@ -107,6 +108,7 @@
@current-change="handleCurrentChange" :current-page="currentPage" /> @current-change="handleCurrentChange" :current-page="currentPage" />
</div> </div>
</div> </div>
</div> </div>
</div> </div>
</template> </template>
...@@ -287,6 +289,12 @@ const handleToReportDetail = item => { ...@@ -287,6 +289,12 @@ const handleToReportDetail = item => {
.main-content { .main-content {
display: flex; display: flex;
gap: 16px; gap: 16px;
height: 100%;
margin-bottom: 100px;
.left { .left {
width: 360px; width: 360px;
...@@ -299,6 +307,7 @@ const handleToReportDetail = item => { ...@@ -299,6 +307,7 @@ const handleToReportDetail = item => {
background: rgba(255, 255, 255, 1); background: rgba(255, 255, 255, 1);
position: relative; position: relative;
.select-research-box { .select-research-box {
width: 360px; width: 360px;
height: 100%; height: 100%;
...@@ -480,14 +489,20 @@ const handleToReportDetail = item => { ...@@ -480,14 +489,20 @@ const handleToReportDetail = item => {
.right { .right {
width: 1224px; width: 1224px;
height: 1377px;
.card-box { .card-box {
width: 100%;
height: 1248px; height: 100%;
display: flex; display: flex;
background: rgba(255, 255, 255, 1); background: rgba(255, 255, 255, 1);
box-sizing: border-box; box-sizing: border-box;
border: 1px solid rgba(234, 236, 238, 1); border: 1px solid rgba(234, 236, 238, 1);
...@@ -495,12 +510,15 @@ const handleToReportDetail = item => { ...@@ -495,12 +510,15 @@ const handleToReportDetail = item => {
box-shadow: 0px 0px 20px 0px rgba(94, 95, 95, 0.1); box-shadow: 0px 0px 20px 0px rgba(94, 95, 95, 0.1);
background: rgba(255, 255, 255, 1); background: rgba(255, 255, 255, 1);
.card-content { .card-content {
width: 1211px; width: 1211px;
height: 1067px;
margin-top: 33px;
margin-top: 33px;
margin-left: 37px; margin-left: 37px;
padding-bottom: 27px;
.card-item { .card-item {
width: 100%; width: 100%;
...@@ -585,8 +603,13 @@ const handleToReportDetail = item => { ...@@ -585,8 +603,13 @@ const handleToReportDetail = item => {
} }
}
.right-footer { .right-footer {
margin-top: 43px;
margin-top: 35px;
display: flex; display: flex;
justify-content: space-between; justify-content: space-between;
...@@ -601,7 +624,6 @@ const handleToReportDetail = item => { ...@@ -601,7 +624,6 @@ const handleToReportDetail = item => {
text-align: left; text-align: left;
} }
} }
}
} }
:deep(.el-checkbox) { :deep(.el-checkbox) {
......
...@@ -58,6 +58,7 @@ ...@@ -58,6 +58,7 @@
<div class="right"> <div class="right">
<div class="card-box"> <div class="card-box">
<div class="card-content"> <div class="card-content">
<div v-for="(item, index) in hearingData" :key="item.id ?? index"> <div v-for="(item, index) in hearingData" :key="item.id ?? index">
<div class="card-item"> <div class="card-item">
<img class="card-item-img" :src="item.coverImgUrl" alt="report image" /> <img class="card-item-img" :src="item.coverImgUrl" alt="report image" />
...@@ -80,9 +81,10 @@ ...@@ -80,9 +81,10 @@
</div> </div>
<div class="divider" v-if="index !== hearingData.length - 1"></div> <div class="divider" v-if="index !== hearingData.length - 1"></div>
</div> </div>
</div>
</div> </div>
</div>
<div class="right-footer"> <div class="right-footer">
<div class="info"> <div class="info">
{{ hearingData.length }} 篇智库报告 {{ hearingData.length }} 篇智库报告
...@@ -92,6 +94,7 @@ ...@@ -92,6 +94,7 @@
@current-change="handlePageChange" :current-page="currentPage" /> @current-change="handlePageChange" :current-page="currentPage" />
</div> </div>
</div> </div>
</div> </div>
</div> </div>
</template> </template>
...@@ -186,6 +189,7 @@ const handlePageChange = page => { ...@@ -186,6 +189,7 @@ const handlePageChange = page => {
.home-main-footer-main { .home-main-footer-main {
margin: 0 auto; margin: 0 auto;
margin-top: 36px; margin-top: 36px;
width: 1600px; width: 1600px;
display: flex; display: flex;
gap: 16px; gap: 16px;
...@@ -270,11 +274,11 @@ const handlePageChange = page => { ...@@ -270,11 +274,11 @@ const handlePageChange = page => {
.right { .right {
width: 1224px; width: 1224px;
height: 1377px;
.card-box { .card-box {
width: 100%; width: 100%;
height: 1134px;
display: flex; display: flex;
background: rgba(255, 255, 255, 1); background: rgba(255, 255, 255, 1);
box-sizing: border-box; box-sizing: border-box;
...@@ -282,16 +286,22 @@ const handlePageChange = page => { ...@@ -282,16 +286,22 @@ const handlePageChange = page => {
border-radius: 10px; border-radius: 10px;
box-shadow: 0px 0px 20px 0px rgba(94, 95, 95, 0.1); box-shadow: 0px 0px 20px 0px rgba(94, 95, 95, 0.1);
padding-right: 36px; padding-right: 36px;
height: 100%;
.card-content { .card-content {
width: 1211px; width: 1211px;
height: 1067px;
margin-top: 33px; margin-top: 33px;
margin-left: 37px; margin-left: 37px;
padding-bottom: 27px;
} }
} }
.right-footer {
}
.right-footer {
margin-top: 43px; margin-top: 43px;
display: flex; display: flex;
justify-content: space-between; justify-content: space-between;
...@@ -306,7 +316,6 @@ const handlePageChange = page => { ...@@ -306,7 +316,6 @@ const handlePageChange = page => {
letter-spacing: 0px; letter-spacing: 0px;
text-align: left; text-align: left;
} }
}
} }
.card-item { .card-item {
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论