Compare commits
8 Commits
e9545c9be1
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| 1f06688237 | |||
| d97a55a992 | |||
| e0729ce600 | |||
| 3ace1a35ee | |||
| 2734306690 | |||
| 543adc1ad6 | |||
| 7bcd8fb873 | |||
| ae87ddb56d |
@@ -1,5 +1,4 @@
|
|||||||
{
|
{
|
||||||
"schemes": [],
|
|
||||||
"swagger": "2.0",
|
"swagger": "2.0",
|
||||||
"info": {
|
"info": {
|
||||||
"description": "这是一个用于管理猪场设备的后端服务。",
|
"description": "这是一个用于管理猪场设备的后端服务。",
|
||||||
@@ -15,8 +14,6 @@
|
|||||||
},
|
},
|
||||||
"version": "1.0"
|
"version": "1.0"
|
||||||
},
|
},
|
||||||
"host": "",
|
|
||||||
"basePath": "",
|
|
||||||
"paths": {
|
"paths": {
|
||||||
"/api/v1/alarm/threshold/active-alarms": {
|
"/api/v1/alarm/threshold/active-alarms": {
|
||||||
"get": {
|
"get": {
|
||||||
@@ -3366,6 +3363,59 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"/api/v1/feed/recipes/{id}/ai-diagnose": {
|
||||||
|
"get": {
|
||||||
|
"security": [
|
||||||
|
{
|
||||||
|
"BearerAuth": []
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "使用AI对指定配方进行点评,并针对目标猪类型给出建议。",
|
||||||
|
"produces": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"tags": [
|
||||||
|
"饲料管理-配方"
|
||||||
|
],
|
||||||
|
"summary": "AI点评配方",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"type": "integer",
|
||||||
|
"description": "配方ID",
|
||||||
|
"name": "id",
|
||||||
|
"in": "path",
|
||||||
|
"required": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "integer",
|
||||||
|
"description": "猪类型ID",
|
||||||
|
"name": "pig_type_id",
|
||||||
|
"in": "query",
|
||||||
|
"required": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "业务码为200代表AI点评成功",
|
||||||
|
"schema": {
|
||||||
|
"allOf": [
|
||||||
|
{
|
||||||
|
"$ref": "#/definitions/controller.Response"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"data": {
|
||||||
|
"$ref": "#/definitions/dto.ReviewRecipeResponse"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"/api/v1/inventory/stock/adjust": {
|
"/api/v1/inventory/stock/adjust": {
|
||||||
"post": {
|
"post": {
|
||||||
"security": [
|
"security": [
|
||||||
@@ -9160,6 +9210,23 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"dto.ReviewRecipeResponse": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"ai_model": {
|
||||||
|
"description": "使用的 AI 模型",
|
||||||
|
"allOf": [
|
||||||
|
{
|
||||||
|
"$ref": "#/definitions/models.AIModel"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"review_message": {
|
||||||
|
"description": "点评内容",
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"dto.SellPigsRequest": {
|
"dto.SellPigsRequest": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"required": [
|
"required": [
|
||||||
@@ -10079,6 +10146,15 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"models.AIModel": {
|
||||||
|
"type": "string",
|
||||||
|
"enum": [
|
||||||
|
"Gemini"
|
||||||
|
],
|
||||||
|
"x-enum-varnames": [
|
||||||
|
"AI_MODEL_GEMINI"
|
||||||
|
]
|
||||||
|
},
|
||||||
"models.AlarmCode": {
|
"models.AlarmCode": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"enum": [
|
"enum": [
|
||||||
|
|||||||
62
node_modules/.package-lock.json
generated
vendored
62
node_modules/.package-lock.json
generated
vendored
@@ -46,6 +46,7 @@
|
|||||||
"resolved": "https://registry.npmmirror.com/@babel/core/-/core-7.28.4.tgz",
|
"resolved": "https://registry.npmmirror.com/@babel/core/-/core-7.28.4.tgz",
|
||||||
"integrity": "sha512-2BCOP7TN8M+gVDj7/ht3hsaO/B/n5oDbiAyyvnRlNOs+u1o+JWNYTQrmpuNp1/Wq2gcFrI01JAW+paEKDMx/CA==",
|
"integrity": "sha512-2BCOP7TN8M+gVDj7/ht3hsaO/B/n5oDbiAyyvnRlNOs+u1o+JWNYTQrmpuNp1/Wq2gcFrI01JAW+paEKDMx/CA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
|
"peer": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/code-frame": "^7.27.1",
|
"@babel/code-frame": "^7.27.1",
|
||||||
"@babel/generator": "^7.28.3",
|
"@babel/generator": "^7.28.3",
|
||||||
@@ -1908,6 +1909,7 @@
|
|||||||
"version": "4.17.12",
|
"version": "4.17.12",
|
||||||
"resolved": "https://registry.npmmirror.com/@types/lodash-es/-/lodash-es-4.17.12.tgz",
|
"resolved": "https://registry.npmmirror.com/@types/lodash-es/-/lodash-es-4.17.12.tgz",
|
||||||
"integrity": "sha512-0NgftHUcV4v34VhXm8QBSftKVXtbkBG3ViCjs6+eJ5a6y6Mi/jiFGPc1sC7QK+9BFhWrURE3EOggmWaSxL9OzQ==",
|
"integrity": "sha512-0NgftHUcV4v34VhXm8QBSftKVXtbkBG3ViCjs6+eJ5a6y6Mi/jiFGPc1sC7QK+9BFhWrURE3EOggmWaSxL9OzQ==",
|
||||||
|
"peer": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@types/lodash": "*"
|
"@types/lodash": "*"
|
||||||
}
|
}
|
||||||
@@ -2063,6 +2065,7 @@
|
|||||||
"resolved": "https://registry.npmmirror.com/@vue/cli-service/-/cli-service-5.0.9.tgz",
|
"resolved": "https://registry.npmmirror.com/@vue/cli-service/-/cli-service-5.0.9.tgz",
|
||||||
"integrity": "sha512-yTX7GVyM19tEbd+y5/gA6MkVKA6K61nVYHYAivD61Hx6odVFmQsaC3/R3cWAHM1P5oVKCevBbumPljbT+tFG2w==",
|
"integrity": "sha512-yTX7GVyM19tEbd+y5/gA6MkVKA6K61nVYHYAivD61Hx6odVFmQsaC3/R3cWAHM1P5oVKCevBbumPljbT+tFG2w==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
|
"peer": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/helper-compilation-targets": "^7.12.16",
|
"@babel/helper-compilation-targets": "^7.12.16",
|
||||||
"@soda/friendly-errors-webpack-plugin": "^1.8.0",
|
"@soda/friendly-errors-webpack-plugin": "^1.8.0",
|
||||||
@@ -2747,6 +2750,7 @@
|
|||||||
"resolved": "https://registry.npmmirror.com/acorn/-/acorn-8.15.0.tgz",
|
"resolved": "https://registry.npmmirror.com/acorn/-/acorn-8.15.0.tgz",
|
||||||
"integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==",
|
"integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
|
"peer": true,
|
||||||
"bin": {
|
"bin": {
|
||||||
"acorn": "bin/acorn"
|
"acorn": "bin/acorn"
|
||||||
},
|
},
|
||||||
@@ -2801,6 +2805,7 @@
|
|||||||
"resolved": "https://registry.npmmirror.com/ajv/-/ajv-6.12.6.tgz",
|
"resolved": "https://registry.npmmirror.com/ajv/-/ajv-6.12.6.tgz",
|
||||||
"integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==",
|
"integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
|
"peer": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"fast-deep-equal": "^3.1.1",
|
"fast-deep-equal": "^3.1.1",
|
||||||
"fast-json-stable-stringify": "^2.0.0",
|
"fast-json-stable-stringify": "^2.0.0",
|
||||||
@@ -3268,6 +3273,7 @@
|
|||||||
"url": "https://github.com/sponsors/ai"
|
"url": "https://github.com/sponsors/ai"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
"peer": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"baseline-browser-mapping": "^2.8.3",
|
"baseline-browser-mapping": "^2.8.3",
|
||||||
"caniuse-lite": "^1.0.30001741",
|
"caniuse-lite": "^1.0.30001741",
|
||||||
@@ -3878,6 +3884,7 @@
|
|||||||
"resolved": "https://registry.npmmirror.com/css-loader/-/css-loader-6.11.0.tgz",
|
"resolved": "https://registry.npmmirror.com/css-loader/-/css-loader-6.11.0.tgz",
|
||||||
"integrity": "sha512-CTJ+AEQJjq5NzLga5pE39qdiSV56F8ywCIsqNIRF0r7BDgWsN25aazToqAFg7ZrtA/U016xudB3ffgweORxX7g==",
|
"integrity": "sha512-CTJ+AEQJjq5NzLga5pE39qdiSV56F8ywCIsqNIRF0r7BDgWsN25aazToqAFg7ZrtA/U016xudB3ffgweORxX7g==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
|
"peer": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"icss-utils": "^5.1.0",
|
"icss-utils": "^5.1.0",
|
||||||
"postcss": "^8.4.33",
|
"postcss": "^8.4.33",
|
||||||
@@ -4632,6 +4639,7 @@
|
|||||||
"integrity": "sha512-ypowyDxpVSYpkXr9WPv2PAZCtNip1Mv5KTW0SCurXv/9iOpcrH9PaqUElksqEB6pChqHGDRCFTyrZlGhnLNGiA==",
|
"integrity": "sha512-ypowyDxpVSYpkXr9WPv2PAZCtNip1Mv5KTW0SCurXv/9iOpcrH9PaqUElksqEB6pChqHGDRCFTyrZlGhnLNGiA==",
|
||||||
"deprecated": "This version is no longer supported. Please see https://eslint.org/version-support for other options.",
|
"deprecated": "This version is no longer supported. Please see https://eslint.org/version-support for other options.",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
|
"peer": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@eslint-community/eslint-utils": "^4.2.0",
|
"@eslint-community/eslint-utils": "^4.2.0",
|
||||||
"@eslint-community/regexpp": "^4.6.1",
|
"@eslint-community/regexpp": "^4.6.1",
|
||||||
@@ -5292,6 +5300,21 @@
|
|||||||
"integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==",
|
"integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"node_modules/fsevents": {
|
||||||
|
"version": "2.3.3",
|
||||||
|
"resolved": "https://registry.npmmirror.com/fsevents/-/fsevents-2.3.3.tgz",
|
||||||
|
"integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==",
|
||||||
|
"dev": true,
|
||||||
|
"hasInstallScript": true,
|
||||||
|
"ideallyInert": true,
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"darwin"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": "^8.16.0 || ^10.6.0 || >=11.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/function-bind": {
|
"node_modules/function-bind": {
|
||||||
"version": "1.1.2",
|
"version": "1.1.2",
|
||||||
"resolved": "https://registry.npmmirror.com/function-bind/-/function-bind-1.1.2.tgz",
|
"resolved": "https://registry.npmmirror.com/function-bind/-/function-bind-1.1.2.tgz",
|
||||||
@@ -6425,12 +6448,14 @@
|
|||||||
"node_modules/lodash": {
|
"node_modules/lodash": {
|
||||||
"version": "4.17.21",
|
"version": "4.17.21",
|
||||||
"resolved": "https://registry.npmmirror.com/lodash/-/lodash-4.17.21.tgz",
|
"resolved": "https://registry.npmmirror.com/lodash/-/lodash-4.17.21.tgz",
|
||||||
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="
|
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==",
|
||||||
|
"peer": true
|
||||||
},
|
},
|
||||||
"node_modules/lodash-es": {
|
"node_modules/lodash-es": {
|
||||||
"version": "4.17.21",
|
"version": "4.17.21",
|
||||||
"resolved": "https://registry.npmmirror.com/lodash-es/-/lodash-es-4.17.21.tgz",
|
"resolved": "https://registry.npmmirror.com/lodash-es/-/lodash-es-4.17.21.tgz",
|
||||||
"integrity": "sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw=="
|
"integrity": "sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==",
|
||||||
|
"peer": true
|
||||||
},
|
},
|
||||||
"node_modules/lodash-unified": {
|
"node_modules/lodash-unified": {
|
||||||
"version": "1.0.3",
|
"version": "1.0.3",
|
||||||
@@ -6660,6 +6685,18 @@
|
|||||||
"@jridgewell/sourcemap-codec": "^1.5.5"
|
"@jridgewell/sourcemap-codec": "^1.5.5"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/marked": {
|
||||||
|
"version": "17.0.1",
|
||||||
|
"resolved": "https://registry.npmmirror.com/marked/-/marked-17.0.1.tgz",
|
||||||
|
"integrity": "sha512-boeBdiS0ghpWcSwoNm/jJBwdpFaMnZWRzjA6SkUMYb40SVaN1x7mmfGKp0jvexGcx+7y2La5zRZsYFZI6Qpypg==",
|
||||||
|
"license": "MIT",
|
||||||
|
"bin": {
|
||||||
|
"marked": "bin/marked.js"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 20"
|
||||||
|
}
|
||||||
|
},
|
||||||
"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.npmmirror.com/math-intrinsics/-/math-intrinsics-1.1.0.tgz",
|
||||||
@@ -7571,6 +7608,7 @@
|
|||||||
"url": "https://github.com/sponsors/ai"
|
"url": "https://github.com/sponsors/ai"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
"peer": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"nanoid": "^3.3.11",
|
"nanoid": "^3.3.11",
|
||||||
"picocolors": "^1.1.1",
|
"picocolors": "^1.1.1",
|
||||||
@@ -8794,6 +8832,7 @@
|
|||||||
"resolved": "https://registry.npmmirror.com/ajv/-/ajv-8.17.1.tgz",
|
"resolved": "https://registry.npmmirror.com/ajv/-/ajv-8.17.1.tgz",
|
||||||
"integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==",
|
"integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
|
"peer": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"fast-deep-equal": "^3.1.3",
|
"fast-deep-equal": "^3.1.3",
|
||||||
"fast-uri": "^3.0.1",
|
"fast-uri": "^3.0.1",
|
||||||
@@ -9676,20 +9715,6 @@
|
|||||||
"node": ">= 0.6"
|
"node": ">= 0.6"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/typescript": {
|
|
||||||
"version": "5.9.3",
|
|
||||||
"resolved": "https://registry.npmmirror.com/typescript/-/typescript-5.9.3.tgz",
|
|
||||||
"integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==",
|
|
||||||
"optional": true,
|
|
||||||
"peer": true,
|
|
||||||
"bin": {
|
|
||||||
"tsc": "bin/tsc",
|
|
||||||
"tsserver": "bin/tsserver"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">=14.17"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/undici-types": {
|
"node_modules/undici-types": {
|
||||||
"version": "7.12.0",
|
"version": "7.12.0",
|
||||||
"resolved": "https://registry.npmmirror.com/undici-types/-/undici-types-7.12.0.tgz",
|
"resolved": "https://registry.npmmirror.com/undici-types/-/undici-types-7.12.0.tgz",
|
||||||
@@ -9846,6 +9871,7 @@
|
|||||||
"version": "3.5.21",
|
"version": "3.5.21",
|
||||||
"resolved": "https://registry.npmmirror.com/vue/-/vue-3.5.21.tgz",
|
"resolved": "https://registry.npmmirror.com/vue/-/vue-3.5.21.tgz",
|
||||||
"integrity": "sha512-xxf9rum9KtOdwdRkiApWL+9hZEMWE90FHh8yS1+KJAiWYh+iGWV1FquPjoO9VUHQ+VIhsCXNNyZ5Sf4++RVZBA==",
|
"integrity": "sha512-xxf9rum9KtOdwdRkiApWL+9hZEMWE90FHh8yS1+KJAiWYh+iGWV1FquPjoO9VUHQ+VIhsCXNNyZ5Sf4++RVZBA==",
|
||||||
|
"peer": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@vue/compiler-dom": "3.5.21",
|
"@vue/compiler-dom": "3.5.21",
|
||||||
"@vue/compiler-sfc": "3.5.21",
|
"@vue/compiler-sfc": "3.5.21",
|
||||||
@@ -9941,6 +9967,7 @@
|
|||||||
"resolved": "https://registry.npmmirror.com/vue-template-compiler/-/vue-template-compiler-2.7.16.tgz",
|
"resolved": "https://registry.npmmirror.com/vue-template-compiler/-/vue-template-compiler-2.7.16.tgz",
|
||||||
"integrity": "sha512-AYbUWAJHLGGQM7+cNTELw+KsOG9nl2CnSv467WobS5Cv9uk3wFcnr1Etsz2sEIHEZvw1U+o9mRlEO6QbZvUPGQ==",
|
"integrity": "sha512-AYbUWAJHLGGQM7+cNTELw+KsOG9nl2CnSv467WobS5Cv9uk3wFcnr1Etsz2sEIHEZvw1U+o9mRlEO6QbZvUPGQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
|
"peer": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"de-indent": "^1.0.2",
|
"de-indent": "^1.0.2",
|
||||||
"he": "^1.2.0"
|
"he": "^1.2.0"
|
||||||
@@ -9999,6 +10026,7 @@
|
|||||||
"resolved": "https://registry.npmmirror.com/webpack/-/webpack-5.101.3.tgz",
|
"resolved": "https://registry.npmmirror.com/webpack/-/webpack-5.101.3.tgz",
|
||||||
"integrity": "sha512-7b0dTKR3Ed//AD/6kkx/o7duS8H3f1a4w3BYpIriX4BzIhjkn4teo05cptsxvLesHFKK5KObnadmCHBwGc+51A==",
|
"integrity": "sha512-7b0dTKR3Ed//AD/6kkx/o7duS8H3f1a4w3BYpIriX4BzIhjkn4teo05cptsxvLesHFKK5KObnadmCHBwGc+51A==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
|
"peer": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@types/eslint-scope": "^3.7.7",
|
"@types/eslint-scope": "^3.7.7",
|
||||||
"@types/estree": "^1.0.8",
|
"@types/estree": "^1.0.8",
|
||||||
@@ -10096,6 +10124,7 @@
|
|||||||
"resolved": "https://registry.npmmirror.com/webpack-cli/-/webpack-cli-5.1.4.tgz",
|
"resolved": "https://registry.npmmirror.com/webpack-cli/-/webpack-cli-5.1.4.tgz",
|
||||||
"integrity": "sha512-pIDJHIEI9LR0yxHXQ+Qh95k2EvXpWzZ5l+d+jIo+RdSm9MiHfzazIxwwni/p7+x4eJZuvG1AJwgC4TNQ7NRgsg==",
|
"integrity": "sha512-pIDJHIEI9LR0yxHXQ+Qh95k2EvXpWzZ5l+d+jIo+RdSm9MiHfzazIxwwni/p7+x4eJZuvG1AJwgC4TNQ7NRgsg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
|
"peer": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@discoveryjs/json-ext": "^0.5.0",
|
"@discoveryjs/json-ext": "^0.5.0",
|
||||||
"@webpack-cli/configtest": "^2.1.1",
|
"@webpack-cli/configtest": "^2.1.1",
|
||||||
@@ -10267,6 +10296,7 @@
|
|||||||
"resolved": "https://registry.npmmirror.com/webpack-sources/-/webpack-sources-3.3.3.tgz",
|
"resolved": "https://registry.npmmirror.com/webpack-sources/-/webpack-sources-3.3.3.tgz",
|
||||||
"integrity": "sha512-yd1RBzSGanHkitROoPFd6qsrxt+oFhg/129YzheDGqeustzX0vTZJZsSsQjVQC4yzBQ56K55XU8gaNCtIzOnTg==",
|
"integrity": "sha512-yd1RBzSGanHkitROoPFd6qsrxt+oFhg/129YzheDGqeustzX0vTZJZsSsQjVQC4yzBQ56K55XU8gaNCtIzOnTg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
|
"peer": true,
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=10.13.0"
|
"node": ">=10.13.0"
|
||||||
}
|
}
|
||||||
|
|||||||
48
package-lock.json
generated
48
package-lock.json
generated
@@ -12,6 +12,7 @@
|
|||||||
"axios": "^1.6.0",
|
"axios": "^1.6.0",
|
||||||
"cron-parser": "^5.4.0",
|
"cron-parser": "^5.4.0",
|
||||||
"element-plus": "^2.4.0",
|
"element-plus": "^2.4.0",
|
||||||
|
"marked": "^17.0.1",
|
||||||
"vue": "^3.4.0",
|
"vue": "^3.4.0",
|
||||||
"vue-router": "^4.2.0",
|
"vue-router": "^4.2.0",
|
||||||
"vue3-cron-plus-picker": "^1.0.2"
|
"vue3-cron-plus-picker": "^1.0.2"
|
||||||
@@ -74,6 +75,7 @@
|
|||||||
"resolved": "https://registry.npmmirror.com/@babel/core/-/core-7.28.4.tgz",
|
"resolved": "https://registry.npmmirror.com/@babel/core/-/core-7.28.4.tgz",
|
||||||
"integrity": "sha512-2BCOP7TN8M+gVDj7/ht3hsaO/B/n5oDbiAyyvnRlNOs+u1o+JWNYTQrmpuNp1/Wq2gcFrI01JAW+paEKDMx/CA==",
|
"integrity": "sha512-2BCOP7TN8M+gVDj7/ht3hsaO/B/n5oDbiAyyvnRlNOs+u1o+JWNYTQrmpuNp1/Wq2gcFrI01JAW+paEKDMx/CA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
|
"peer": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/code-frame": "^7.27.1",
|
"@babel/code-frame": "^7.27.1",
|
||||||
"@babel/generator": "^7.28.3",
|
"@babel/generator": "^7.28.3",
|
||||||
@@ -1936,6 +1938,7 @@
|
|||||||
"version": "4.17.12",
|
"version": "4.17.12",
|
||||||
"resolved": "https://registry.npmmirror.com/@types/lodash-es/-/lodash-es-4.17.12.tgz",
|
"resolved": "https://registry.npmmirror.com/@types/lodash-es/-/lodash-es-4.17.12.tgz",
|
||||||
"integrity": "sha512-0NgftHUcV4v34VhXm8QBSftKVXtbkBG3ViCjs6+eJ5a6y6Mi/jiFGPc1sC7QK+9BFhWrURE3EOggmWaSxL9OzQ==",
|
"integrity": "sha512-0NgftHUcV4v34VhXm8QBSftKVXtbkBG3ViCjs6+eJ5a6y6Mi/jiFGPc1sC7QK+9BFhWrURE3EOggmWaSxL9OzQ==",
|
||||||
|
"peer": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@types/lodash": "*"
|
"@types/lodash": "*"
|
||||||
}
|
}
|
||||||
@@ -2091,6 +2094,7 @@
|
|||||||
"resolved": "https://registry.npmmirror.com/@vue/cli-service/-/cli-service-5.0.9.tgz",
|
"resolved": "https://registry.npmmirror.com/@vue/cli-service/-/cli-service-5.0.9.tgz",
|
||||||
"integrity": "sha512-yTX7GVyM19tEbd+y5/gA6MkVKA6K61nVYHYAivD61Hx6odVFmQsaC3/R3cWAHM1P5oVKCevBbumPljbT+tFG2w==",
|
"integrity": "sha512-yTX7GVyM19tEbd+y5/gA6MkVKA6K61nVYHYAivD61Hx6odVFmQsaC3/R3cWAHM1P5oVKCevBbumPljbT+tFG2w==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
|
"peer": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/helper-compilation-targets": "^7.12.16",
|
"@babel/helper-compilation-targets": "^7.12.16",
|
||||||
"@soda/friendly-errors-webpack-plugin": "^1.8.0",
|
"@soda/friendly-errors-webpack-plugin": "^1.8.0",
|
||||||
@@ -2775,6 +2779,7 @@
|
|||||||
"resolved": "https://registry.npmmirror.com/acorn/-/acorn-8.15.0.tgz",
|
"resolved": "https://registry.npmmirror.com/acorn/-/acorn-8.15.0.tgz",
|
||||||
"integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==",
|
"integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
|
"peer": true,
|
||||||
"bin": {
|
"bin": {
|
||||||
"acorn": "bin/acorn"
|
"acorn": "bin/acorn"
|
||||||
},
|
},
|
||||||
@@ -2829,6 +2834,7 @@
|
|||||||
"resolved": "https://registry.npmmirror.com/ajv/-/ajv-6.12.6.tgz",
|
"resolved": "https://registry.npmmirror.com/ajv/-/ajv-6.12.6.tgz",
|
||||||
"integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==",
|
"integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
|
"peer": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"fast-deep-equal": "^3.1.1",
|
"fast-deep-equal": "^3.1.1",
|
||||||
"fast-json-stable-stringify": "^2.0.0",
|
"fast-json-stable-stringify": "^2.0.0",
|
||||||
@@ -3296,6 +3302,7 @@
|
|||||||
"url": "https://github.com/sponsors/ai"
|
"url": "https://github.com/sponsors/ai"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
"peer": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"baseline-browser-mapping": "^2.8.3",
|
"baseline-browser-mapping": "^2.8.3",
|
||||||
"caniuse-lite": "^1.0.30001741",
|
"caniuse-lite": "^1.0.30001741",
|
||||||
@@ -3906,6 +3913,7 @@
|
|||||||
"resolved": "https://registry.npmmirror.com/css-loader/-/css-loader-6.11.0.tgz",
|
"resolved": "https://registry.npmmirror.com/css-loader/-/css-loader-6.11.0.tgz",
|
||||||
"integrity": "sha512-CTJ+AEQJjq5NzLga5pE39qdiSV56F8ywCIsqNIRF0r7BDgWsN25aazToqAFg7ZrtA/U016xudB3ffgweORxX7g==",
|
"integrity": "sha512-CTJ+AEQJjq5NzLga5pE39qdiSV56F8ywCIsqNIRF0r7BDgWsN25aazToqAFg7ZrtA/U016xudB3ffgweORxX7g==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
|
"peer": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"icss-utils": "^5.1.0",
|
"icss-utils": "^5.1.0",
|
||||||
"postcss": "^8.4.33",
|
"postcss": "^8.4.33",
|
||||||
@@ -4660,6 +4668,7 @@
|
|||||||
"integrity": "sha512-ypowyDxpVSYpkXr9WPv2PAZCtNip1Mv5KTW0SCurXv/9iOpcrH9PaqUElksqEB6pChqHGDRCFTyrZlGhnLNGiA==",
|
"integrity": "sha512-ypowyDxpVSYpkXr9WPv2PAZCtNip1Mv5KTW0SCurXv/9iOpcrH9PaqUElksqEB6pChqHGDRCFTyrZlGhnLNGiA==",
|
||||||
"deprecated": "This version is no longer supported. Please see https://eslint.org/version-support for other options.",
|
"deprecated": "This version is no longer supported. Please see https://eslint.org/version-support for other options.",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
|
"peer": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@eslint-community/eslint-utils": "^4.2.0",
|
"@eslint-community/eslint-utils": "^4.2.0",
|
||||||
"@eslint-community/regexpp": "^4.6.1",
|
"@eslint-community/regexpp": "^4.6.1",
|
||||||
@@ -6467,12 +6476,14 @@
|
|||||||
"node_modules/lodash": {
|
"node_modules/lodash": {
|
||||||
"version": "4.17.21",
|
"version": "4.17.21",
|
||||||
"resolved": "https://registry.npmmirror.com/lodash/-/lodash-4.17.21.tgz",
|
"resolved": "https://registry.npmmirror.com/lodash/-/lodash-4.17.21.tgz",
|
||||||
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="
|
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==",
|
||||||
|
"peer": true
|
||||||
},
|
},
|
||||||
"node_modules/lodash-es": {
|
"node_modules/lodash-es": {
|
||||||
"version": "4.17.21",
|
"version": "4.17.21",
|
||||||
"resolved": "https://registry.npmmirror.com/lodash-es/-/lodash-es-4.17.21.tgz",
|
"resolved": "https://registry.npmmirror.com/lodash-es/-/lodash-es-4.17.21.tgz",
|
||||||
"integrity": "sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw=="
|
"integrity": "sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==",
|
||||||
|
"peer": true
|
||||||
},
|
},
|
||||||
"node_modules/lodash-unified": {
|
"node_modules/lodash-unified": {
|
||||||
"version": "1.0.3",
|
"version": "1.0.3",
|
||||||
@@ -6702,6 +6713,18 @@
|
|||||||
"@jridgewell/sourcemap-codec": "^1.5.5"
|
"@jridgewell/sourcemap-codec": "^1.5.5"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/marked": {
|
||||||
|
"version": "17.0.1",
|
||||||
|
"resolved": "https://registry.npmmirror.com/marked/-/marked-17.0.1.tgz",
|
||||||
|
"integrity": "sha512-boeBdiS0ghpWcSwoNm/jJBwdpFaMnZWRzjA6SkUMYb40SVaN1x7mmfGKp0jvexGcx+7y2La5zRZsYFZI6Qpypg==",
|
||||||
|
"license": "MIT",
|
||||||
|
"bin": {
|
||||||
|
"marked": "bin/marked.js"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 20"
|
||||||
|
}
|
||||||
|
},
|
||||||
"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.npmmirror.com/math-intrinsics/-/math-intrinsics-1.1.0.tgz",
|
||||||
@@ -7613,6 +7636,7 @@
|
|||||||
"url": "https://github.com/sponsors/ai"
|
"url": "https://github.com/sponsors/ai"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
"peer": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"nanoid": "^3.3.11",
|
"nanoid": "^3.3.11",
|
||||||
"picocolors": "^1.1.1",
|
"picocolors": "^1.1.1",
|
||||||
@@ -8836,6 +8860,7 @@
|
|||||||
"resolved": "https://registry.npmmirror.com/ajv/-/ajv-8.17.1.tgz",
|
"resolved": "https://registry.npmmirror.com/ajv/-/ajv-8.17.1.tgz",
|
||||||
"integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==",
|
"integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
|
"peer": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"fast-deep-equal": "^3.1.3",
|
"fast-deep-equal": "^3.1.3",
|
||||||
"fast-uri": "^3.0.1",
|
"fast-uri": "^3.0.1",
|
||||||
@@ -9718,20 +9743,6 @@
|
|||||||
"node": ">= 0.6"
|
"node": ">= 0.6"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/typescript": {
|
|
||||||
"version": "5.9.3",
|
|
||||||
"resolved": "https://registry.npmmirror.com/typescript/-/typescript-5.9.3.tgz",
|
|
||||||
"integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==",
|
|
||||||
"optional": true,
|
|
||||||
"peer": true,
|
|
||||||
"bin": {
|
|
||||||
"tsc": "bin/tsc",
|
|
||||||
"tsserver": "bin/tsserver"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">=14.17"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/undici-types": {
|
"node_modules/undici-types": {
|
||||||
"version": "7.12.0",
|
"version": "7.12.0",
|
||||||
"resolved": "https://registry.npmmirror.com/undici-types/-/undici-types-7.12.0.tgz",
|
"resolved": "https://registry.npmmirror.com/undici-types/-/undici-types-7.12.0.tgz",
|
||||||
@@ -9888,6 +9899,7 @@
|
|||||||
"version": "3.5.21",
|
"version": "3.5.21",
|
||||||
"resolved": "https://registry.npmmirror.com/vue/-/vue-3.5.21.tgz",
|
"resolved": "https://registry.npmmirror.com/vue/-/vue-3.5.21.tgz",
|
||||||
"integrity": "sha512-xxf9rum9KtOdwdRkiApWL+9hZEMWE90FHh8yS1+KJAiWYh+iGWV1FquPjoO9VUHQ+VIhsCXNNyZ5Sf4++RVZBA==",
|
"integrity": "sha512-xxf9rum9KtOdwdRkiApWL+9hZEMWE90FHh8yS1+KJAiWYh+iGWV1FquPjoO9VUHQ+VIhsCXNNyZ5Sf4++RVZBA==",
|
||||||
|
"peer": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@vue/compiler-dom": "3.5.21",
|
"@vue/compiler-dom": "3.5.21",
|
||||||
"@vue/compiler-sfc": "3.5.21",
|
"@vue/compiler-sfc": "3.5.21",
|
||||||
@@ -9983,6 +9995,7 @@
|
|||||||
"resolved": "https://registry.npmmirror.com/vue-template-compiler/-/vue-template-compiler-2.7.16.tgz",
|
"resolved": "https://registry.npmmirror.com/vue-template-compiler/-/vue-template-compiler-2.7.16.tgz",
|
||||||
"integrity": "sha512-AYbUWAJHLGGQM7+cNTELw+KsOG9nl2CnSv467WobS5Cv9uk3wFcnr1Etsz2sEIHEZvw1U+o9mRlEO6QbZvUPGQ==",
|
"integrity": "sha512-AYbUWAJHLGGQM7+cNTELw+KsOG9nl2CnSv467WobS5Cv9uk3wFcnr1Etsz2sEIHEZvw1U+o9mRlEO6QbZvUPGQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
|
"peer": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"de-indent": "^1.0.2",
|
"de-indent": "^1.0.2",
|
||||||
"he": "^1.2.0"
|
"he": "^1.2.0"
|
||||||
@@ -10041,6 +10054,7 @@
|
|||||||
"resolved": "https://registry.npmmirror.com/webpack/-/webpack-5.101.3.tgz",
|
"resolved": "https://registry.npmmirror.com/webpack/-/webpack-5.101.3.tgz",
|
||||||
"integrity": "sha512-7b0dTKR3Ed//AD/6kkx/o7duS8H3f1a4w3BYpIriX4BzIhjkn4teo05cptsxvLesHFKK5KObnadmCHBwGc+51A==",
|
"integrity": "sha512-7b0dTKR3Ed//AD/6kkx/o7duS8H3f1a4w3BYpIriX4BzIhjkn4teo05cptsxvLesHFKK5KObnadmCHBwGc+51A==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
|
"peer": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@types/eslint-scope": "^3.7.7",
|
"@types/eslint-scope": "^3.7.7",
|
||||||
"@types/estree": "^1.0.8",
|
"@types/estree": "^1.0.8",
|
||||||
@@ -10138,6 +10152,7 @@
|
|||||||
"resolved": "https://registry.npmmirror.com/webpack-cli/-/webpack-cli-5.1.4.tgz",
|
"resolved": "https://registry.npmmirror.com/webpack-cli/-/webpack-cli-5.1.4.tgz",
|
||||||
"integrity": "sha512-pIDJHIEI9LR0yxHXQ+Qh95k2EvXpWzZ5l+d+jIo+RdSm9MiHfzazIxwwni/p7+x4eJZuvG1AJwgC4TNQ7NRgsg==",
|
"integrity": "sha512-pIDJHIEI9LR0yxHXQ+Qh95k2EvXpWzZ5l+d+jIo+RdSm9MiHfzazIxwwni/p7+x4eJZuvG1AJwgC4TNQ7NRgsg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
|
"peer": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@discoveryjs/json-ext": "^0.5.0",
|
"@discoveryjs/json-ext": "^0.5.0",
|
||||||
"@webpack-cli/configtest": "^2.1.1",
|
"@webpack-cli/configtest": "^2.1.1",
|
||||||
@@ -10309,6 +10324,7 @@
|
|||||||
"resolved": "https://registry.npmmirror.com/webpack-sources/-/webpack-sources-3.3.3.tgz",
|
"resolved": "https://registry.npmmirror.com/webpack-sources/-/webpack-sources-3.3.3.tgz",
|
||||||
"integrity": "sha512-yd1RBzSGanHkitROoPFd6qsrxt+oFhg/129YzheDGqeustzX0vTZJZsSsQjVQC4yzBQ56K55XU8gaNCtIzOnTg==",
|
"integrity": "sha512-yd1RBzSGanHkitROoPFd6qsrxt+oFhg/129YzheDGqeustzX0vTZJZsSsQjVQC4yzBQ56K55XU8gaNCtIzOnTg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
|
"peer": true,
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=10.13.0"
|
"node": ">=10.13.0"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,6 +20,7 @@
|
|||||||
"axios": "^1.6.0",
|
"axios": "^1.6.0",
|
||||||
"cron-parser": "^5.4.0",
|
"cron-parser": "^5.4.0",
|
||||||
"element-plus": "^2.4.0",
|
"element-plus": "^2.4.0",
|
||||||
|
"marked": "^17.0.1",
|
||||||
"vue": "^3.4.0",
|
"vue": "^3.4.0",
|
||||||
"vue-router": "^4.2.0",
|
"vue-router": "^4.2.0",
|
||||||
"vue3-cron-plus-picker": "^1.0.2"
|
"vue3-cron-plus-picker": "^1.0.2"
|
||||||
|
|||||||
@@ -327,6 +327,17 @@ import {PaginationDTO, Response} from '../enums';
|
|||||||
* @property {string} description - 新生成的配方描述
|
* @property {string} description - 新生成的配方描述
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @typedef {string} AIModel - AI模型枚举
|
||||||
|
* @enum {string}
|
||||||
|
* @property {"Gemini"} Gemini - Gemini模型
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @typedef {object} ReviewRecipeResponse
|
||||||
|
* @property {AIModel} ai_model - 使用的 AI 模型
|
||||||
|
* @property {string} review_message - 点评内容
|
||||||
|
*/
|
||||||
|
|
||||||
// --- API Functions ---
|
// --- API Functions ---
|
||||||
|
|
||||||
@@ -656,6 +667,16 @@ export const generatePrioritizedStockRecipe = (pigTypeId) => {
|
|||||||
return http.post(`/api/v1/feed/recipes/generate-prioritized-stock/${pigTypeId}`);
|
return http.post(`/api/v1/feed/recipes/generate-prioritized-stock/${pigTypeId}`);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 使用AI对指定配方进行点评,并针对目标猪类型给出建议。
|
||||||
|
* @param {number} id - 配方ID
|
||||||
|
* @param {number} pigTypeId - 猪类型ID
|
||||||
|
* @returns {Promise<Response<ReviewRecipeResponse>>}
|
||||||
|
*/
|
||||||
|
export const aiDiagnoseRecipe = (id, pigTypeId) => {
|
||||||
|
return http.get(`/api/v1/feed/recipes/${id}/ai-diagnose`, {params: {pig_type_id: pigTypeId}, timeout: 0});
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
export const FeedApi = {
|
export const FeedApi = {
|
||||||
getNutrients,
|
getNutrients,
|
||||||
@@ -692,4 +713,5 @@ export const FeedApi = {
|
|||||||
deleteRecipe,
|
deleteRecipe,
|
||||||
generateRecipeFromAllMaterials,
|
generateRecipeFromAllMaterials,
|
||||||
generatePrioritizedStockRecipe,
|
generatePrioritizedStockRecipe,
|
||||||
|
aiDiagnoseRecipe,
|
||||||
};
|
};
|
||||||
|
|||||||
283
src/components/feed/AIRecipeReviewDialog.vue
Normal file
283
src/components/feed/AIRecipeReviewDialog.vue
Normal file
@@ -0,0 +1,283 @@
|
|||||||
|
<template>
|
||||||
|
<el-dialog
|
||||||
|
v-model="dialogVisible"
|
||||||
|
title="AI点评配方"
|
||||||
|
width="80%"
|
||||||
|
:before-close="handleClose"
|
||||||
|
destroy-on-close
|
||||||
|
align-center
|
||||||
|
>
|
||||||
|
<el-form label-width="100px">
|
||||||
|
<el-form-item label="配方名称:">
|
||||||
|
<span>{{ recipe ? recipe.name : 'N/A' }}</span>
|
||||||
|
</el-form-item>
|
||||||
|
|
||||||
|
<el-form-item label="目标猪类型:">
|
||||||
|
<el-select
|
||||||
|
v-model="selectedPigTypeId"
|
||||||
|
placeholder="请选择目标猪类型"
|
||||||
|
filterable
|
||||||
|
:loading="loadingPigTypes"
|
||||||
|
:disabled="loadingAIReview"
|
||||||
|
style="width: 100%;"
|
||||||
|
>
|
||||||
|
<el-option
|
||||||
|
v-for="item in pigTypes"
|
||||||
|
:key="item.id"
|
||||||
|
:label="item.label"
|
||||||
|
:value="item.id"
|
||||||
|
></el-option>
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
|
|
||||||
|
<!-- 将AI点评结果移出el-form -->
|
||||||
|
<div v-if="aiReviewResult || error" style="margin-top: 20px;">
|
||||||
|
<label class="el-form-item__label" style="width: 100px;">AI点评结果:</label>
|
||||||
|
<div class="ai-review-content-wrapper" style="margin-top: 10px;">
|
||||||
|
<el-alert
|
||||||
|
v-if="error"
|
||||||
|
:title="error"
|
||||||
|
type="error"
|
||||||
|
show-icon
|
||||||
|
:closable="false"
|
||||||
|
></el-alert>
|
||||||
|
<div v-else-if="aiReviewResult" class="ai-review-content">
|
||||||
|
<p style="text-align: center; margin-bottom: 20px; color: #888;">
|
||||||
|
由 <strong>{{ aiReviewResult.ai_model }}</strong> 生成
|
||||||
|
</p>
|
||||||
|
<div v-html="renderedReview" class="markdown-body"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<template #footer>
|
||||||
|
<span class="dialog-footer">
|
||||||
|
<el-button @click="handleClose" :disabled="loadingAIReview">取消</el-button>
|
||||||
|
<el-button
|
||||||
|
type="primary"
|
||||||
|
@click="handleConfirm"
|
||||||
|
:loading="loadingAIReview"
|
||||||
|
:disabled="!selectedPigTypeId || loadingPigTypes"
|
||||||
|
>
|
||||||
|
{{ aiReviewResult ? '重新点评' : '开始点评' }}
|
||||||
|
</el-button>
|
||||||
|
</span>
|
||||||
|
</template>
|
||||||
|
</el-dialog>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { getPigTypes, aiDiagnoseRecipe } from '../../api/feed';
|
||||||
|
import { ElMessage } from 'element-plus';
|
||||||
|
import { marked } from 'marked';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'AIRecipeReviewDialog',
|
||||||
|
props: {
|
||||||
|
visible: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false,
|
||||||
|
},
|
||||||
|
recipe: {
|
||||||
|
type: Object,
|
||||||
|
default: null,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
emits: ['update:visible', 'cancel'],
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
dialogVisible: this.visible,
|
||||||
|
pigTypes: [], // 格式化后的猪类型列表
|
||||||
|
selectedPigTypeId: null,
|
||||||
|
aiReviewResult: null,
|
||||||
|
loadingPigTypes: false,
|
||||||
|
loadingAIReview: false,
|
||||||
|
error: null,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
renderedReview() {
|
||||||
|
if (this.aiReviewResult && this.aiReviewResult.review_message) {
|
||||||
|
return marked(this.aiReviewResult.review_message);
|
||||||
|
}
|
||||||
|
return '';
|
||||||
|
},
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
visible(newVal) {
|
||||||
|
this.dialogVisible = newVal;
|
||||||
|
if (newVal) {
|
||||||
|
this.resetState();
|
||||||
|
this.loadPigTypes();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
dialogVisible(newVal) {
|
||||||
|
this.$emit('update:visible', newVal);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
/**
|
||||||
|
* 重置组件内部状态
|
||||||
|
*/
|
||||||
|
resetState() {
|
||||||
|
this.selectedPigTypeId = null;
|
||||||
|
this.aiReviewResult = null;
|
||||||
|
this.error = null;
|
||||||
|
this.pigTypes = [];
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* 加载猪类型列表
|
||||||
|
*/
|
||||||
|
async loadPigTypes() {
|
||||||
|
this.loadingPigTypes = true;
|
||||||
|
this.error = null;
|
||||||
|
try {
|
||||||
|
// 获取所有猪类型,假设一次性获取足够的数据
|
||||||
|
const response = await getPigTypes({ page: 1, page_size: 1000 });
|
||||||
|
if (response.code === 2000 && response.data && response.data.list) {
|
||||||
|
this.pigTypes = response.data.list.map(type => ({
|
||||||
|
id: type.id,
|
||||||
|
label: `${type.breed_name} - ${type.age_stage_name}`,
|
||||||
|
}));
|
||||||
|
} else {
|
||||||
|
this.error = response.msg || '获取猪类型失败';
|
||||||
|
ElMessage.error(this.error);
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
this.error = '加载猪类型失败: ' + (err.message || '未知错误');
|
||||||
|
ElMessage.error(this.error);
|
||||||
|
console.error('加载猪类型失败:', err);
|
||||||
|
} finally {
|
||||||
|
this.loadingPigTypes = false;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* 处理确认按钮点击,调用AI点评接口
|
||||||
|
*/
|
||||||
|
async handleConfirm() {
|
||||||
|
if (!this.recipe || !this.recipe.id) {
|
||||||
|
ElMessage.warning('未选择配方');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!this.selectedPigTypeId) {
|
||||||
|
ElMessage.warning('请选择目标猪类型');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.loadingAIReview = true;
|
||||||
|
this.aiReviewResult = null;
|
||||||
|
this.error = null;
|
||||||
|
try {
|
||||||
|
const response = await aiDiagnoseRecipe(this.recipe.id, this.selectedPigTypeId);
|
||||||
|
if (response.code === 2000 && response.data) {
|
||||||
|
this.aiReviewResult = response.data;
|
||||||
|
ElMessage.success('AI点评成功');
|
||||||
|
} else {
|
||||||
|
this.error = response.msg || 'AI点评失败';
|
||||||
|
ElMessage.error(this.error);
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
this.error = 'AI点评请求失败: ' + (err.message || '未知错误');
|
||||||
|
ElMessage.error(this.error);
|
||||||
|
console.error('AI点评请求失败:', err);
|
||||||
|
} finally {
|
||||||
|
this.loadingAIReview = false;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* 处理对话框关闭
|
||||||
|
*/
|
||||||
|
handleClose() {
|
||||||
|
this.dialogVisible = false;
|
||||||
|
this.$emit('cancel');
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.ai-review-content {
|
||||||
|
background-color: #f5f5f5;
|
||||||
|
padding: 15px;
|
||||||
|
border-radius: 4px;
|
||||||
|
max-height: 60vh;
|
||||||
|
overflow-y: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body {
|
||||||
|
line-height: 1.6;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body :deep(h1),
|
||||||
|
.markdown-body :deep(h2),
|
||||||
|
.markdown-body :deep(h3) {
|
||||||
|
margin-top: 24px;
|
||||||
|
margin-bottom: 16px;
|
||||||
|
font-weight: 600;
|
||||||
|
line-height: 1.25;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body :deep(h1) {
|
||||||
|
font-size: 2em;
|
||||||
|
border-bottom: 1px solid #eaecef;
|
||||||
|
padding-bottom: .3em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body :deep(h2) {
|
||||||
|
font-size: 1.5em;
|
||||||
|
border-bottom: 1px solid #eaecef;
|
||||||
|
padding-bottom: .3em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body :deep(h3) {
|
||||||
|
font-size: 1.25em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body :deep(p) {
|
||||||
|
margin-bottom: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body :deep(ul),
|
||||||
|
.markdown-body :deep(ol) {
|
||||||
|
padding-left: 2em;
|
||||||
|
margin-bottom: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body :deep(li) {
|
||||||
|
margin-bottom: .5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body :deep(table) {
|
||||||
|
width: 100%;
|
||||||
|
border-collapse: collapse;
|
||||||
|
margin-bottom: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body :deep(th),
|
||||||
|
.markdown-body :deep(td) {
|
||||||
|
border: 1px solid #dfe2e5;
|
||||||
|
padding: 8px 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body :deep(th) {
|
||||||
|
background-color: #f6f8fa;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body :deep(blockquote) {
|
||||||
|
color: #6a737d;
|
||||||
|
border-left: .25em solid #dfe2e5;
|
||||||
|
padding: 0 1em;
|
||||||
|
margin-left: 0;
|
||||||
|
margin-bottom: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body :deep(code) {
|
||||||
|
padding: .2em .4em;
|
||||||
|
margin: 0;
|
||||||
|
font-size: 85%;
|
||||||
|
background-color: rgba(27,31,35,.05);
|
||||||
|
border-radius: 3px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -199,12 +199,23 @@ export default {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// 处理查看营养需求详情
|
// 处理查看营养需求详情
|
||||||
const handleViewNutrientRequirements = (pigType) => {
|
const handleViewNutrientRequirements = async (pigType) => { // 添加 async
|
||||||
currentNutrientRequirements.value = pigType.pig_nutrient_requirements || [];
|
try {
|
||||||
currentBreedName.value = pigType.breed_name;
|
// 强制重新获取该 pigType 的最新详情
|
||||||
currentAgeStageName.value = pigType.age_stage_name;
|
const response = await FeedApi.getPigTypeById(pigType.id);
|
||||||
currentPigTypeId.value = pigType.id; // 设置当前的 pigType ID
|
if (response.data) {
|
||||||
showNutrientDialog.value = true;
|
currentNutrientRequirements.value = response.data.pig_nutrient_requirements || [];
|
||||||
|
currentBreedName.value = response.data.breed_name;
|
||||||
|
currentAgeStageName.value = response.data.age_stage_name;
|
||||||
|
currentPigTypeId.value = response.data.id; // 设置当前的 pigType ID
|
||||||
|
showNutrientDialog.value = true;
|
||||||
|
} else {
|
||||||
|
ElMessage.error('获取猪类型详情失败');
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('获取猪类型详情失败:', error);
|
||||||
|
ElMessage.error('获取猪类型详情失败');
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleEdit = (row) => {
|
const handleEdit = (row) => {
|
||||||
|
|||||||
@@ -275,12 +275,23 @@ export default {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// 处理查看营养需求详情
|
// 处理查看营养需求详情
|
||||||
const handleViewNutrientRequirements = (pigType) => {
|
const handleViewNutrientRequirements = async (pigType) => { // 添加 async
|
||||||
currentNutrientRequirements.value = pigType.pig_nutrient_requirements || [];
|
try {
|
||||||
currentBreedName.value = pigType.breed_name;
|
// 强制重新获取该 pigType 的最新详情
|
||||||
currentAgeStageName.value = pigType.age_stage_name;
|
const response = await FeedApi.getPigTypeById(pigType.id);
|
||||||
currentPigTypeId.value = pigType.id; // 设置当前的 pigType ID
|
if (response.data) {
|
||||||
showNutrientDialog.value = true;
|
currentNutrientRequirements.value = response.data.pig_nutrient_requirements || [];
|
||||||
|
currentBreedName.value = response.data.breed_name;
|
||||||
|
currentAgeStageName.value = response.data.age_stage_name;
|
||||||
|
currentPigTypeId.value = response.data.id; // 设置当前的 pigType ID
|
||||||
|
showNutrientDialog.value = true;
|
||||||
|
} else {
|
||||||
|
ElMessage.error('获取猪类型详情失败');
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('获取猪类型详情失败:', error);
|
||||||
|
ElMessage.error('获取猪类型详情失败');
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleEdit = (row) => {
|
const handleEdit = (row) => {
|
||||||
|
|||||||
@@ -132,7 +132,7 @@ export default {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
// 调用API更新营养需求
|
// 调用API更新营养需求
|
||||||
await FeedApi.updatePigNutrientRequirements(props.pigTypeId, { pig_nutrient_requirements: requirementsToSave });
|
await FeedApi.updatePigTypeNutrientRequirements(props.pigTypeId, { nutrient_requirements: requirementsToSave });
|
||||||
ElMessage.success('营养需求更新成功');
|
ElMessage.success('营养需求更新成功');
|
||||||
emit('save'); // 通知父组件保存成功
|
emit('save'); // 通知父组件保存成功
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
|||||||
@@ -1,28 +1,28 @@
|
|||||||
<template>
|
<template>
|
||||||
<el-dialog
|
<el-dialog
|
||||||
:model-value="visible"
|
:model-value="visible"
|
||||||
:title="`配方详情: ${recipe ? recipe.name : ''}` + (isEditing ? ' (编辑中)' : '')"
|
:title="`配方详情: ${recipe ? recipe.name : ''}` + (isEditing ? ' (编辑中)' : '')"
|
||||||
@close="handleClose"
|
@close="handleClose"
|
||||||
width="70%"
|
width="70%"
|
||||||
top="5vh"
|
top="5vh"
|
||||||
>
|
>
|
||||||
<div v-if="loading" class="loading-spinner">
|
<div v-if="loading" class="loading-spinner">
|
||||||
<el-skeleton :rows="5" animated />
|
<el-skeleton :rows="5" animated/>
|
||||||
</div>
|
</div>
|
||||||
<div v-else-if="error" class="error-message">
|
<div v-else-if="error" class="error-message">
|
||||||
<el-alert
|
<el-alert
|
||||||
title="加载配方详情失败"
|
title="加载配方详情失败"
|
||||||
:description="error"
|
:description="error"
|
||||||
type="error"
|
type="error"
|
||||||
show-icon
|
show-icon
|
||||||
@close="error = null"
|
@close="error = null"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<el-tabs v-else v-model="activeTab">
|
<el-tabs v-else v-model="activeTab">
|
||||||
<el-tab-pane label="原料列表" name="ingredients">
|
<el-tab-pane label="原料列表" name="ingredients">
|
||||||
<div v-if="!isEditing">
|
<div v-if="!isEditing">
|
||||||
<el-table :data="ingredientDetails" style="width: 100%">
|
<el-table :data="ingredientDetails" style="width: 100%">
|
||||||
<el-table-column prop="name" label="原料名称" />
|
<el-table-column prop="name" label="原料名称"/>
|
||||||
<el-table-column prop="percentage" label="占比">
|
<el-table-column prop="percentage" label="占比">
|
||||||
<template #default="scope">
|
<template #default="scope">
|
||||||
{{ scope.row.percentage.toFixed(2) }}%
|
{{ scope.row.percentage.toFixed(2) }}%
|
||||||
@@ -32,10 +32,11 @@
|
|||||||
</div>
|
</div>
|
||||||
<div v-else>
|
<div v-else>
|
||||||
<el-table :data="localIngredientDetails" style="width: 100%">
|
<el-table :data="localIngredientDetails" style="width: 100%">
|
||||||
<el-table-column prop="name" label="原料名称" />
|
<el-table-column prop="name" label="原料名称"/>
|
||||||
<el-table-column label="占比">
|
<el-table-column label="占比">
|
||||||
<template #default="scope">
|
<template #default="scope">
|
||||||
<el-input-number v-model="scope.row.percentage" :min="0" :max="100" :step="1" :precision="2" @change="updateNutrientSummary"></el-input-number>
|
<el-input-number v-model="scope.row.percentage" :min="0" :max="100" :step="1" :precision="2"
|
||||||
|
@change="updateNutrientSummary"></el-input-number>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column label="操作">
|
<el-table-column label="操作">
|
||||||
@@ -46,7 +47,8 @@
|
|||||||
</el-table>
|
</el-table>
|
||||||
<div class="add-ingredient-section">
|
<div class="add-ingredient-section">
|
||||||
<el-select v-model="newIngredientId" placeholder="选择要添加的原料" filterable style="flex-grow: 1;">
|
<el-select v-model="newIngredientId" placeholder="选择要添加的原料" filterable style="flex-grow: 1;">
|
||||||
<el-option v-for="item in availableRawMaterials" :key="item.id" :label="item.name" :value="item.id"></el-option>
|
<el-option v-for="item in availableRawMaterials" :key="item.id" :label="item.name"
|
||||||
|
:value="item.id"></el-option>
|
||||||
</el-select>
|
</el-select>
|
||||||
<el-button type="primary" @click="addIngredient" style="margin-left: 10px;">添加原料</el-button>
|
<el-button type="primary" @click="addIngredient" style="margin-left: 10px;">添加原料</el-button>
|
||||||
</div>
|
</div>
|
||||||
@@ -54,17 +56,18 @@
|
|||||||
</el-tab-pane>
|
</el-tab-pane>
|
||||||
<el-tab-pane label="营养成分汇总" name="nutrients">
|
<el-tab-pane label="营养成分汇总" name="nutrients">
|
||||||
<el-table :data="nutrientSummary" style="width: 100%" ref="nutrientTableRef">
|
<el-table :data="nutrientSummary" style="width: 100%" ref="nutrientTableRef">
|
||||||
<el-table-column prop="name" label="营养素名称" />
|
<el-table-column prop="name" label="营养素名称"/>
|
||||||
<el-table-column prop="value" label="总含量">
|
<el-table-column prop="value" label="总含量">
|
||||||
<template #default="scope">
|
<template #default="scope">
|
||||||
{{ scope.row.value.toFixed(2) }}
|
{{ scope.row.value.toFixed(2) }}
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
</el-table>
|
</el-table>
|
||||||
</el-tab-pane>
|
</el-tab-pane>
|
||||||
</el-tabs>
|
</el-tabs>
|
||||||
<template #footer>
|
<template #footer>
|
||||||
<span class="dialog-footer">
|
<span class="dialog-footer">
|
||||||
|
<el-button v-if="!isEditing" @click="openAIReviewDialog">AI点评</el-button>
|
||||||
<el-button v-if="!isEditing" @click="openCompareDialog">对比</el-button>
|
<el-button v-if="!isEditing" @click="openCompareDialog">对比</el-button>
|
||||||
<el-button v-if="!isEditing" @click="handleEdit">编辑配方</el-button>
|
<el-button v-if="!isEditing" @click="handleEdit">编辑配方</el-button>
|
||||||
<el-button v-else @click="handleCancelEdit">取消</el-button>
|
<el-button v-else @click="handleCancelEdit">取消</el-button>
|
||||||
@@ -73,19 +76,25 @@
|
|||||||
</span>
|
</span>
|
||||||
</template>
|
</template>
|
||||||
<RecipeCompareDialog
|
<RecipeCompareDialog
|
||||||
v-model:visible="compareDialogVisible"
|
v-model:visible="compareDialogVisible"
|
||||||
:current-recipe="recipe"
|
:current-recipe="recipe"
|
||||||
@close="compareDialogVisible = false"
|
@close="compareDialogVisible = false"
|
||||||
|
/>
|
||||||
|
<AIRecipeReviewDialog
|
||||||
|
v-model:visible="aiReviewDialogVisible"
|
||||||
|
:recipe="recipe"
|
||||||
|
@cancel="aiReviewDialogVisible = false"
|
||||||
/>
|
/>
|
||||||
</el-dialog>
|
</el-dialog>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { ref, watch, nextTick, computed } from 'vue';
|
import {ref, watch, nextTick, computed} from 'vue';
|
||||||
import { getRawMaterialById, getRawMaterials, updateRecipe, getRecipeById } from '../../api/feed';
|
import {getRawMaterialById, getRawMaterials, updateRecipe, getRecipeById} from '../../api/feed';
|
||||||
import { ElMessage } from 'element-plus';
|
import {ElMessage} from 'element-plus';
|
||||||
import { Delete } from '@element-plus/icons-vue';
|
import {Delete} from '@element-plus/icons-vue';
|
||||||
import RecipeCompareDialog from './RecipeCompareDialog.vue'; // 引入对比组件
|
import RecipeCompareDialog from './RecipeCompareDialog.vue';
|
||||||
|
import AIRecipeReviewDialog from './AIRecipeReviewDialog.vue';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'RecipeDetailDialog',
|
name: 'RecipeDetailDialog',
|
||||||
@@ -96,19 +105,20 @@ export default {
|
|||||||
default: () => null,
|
default: () => null,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
emits: ['update:visible', 'recipe-updated'], // 添加 recipe-updated 事件
|
emits: ['update:visible', 'recipe-updated'],
|
||||||
setup(props, { emit }) {
|
setup(props, {emit}) {
|
||||||
const isEditing = ref(false); // 控制是否处于编辑模式
|
const isEditing = ref(false);
|
||||||
const activeTab = ref('ingredients');
|
const activeTab = ref('ingredients');
|
||||||
const loading = ref(false);
|
const loading = ref(false);
|
||||||
const error = ref(null);
|
const error = ref(null);
|
||||||
const ingredientDetails = ref([]); // 显示模式下的原料详情
|
const ingredientDetails = ref([]);
|
||||||
const localIngredientDetails = ref([]); // 编辑模式下的原料详情
|
const localIngredientDetails = ref([]);
|
||||||
const nutrientSummary = ref([]);
|
const nutrientSummary = ref([]);
|
||||||
const nutrientTableRef = ref(null);
|
const nutrientTableRef = ref(null);
|
||||||
const allRawMaterials = ref([]); // 所有可用原料列表
|
const allRawMaterials = ref([]);
|
||||||
const newIngredientId = ref(null); // 待添加的新原料ID
|
const newIngredientId = ref(null);
|
||||||
const compareDialogVisible = ref(false); // 控制对比对话框的显示
|
const compareDialogVisible = ref(false);
|
||||||
|
const aiReviewDialogVisible = ref(false);
|
||||||
|
|
||||||
const handleClose = () => {
|
const handleClose = () => {
|
||||||
emit('update:visible', false);
|
emit('update:visible', false);
|
||||||
@@ -118,12 +128,16 @@ export default {
|
|||||||
compareDialogVisible.value = true;
|
compareDialogVisible.value = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const openAIReviewDialog = () => {
|
||||||
|
aiReviewDialogVisible.value = true;
|
||||||
|
};
|
||||||
|
|
||||||
const calculateNutrientSummary = (ingredients) => {
|
const calculateNutrientSummary = (ingredients) => {
|
||||||
const summary = new Map();
|
const summary = new Map();
|
||||||
ingredients.forEach(ing => {
|
ingredients.forEach(ing => {
|
||||||
if (ing.raw_material_nutrients) {
|
if (ing.raw_material_nutrients) {
|
||||||
ing.raw_material_nutrients.forEach(nutrient => {
|
ing.raw_material_nutrients.forEach(nutrient => {
|
||||||
const contribution = nutrient.value * (ing.percentage / 100); // 修正:计算时需要将百分比转换为小数
|
const contribution = nutrient.value * (ing.percentage / 100);
|
||||||
if (summary.has(nutrient.nutrient_name)) {
|
if (summary.has(nutrient.nutrient_name)) {
|
||||||
summary.set(nutrient.nutrient_name, summary.get(nutrient.nutrient_name) + contribution);
|
summary.set(nutrient.nutrient_name, summary.get(nutrient.nutrient_name) + contribution);
|
||||||
} else {
|
} else {
|
||||||
@@ -132,19 +146,14 @@ export default {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
return Array.from(summary, ([name, value]) => ({ name, value }));
|
return Array.from(summary, ([name, value]) => ({name, value}));
|
||||||
};
|
};
|
||||||
|
|
||||||
// 计算属性,用于过滤掉已经存在的原料
|
|
||||||
const availableRawMaterials = computed(() => {
|
const availableRawMaterials = computed(() => {
|
||||||
const existingIngredientIds = new Set(localIngredientDetails.value.map(ing => ing.id));
|
const existingIngredientIds = new Set(localIngredientDetails.value.map(ing => ing.id));
|
||||||
return allRawMaterials.value.filter(material => !existingIngredientIds.has(material.id));
|
return allRawMaterials.value.filter(material => !existingIngredientIds.has(material.id));
|
||||||
});
|
});
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取并设置配方详情数据
|
|
||||||
* @param {number} recipeId - 配方ID
|
|
||||||
*/
|
|
||||||
const fetchAndSetRecipeDetails = async (recipeId) => {
|
const fetchAndSetRecipeDetails = async (recipeId) => {
|
||||||
loading.value = true;
|
loading.value = true;
|
||||||
error.value = null;
|
error.value = null;
|
||||||
@@ -160,8 +169,8 @@ export default {
|
|||||||
percentage: latestRecipe.recipe_ingredients[index].percentage,
|
percentage: latestRecipe.recipe_ingredients[index].percentage,
|
||||||
}));
|
}));
|
||||||
|
|
||||||
ingredientDetails.value = details; // 用于显示模式
|
ingredientDetails.value = details;
|
||||||
localIngredientDetails.value = JSON.parse(JSON.stringify(details)); // 用于编辑模式,深拷贝
|
localIngredientDetails.value = JSON.parse(JSON.stringify(details));
|
||||||
|
|
||||||
nutrientSummary.value = calculateNutrientSummary(details);
|
nutrientSummary.value = calculateNutrientSummary(details);
|
||||||
|
|
||||||
@@ -177,12 +186,11 @@ export default {
|
|||||||
if (newVal && props.recipe) {
|
if (newVal && props.recipe) {
|
||||||
await fetchAndSetRecipeDetails(props.recipe.id);
|
await fetchAndSetRecipeDetails(props.recipe.id);
|
||||||
} else {
|
} else {
|
||||||
// 重置数据
|
|
||||||
ingredientDetails.value = [];
|
ingredientDetails.value = [];
|
||||||
localIngredientDetails.value = [];
|
localIngredientDetails.value = [];
|
||||||
nutrientSummary.value = [];
|
nutrientSummary.value = [];
|
||||||
activeTab.value = 'ingredients';
|
activeTab.value = 'ingredients';
|
||||||
isEditing.value = false; // 关闭对话框时重置编辑状态
|
isEditing.value = false;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -196,17 +204,14 @@ export default {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// 实时更新营养成分汇总
|
|
||||||
const updateNutrientSummary = () => {
|
const updateNutrientSummary = () => {
|
||||||
nutrientSummary.value = calculateNutrientSummary(localIngredientDetails.value);
|
nutrientSummary.value = calculateNutrientSummary(localIngredientDetails.value);
|
||||||
};
|
};
|
||||||
|
|
||||||
// 进入编辑模式
|
|
||||||
const handleEdit = async () => {
|
const handleEdit = async () => {
|
||||||
isEditing.value = true;
|
isEditing.value = true;
|
||||||
// 获取所有原料列表
|
|
||||||
try {
|
try {
|
||||||
const response = await getRawMaterials({ page_size: 999 });
|
const response = await getRawMaterials({page_size: 999});
|
||||||
if (response.data && response.data.list) {
|
if (response.data && response.data.list) {
|
||||||
allRawMaterials.value = response.data.list;
|
allRawMaterials.value = response.data.list;
|
||||||
}
|
}
|
||||||
@@ -215,29 +220,24 @@ export default {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// 取消编辑
|
|
||||||
const handleCancelEdit = () => {
|
const handleCancelEdit = () => {
|
||||||
isEditing.value = false;
|
isEditing.value = false;
|
||||||
// 恢复到原始数据
|
|
||||||
localIngredientDetails.value = JSON.parse(JSON.stringify(ingredientDetails.value));
|
localIngredientDetails.value = JSON.parse(JSON.stringify(ingredientDetails.value));
|
||||||
updateNutrientSummary(); // 重新计算营养成分
|
updateNutrientSummary();
|
||||||
};
|
};
|
||||||
|
|
||||||
// 保存配方
|
|
||||||
const handleSaveRecipe = async () => {
|
const handleSaveRecipe = async () => {
|
||||||
// 验证占比总和是否为100
|
|
||||||
const totalPercentage = localIngredientDetails.value.reduce((sum, ing) => sum + ing.percentage, 0);
|
const totalPercentage = localIngredientDetails.value.reduce((sum, ing) => sum + ing.percentage, 0);
|
||||||
|
|
||||||
if (Math.abs(totalPercentage - 100) > 0.001) { // 允许浮点数误差
|
if (totalPercentage > 100.001) {
|
||||||
ElMessage.error(`原料总占比必须为100%,当前为${totalPercentage.toFixed(2)}%`);
|
ElMessage.error(`原料总占比不能超过100%,当前为${totalPercentage.toFixed(2)}%`);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 构造保存数据
|
|
||||||
const recipeToSave = {
|
const recipeToSave = {
|
||||||
id: props.recipe.id,
|
id: props.recipe.id,
|
||||||
name: props.recipe.name, // 名称不变
|
name: props.recipe.name,
|
||||||
description: props.recipe.description, // 描述不变
|
description: props.recipe.description,
|
||||||
recipe_ingredients: localIngredientDetails.value.map(ing => ({
|
recipe_ingredients: localIngredientDetails.value.map(ing => ({
|
||||||
raw_material_id: ing.id,
|
raw_material_id: ing.id,
|
||||||
percentage: ing.percentage,
|
percentage: ing.percentage,
|
||||||
@@ -248,21 +248,18 @@ export default {
|
|||||||
await updateRecipe(recipeToSave.id, recipeToSave);
|
await updateRecipe(recipeToSave.id, recipeToSave);
|
||||||
ElMessage.success('配方更新成功');
|
ElMessage.success('配方更新成功');
|
||||||
isEditing.value = false;
|
isEditing.value = false;
|
||||||
emit('recipe-updated'); // 通知父组件配方已更新
|
emit('recipe-updated');
|
||||||
// 重新加载配方详情以刷新显示
|
|
||||||
await fetchAndSetRecipeDetails(props.recipe.id);
|
await fetchAndSetRecipeDetails(props.recipe.id);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
ElMessage.error('保存配方失败: ' + (err.message || '未知错误'));
|
ElMessage.error('保存配方失败: ' + (err.message || '未知错误'));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// 移除原料
|
|
||||||
const removeIngredient = (index) => {
|
const removeIngredient = (index) => {
|
||||||
localIngredientDetails.value.splice(index, 1);
|
localIngredientDetails.value.splice(index, 1);
|
||||||
updateNutrientSummary();
|
updateNutrientSummary();
|
||||||
};
|
};
|
||||||
|
|
||||||
// 添加原料
|
|
||||||
const addIngredient = () => {
|
const addIngredient = () => {
|
||||||
if (!newIngredientId.value) {
|
if (!newIngredientId.value) {
|
||||||
ElMessage.warning('请选择要添加的原料');
|
ElMessage.warning('请选择要添加的原料');
|
||||||
@@ -270,7 +267,7 @@ export default {
|
|||||||
}
|
}
|
||||||
const materialToAdd = allRawMaterials.value.find(m => m.id === newIngredientId.value);
|
const materialToAdd = allRawMaterials.value.find(m => m.id === newIngredientId.value);
|
||||||
if (materialToAdd && !localIngredientDetails.value.some(ing => ing.id === materialToAdd.id)) {
|
if (materialToAdd && !localIngredientDetails.value.some(ing => ing.id === materialToAdd.id)) {
|
||||||
localIngredientDetails.value.push({ ...materialToAdd, percentage: 0 }); // 默认占比0
|
localIngredientDetails.value.push({...materialToAdd, percentage: 0});
|
||||||
newIngredientId.value = null;
|
newIngredientId.value = null;
|
||||||
updateNutrientSummary();
|
updateNutrientSummary();
|
||||||
} else if (localIngredientDetails.value.some(ing => ing.id === materialToAdd.id)) {
|
} else if (localIngredientDetails.value.some(ing => ing.id === materialToAdd.id)) {
|
||||||
@@ -296,14 +293,17 @@ export default {
|
|||||||
availableRawMaterials,
|
availableRawMaterials,
|
||||||
newIngredientId,
|
newIngredientId,
|
||||||
updateNutrientSummary,
|
updateNutrientSummary,
|
||||||
Delete, // 暴露 Delete 图标组件
|
Delete,
|
||||||
compareDialogVisible, // 暴露对比对话框的可见性
|
compareDialogVisible,
|
||||||
openCompareDialog, // 暴露打开对比对话框的方法
|
openCompareDialog,
|
||||||
|
aiReviewDialogVisible,
|
||||||
|
openAIReviewDialog,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
components: {
|
components: {
|
||||||
Delete,
|
Delete,
|
||||||
RecipeCompareDialog, // 注册对比组件
|
RecipeCompareDialog,
|
||||||
|
AIRecipeReviewDialog,
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
@@ -313,9 +313,11 @@ export default {
|
|||||||
padding: 20px;
|
padding: 20px;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
.dialog-footer {
|
.dialog-footer {
|
||||||
text-align: right;
|
text-align: right;
|
||||||
}
|
}
|
||||||
|
|
||||||
.add-ingredient-section {
|
.add-ingredient-section {
|
||||||
margin-top: 20px;
|
margin-top: 20px;
|
||||||
display: flex;
|
display: flex;
|
||||||
|
|||||||
@@ -24,8 +24,9 @@
|
|||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column prop="description" label="配方简介"/>
|
<el-table-column prop="description" label="配方简介"/>
|
||||||
<el-table-column label="操作" width="150" align="center">
|
<el-table-column label="操作" width="250" align="center">
|
||||||
<template #default="scope">
|
<template #default="scope">
|
||||||
|
<el-button size="small" type="primary" @click="$emit('ai-review', scope.row)">AI点评</el-button>
|
||||||
<el-button size="small" @click="$emit('edit', scope.row)">编辑</el-button>
|
<el-button size="small" @click="$emit('edit', scope.row)">编辑</el-button>
|
||||||
<el-button size="small" type="danger" @click="$emit('delete', scope.row)">删除</el-button>
|
<el-button size="small" type="danger" @click="$emit('delete', scope.row)">删除</el-button>
|
||||||
</template>
|
</template>
|
||||||
@@ -43,6 +44,7 @@ export default {
|
|||||||
default: () => []
|
default: () => []
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
emits: ['edit', 'delete', 'show-details']
|
// 声明新的ai-review事件
|
||||||
|
emits: ['edit', 'delete', 'show-details', 'ai-review']
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -330,6 +330,14 @@ export const AlarmSourceType = {
|
|||||||
SYSTEM: '系统',
|
SYSTEM: '系统',
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* AI模型
|
||||||
|
* @enum {string}
|
||||||
|
*/
|
||||||
|
export const AIModel = {
|
||||||
|
GEMINI: 'Gemini',
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 操作符
|
* 操作符
|
||||||
* @enum {string}
|
* @enum {string}
|
||||||
|
|||||||
@@ -41,6 +41,7 @@
|
|||||||
@edit="editRecipe"
|
@edit="editRecipe"
|
||||||
@delete="deleteRecipe"
|
@delete="deleteRecipe"
|
||||||
@show-details="handleShowDetails"
|
@show-details="handleShowDetails"
|
||||||
|
@ai-review="openAIRecipeReviewDialog"
|
||||||
/>
|
/>
|
||||||
</el-card>
|
</el-card>
|
||||||
|
|
||||||
@@ -65,6 +66,13 @@
|
|||||||
@success="onGenerateRecipeSuccess"
|
@success="onGenerateRecipeSuccess"
|
||||||
@cancel="generateRecipeDialogVisible = false"
|
@cancel="generateRecipeDialogVisible = false"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
<!-- AI点评配方对话框 -->
|
||||||
|
<AIRecipeReviewDialog
|
||||||
|
v-model:visible="aiReviewDialogVisible"
|
||||||
|
:recipe="selectedRecipeForAIReview"
|
||||||
|
@cancel="aiReviewDialogVisible = false"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@@ -75,7 +83,8 @@ import RecipeTable from '../../components/feed/RecipeTable.vue';
|
|||||||
import RecipeForm from '../../components/feed/RecipeForm.vue';
|
import RecipeForm from '../../components/feed/RecipeForm.vue';
|
||||||
import RecipeDetailDialog from '../../components/feed/RecipeDetailDialog.vue';
|
import RecipeDetailDialog from '../../components/feed/RecipeDetailDialog.vue';
|
||||||
import { ElMessage, ElMessageBox } from 'element-plus';
|
import { ElMessage, ElMessageBox } from 'element-plus';
|
||||||
import GenerateRecipeDialog from '../../components/feed/GenerateRecipeDialog.vue'; // 引入新的组件
|
import GenerateRecipeDialog from '../../components/feed/GenerateRecipeDialog.vue';
|
||||||
|
import AIRecipeReviewDialog from '../../components/feed/AIRecipeReviewDialog.vue'; // 引入新的AI点评组件
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'RecipeList',
|
name: 'RecipeList',
|
||||||
@@ -84,7 +93,8 @@ export default {
|
|||||||
RecipeForm,
|
RecipeForm,
|
||||||
RecipeDetailDialog,
|
RecipeDetailDialog,
|
||||||
Refresh,
|
Refresh,
|
||||||
GenerateRecipeDialog, // 注册新的组件
|
GenerateRecipeDialog,
|
||||||
|
AIRecipeReviewDialog, // 注册新的AI点评组件
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
@@ -97,6 +107,8 @@ export default {
|
|||||||
detailDialogVisible: false,
|
detailDialogVisible: false,
|
||||||
selectedRecipe: null,
|
selectedRecipe: null,
|
||||||
generateRecipeDialogVisible: false, // 控制一键生成配方弹窗的显示
|
generateRecipeDialogVisible: false, // 控制一键生成配方弹窗的显示
|
||||||
|
aiReviewDialogVisible: false, // 控制AI点评弹窗的显示
|
||||||
|
selectedRecipeForAIReview: null, // 存储当前选择进行AI点评的配方
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
async mounted() {
|
async mounted() {
|
||||||
@@ -165,7 +177,15 @@ export default {
|
|||||||
ElMessage.success(`配方 "${recipeName}" 生成成功: ${recipeDescription}`);
|
ElMessage.success(`配方 "${recipeName}" 生成成功: ${recipeDescription}`);
|
||||||
this.generateRecipeDialogVisible = false;
|
this.generateRecipeDialogVisible = false;
|
||||||
this.loadRecipes(); // 刷新配方列表
|
this.loadRecipes(); // 刷新配方列表
|
||||||
}
|
},
|
||||||
|
/**
|
||||||
|
* 打开AI点评配方对话框
|
||||||
|
* @param {object} recipe - 需要AI点评的配方对象
|
||||||
|
*/
|
||||||
|
openAIRecipeReviewDialog(recipe) {
|
||||||
|
this.selectedRecipeForAIReview = recipe;
|
||||||
|
this.aiReviewDialogVisible = true;
|
||||||
|
},
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
Reference in New Issue
Block a user