feat: 对话功能开发
This commit is contained in:
164
package-lock.json
generated
164
package-lock.json
generated
@@ -17,6 +17,7 @@
|
|||||||
"js-base64": "3.7.5",
|
"js-base64": "3.7.5",
|
||||||
"jsencrypt": "^3.5.4",
|
"jsencrypt": "^3.5.4",
|
||||||
"lucide-vue-next": "^1.0.0",
|
"lucide-vue-next": "^1.0.0",
|
||||||
|
"pdfkit": "^0.18.0",
|
||||||
"pinia": "^3.0.4",
|
"pinia": "^3.0.4",
|
||||||
"vue": "^3.5.32",
|
"vue": "^3.5.32",
|
||||||
"vue-router": "^4.6.4"
|
"vue-router": "^4.6.4"
|
||||||
@@ -2319,6 +2320,30 @@
|
|||||||
"node": ">= 12.13.0"
|
"node": ">= 12.13.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@noble/ciphers": {
|
||||||
|
"version": "1.3.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@noble/ciphers/-/ciphers-1.3.0.tgz",
|
||||||
|
"integrity": "sha512-2I0gnIVPtfnMw9ee9h1dJG7tp81+8Ob3OJb3Mv37rx5L40/b0i7djjCVvGOVqc9AEIQyvyu1i6ypKdFw8R8gQw==",
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": "^14.21.3 || >=16"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://paulmillr.com/funding/"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@noble/hashes": {
|
||||||
|
"version": "1.8.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.8.0.tgz",
|
||||||
|
"integrity": "sha512-jCs9ldd7NwzpgXDIf6P3+NrHh9/sD6CQdxHyjQI+h/6rDNo88ypBxxz45UDuZHz9r3tNz7N/VInSVoVdtXEI4A==",
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": "^14.21.3 || >=16"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://paulmillr.com/funding/"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@nodelib/fs.scandir": {
|
"node_modules/@nodelib/fs.scandir": {
|
||||||
"version": "2.1.5",
|
"version": "2.1.5",
|
||||||
"resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz",
|
"resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz",
|
||||||
@@ -2796,6 +2821,15 @@
|
|||||||
"url": "https://github.com/sindresorhus/is?sponsor=1"
|
"url": "https://github.com/sindresorhus/is?sponsor=1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@swc/helpers": {
|
||||||
|
"version": "0.5.21",
|
||||||
|
"resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.21.tgz",
|
||||||
|
"integrity": "sha512-jI/VAmtdjB/RnI8GTnokyX7Ug8c+g+ffD6QRLa6XQewtnGyukKkKSk3wLTM3b5cjt1jNh9x0jfVlagdN2gDKQg==",
|
||||||
|
"license": "Apache-2.0",
|
||||||
|
"dependencies": {
|
||||||
|
"tslib": "^2.8.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@szmarczak/http-timer": {
|
"node_modules/@szmarczak/http-timer": {
|
||||||
"version": "4.0.6",
|
"version": "4.0.6",
|
||||||
"resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-4.0.6.tgz",
|
"resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-4.0.6.tgz",
|
||||||
@@ -3655,7 +3689,6 @@
|
|||||||
"version": "1.5.1",
|
"version": "1.5.1",
|
||||||
"resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz",
|
"resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz",
|
||||||
"integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==",
|
"integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==",
|
||||||
"dev": true,
|
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
"type": "github",
|
"type": "github",
|
||||||
@@ -3769,6 +3802,15 @@
|
|||||||
"node": ">=8"
|
"node": ">=8"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/brotli": {
|
||||||
|
"version": "1.3.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/brotli/-/brotli-1.3.3.tgz",
|
||||||
|
"integrity": "sha512-oTKjJdShmDuGW94SyyaoQvAjf30dZaHnjJ8uAF+u2/vGJkJbJPJAT1gDiOJP5v1Zb6f9KEyW/1HpuaWIXtGHPg==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"base64-js": "^1.1.2"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/browserslist": {
|
"node_modules/browserslist": {
|
||||||
"version": "4.28.2",
|
"version": "4.28.2",
|
||||||
"resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.2.tgz",
|
"resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.2.tgz",
|
||||||
@@ -4654,6 +4696,12 @@
|
|||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"optional": true
|
"optional": true
|
||||||
},
|
},
|
||||||
|
"node_modules/dfa": {
|
||||||
|
"version": "1.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/dfa/-/dfa-1.2.0.tgz",
|
||||||
|
"integrity": "sha512-ED3jP8saaweFTjeGX8HQPjeC1YYyZs98jGNZx6IiBvxW7JG5v492kamAQB3m2wop07CvU/RQmzcKr6bgcC5D/Q==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/didyoumean": {
|
"node_modules/didyoumean": {
|
||||||
"version": "1.2.2",
|
"version": "1.2.2",
|
||||||
"resolved": "https://registry.npmjs.org/didyoumean/-/didyoumean-1.2.2.tgz",
|
"resolved": "https://registry.npmjs.org/didyoumean/-/didyoumean-1.2.2.tgz",
|
||||||
@@ -5982,6 +6030,32 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/fontkit": {
|
||||||
|
"version": "2.0.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/fontkit/-/fontkit-2.0.4.tgz",
|
||||||
|
"integrity": "sha512-syetQadaUEDNdxdugga9CpEYVaQIxOwk7GlwZWWZ19//qW4zE5bknOKeMBDYAASwnpaSHKJITRLMF9m1fp3s6g==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@swc/helpers": "^0.5.12",
|
||||||
|
"brotli": "^1.3.2",
|
||||||
|
"clone": "^2.1.2",
|
||||||
|
"dfa": "^1.2.0",
|
||||||
|
"fast-deep-equal": "^3.1.3",
|
||||||
|
"restructure": "^3.0.0",
|
||||||
|
"tiny-inflate": "^1.0.3",
|
||||||
|
"unicode-properties": "^1.4.0",
|
||||||
|
"unicode-trie": "^2.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/fontkit/node_modules/clone": {
|
||||||
|
"version": "2.1.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/clone/-/clone-2.1.2.tgz",
|
||||||
|
"integrity": "sha512-3Pe/CF1Nn94hyhIYpjtiLhdCoEoz0DqQ+988E9gmeEdQZlojxnOb74wctFyuwWQHzqyf9X7C7MG8juUpqBJT8w==",
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=0.8"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/form-data": {
|
"node_modules/form-data": {
|
||||||
"version": "4.0.5",
|
"version": "4.0.5",
|
||||||
"resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.5.tgz",
|
"resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.5.tgz",
|
||||||
@@ -6927,6 +7001,12 @@
|
|||||||
"integrity": "sha512-3MEt5DTINKqfScXKfJFrRbxkrnk2AxPWGBL/ycjz4dK8iqiSJ06UxD8jh8xuh6p10TX4t2+7FsBYVxxQbMg+qA==",
|
"integrity": "sha512-3MEt5DTINKqfScXKfJFrRbxkrnk2AxPWGBL/ycjz4dK8iqiSJ06UxD8jh8xuh6p10TX4t2+7FsBYVxxQbMg+qA==",
|
||||||
"license": "BSD-3-Clause"
|
"license": "BSD-3-Clause"
|
||||||
},
|
},
|
||||||
|
"node_modules/js-md5": {
|
||||||
|
"version": "0.8.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/js-md5/-/js-md5-0.8.3.tgz",
|
||||||
|
"integrity": "sha512-qR0HB5uP6wCuRMrWPTrkMaev7MJZwJuuw4fnwAzRgP4J4/F8RwtodOKpGp4XpqsLBFzzgqIO42efFAyz2Et6KQ==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/js-tokens": {
|
"node_modules/js-tokens": {
|
||||||
"version": "4.0.0",
|
"version": "4.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
|
||||||
@@ -7028,6 +7108,25 @@
|
|||||||
"url": "https://github.com/sponsors/antonk52"
|
"url": "https://github.com/sponsors/antonk52"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/linebreak": {
|
||||||
|
"version": "1.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/linebreak/-/linebreak-1.1.0.tgz",
|
||||||
|
"integrity": "sha512-MHp03UImeVhB7XZtjd0E4n6+3xr5Dq/9xI/5FptGk5FrbDR3zagPa2DS6U8ks/3HjbKWG9Q1M2ufOzxV2qLYSQ==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"base64-js": "0.0.8",
|
||||||
|
"unicode-trie": "^2.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/linebreak/node_modules/base64-js": {
|
||||||
|
"version": "0.0.8",
|
||||||
|
"resolved": "https://registry.npmjs.org/base64-js/-/base64-js-0.0.8.tgz",
|
||||||
|
"integrity": "sha512-3XSA2cR/h/73EzlXXdU6YNycmYI7+kicTxks4eJg2g39biHR84slg2+des+p7iHYhbRg/udIS4TD53WabcOUkw==",
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.4"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/lines-and-columns": {
|
"node_modules/lines-and-columns": {
|
||||||
"version": "1.2.4",
|
"version": "1.2.4",
|
||||||
"resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz",
|
"resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz",
|
||||||
@@ -8347,6 +8446,12 @@
|
|||||||
"node": ">=4"
|
"node": ">=4"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/pako": {
|
||||||
|
"version": "0.2.9",
|
||||||
|
"resolved": "https://registry.npmjs.org/pako/-/pako-0.2.9.tgz",
|
||||||
|
"integrity": "sha512-NUcwaKxUxWrZLpDG+z/xZaCgQITkA/Dv4V/T6bw7VON6l1Xz/VnrBqrYjZQ12TamKHzITTfOEIYUj48y2KXImA==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/parent-module": {
|
"node_modules/parent-module": {
|
||||||
"version": "1.0.1",
|
"version": "1.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz",
|
||||||
@@ -8436,6 +8541,20 @@
|
|||||||
"node": ">=4"
|
"node": ">=4"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/pdfkit": {
|
||||||
|
"version": "0.18.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/pdfkit/-/pdfkit-0.18.0.tgz",
|
||||||
|
"integrity": "sha512-NvUwSDZ0eYEzqAiWwVQkRkjYUkZ48kcsHuCO31ykqPPIVkwoSDjDGiwIgHHNtsiwls3z3P/zy4q00hl2chg2Ug==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@noble/ciphers": "^1.0.0",
|
||||||
|
"@noble/hashes": "^1.6.0",
|
||||||
|
"fontkit": "^2.0.4",
|
||||||
|
"js-md5": "^0.8.3",
|
||||||
|
"linebreak": "^1.1.0",
|
||||||
|
"png-js": "^1.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/pe-library": {
|
"node_modules/pe-library": {
|
||||||
"version": "1.0.1",
|
"version": "1.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/pe-library/-/pe-library-1.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/pe-library/-/pe-library-1.0.1.tgz",
|
||||||
@@ -8539,6 +8658,11 @@
|
|||||||
"node": ">=10.4.0"
|
"node": ">=10.4.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/png-js": {
|
||||||
|
"version": "1.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/png-js/-/png-js-1.0.0.tgz",
|
||||||
|
"integrity": "sha512-k+YsbhpA9e+EFfKjTCH3VW6aoKlyNYI6NYdTfDL4CIvFnvsuO84ttonmZE7rc+v23SLTH8XX+5w/Ak9v0xGY4g=="
|
||||||
|
},
|
||||||
"node_modules/postcss": {
|
"node_modules/postcss": {
|
||||||
"version": "8.5.9",
|
"version": "8.5.9",
|
||||||
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.9.tgz",
|
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.9.tgz",
|
||||||
@@ -9038,6 +9162,12 @@
|
|||||||
"url": "https://github.com/sponsors/sindresorhus"
|
"url": "https://github.com/sponsors/sindresorhus"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/restructure": {
|
||||||
|
"version": "3.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/restructure/-/restructure-3.0.2.tgz",
|
||||||
|
"integrity": "sha512-gSfoiOEA0VPE6Tukkrr7I0RBdE0s7H1eFCDBk05l1KIQT1UIKNc5JZy6jdyW6eYH3aR3g5b3PuL77rq0hvwtAw==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/retry": {
|
"node_modules/retry": {
|
||||||
"version": "0.12.0",
|
"version": "0.12.0",
|
||||||
"resolved": "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz",
|
"resolved": "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz",
|
||||||
@@ -9893,6 +10023,12 @@
|
|||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"optional": true
|
"optional": true
|
||||||
},
|
},
|
||||||
|
"node_modules/tiny-inflate": {
|
||||||
|
"version": "1.0.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/tiny-inflate/-/tiny-inflate-1.0.3.tgz",
|
||||||
|
"integrity": "sha512-pkY1fj1cKHb2seWDy0B16HeWyczlJA9/WW3u3c4z/NiWDsO3DOU5D7nhTLE9CF0yXv/QZFY7sEJmj24dK+Rrqw==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/tinyexec": {
|
"node_modules/tinyexec": {
|
||||||
"version": "1.1.1",
|
"version": "1.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-1.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-1.1.1.tgz",
|
||||||
@@ -10037,6 +10173,12 @@
|
|||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "Apache-2.0"
|
"license": "Apache-2.0"
|
||||||
},
|
},
|
||||||
|
"node_modules/tslib": {
|
||||||
|
"version": "2.8.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz",
|
||||||
|
"integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==",
|
||||||
|
"license": "0BSD"
|
||||||
|
},
|
||||||
"node_modules/type-fest": {
|
"node_modules/type-fest": {
|
||||||
"version": "1.4.0",
|
"version": "1.4.0",
|
||||||
"resolved": "https://registry.npmjs.org/type-fest/-/type-fest-1.4.0.tgz",
|
"resolved": "https://registry.npmjs.org/type-fest/-/type-fest-1.4.0.tgz",
|
||||||
@@ -10072,6 +10214,26 @@
|
|||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
|
"node_modules/unicode-properties": {
|
||||||
|
"version": "1.4.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/unicode-properties/-/unicode-properties-1.4.1.tgz",
|
||||||
|
"integrity": "sha512-CLjCCLQ6UuMxWnbIylkisbRj31qxHPAurvena/0iwSVbQ2G1VY5/HjV0IRabOEbDHlzZlRdCrD4NhB0JtU40Pg==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"base64-js": "^1.3.0",
|
||||||
|
"unicode-trie": "^2.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/unicode-trie": {
|
||||||
|
"version": "2.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/unicode-trie/-/unicode-trie-2.0.0.tgz",
|
||||||
|
"integrity": "sha512-x7bc76x0bm4prf1VLg79uhAzKw8DVboClSN5VxJuQ+LKDOVEW9CdH+VY7SP+vX7xCYQqzzgQpFqz15zeLvAtZQ==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"pako": "^0.2.5",
|
||||||
|
"tiny-inflate": "^1.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/unique-filename": {
|
"node_modules/unique-filename": {
|
||||||
"version": "2.0.1",
|
"version": "2.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/unique-filename/-/unique-filename-2.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/unique-filename/-/unique-filename-2.0.1.tgz",
|
||||||
|
|||||||
@@ -46,12 +46,13 @@
|
|||||||
"bonjour-service": "^1.3.0",
|
"bonjour-service": "^1.3.0",
|
||||||
"electron-squirrel-startup": "^1.0.1",
|
"electron-squirrel-startup": "^1.0.1",
|
||||||
"element-plus": "^2.13.6",
|
"element-plus": "^2.13.6",
|
||||||
|
"js-base64": "3.7.5",
|
||||||
|
"jsencrypt": "^3.5.4",
|
||||||
"lucide-vue-next": "^1.0.0",
|
"lucide-vue-next": "^1.0.0",
|
||||||
|
"pdfkit": "^0.18.0",
|
||||||
"pinia": "^3.0.4",
|
"pinia": "^3.0.4",
|
||||||
"vue": "^3.5.32",
|
"vue": "^3.5.32",
|
||||||
"vue-router": "^4.6.4",
|
"vue-router": "^4.6.4"
|
||||||
"js-base64": "3.7.5",
|
|
||||||
"jsencrypt": "^3.5.4"
|
|
||||||
},
|
},
|
||||||
"lint-staged": {
|
"lint-staged": {
|
||||||
"*.{js,vue}": [
|
"*.{js,vue}": [
|
||||||
|
|||||||
@@ -161,14 +161,6 @@ async function loadHistorySessions() {
|
|||||||
|
|
||||||
// 点击历史会话,跳转到对话页面并加载该会话
|
// 点击历史会话,跳转到对话页面并加载该会话
|
||||||
async function onHistoryClick(item) {
|
async function onHistoryClick(item) {
|
||||||
try {
|
|
||||||
const baseUrl = window.__opencodeBaseUrl || 'http://127.0.0.1:4096';
|
|
||||||
const detailUrl = `${baseUrl}/session/${item.id}/message`;
|
|
||||||
const response = await axios.get(detailUrl);
|
|
||||||
console.log('[onHistoryClick] 会话详情数据:', response.data);
|
|
||||||
} catch (err) {
|
|
||||||
console.error('[onHistoryClick] 获取会话详情失败:', err);
|
|
||||||
}
|
|
||||||
// 跳转到对话页面
|
// 跳转到对话页面
|
||||||
router.push({
|
router.push({
|
||||||
name: 'Chat',
|
name: 'Chat',
|
||||||
|
|||||||
@@ -9,25 +9,102 @@
|
|||||||
<div v-for="msg in messages" :key="msg.id" class="bubble-wrap" :class="msg.role">
|
<div v-for="msg in messages" :key="msg.id" class="bubble-wrap" :class="msg.role">
|
||||||
<div class="bubble">
|
<div class="bubble">
|
||||||
<!-- 推理过程(仅助手消息显示) -->
|
<!-- 推理过程(仅助手消息显示) -->
|
||||||
<div v-if="msg.parts?.reasoning?.length > 0" class="reasoning-section">
|
<div v-if="msg.parts?.filter((p) => p.type === 'reasoning').length > 0" class="reasoning-section">
|
||||||
<div class="reasoning-header" @click="msg.showReasoning = !msg.showReasoning">
|
<div class="reasoning-header" @click="msg.showReasoning = !msg.showReasoning">
|
||||||
<el-icon :size="14"><ArrowRight v-if="!msg.showReasoning" /><ArrowDown v-else /></el-icon>
|
<el-icon :size="14"><ArrowRight v-if="!msg.showReasoning" /><ArrowDown v-else /></el-icon>
|
||||||
<span>思考过程</span>
|
<span>思考过程</span>
|
||||||
</div>
|
</div>
|
||||||
<div v-show="msg.showReasoning" class="reasoning-content">
|
<div v-show="msg.showReasoning" class="reasoning-content">
|
||||||
<div v-for="(r, idx) in msg.parts.reasoning" :key="idx" class="reasoning-item">
|
<div v-for="(r, idx) in msg.parts.filter((p) => p.type === 'reasoning')" :key="idx" class="reasoning-item">
|
||||||
{{ r.text }}
|
{{ r.text }}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<!-- 文本内容 -->
|
<!-- 文本内容 -->
|
||||||
<pre class="bubble-text">{{ msg.text }}</pre>
|
<pre v-if="msg.text" class="bubble-text">{{ msg.text }}</pre>
|
||||||
|
<!-- question 类型 part 展示 -->
|
||||||
|
<template v-if="msg.parts">
|
||||||
|
<div v-for="(p, idx) in msg.parts.filter((p) => p.type === 'question')" :key="'question-' + idx" class="question-part">
|
||||||
|
<div v-for="(q, qi) in p.questions" :key="qi" class="question-item">
|
||||||
|
<div class="question-header">{{ q.header }}</div>
|
||||||
|
<div class="question-text">{{ q.question }}</div>
|
||||||
|
<div class="question-options">
|
||||||
|
<div v-for="(opt, oi) in q.options" :key="oi" class="question-option" @click="sendAnswer(p.id, opt.label)">
|
||||||
|
<span class="option-label">{{ opt.label }}</span>
|
||||||
|
<span v-if="opt.description" class="option-desc">{{ opt.description }}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<!-- tool 类型 part 展示 -->
|
||||||
|
<template v-if="msg.parts">
|
||||||
|
<template v-for="(p, idx) in msg.parts.filter((p) => p.type === 'tool')" :key="'tool-' + idx">
|
||||||
|
<!-- question 工具:展示问答卡片(历史加载,状态为 running 时仍可回复) -->
|
||||||
|
<div v-if="p.tool === 'question'" class="question-part">
|
||||||
|
<div v-for="(q, qi) in p.state?.input?.questions || []" :key="qi" class="question-item">
|
||||||
|
<div class="question-header">{{ q.header }}</div>
|
||||||
|
<div class="question-text">{{ q.question }}</div>
|
||||||
|
<div class="question-options">
|
||||||
|
<div
|
||||||
|
v-for="(opt, oi) in q.options"
|
||||||
|
:key="oi"
|
||||||
|
class="question-option"
|
||||||
|
:class="{ disabled: p.state?.status !== 'running' }"
|
||||||
|
@click="p.state?.status === 'running' && p._questionId && sendAnswer(p._questionId, opt.label)"
|
||||||
|
>
|
||||||
|
<span class="option-radio"></span>
|
||||||
|
<span class="option-content">
|
||||||
|
<span class="option-label">{{ opt.label }}</span>
|
||||||
|
<span v-if="opt.description" class="option-desc">{{ opt.description }}</span>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- 普通工具:展示终端卡片 -->
|
||||||
|
<div v-else class="tool-part">
|
||||||
|
<div class="tool-header" @click="p._expanded = !p._expanded">
|
||||||
|
<el-icon :size="13"><ArrowRight v-if="!p._expanded" /><ArrowDown v-else /></el-icon>
|
||||||
|
<span class="tool-name">{{ p.tool }}</span>
|
||||||
|
<span class="tool-desc">{{ p.state?.input?.description || p.state?.title || '' }}</span>
|
||||||
|
<span class="tool-status" :class="'status-' + (p.state?.status || 'unknown')">{{ p.state?.status || '' }}</span>
|
||||||
|
</div>
|
||||||
|
<div v-show="p._expanded" class="tool-body">
|
||||||
|
<div v-if="p.state?.input?.command" class="tool-command">
|
||||||
|
<span class="tool-label">$ </span><code>{{ p.state.input.command }}</code>
|
||||||
|
</div>
|
||||||
|
<pre v-if="p.state?.output" class="tool-output">{{ p.state.output }}</pre>
|
||||||
|
<div v-if="p.state?.time" class="tool-time">耗时 {{ p.state.time.end - p.state.time.start }} ms</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</template>
|
||||||
|
<!-- 未知类型 part 原始展示 -->
|
||||||
|
<template v-if="msg.parts">
|
||||||
|
<div
|
||||||
|
v-for="(p, idx) in msg.parts.filter(
|
||||||
|
(p) =>
|
||||||
|
p.type !== 'text' &&
|
||||||
|
p.type !== 'reasoning' &&
|
||||||
|
p.type !== 'tool' &&
|
||||||
|
p.type !== 'question' &&
|
||||||
|
p.type !== 'step-start' &&
|
||||||
|
p.type !== 'step-finish'
|
||||||
|
)"
|
||||||
|
:key="'raw-' + idx"
|
||||||
|
class="raw-part"
|
||||||
|
>
|
||||||
|
<span class="raw-part-type">[{{ p.type }}]</span>
|
||||||
|
<pre class="raw-part-content">{{ JSON.stringify(p, null, 2) }}</pre>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- 输入区 -->
|
<!-- 输入区 -->
|
||||||
<div class="input-area">
|
<div v-if="!hasActiveQuestion" class="input-area">
|
||||||
<el-input
|
<el-input
|
||||||
v-model="inputText"
|
v-model="inputText"
|
||||||
type="textarea"
|
type="textarea"
|
||||||
@@ -43,7 +120,7 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { ref, computed, onMounted, onUnmounted, nextTick, watch } from 'vue';
|
import { ref, computed, onMounted, onUnmounted, nextTick, watch, reactive } from 'vue';
|
||||||
import { useRoute, useRouter } from 'vue-router';
|
import { useRoute, useRouter } from 'vue-router';
|
||||||
import { ElMessage } from 'element-plus';
|
import { ElMessage } from 'element-plus';
|
||||||
import { ChatDotRound, ArrowRight, ArrowDown } from '@element-plus/icons-vue';
|
import { ChatDotRound, ArrowRight, ArrowDown } from '@element-plus/icons-vue';
|
||||||
@@ -60,6 +137,18 @@ const messages = ref([]);
|
|||||||
const messagesRef = ref(null);
|
const messagesRef = ref(null);
|
||||||
const currentSessionId = ref(null);
|
const currentSessionId = ref(null);
|
||||||
const localAssistantMessageIds = new Set();
|
const localAssistantMessageIds = new Set();
|
||||||
|
|
||||||
|
// 是否有正在等待回答的 question
|
||||||
|
const hasActiveQuestion = computed(() => {
|
||||||
|
for (const msg of messages.value) {
|
||||||
|
if (!msg.parts) continue;
|
||||||
|
for (const p of msg.parts) {
|
||||||
|
if (p.type === 'tool' && p.tool === 'question' && p.state?.status === 'running' && p._questionId) return true;
|
||||||
|
if (p.type === 'question') return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
});
|
||||||
let unsubscribeCallbacks = [];
|
let unsubscribeCallbacks = [];
|
||||||
|
|
||||||
// 从路由参数中获取 sessionId
|
// 从路由参数中获取 sessionId
|
||||||
@@ -92,38 +181,22 @@ async function loadHistoryMessages(sessionId) {
|
|||||||
const { info, parts } = item;
|
const { info, parts } = item;
|
||||||
if (!info || !parts) return;
|
if (!info || !parts) return;
|
||||||
|
|
||||||
// 按 type 分类存储 parts
|
|
||||||
const partsByType = {
|
|
||||||
text: [],
|
|
||||||
reasoning: [],
|
|
||||||
'step-start': [],
|
|
||||||
'step-finish': [],
|
|
||||||
// 可以在这里添加更多 type
|
|
||||||
};
|
|
||||||
|
|
||||||
parts.forEach((part) => {
|
|
||||||
if (partsByType.hasOwnProperty(part.type)) {
|
|
||||||
partsByType[part.type].push(part);
|
|
||||||
} else {
|
|
||||||
// 未识别的 type 统一放到 others
|
|
||||||
if (!partsByType.others) partsByType.others = [];
|
|
||||||
partsByType.others.push(part);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
console.log(`[loadHistoryMessages] 消息 ${info.id} 的 parts 分类:`, partsByType);
|
|
||||||
|
|
||||||
// 提取文本内容(用于展示)
|
// 提取文本内容(用于展示)
|
||||||
const text = partsByType.text.map((part) => part.text).join('');
|
const text = parts
|
||||||
|
.filter((p) => p.type === 'text')
|
||||||
|
.map((part) => part.text)
|
||||||
|
.join('');
|
||||||
|
// 为每个 part 初始化响应式字段
|
||||||
|
const normalizedParts = parts.map((p) => (p.type === 'tool' ? { ...p, _expanded: true, _freeInput: p.tool === 'question' ? '' : undefined } : p));
|
||||||
|
// 提取 question 类型 part(来自 question.asked 事件,历史中可能存在)
|
||||||
|
|
||||||
if (text || info.role === 'assistant') {
|
if (text || info.role === 'assistant') {
|
||||||
messages.value.push({
|
messages.value.push({
|
||||||
id: info.id,
|
id: info.id,
|
||||||
role: info.role,
|
role: info.role,
|
||||||
text: text,
|
text: text,
|
||||||
parts: partsByType, // 存储分类后的 parts,方便后续按 type 渲染
|
parts: normalizedParts,
|
||||||
rawParts: parts, // 保留原始 parts
|
showReasoning: true, // 默认展开推理过程
|
||||||
showReasoning: false, // 默认折叠推理过程
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// 记录 assistant 消息 ID
|
// 记录 assistant 消息 ID
|
||||||
@@ -181,13 +254,32 @@ function scrollToBottom() {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function upsertAssistantBubble(msgId, text) {
|
function upsertAssistantPart(msgId, part) {
|
||||||
const existing = messages.value.find((m) => m.id === msgId);
|
let existing = messages.value.find((m) => m.id === msgId);
|
||||||
if (existing) {
|
if (!existing) {
|
||||||
existing.text = text;
|
existing = { id: msgId, role: 'assistant', text: '', parts: [], showReasoning: true };
|
||||||
} else {
|
messages.value.push(existing);
|
||||||
messages.value.push({ id: msgId, role: 'assistant', text });
|
|
||||||
}
|
}
|
||||||
|
if (!existing.parts) existing.parts = [];
|
||||||
|
|
||||||
|
// 找到同类型同 partID 的 part,有则更新,无则追加
|
||||||
|
const partId = part.id || part.partID;
|
||||||
|
const idx = partId ? existing.parts.findIndex((p) => (p.id || p.partID) === partId) : -1;
|
||||||
|
if (idx >= 0) {
|
||||||
|
const preserved = { _expanded: existing.parts[idx]._expanded, _freeInput: existing.parts[idx]._freeInput, _questionId: existing.parts[idx]._questionId };
|
||||||
|
existing.parts[idx] = { ...existing.parts[idx], ...part, ...preserved };
|
||||||
|
} else {
|
||||||
|
const newPart = { ...part };
|
||||||
|
if (newPart.type === 'tool' && newPart._expanded === undefined) newPart._expanded = true;
|
||||||
|
if (newPart.type === 'tool' && newPart.tool === 'question' && newPart._freeInput === undefined) newPart._freeInput = '';
|
||||||
|
existing.parts.push(newPart);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 同步 text 字段(取所有 text 类型 part 拼接)
|
||||||
|
existing.text = existing.parts
|
||||||
|
.filter((p) => p.type === 'text')
|
||||||
|
.map((p) => p.text || '')
|
||||||
|
.join('');
|
||||||
scrollToBottom();
|
scrollToBottom();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -199,12 +291,12 @@ function registerSSEListeners() {
|
|||||||
const unsubscribePartUpdated = sseManager.on('message.part.updated', (data) => {
|
const unsubscribePartUpdated = sseManager.on('message.part.updated', (data) => {
|
||||||
const props = data.properties || {};
|
const props = data.properties || {};
|
||||||
const part = props.part;
|
const part = props.part;
|
||||||
if (!part || part.type !== 'text') return;
|
if (!part) return;
|
||||||
if (part.sessionID !== currentSessionId.value) return;
|
if (part.sessionID !== currentSessionId.value) return;
|
||||||
// 通过 messageID 前缀区分用户/助手消息:只渲染 assistant 消息的 part
|
// 通过 messageID 前缀区分用户/助手消息:只渲染 assistant 消息的 part
|
||||||
// assistant 消息的 messageID 会在 message.updated 事件中记录,用 localAssistantMessageIds 集合过滤
|
// assistant 消息的 messageID 会在 message.updated 事件中记录,用 localAssistantMessageIds 集合过滤
|
||||||
if (!localAssistantMessageIds.has(part.messageID) && !appStore.isAssistantMessage(part.messageID)) return;
|
if (!localAssistantMessageIds.has(part.messageID) && !appStore.isAssistantMessage(part.messageID)) return;
|
||||||
upsertAssistantBubble(part.messageID, part.text || '');
|
upsertAssistantPart(part.messageID, part);
|
||||||
});
|
});
|
||||||
|
|
||||||
// 监听消息更新事件
|
// 监听消息更新事件
|
||||||
@@ -227,8 +319,31 @@ function registerSSEListeners() {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// 监听 question.asked 事件
|
||||||
|
const unsubscribeQuestionAsked = sseManager.on('question.asked', (data) => {
|
||||||
|
const props = data.properties || {};
|
||||||
|
if (props.sessionID !== currentSessionId.value) return;
|
||||||
|
const msgId = props.tool?.messageID;
|
||||||
|
const callId = props.tool?.callID;
|
||||||
|
if (!msgId) return;
|
||||||
|
// 将 question 作为一个 part 插入对应消息
|
||||||
|
upsertAssistantPart(msgId, {
|
||||||
|
id: props.id,
|
||||||
|
type: 'question',
|
||||||
|
questions: props.questions || [],
|
||||||
|
});
|
||||||
|
// 同时将 question id 关联到对应的 tool part(通过 callID 匹配)
|
||||||
|
if (callId) {
|
||||||
|
const msg = messages.value.find((m) => m.id === msgId);
|
||||||
|
if (msg && msg.parts) {
|
||||||
|
const toolPart = msg.parts.find((p) => p.type === 'tool' && p.callID === callId);
|
||||||
|
if (toolPart) toolPart._questionId = props.id;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
// 保存取消订阅函数
|
// 保存取消订阅函数
|
||||||
unsubscribeCallbacks.push(unsubscribePartUpdated, unsubscribeMessageUpdated, unsubscribeSessionIdle);
|
unsubscribeCallbacks.push(unsubscribePartUpdated, unsubscribeMessageUpdated, unsubscribeSessionIdle, unsubscribeQuestionAsked);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -243,6 +358,21 @@ function unregisterSSEListeners() {
|
|||||||
unsubscribeCallbacks = [];
|
unsubscribeCallbacks = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function sendAnswer(questionId, label) {
|
||||||
|
if (!currentSessionId.value) return;
|
||||||
|
messages.value.push({ id: Date.now(), role: 'user', text: label });
|
||||||
|
isSending.value = true;
|
||||||
|
scrollToBottom();
|
||||||
|
try {
|
||||||
|
const baseUrl = window.__opencodeBaseUrl || 'http://127.0.0.1:4096';
|
||||||
|
await axios.post(`${baseUrl}/question/${questionId}/reply`, { answers: [[label]] });
|
||||||
|
} catch (err) {
|
||||||
|
console.error('发送答案失败:', err);
|
||||||
|
ElMessage.error(`发送失败: ${err.message}`);
|
||||||
|
isSending.value = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
async function send() {
|
async function send() {
|
||||||
const text = inputText.value.trim();
|
const text = inputText.value.trim();
|
||||||
if (!text || isSending.value) return;
|
if (!text || isSending.value) return;
|
||||||
@@ -399,6 +529,243 @@ onUnmounted(() => {
|
|||||||
margin: 4px 0;
|
margin: 4px 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.tool-part {
|
||||||
|
margin-top: 6px;
|
||||||
|
border-radius: 6px;
|
||||||
|
background: #1e1e2e;
|
||||||
|
color: #cdd6f4;
|
||||||
|
overflow: hidden;
|
||||||
|
font-size: 13px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tool-header {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 6px;
|
||||||
|
padding: 6px 10px;
|
||||||
|
cursor: pointer;
|
||||||
|
user-select: none;
|
||||||
|
transition: background 0.2s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tool-header:hover {
|
||||||
|
background: rgba(255, 255, 255, 0.05);
|
||||||
|
}
|
||||||
|
|
||||||
|
.tool-name {
|
||||||
|
font-weight: bold;
|
||||||
|
color: #89b4fa;
|
||||||
|
font-family: monospace;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tool-desc {
|
||||||
|
flex: 1;
|
||||||
|
color: #a6adc8;
|
||||||
|
font-size: 12px;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tool-status {
|
||||||
|
font-size: 11px;
|
||||||
|
padding: 1px 6px;
|
||||||
|
border-radius: 10px;
|
||||||
|
background: rgba(255, 255, 255, 0.08);
|
||||||
|
}
|
||||||
|
|
||||||
|
.tool-status.status-completed {
|
||||||
|
color: #a6e3a1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tool-status.status-running {
|
||||||
|
color: #f9e2af;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tool-status.status-error {
|
||||||
|
color: #f38ba8;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tool-body {
|
||||||
|
padding: 0 10px 8px;
|
||||||
|
border-top: 1px solid rgba(255, 255, 255, 0.06);
|
||||||
|
}
|
||||||
|
|
||||||
|
.tool-command {
|
||||||
|
padding: 6px 0 4px;
|
||||||
|
font-family: monospace;
|
||||||
|
font-size: 13px;
|
||||||
|
color: #cba6f7;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tool-label {
|
||||||
|
color: #a6e3a1;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tool-output {
|
||||||
|
margin: 4px 0 0;
|
||||||
|
padding: 6px 8px;
|
||||||
|
background: rgba(0, 0, 0, 0.3);
|
||||||
|
border-radius: 4px;
|
||||||
|
font-size: 12px;
|
||||||
|
color: #cdd6f4;
|
||||||
|
white-space: pre-wrap;
|
||||||
|
word-break: break-all;
|
||||||
|
font-family: monospace;
|
||||||
|
max-height: 300px;
|
||||||
|
overflow-y: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tool-time {
|
||||||
|
font-size: 11px;
|
||||||
|
color: #6c7086;
|
||||||
|
margin-top: 4px;
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
|
|
||||||
|
.question-part {
|
||||||
|
margin-top: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.question-item {
|
||||||
|
border: 1px solid #e0e4ea;
|
||||||
|
border-radius: 8px;
|
||||||
|
padding: 10px 12px;
|
||||||
|
margin-bottom: 6px;
|
||||||
|
background: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.question-header {
|
||||||
|
font-size: 12px;
|
||||||
|
font-weight: bold;
|
||||||
|
color: #409eff;
|
||||||
|
margin-bottom: 4px;
|
||||||
|
text-transform: uppercase;
|
||||||
|
letter-spacing: 0.5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.question-text {
|
||||||
|
font-size: 13px;
|
||||||
|
color: #303133;
|
||||||
|
margin-bottom: 8px;
|
||||||
|
line-height: 1.5;
|
||||||
|
}
|
||||||
|
|
||||||
|
.question-options {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.question-option {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
align-items: flex-start;
|
||||||
|
gap: 8px;
|
||||||
|
padding: 7px 10px;
|
||||||
|
border-radius: 6px;
|
||||||
|
border: 1px solid #dcdfe6;
|
||||||
|
cursor: pointer;
|
||||||
|
transition:
|
||||||
|
background 0.15s,
|
||||||
|
border-color 0.15s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.option-radio {
|
||||||
|
flex-shrink: 0;
|
||||||
|
width: 14px;
|
||||||
|
height: 14px;
|
||||||
|
margin-top: 2px;
|
||||||
|
border-radius: 50%;
|
||||||
|
border: 2px solid #c0c4cc;
|
||||||
|
background: #fff;
|
||||||
|
transition: border-color 0.15s;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
.question-option:hover .option-radio {
|
||||||
|
border-color: #409eff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.question-option.disabled .option-radio {
|
||||||
|
border-color: #dcdfe6;
|
||||||
|
}
|
||||||
|
|
||||||
|
.option-content {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.question-option:hover {
|
||||||
|
background: #ecf5ff;
|
||||||
|
border-color: #409eff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.question-option.disabled {
|
||||||
|
cursor: not-allowed;
|
||||||
|
opacity: 0.5;
|
||||||
|
}
|
||||||
|
|
||||||
|
.question-option.disabled:hover {
|
||||||
|
background: transparent;
|
||||||
|
border-color: #dcdfe6;
|
||||||
|
}
|
||||||
|
|
||||||
|
.option-label {
|
||||||
|
font-size: 13px;
|
||||||
|
color: #303133;
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
.option-desc {
|
||||||
|
font-size: 11px;
|
||||||
|
color: #909399;
|
||||||
|
}
|
||||||
|
|
||||||
|
.question-free-input {
|
||||||
|
display: flex;
|
||||||
|
gap: 8px;
|
||||||
|
align-items: flex-end;
|
||||||
|
margin-top: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.question-free-input .el-textarea {
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.question-free-input .el-button {
|
||||||
|
height: 60px;
|
||||||
|
padding: 0 16px;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.raw-part {
|
||||||
|
margin-top: 6px;
|
||||||
|
border-radius: 6px;
|
||||||
|
background: rgba(0, 0, 0, 0.03);
|
||||||
|
padding: 6px 10px;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.raw-part-type {
|
||||||
|
font-size: 11px;
|
||||||
|
color: #999;
|
||||||
|
font-weight: bold;
|
||||||
|
display: block;
|
||||||
|
margin-bottom: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.raw-part-content {
|
||||||
|
margin: 0;
|
||||||
|
font-size: 12px;
|
||||||
|
color: #555;
|
||||||
|
white-space: pre-wrap;
|
||||||
|
word-break: break-all;
|
||||||
|
font-family: monospace;
|
||||||
|
}
|
||||||
|
|
||||||
.input-area {
|
.input-area {
|
||||||
display: flex;
|
display: flex;
|
||||||
gap: 10px;
|
gap: 10px;
|
||||||
|
|||||||
Reference in New Issue
Block a user