作者 dong

首页增加统计项,日志管理增加存入知识库功能,按钮管理增加字段code,日志管理增加提问方式字段

... ... @@ -21,48 +21,51 @@
"husky:install": "husky install"
},
"dependencies": {
"@jeecg/online": "3.7.4-beta",
"@ant-design/colors": "^7.2.0",
"@ant-design/icons-vue": "^7.0.1",
"@iconify/iconify": "^3.1.1",
"@jeecg/aiflow": "1.0.0",
"@jeecg/online": "3.7.4-beta",
"@logicflow/core": "^2.0.10",
"@logicflow/extension": "^2.0.14",
"@logicflow/vue-node-registry": "^1.0.12",
"@iconify/iconify": "^3.1.1",
"@ant-design/colors": "^7.2.0",
"@ant-design/icons-vue": "^7.0.1",
"@tinymce/tinymce-vue": "4.0.7",
"@traptitech/markdown-it-katex": "^3.6.0",
"@vant/area-data": "^1.5.2",
"@vue/shared": "^3.5.13",
"@vueuse/core": "^10.11.1",
"@tinymce/tinymce-vue": "4.0.7",
"@zxcvbn-ts/core": "^3.0.4",
"ant-design-vue": "^4.2.6",
"axios": "^1.7.9",
"china-area-data": "^5.0.1",
"@vant/area-data": "^1.5.2",
"clipboard": "^2.0.11",
"codemirror": "^5.65.18",
"cron-parser": "^4.9.0",
"cropperjs": "^1.6.2",
"crypto-js": "^4.2.0",
"dayjs": "^1.11.13",
"docx-preview": "^0.3.5",
"dom-align": "^1.12.4",
"echarts": "^5.6.0",
"emoji-mart-vue-fast": "^15.0.3",
"enquire.js": "^2.1.6",
"event-source-polyfill": "^1.0.31",
"highlight.js": "^11.11.1",
"intro.js": "^7.2.0",
"lodash-es": "^4.17.21",
"lodash.get": "^4.4.2",
"mammoth": "^1.9.1",
"markdown-it": "^14.1.0",
"markdown-it-link-attributes": "^4.0.1",
"event-source-polyfill": "^1.0.31",
"highlight.js": "^11.11.1",
"@traptitech/markdown-it-katex": "^3.6.0",
"md5": "^2.3.0",
"mockjs": "^1.1.0",
"nprogress": "^0.2.0",
"path-to-regexp": "^6.3.0",
"pdfjs-dist": "^5.3.31",
"pinia": "2.1.7",
"print-js": "^1.6.0",
"qs": "^6.13.1",
"qrcode": "^1.5.4",
"qs": "^6.13.1",
"resize-observer-polyfill": "^1.5.1",
"showdown": "^2.1.0",
"sortablejs": "^1.15.6",
... ... @@ -78,9 +81,9 @@
"vue-router": "^4.5.0",
"vue-types": "^5.1.3",
"vuedraggable": "^4.1.0",
"vxe-pc-ui": "4.6.12",
"vxe-table": "4.13.31",
"vxe-table-plugin-antd": "4.0.8",
"vxe-pc-ui": "4.6.12",
"xe-utils": "3.5.26",
"xss": "^1.0.15"
},
... ... @@ -89,6 +92,7 @@
"@commitlint/config-conventional": "^18.6.3",
"@iconify/json": "^2.2.292",
"@purge-icons/generated": "^0.10.0",
"@rys-fe/vite-plugin-theme": "^0.8.6",
"@types/codemirror": "^5.60.15",
"@types/crypto-js": "^4.2.2",
"@types/fs-extra": "^11.0.4",
... ... @@ -110,11 +114,13 @@
"@vue/compiler-sfc": "^3.5.13",
"@vue/test-utils": "^2.4.6",
"autoprefixer": "^10.4.20",
"big.js": "^6.2.2",
"commitizen": "^4.3.1",
"conventional-changelog-cli": "^4.1.0",
"cross-env": "^7.0.3",
"cz-git": "^1.11.0",
"czg": "^1.11.0",
"dingtalk-jsapi": "^3.0.42",
"dotenv": "^16.4.7",
"eslint": "^8.57.1",
"eslint-config-prettier": "^9.1.0",
... ... @@ -150,6 +156,7 @@
"ts-jest": "^29.2.5",
"ts-node": "^10.9.2",
"typescript": "^4.9.5",
"unocss": "^0.58.9",
"vite": "^6.0.7",
"vite-plugin-compression": "^0.5.1",
"vite-plugin-html": "^3.2.2",
... ... @@ -158,15 +165,11 @@
"vite-plugin-optimize-persist": "^0.1.2",
"vite-plugin-package-config": "^0.1.1",
"vite-plugin-purge-icons": "^0.10.0",
"vite-plugin-svg-icons": "^2.0.1",
"vite-plugin-qiankun": "^1.0.15",
"@rys-fe/vite-plugin-theme": "^0.8.6",
"vite-plugin-svg-icons": "^2.0.1",
"vite-plugin-vue-setup-extend-plus": "^0.1.0",
"unocss": "^0.58.9",
"vue-eslint-parser": "^9.4.3",
"vue-tsc": "^1.8.27",
"dingtalk-jsapi": "^3.0.42",
"big.js": "^6.2.2"
"vue-tsc": "^1.8.27"
},
"repository": {
"type": "git",
... ...
... ... @@ -77,6 +77,9 @@ importers:
dayjs:
specifier: ^1.11.13
version: 1.11.13
docx-preview:
specifier: ^0.3.5
version: 0.3.5
dom-align:
specifier: ^1.12.4
version: 1.12.4
... ... @@ -104,6 +107,9 @@ importers:
lodash.get:
specifier: ^4.4.2
version: 4.4.2
mammoth:
specifier: ^1.9.1
version: 1.9.1
markdown-it:
specifier: ^14.1.0
version: 14.1.0
... ... @@ -122,6 +128,9 @@ importers:
path-to-regexp:
specifier: ^6.3.0
version: 6.3.0
pdfjs-dist:
specifier: ^5.3.31
version: 5.3.31
pinia:
specifier: 2.1.7
version: 2.1.7(typescript@4.9.5)(vue@3.5.14(typescript@4.9.5))
... ... @@ -1171,6 +1180,70 @@ packages:
'@vue/composition-api':
optional: true
'@napi-rs/canvas-android-arm64@0.1.71':
resolution: {integrity: sha512-cxi3VCotIOS9kNFQI7dcysbVJi106pxryVY1Hi85pX+ZeqahRyeqc/NsLaZ998Ae99+F3HI5X/39G1Y/Byrf0A==}
engines: {node: '>= 10'}
cpu: [arm64]
os: [android]
'@napi-rs/canvas-darwin-arm64@0.1.71':
resolution: {integrity: sha512-7Y4D/6vIuMLYsVNtRM/w2j0+fB1GyqeOxc7I0BTx8eLP1S6BZE2Rj6zJfdG+zmLEOW0IlHa+VQq1q2MUAjW84w==}
engines: {node: '>= 10'}
cpu: [arm64]
os: [darwin]
'@napi-rs/canvas-darwin-x64@0.1.71':
resolution: {integrity: sha512-Z0IUqxclrYdfVt/SK9nKCzUHTOXKTWiygtO71YCzs0OtxKdNI7GJRJdYG48wXZEDQ/pqTF4F7Ifgtidfc2tYpg==}
engines: {node: '>= 10'}
cpu: [x64]
os: [darwin]
'@napi-rs/canvas-linux-arm-gnueabihf@0.1.71':
resolution: {integrity: sha512-KlpqqCASak5ruY+UIolJgmhMZ9Pa2o1QyaNu648L8sz4WNBbNa+aOT60XCLCL1VIKLv11B3MlNgiOHoYNmDhXQ==}
engines: {node: '>= 10'}
cpu: [arm]
os: [linux]
'@napi-rs/canvas-linux-arm64-gnu@0.1.71':
resolution: {integrity: sha512-bdGZCGu8YQNAiu3nkIVVUp6nIn6fPd36IuZsLXTG027E52KyIuZ3obCxehSwjDIUNkFWvmff5D6JYfWwAoioEw==}
engines: {node: '>= 10'}
cpu: [arm64]
os: [linux]
'@napi-rs/canvas-linux-arm64-musl@0.1.71':
resolution: {integrity: sha512-1R5sMWe9ur8uM+hAeylBwG0b6UHDR+iWQNgzXmF9vbBYRooQvmDWqpcgytKLJAC0vnWhIkKwqd7yExn7cwczmg==}
engines: {node: '>= 10'}
cpu: [arm64]
os: [linux]
'@napi-rs/canvas-linux-riscv64-gnu@0.1.71':
resolution: {integrity: sha512-xjjKsipueuG+LdKIk6/uAlqdo+rzGcmNpTZPXdakIT1sHX4NNSnQTzjRaj9Gh96Czjd9G89UWR0KIlE7fwOgFA==}
engines: {node: '>= 10'}
cpu: [riscv64]
os: [linux]
'@napi-rs/canvas-linux-x64-gnu@0.1.71':
resolution: {integrity: sha512-3s6YpklXDB4OeeULG1XTRyKrKAOo7c3HHEqM9A6N4STSjMaJtzmpp7tB/JTvAFeOeFte6gWN8IwC+7AjGJ6MpQ==}
engines: {node: '>= 10'}
cpu: [x64]
os: [linux]
'@napi-rs/canvas-linux-x64-musl@0.1.71':
resolution: {integrity: sha512-5v9aCLzCXw7u10ray5juQMdl7TykZSn1X5AIGYwBvTAcKSgrqaR9QkRxp1Lqk3njQmFekOW1SFN9bZ/i/6y6kA==}
engines: {node: '>= 10'}
cpu: [x64]
os: [linux]
'@napi-rs/canvas-win32-x64-msvc@0.1.71':
resolution: {integrity: sha512-oJughk6xjsRIr0Rd9EqjmZmhIMkvcPuXgr3MNn2QexTqn+YFOizrwHS5ha0BDfFl7TEGRvwaDUXBQtu8JKXb8A==}
engines: {node: '>= 10'}
cpu: [x64]
os: [win32]
'@napi-rs/canvas@0.1.71':
resolution: {integrity: sha512-92ybDocKl6JM48ZpYbj+A7Qt45IaTABDk0y3sDecEQfgdhfNzJtEityqNHoCZ4Vty2dldPkJhxgvOnbrQMXTTA==}
engines: {node: '>= 10'}
'@nodelib/fs.scandir@2.1.5':
resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==}
engines: {node: '>= 8'}
... ... @@ -1756,6 +1829,10 @@ packages:
peerDependencies:
vue: ^3.2.0
'@xmldom/xmldom@0.8.10':
resolution: {integrity: sha512-2WALfTl4xo2SkGCYRt6rDTFfk9R1czmBvUQy12gK2KuRKIpWEhcbbzy8EZXtz/jkRqHX8bFEc6FC1HjX4TUWYw==}
engines: {node: '>=10.0.0'}
'@zxcvbn-ts/core@3.0.4':
resolution: {integrity: sha512-aQeiT0F09FuJaAqNrxynlAwZ2mW/1MdXakKWNmGM1Qp/VaY6CnB/GfnMS2T8gB2231Esp1/maCWd8vTG4OuShw==}
... ... @@ -1995,6 +2072,9 @@ packages:
bl@4.1.0:
resolution: {integrity: sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==}
bluebird@3.4.7:
resolution: {integrity: sha512-iD3898SR7sWVRHbiQv+sHUtHnMvC1o3nW5rAcqnq3uOn07DSAppZYUkIGslDz6gXC7HfunPe7YVBgoEJASPcHA==}
bluebird@3.7.2:
resolution: {integrity: sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==}
... ... @@ -2384,6 +2464,9 @@ packages:
core-js@3.42.0:
resolution: {integrity: sha512-Sz4PP4ZA+Rq4II21qkNqOEDTDrCvcANId3xpIgB34NDkWc3UduWj2dqEtN9yZIq8Dk3HyPI33x9sqqU5C8sr0g==}
core-util-is@1.0.3:
resolution: {integrity: sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==}
cors@2.8.5:
resolution: {integrity: sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==}
engines: {node: '>= 0.10'}
... ... @@ -2665,6 +2748,9 @@ packages:
dijkstrajs@1.0.3:
resolution: {integrity: sha512-qiSlmBq9+BCdCA/L46dw8Uy93mloxsPSbwnm5yrKn2vMPiy8KyAskTF6zuV/j5BMsmOGZDPs7KjU+mjb670kfA==}
dingbat-to-unicode@1.0.1:
resolution: {integrity: sha512-98l0sW87ZT58pU4i61wa2OHwxbiYSbuxsCBozaVnYX2iCnr3bLM3fIes1/ej7h1YdOKuKt/MLs706TVnALA65w==}
dingtalk-jsapi@3.1.0:
resolution: {integrity: sha512-2W1XuOR3g/0eYbqXXOMKwmTSUzyIeKNIQ1DDgUrMmf3eNdfOb8ShcQZ02QNvn/j5Vpy6Pd0Yf+uRkWVB3Pl9gA==}
... ... @@ -2676,6 +2762,9 @@ packages:
resolution: {integrity: sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==}
engines: {node: '>=6.0.0'}
docx-preview@0.3.5:
resolution: {integrity: sha512-nod1jG5PkvzDIiZAcgAY4gSFQzgmAAChcuZH4Hj9dj7oCzscY3Hn8NfbUv7X7Jk4xL1lfKO113JLDhWKOt6fYw==}
dom-align@1.12.4:
resolution: {integrity: sha512-R8LUSEay/68zE5c8/3BDxiTEvgb4xZTF0RKmAHfiEVN3klfIpXfi2/QCoiWPccVQ0J/ZGdz9OjzL4uJEP/MRAw==}
... ... @@ -2735,6 +2824,9 @@ packages:
resolution: {integrity: sha512-m/C+AwOAr9/W1UOIZUo232ejMNnJAJtYQjUbHoNTBNTJSvqzzDh7vnrei3o3r3m9blf6ZoDkvcw0VmozNRFJxg==}
engines: {node: '>=12'}
duck@0.1.12:
resolution: {integrity: sha512-wkctla1O6VfP89gQ+J/yDesM0S7B7XLXjKGzXxMDVFg7uEn706niAtyYovKbyq1oT9YwDcly721/iUWoc8MVRg==}
dunder-proto@1.0.1:
resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==}
engines: {node: '>= 0.4'}
... ... @@ -3618,6 +3710,9 @@ packages:
engines: {node: '>=0.10.0'}
hasBin: true
immediate@3.0.6:
resolution: {integrity: sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ==}
import-fresh@3.3.1:
resolution: {integrity: sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==}
engines: {node: '>=6'}
... ... @@ -4142,6 +4237,9 @@ packages:
resolution: {integrity: sha512-POQXvpdL69+CluYsillJ7SUhKvytYjW9vG/GKpnf+xP8UWgYEM/RaMzHHofbALDiKbbP1W8UEYmgGl39WkPZsg==}
engines: {'0': node >= 0.2.0}
jszip@3.10.1:
resolution: {integrity: sha512-xXDvecyTpGLrqFrvkrUSoxxfJI5AH7U8zxxtVclpsUtMCq4JQ290LY8AW5c7Ggnr/Y/oK+bQMbqK2qmtk3pN4g==}
katex@0.16.22:
resolution: {integrity: sha512-XCHRdUw4lf3SKBaJe4EvgqIuWwkPSo9XoeO8GjQW94Bp7TWv9hNhzZjZ+OH9yf1UmLygb7DIT5GSFQiyt16zYg==}
hasBin: true
... ... @@ -4191,6 +4289,9 @@ packages:
resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==}
engines: {node: '>= 0.8.0'}
lie@3.3.0:
resolution: {integrity: sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ==}
lilconfig@3.0.0:
resolution: {integrity: sha512-K2U4W2Ff5ibV7j7ydLr+zLAkIg5JJ4lPn1Ltsdt+Tz/IjQ8buJ55pZAxoP34lqIiwtF9iAvtLv3JGv7CAyAg+g==}
engines: {node: '>=14'}
... ... @@ -4303,6 +4404,9 @@ packages:
resolution: {integrity: sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==}
hasBin: true
lop@0.4.2:
resolution: {integrity: sha512-RefILVDQ4DKoRZsJ4Pj22TxE3omDO47yFpkIBoDKzkqPRISs5U1cnAdg/5583YPkWPaLIYHOKRMQSvjFsO26cw==}
lower-case@2.0.2:
resolution: {integrity: sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg==}
... ... @@ -4337,6 +4441,11 @@ packages:
makeerror@1.0.12:
resolution: {integrity: sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==}
mammoth@1.9.1:
resolution: {integrity: sha512-4S2v1eP4Yo4so0zGNicJKcP93su3wDPcUk+xvkjSG75nlNjSkDJu8BhWQ+e54BROM0HfA6nPzJn12S6bq2Ko6w==}
engines: {node: '>=12.0.0'}
hasBin: true
map-cache@0.2.2:
resolution: {integrity: sha512-8y/eV9QQZCiyn1SprXSrCmqJN0yNRATe+PO8ztwqrvrbdRLA3eYJF0yaR0YayLWkMbsQSKWS9N2gPcGEc4UsZg==}
engines: {node: '>=0.10.0'}
... ... @@ -4695,6 +4804,9 @@ packages:
resolution: {integrity: sha512-ur5UIdyw5Y7yEj9wLzhqXiy6GZ3Mwx0yGI+5sMn2r0N0v3cKJvUmFH5yPP+WXh9e0xfyzyJX95D8l088DNFj7A==}
hasBin: true
option@0.2.4:
resolution: {integrity: sha512-pkEqbDyl8ou5cpq+VsnQbe/WlEy5qS7xPzMS1U55OCG9KPvwFD46zDbxQIj3egJSFc3D+XhYOPUzz49zQAVy7A==}
optionator@0.9.4:
resolution: {integrity: sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==}
engines: {node: '>= 0.8.0'}
... ... @@ -4745,6 +4857,9 @@ packages:
package-manager-detector@1.3.0:
resolution: {integrity: sha512-ZsEbbZORsyHuO00lY1kV3/t72yp6Ysay6Pd17ZAlNGuGwmWDLCJxFpRs0IzfXfj1o4icJOkUEioexFHzyPurSQ==}
pako@1.0.11:
resolution: {integrity: sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==}
param-case@3.0.4:
resolution: {integrity: sha512-RXlj7zCYokReqWpOPH9oYivUzLYZ5vAPIfEmCTNViosC78F8F0H9y7T7gG2M39ymgutxF5gcFEsyZQSph9Bp3A==}
... ... @@ -4846,6 +4961,10 @@ packages:
pathe@2.0.3:
resolution: {integrity: sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==}
pdfjs-dist@5.3.31:
resolution: {integrity: sha512-EhPdIjNX0fcdwYQO+e3BAAJPXt+XI29TZWC7COhIXs/K0JHcUt1Gdz1ITpebTwVMFiLsukdUZ3u0oTO7jij+VA==}
engines: {node: '>=20.16.0 || >=22.3.0'}
perfect-debounce@1.0.0:
resolution: {integrity: sha512-xCy9V055GLEqoFaHoC1SoLIaLmWctgCUaBaWxDZ7/Zx4CTyX7cJQLJOok/orfjZAh9kEYpjJa4d0KcJmCbctZA==}
... ... @@ -5021,6 +5140,9 @@ packages:
print-js@1.6.0:
resolution: {integrity: sha512-BfnOIzSKbqGRtO4o0rnj/K3681BSd2QUrsIZy/+WdCIugjIswjmx3lDEZpXB2ruGf9d4b3YNINri81+J0FsBWg==}
process-nextick-args@2.0.1:
resolution: {integrity: sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==}
promise-polyfill@7.1.2:
resolution: {integrity: sha512-FuEc12/eKqqoRYIGBrUptCBRhobL19PS2U31vMNTfyck1FxPyMfgsXyW4Mav85y/ZN1hop3hOwRlUDok23oYfQ==}
... ... @@ -5097,6 +5219,9 @@ packages:
resolution: {integrity: sha512-PORM8AgzXeskHO/WEv312k9U03B8K9JSiWF/8N9sUuFjBa+9SF2u6K7VClzXwDXab51jCd8Nd36CNM+zR97ScQ==}
engines: {node: '>=16'}
readable-stream@2.3.8:
resolution: {integrity: sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==}
readable-stream@3.6.2:
resolution: {integrity: sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==}
engines: {node: '>= 6'}
... ... @@ -5326,6 +5451,9 @@ packages:
resolution: {integrity: sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw==}
engines: {node: '>=0.10.0'}
setimmediate@1.0.5:
resolution: {integrity: sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==}
shallow-equal@1.2.1:
resolution: {integrity: sha512-S4vJDjHHMBaiZuT9NPb616CSmLf618jawtv3sufLl6ivK8WocjAo58cXwbRV1cgqxH0Qbv+iUt6m05eqEa2IRA==}
... ... @@ -5529,6 +5657,9 @@ packages:
resolution: {integrity: sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==}
engines: {node: '>= 0.4'}
string_decoder@1.1.1:
resolution: {integrity: sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==}
string_decoder@1.3.0:
resolution: {integrity: sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==}
... ... @@ -5901,6 +6032,9 @@ packages:
unconfig@0.3.13:
resolution: {integrity: sha512-N9Ph5NC4+sqtcOjPfHrRcHekBCadCXWTBzp2VYYbySOHW0PfD9XLCeXshTXjkPYwLrBr9AtSeU0CZmkYECJhng==}
underscore@1.13.7:
resolution: {integrity: sha512-GMXzWtsc57XAtguZgaQViUOzs0KTkk8ojr3/xAxXLITqf/3EMwxC0inyETfDFjH/Krbhuep0HNbbjI9i/q3F3g==}
undici-types@6.19.8:
resolution: {integrity: sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==}
... ... @@ -6277,6 +6411,10 @@ packages:
resolution: {integrity: sha512-ICP2e+jsHvAj2E2lIHxa5tjXRlKDJo4IdvPvCXbXQGdzSfmSpNVyIKMvoZHjDY9DP0zV17iI85o90vRFXNccRw==}
engines: {node: '>=12'}
xmlbuilder@10.1.1:
resolution: {integrity: sha512-OyzrcFLL/nb6fMGHbiRDuPup9ljBycsdCypwuyg5AAHvyWzGfChJpCXMG88AGTIMFhGZ9RccFN1e6lhg3hkwKg==}
engines: {node: '>=4.0'}
xss@1.0.15:
resolution: {integrity: sha512-FVdlVVC67WOIPvfOwhoMETV72f6GbW7aOabBC3WxN/oUdoEMDyLz4OgRv5/gck2ZeNqEQu+Tb0kloovXOfpYVg==}
engines: {node: '>= 0.10.0'}
... ... @@ -7226,6 +7364,50 @@ snapshots:
vue: 3.5.14(typescript@4.9.5)
vue-demi: 0.14.10(vue@3.5.14(typescript@4.9.5))
'@napi-rs/canvas-android-arm64@0.1.71':
optional: true
'@napi-rs/canvas-darwin-arm64@0.1.71':
optional: true
'@napi-rs/canvas-darwin-x64@0.1.71':
optional: true
'@napi-rs/canvas-linux-arm-gnueabihf@0.1.71':
optional: true
'@napi-rs/canvas-linux-arm64-gnu@0.1.71':
optional: true
'@napi-rs/canvas-linux-arm64-musl@0.1.71':
optional: true
'@napi-rs/canvas-linux-riscv64-gnu@0.1.71':
optional: true
'@napi-rs/canvas-linux-x64-gnu@0.1.71':
optional: true
'@napi-rs/canvas-linux-x64-musl@0.1.71':
optional: true
'@napi-rs/canvas-win32-x64-msvc@0.1.71':
optional: true
'@napi-rs/canvas@0.1.71':
optionalDependencies:
'@napi-rs/canvas-android-arm64': 0.1.71
'@napi-rs/canvas-darwin-arm64': 0.1.71
'@napi-rs/canvas-darwin-x64': 0.1.71
'@napi-rs/canvas-linux-arm-gnueabihf': 0.1.71
'@napi-rs/canvas-linux-arm64-gnu': 0.1.71
'@napi-rs/canvas-linux-arm64-musl': 0.1.71
'@napi-rs/canvas-linux-riscv64-gnu': 0.1.71
'@napi-rs/canvas-linux-x64-gnu': 0.1.71
'@napi-rs/canvas-linux-x64-musl': 0.1.71
'@napi-rs/canvas-win32-x64-msvc': 0.1.71
optional: true
'@nodelib/fs.scandir@2.1.5':
dependencies:
'@nodelib/fs.stat': 2.0.5
... ... @@ -7958,6 +8140,8 @@ snapshots:
vue: 3.5.14(typescript@4.9.5)
xe-utils: 3.7.4
'@xmldom/xmldom@0.8.10': {}
'@zxcvbn-ts/core@3.0.4':
dependencies:
fastest-levenshtein: 1.0.16
... ... @@ -8233,6 +8417,8 @@ snapshots:
inherits: 2.0.4
readable-stream: 3.6.2
bluebird@3.4.7: {}
bluebird@3.7.2: {}
boolbase@1.0.0: {}
... ... @@ -8668,6 +8854,8 @@ snapshots:
core-js@3.42.0: {}
core-util-is@1.0.3: {}
cors@2.8.5:
dependencies:
object-assign: 4.1.1
... ... @@ -8930,6 +9118,8 @@ snapshots:
dijkstrajs@1.0.3: {}
dingbat-to-unicode@1.0.1: {}
dingtalk-jsapi@3.1.0:
dependencies:
promise-polyfill: 7.1.2
... ... @@ -8942,6 +9132,10 @@ snapshots:
dependencies:
esutils: 2.0.3
docx-preview@0.3.5:
dependencies:
jszip: 3.10.1
dom-align@1.12.4: {}
dom-scroll-into-view@2.0.1: {}
... ... @@ -9011,6 +9205,10 @@ snapshots:
dotenv@16.5.0: {}
duck@0.1.12:
dependencies:
underscore: 1.13.7
dunder-proto@1.0.1:
dependencies:
call-bind-apply-helpers: 1.0.2
... ... @@ -10008,6 +10206,8 @@ snapshots:
image-size@0.5.5: {}
immediate@3.0.6: {}
import-fresh@3.3.1:
dependencies:
parent-module: 1.0.1
... ... @@ -10708,6 +10908,13 @@ snapshots:
jsonparse@1.3.1: {}
jszip@3.10.1:
dependencies:
lie: 3.3.0
pako: 1.0.11
readable-stream: 2.3.8
setimmediate: 1.0.5
katex@0.16.22:
dependencies:
commander: 8.3.0
... ... @@ -10759,6 +10966,10 @@ snapshots:
prelude-ls: 1.2.1
type-check: 0.4.0
lie@3.3.0:
dependencies:
immediate: 3.0.6
lilconfig@3.0.0: {}
lines-and-columns@1.2.4: {}
... ... @@ -10875,6 +11086,12 @@ snapshots:
dependencies:
js-tokens: 4.0.0
lop@0.4.2:
dependencies:
duck: 0.1.12
option: 0.2.4
underscore: 1.13.7
lower-case@2.0.2:
dependencies:
tslib: 2.8.1
... ... @@ -10911,6 +11128,19 @@ snapshots:
dependencies:
tmpl: 1.0.5
mammoth@1.9.1:
dependencies:
'@xmldom/xmldom': 0.8.10
argparse: 1.0.10
base64-js: 1.5.1
bluebird: 3.4.7
dingbat-to-unicode: 1.0.1
jszip: 3.10.1
lop: 0.4.2
path-is-absolute: 1.0.1
underscore: 1.13.7
xmlbuilder: 10.1.1
map-cache@0.2.2: {}
map-obj@1.0.1: {}
... ... @@ -11273,6 +11503,8 @@ snapshots:
opener@1.5.2: {}
option@0.2.4: {}
optionator@0.9.4:
dependencies:
deep-is: 0.1.4
... ... @@ -11332,6 +11564,8 @@ snapshots:
package-manager-detector@1.3.0: {}
pako@1.0.11: {}
param-case@3.0.4:
dependencies:
dot-case: 3.0.4
... ... @@ -11422,6 +11656,10 @@ snapshots:
pathe@2.0.3: {}
pdfjs-dist@5.3.31:
optionalDependencies:
'@napi-rs/canvas': 0.1.71
perfect-debounce@1.0.0: {}
picocolors@1.1.1: {}
... ... @@ -11584,6 +11822,8 @@ snapshots:
print-js@1.6.0: {}
process-nextick-args@2.0.1: {}
promise-polyfill@7.1.2: {}
prompts@2.4.2:
... ... @@ -11661,6 +11901,16 @@ snapshots:
parse-json: 7.1.1
type-fest: 4.41.0
readable-stream@2.3.8:
dependencies:
core-util-is: 1.0.3
inherits: 2.0.4
isarray: 1.0.0
process-nextick-args: 2.0.1
safe-buffer: 5.1.2
string_decoder: 1.1.1
util-deprecate: 1.0.2
readable-stream@3.6.2:
dependencies:
inherits: 2.0.4
... ... @@ -11908,6 +12158,8 @@ snapshots:
is-plain-object: 2.0.4
split-string: 3.1.0
setimmediate@1.0.5: {}
shallow-equal@1.2.1: {}
shebang-command@1.2.0:
... ... @@ -12137,6 +12389,10 @@ snapshots:
define-properties: 1.2.1
es-object-atoms: 1.1.1
string_decoder@1.1.1:
dependencies:
safe-buffer: 5.1.2
string_decoder@1.3.0:
dependencies:
safe-buffer: 5.2.1
... ... @@ -12548,6 +12804,8 @@ snapshots:
defu: 6.1.4
jiti: 1.21.7
underscore@1.13.7: {}
undici-types@6.19.8: {}
undici@6.21.3: {}
... ... @@ -12983,6 +13241,8 @@ snapshots:
xml-name-validator@4.0.0: {}
xmlbuilder@10.1.1: {}
xss@1.0.15:
dependencies:
commander: 2.20.3
... ...
... ... @@ -14,3 +14,5 @@ export const getLoginfo = (params) => defHttp.get({ url: Api.loginfo, params },
* @param params
*/
export const getVisitInfo = (params) => defHttp.get({ url: Api.visitInfo, params }, { isTransformResponse: false });
export const getStatistics = () => defHttp.get({ url: '/airaglog/airagLog/getStatistics' });
... ...
... ... @@ -16,7 +16,12 @@
<a-tab-pane loading="true" tab="受理监管" key="1">
<a-row>
<a-col :xl="16" :lg="12" :md="12" :sm="24" :xs="24">
<Bar :chartData="barData" :option="{ title: { text: '', textStyle: { fontWeight: 'lighter' } } }" height="40vh" :seriesColor="seriesColor" />
<Bar
:chartData="barData"
:option="{ title: { text: '', textStyle: { fontWeight: 'lighter' } } }"
height="40vh"
:seriesColor="seriesColor"
/>
</a-col>
<a-col :xl="8" :lg="12" :md="12" :sm="24" :xs="24">
<QuickNav :loading="loading" class="enter-y" :bordered="false" :body-style="{ padding: 0 }" />
... ... @@ -41,8 +46,8 @@
<a-tab-pane tab="存储监管" key="3">
<a-row>
<a-col :xl="16" :lg="12" :md="12" :sm="24" :xs="24" style="display: flex">
<Gauge :seriesColor="seriesColor" :chartData="{ name: 'C盘', value: 70 }" height="30vh"></Gauge>
<Gauge :seriesColor="seriesColor" :chartData="{ name: 'D盘', value: 50 }" height="30vh"></Gauge>
<Gauge :seriesColor="seriesColor" :chartData="{ name: 'C盘', value: 70 }" height="30vh" />
<Gauge :seriesColor="seriesColor" :chartData="{ name: 'D盘', value: 50 }" height="30vh" />
</a-col>
<a-col :xl="8" :lg="12" :md="12" :sm="24" :xs="24">
<QuickNav :loading="loading" class="enter-y" :bordered="false" :body-style="{ padding: 0 }" />
... ...
... ... @@ -4,7 +4,7 @@
<ChartCard
:loading="loading"
:title="item.title"
:total="getTotal(item.total, index)"
:total="item.total"
class="md:w-1/4 w-full !md:mt-0 !mt-4"
:class="[index + 1 < 4 && '!md:mr-4']"
>
... ... @@ -14,31 +14,38 @@
</a-tooltip>
</template>
<div v-if="type === 'chart'">
<Trend term="周同比" :percentage="12" v-if="index === 0" />
<Trend term="日同比" :percentage="11" v-if="index === 0" :type="false" />
<SingleLine v-if="index === 1" :option="option" :chartData="chartData" :seriesColor="seriesColor" height="50px"></SingleLine>
<!-- <Trend term="周同比" :percentage="12" v-if="index === 0" />-->
<!-- <Trend term="日同比" :percentage="11" v-if="index === 0" :type="false" />-->
<div v-if="index === 0" class="p-2 px-4 flex justify-between">
<span>平均问答次数</span>
<span>{{ formatNumber(statistics.averageCount) }}</span>
</div>
<SingleLine v-if="index === 1" :option="option" :chartData="chartData" :seriesColor="seriesColor" height="50px" />
<Bar v-if="index === 2" :option="option" :chartData="chartData" :seriesColor="seriesColor" height="50px"></Bar>
<Bar v-if="index === 2" :option="option" :chartData="chartData" :seriesColor="seriesColor" height="50px" />
<Progress v-if="index === 3" :percent="78" :show-info="false"></Progress>
<Trend
v-if="index === 3"
:term="statistics.growthRate >= 0 ? '日增长' : '日下降'"
:percentage="Math.abs(statistics.growthRate)"
:type="statistics.growthRate >= 0"
/>
</div>
<div v-else>
<SingleLine :seriesColor="seriesColor" v-if="index === 0" :option="option" :chartData="chartData" height="50px"></SingleLine>
<SingleLine :seriesColor="seriesColor" v-if="index === 1" :option="option" :chartData="chartData" height="50px"></SingleLine>
<SingleLine :seriesColor="seriesColor" v-if="index === 0" :option="option" :chartData="chartData" height="50px" />
<Bar :seriesColor="seriesColor" v-if="index === 2" :option="option" :chartData="chartData" height="50px"></Bar>
<SingleLine :seriesColor="seriesColor" v-if="index === 1" :option="option" :chartData="chartData" height="50px" />
<Progress v-if="index === 3" :percent="78" :show-info="false"></Progress>
<Bar :seriesColor="seriesColor" v-if="index === 2" :option="option" :chartData="chartData" height="50px" />
<Progress v-if="index === 3" :percent="78" :show-info="false" />
</div>
<template #footer v-if="type === 'chart'">
<span v-if="index !== 3"
>{{ item.footer }}<span>{{ item.value }}</span></span
>
<Trend term="周同比" :percentage="12" v-if="index === 3" />
<Trend term="日同比" :percentage="11" v-if="index === 3" :type="false" />
<!-- <Trend term="周同比" :percentage="12" v-if="index === 3" />-->
<!-- <Trend term="日同比" :percentage="11" v-if="index === 3" :type="false" />-->
</template>
<template #footer v-else>
<span
... ... @@ -50,18 +57,28 @@
</div>
</template>
<script lang="ts" setup>
import { ref, computed } from 'vue';
import { ref, computed, watch, toRaw } from 'vue';
import { Icon } from '/@/components/Icon';
import { Progress } from 'ant-design-vue';
import ChartCard from '/@/components/chart/ChartCard.vue';
import Trend from '/@/components/chart/Trend.vue';
import Bar from '/@/components/chart/Bar.vue';
import SingleLine from '/@/components/chart/SingleLine.vue';
import { chartCardList, bdcCardList } from '../data';
import { bdcCardList } from '../data';
import { useRootSetting } from '/@/hooks/setting/useRootSetting';
const { getThemeColor } = useRootSetting();
const props = defineProps({
statistics: {
type: Object,
default: () => ({
todayCount: 0,
rejectedCount: 0,
totalCount: 0,
averageCount: 0,
monthlyData: [],
}),
},
loading: {
type: Boolean,
},
... ... @@ -100,10 +117,75 @@
]);
const seriesColor = computed(() => {
return getThemeColor.value;
})
const dataList = computed(() => (props.type === 'dbc' ? bdcCardList : chartCardList));
});
console.log('ChartGroupCard 组件渲染,接收到的 statistics:', toRaw(props.statistics));
// 动态生成数据
// 修复计算属性:使用props.statistics直接访问
const dataList = computed(() => {
if (props.type === 'dbc') {
return bdcCardList;
}
// 使用解构确保响应式依赖
const { todayCount, rejectedCount, totalCount, growthRate } = props.statistics;
return [
{
title: '累计问答次数',
icon: 'visit-count|svg',
total: totalCount || 0,
},
{
title: '今日问答次数',
icon: 'total-sales|svg',
total: todayCount || 0,
color: 'blue',
},
{
title: '拒绝回答次数',
icon: 'download-count|svg',
total: rejectedCount || 0,
color: 'orange',
},
{
title: '对比前一日增长同比',
icon: 'transaction|svg',
total: formatGrowthRate(growthRate),
},
];
});
// 添加数字格式化函数
const formatNumber = (value: number) => {
if (isNaN(value)) return '0';
return value.toFixed(2);
};
function getTotal(total, index) {
return index === 0 ? `¥${total}` : index === 3 ? `${total}%` : total;
// 格式化增长率显示
function formatGrowthRate(rate: number): string {
if (rate > 0) {
return `+${rate.toFixed(2)}%`;
} else if (rate < 0) {
return `${rate.toFixed(2)}%`;
}
return '0.00%';
}
// 监测 props.statistics 的变化
watch(
() => props.statistics,
(newStatistics) => {
console.log('statistics 更新:', newStatistics);
// 这里可以添加其他处理逻辑,如果有必要的话
},
{ deep: true }
);
// 使用 toRaw 确保打印真实值
watch(
() => props.statistics,
(newVal) => {
console.log('子组件接收到新的 statistics:', toRaw(newVal));
},
{ deep: true, immediate: true }
);
</script>
... ...
... ... @@ -47,7 +47,7 @@
title: '我的任务',
icon: 'ion:person-stalker',
color: '#b27315',
}
},
];
function goPage() {
... ...
... ... @@ -13,61 +13,64 @@
<a-range-picker :style="{ width: '256px' }" />
</div>
</template>
<a-tab-pane loading="true" tab="销售额" key="1">
<a-tab-pane loading="true" tab="每月问答次数" key="1">
<a-row>
<a-col :xl="16" :lg="12" :md="12" :sm="24" :xs="24">
<Bar :chartData="barData" :option="{ title: { text: '', textStyle: { fontWeight: 'lighter' } } }" height="40vh" :seriesColor="seriesColor" />
<Bar
:chartData="barData"
:option="{ title: { text: '', textStyle: { fontWeight: 'lighter' } } }"
height="40vh"
:seriesColor="seriesColor"
/>
</a-col>
<a-col :xl="8" :lg="12" :md="12" :sm="24" :xs="24">
<RankList title="门店销售排行榜" :list="rankList" />
</a-col>
</a-row>
</a-tab-pane>
<a-tab-pane tab="销售趋势" key="2">
<a-row>
<a-col :xl="16" :lg="12" :md="12" :sm="24" :xs="24">
<Bar :chartData="barData.reverse()" :option="{ title: { text: '', textStyle: { fontWeight: 'lighter' } } }" height="40vh" :seriesColor="seriesColor" />
</a-col>
<a-col :xl="8" :lg="12" :md="12" :sm="24" :xs="24">
<RankList title="门店销售排行榜" :list="rankList" />
<RankList title="按钮统计榜" :list="buttonStats" />
</a-col>
</a-row>
</a-tab-pane>
<!-- <a-tab-pane tab="销售趋势" key="2">-->
<!-- <a-row>-->
<!-- <a-col :xl="16" :lg="12" :md="12" :sm="24" :xs="24">-->
<!-- <Bar-->
<!-- :chartData="barData.reverse()"-->
<!-- :option="{ title: { text: '', textStyle: { fontWeight: 'lighter' } } }"-->
<!-- height="40vh"-->
<!-- :seriesColor="seriesColor"-->
<!-- />-->
<!-- </a-col>-->
<!-- <a-col :xl="8" :lg="12" :md="12" :sm="24" :xs="24">-->
<!-- <RankList title="门店销售排行榜" :list="rankList" />-->
<!-- </a-col>-->
<!-- </a-row>-->
<!-- </a-tab-pane>-->
</a-tabs>
</div>
</a-card>
</template>
<script lang="ts" setup>
import { ref, computed } from 'vue';
import { computed } from 'vue';
import Bar from '/@/components/chart/Bar.vue';
import RankList from '/@/components/chart/RankList.vue';
import { useRootSetting } from '/@/hooks/setting/useRootSetting';
defineProps({
loading: {
type: Boolean,
},
barData: {
type: Array as () => Array<{ name: string; value: number }>, // 直接定义类型
default: () => [],
},
buttonStats: {
// 添加按钮统计属性
type: Array as () => Array<{ question: string; total: number }>,
default: () => [],
},
});
const { getThemeColor } = useRootSetting();
const rankList = [];
for (let i = 0; i < 7; i++) {
rankList.push({
name: '白鹭岛 ' + (i + 1) + ' 号店',
total: 1234.56 - i * 100,
});
}
const barData = [];
for (let i = 0; i < 12; i += 1) {
barData.push({
name: `${i + 1}月`,
value: Math.floor(Math.random() * 1000) + 200,
});
}
const seriesColor = computed(() => {
return getThemeColor.value
})
return getThemeColor.value;
});
</script>
<style lang="less" scoped>
... ...
... ... @@ -43,32 +43,26 @@ export const growCardList: GrowCardItem[] = [
},
];
export const chartCardList: GrowCardItem[] = [
export const getChartCardList = (statistics) => [
{
title: '总销售额',
title: '累计问答次数',
icon: 'visit-count|svg',
total: 126560,
value: 234.56,
footer: '日均销售额',
total: statistics.totalCount || 0,
},
{
title: '订单量',
title: '今日问答次数',
icon: 'total-sales|svg',
value: 1234,
total: 8846,
total: statistics.todayCount || 0,
color: 'blue',
footer: '日订单量',
},
{
title: '支付笔数',
title: '拒绝回答次数',
icon: 'download-count|svg',
value: 60,
total: 6560,
total: statistics.rejectedCount || 0,
color: 'orange',
footer: '转化率',
},
{
title: '运营活动效果',
title: '对比前一日增长同比',
icon: 'transaction|svg',
total: 78,
},
... ...
<template>
<div class="p-4">
<ChartGroupCard class="enter-y" :loading="loading" type="chart" />
<SaleTabCard class="!my-4 enter-y" :loading="loading" />
<ChartGroupCard class="enter-y" :loading="loading" type="chart" :statistics="statistics" />
<SaleTabCard class="!my-4 enter-y" :loading="loading" :barData="barData" :buttonStats="buttonStats" />
<a-row>
<a-col :span="24">
<a-card :loading="loading" :bordered="false" title="最近一周访问量统计">
<div class="infoArea">
<HeadInfo title="今日IP" :iconColor="ipColor" :content="loginfo.todayIp" icon="environment"></HeadInfo>
<HeadInfo title="今日访问" :iconColor="visitColor" :content="loginfo.todayVisitCount" icon="team"></HeadInfo>
<HeadInfo title="总访问量" :iconColor="seriesColor" :content="loginfo.totalVisitCount" icon="rise"></HeadInfo>
<HeadInfo title="今日IP" :iconColor="ipColor" :content="loginfo.todayIp" icon="environment" />
<HeadInfo title="今日访问" :iconColor="visitColor" :content="loginfo.todayVisitCount" icon="team" />
<HeadInfo title="总访问量" :iconColor="seriesColor" :content="loginfo.totalVisitCount" icon="rise" />
</div>
<LineMulti :chartData="lineMultiData" height="33vh" type="line" :option="{ legend: { top: 'bottom' } }"></LineMulti>
<!-- <LineMulti :chartData="lineMultiData" height="33vh" type="line" :option="{ legend: { top: 'bottom' } }" />-->
</a-card>
</a-col>
</a-row>
</div>
</template>
<script lang="ts" setup>
import { ref, watch } from 'vue';
import { computed, onMounted, onUnmounted, ref, watch } from 'vue';
import ChartGroupCard from '../components/ChartGroupCard.vue';
import SaleTabCard from '../components/SaleTabCard.vue';
import LineMulti from '/@/components/chart/LineMulti.vue';
import HeadInfo from '/@/components/chart/HeadInfo.vue';
import { getLoginfo, getVisitInfo } from '../api.ts';
import { getLoginfo, getStatistics, getVisitInfo } from '../api';
import { useRootSetting } from '/@/hooks/setting/useRootSetting';
const loading = ref(true);
const { getThemeColor } = useRootSetting();
// 使用实时数据对象
const statistics = ref({
todayCount: 0,
yesterdayCount: 0,
growthRate: 0,
rejectedCount: 0,
totalCount: 0,
averageCount: 0,
buttonStats: [] as { question: string; count: number }[],
monthlyData: [] as { month: string; count: number }[],
});
// 实时数据获取函数
async function fetchStatistics() {
try {
const res = await getStatistics();
console.log('接收到的统计数据:', res); // 添加日志输出
console.log('res是否有success属性:', 'success' in res);
// 直接使用响应数据,不检查 success 属性
statistics.value = {
todayCount: res.todayCount || res.data?.todayCount || 0,
yesterdayCount: res.yesterdayCount || 0,
growthRate: res.growthRate || 0,
rejectedCount: res.rejectedCount || res.data?.rejectedCount || 0,
totalCount: res.totalCount || res.data?.totalCount || 0,
averageCount: res.averageCount || 0,
buttonStats: res.buttonStats || [],
monthlyData: res.monthlyData || res.data?.monthlyData || generateMonthlyData(),
};
console.log('更新后的 statistics:', statistics.value);
} catch (e) {
console.error('获取统计数据失败', e);
}
}
// 生成模拟月度数据(当后端未提供时)
function generateMonthlyData() {
return Array.from({ length: 12 }, (_, i) => ({
name: `${i + 1}月`,
value: Math.floor(Math.random() * 1000) + 200,
}));
}
// 转换按钮统计数据格式
const buttonStats = computed(() => {
return statistics.value.buttonStats.map((item) => ({
name: item.question,
total: item.count,
}));
});
// 在 setup 中添加转换函数
const barData = computed(() => {
if (!statistics.value.monthlyData) return [];
return statistics.value.monthlyData.map((item) => {
// 提取月份数字 (格式如 "2025-05" -> 5)
const monthNum = parseInt(item.month.split('-')[1]);
return {
name: `${monthNum}月`,
value: item.count,
};
});
});
// 设置实时更新
let refreshTimer: number | null = null;
onMounted(() => {
fetchStatistics();
// 每5秒更新一次数据(根据需求调整间隔)
refreshTimer = setInterval(fetchStatistics, 5000) as unknown as number;
});
onUnmounted(() => {
if (refreshTimer) clearInterval(refreshTimer);
});
setTimeout(() => {
loading.value = false;
}, 500);
const loginfo = ref({});
const lineMultiData = ref([]);
function initLogInfo() {
getLoginfo(null).then((res) => {
if (res.success) {
... ...
<template>
<IndexChart v-if="indexStyle === 0"></IndexChart>
<IndexDef v-if="indexStyle === 1"></IndexDef>
<IndexBdc v-if="indexStyle == 2"></IndexBdc>
<IndexTask v-if="indexStyle == 3"></IndexTask>
<IndexChart v-if="indexStyle === 0" />
<IndexDef v-if="indexStyle === 1" />
<IndexBdc v-if="indexStyle == 2" />
<IndexTask v-if="indexStyle == 3" />
<div style="width: 100%; text-align: right; margin-top: 20px">
首页主题:
<a-radio-group v-model:value="indexStyle">
... ...
<template>
<div class="wrap">
<div class="content">
<AiChat></AiChat>
<AiChat />
</div>
</div>
</template>
<script setup>
import AiChat from '/@/views/super/airag/aiapp/chat/AiChat.vue';
</script>
<style lang="less" scoped>
... ...
... ... @@ -35,6 +35,11 @@ export const columns: BasicColumn[] = [
align: 'center',
dataIndex: 'buttonValues',
},
{
title: '按钮code',
align: 'center',
dataIndex: 'code',
},
];
// 定义开关状态映射
const switchLoading = reactive<Record<string, boolean>>({});
... ... @@ -93,6 +98,12 @@ export const formSchema: FormSchema[] = [
componentProps: {},
},
{
label: '按钮code',
field: 'code',
component: 'Input',
required: true,
},
{
label: '发送内容',
field: 'buttonValues',
component: 'InputTextArea', // 替换为文本域组件
... ...
... ... @@ -9,6 +9,7 @@ enum Api {
listKnowledgeName = '/airaglog/airagLog/listKnowledgeName',
save = '/airaglog/airagLog/add',
saveToQuestionLibrary = '/airaglog/airagLog/saveToQuestionLibrary',
saveToEmbeddingLibrary = '/airaglog/airagLog/saveToEmbeddingLibrary',
edit = '/airaglog/airagLog/edit',
deleteOne = '/airaglog/airagLog/delete',
deleteBatch = '/airaglog/airagLog/deleteBatch',
... ... @@ -40,6 +41,14 @@ export const saveToQuestionLibrary = (params) =>
'Content-Type': 'application/json',
},
});
export const saveToEmbeddingLibrary = (params) =>
defHttp.post({
url: Api.saveToEmbeddingLibrary,
params,
headers: {
'Content-Type': 'application/json',
},
});
/**
* 删除单个
*/
... ...
... ... @@ -51,6 +51,19 @@ export const columns: BasicColumn[] = [
},
},
{
title: '提问方式',
align: 'center',
dataIndex: 'codeType',
customRender: ({ text }) => {
return text === 1 ? '输入框提问' : '快捷按钮提问';
},
},
{
title: '按钮code',
align: 'center',
dataIndex: 'code',
},
{
title: '是否存入问题库',
align: 'center',
dataIndex: 'isStorage',
... ...
<template>
<div>
<!--引用表格-->
<BasicTable @register="registerTable" :rowSelection="rowSelection" @change="handleTableChange">
<BasicTable @register="registerTable" :rowSelection="rowSelection">
<!--插槽:table标题-->
<template #tableTitle>
<a-button type="primary" v-auth="'airaglog:airag_log:add'" @click="handleAdd" preIcon="ant-design:plus-outlined"> 新增</a-button>
... ... @@ -40,7 +40,7 @@
<script lang="ts" name="airaglog-airagLog" setup>
import { ref, reactive } from 'vue';
import { BasicTable, TableAction } from '/@/components/Table';
import { BasicTable, TableAction, type ActionItem } from '/@/components/Table';
import { useModal } from '/@/components/Modal';
import { useListPage } from '/@/hooks/system/useListPage';
import AiragLogModal from './components/AiragLogModal.vue';
... ... @@ -87,7 +87,7 @@
],
},
actionColumn: {
width: 120,
width: 200,
fixed: 'right',
},
beforeFetch: (params) => {
... ... @@ -174,20 +174,22 @@
* 操作栏
*/
function getTableAction(record) {
if (record.isStorage == 0)
return [
{
const actions: ActionItem[] = [];
if (record.isStorage == 0) {
actions.push({
label: '存入问题库',
onClick: () => handleSaveToQuestionLibrary(record),
auth: 'airaglog:airag_log:saveToQuestionLibrary',
},
];
else
return [
{
label: '',
},
];
});
}
if (record.ifSaveKnowledge == 0) {
actions.push({
label: '存入知识库',
onClick: () => handleSaveToEmbeddingLibrary(record),
auth: 'airaglog:airag_log:saveToEmbeddingLibrary',
});
}
return actions;
}
/**
* 存入问题库事件
... ... @@ -198,8 +200,10 @@
isUpdate: true,
showFooter: true,
showSaveButton: true,
operationType: 'question', // 指定操作类型
onConfirm: async (record) => {
try {
console.log('执行知识库保存操作...');
await defHttp.post({ url: '/airaglog/airagLog/saveToQuestionLibrary', params: record });
// 刷新列表
reload();
... ... @@ -210,24 +214,27 @@
});
}
/**
* 下拉操作栏
* 存入问题库事件
*/
function getDropDownAction(record) {
return [
{
label: '详情',
onClick: handleDetail.bind(null, record),
},
{
label: '删除',
popConfirm: {
title: '是否确认删除',
confirm: handleDelete.bind(null, record),
placement: 'topLeft',
},
auth: 'airaglog:airag_log:delete',
async function handleSaveToEmbeddingLibrary(record) {
console.log('点击存入知识库按钮,记录ID:', record.id);
openModal(true, {
record,
isUpdate: true,
showFooter: true,
showSaveButton: true,
operationType: 'knowledge', // 指定操作类型
onConfirm: async (record) => {
console.log("执行知识库确认回调");
try {
await defHttp.post({ url: '/airaglog/airagLog/saveToEmbeddingLibrary', params: record });
// 刷新列表
reload();
} catch (error) {
console.error('存入知识库失败', error);
}
},
];
});
}
</script>
... ...
... ... @@ -4,8 +4,13 @@
<template #footer>
<a-button @click="closeModal">取消</a-button>
<!-- 根据 showSaveButton 决定显示哪个按钮 -->
<template v-if="showSaveButton">
<a-button @click="handleSubmit" type="primary">存入</a-button>
<!-- 根据操作类型显示不同按钮 -->
<template v-if="operationType === 'question'">
<a-button @click="handleSubmit" type="primary">存入问题库</a-button>
</template>
<template v-else-if="operationType === 'knowledge'">
<a-button @click="handleSubmit" type="primary">存入知识库</a-button>
</template>
<template v-else>
<a-button @click="handleSubmit">确认</a-button>
... ... @@ -20,17 +25,14 @@
import { BasicForm, useForm } from '/@/components/Form/index';
import { formSchema } from '../AiragLog.data';
import { saveOrUpdate } from '../AiragLog.api';
// 添加操作类型标识
const operationType = ref<string>('');
// Emits声明
const emit = defineEmits(['register', 'success']);
const isUpdate = ref(true);
const isDetail = ref(false);
const showSaveButton = ref(true);
const props = defineProps({
onConfirm: {
type: Function,
default: null,
},
});
let customOnConfirm = ref<Function | null>(null);
//表单配置
const [registerForm, { setProps, resetFields, setFieldsValue, validate, scrollToField }] = useForm({
labelWidth: 150,
... ... @@ -40,9 +42,13 @@
});
//表单赋值
const [registerModal, { setModalProps, closeModal }] = useModalInner(async (data) => {
console.log("模态框打开,操作类型:", data?.operationType);
//重置表单
await resetFields();
setModalProps({ confirmLoading: false, showCancelBtn: !!data?.showFooter, showOkBtn: !!data?.showFooter });
// 设置操作类型
operationType.value = data?.operationType || '';
customOnConfirm.value = data?.onConfirm || null;
isUpdate.value = !!data?.isUpdate;
isDetail.value = !!data?.showFooter;
if (unref(isUpdate)) {
... ... @@ -54,17 +60,26 @@
// 隐藏底部时禁用整个表单
setProps({ disabled: !data?.showFooter });
});
//设置标题
const title = computed(() => (!unref(isUpdate) ? '新增' : !unref(isDetail) ? '详情' : '编辑'));
// 根据操作类型设置标题
const title = computed(() => {
if (operationType.value === 'question') return '存入问题库';
if (operationType.value === 'knowledge') return '存入知识库';
return !unref(isUpdate) ? '新增' : !unref(isDetail) ? '详情' : '编辑';
});
//表单提交事件
async function handleSubmit(v) {
console.log('表单提交,操作类型:', operationType.value);
try {
let values = await validate();
setModalProps({ confirmLoading: true });
if (props.onConfirm) {
await props.onConfirm(values);
console.log('当前操作类型:', operationType.value);
// 如果有传入的onConfirm函数,则执行它
if (typeof customOnConfirm.value === 'function') {
console.log('执行自定义确认函数');
await customOnConfirm.value(values);
} else {
//提交表单
// 否则执行默认的保存
console.log('执行默认保存');
await saveOrUpdate(values, isUpdate.value);
}
//关闭弹窗
... ...
import { defHttp } from '/@/utils/http/axios';
import { useMessage } from '/@/hooks/web/useMessage';
import { useUserStore } from '/@/store/modules/user'; // 引入用户store获取token
const { createMessage } = useMessage();
... ...
... ... @@ -13,37 +13,37 @@ export const columns: BasicColumn[] = [
title: '文本内容',
align: 'center',
dataIndex: 'text',
width: 300
width: 300,
},
{
title: '文件名称',
align: 'center',
dataIndex: 'docName',
width: 150
width: 150,
},
{
title: '知识ID',
align: 'center',
dataIndex: 'knowledgeId',
width: 150
width: 150,
},
{
title: '文档ID',
align: 'center',
dataIndex: 'docId',
width: 150
width: 150,
},
{
title: '索引',
align: 'center',
dataIndex: 'index',
width: 80
width: 80,
},
{
title: '相似度',
align: 'center',
dataIndex: 'similarity',
width: 100
width: 100,
},
];
... ...
... ... @@ -50,7 +50,7 @@
</div>
<div class="preview-content">
<div v-if="previewType === 'txt' || previewType === 'md'" class="text-preview">
<pre style="white-space: pre-wrap;">{{ previewContent }}</pre>
<pre>{{ previewContent }}</pre>
</div>
<div v-else-if="previewType === 'pdf'" class="pdf-preview" ref="pdfPreview"></div>
<div v-else-if="previewType === 'docx'" class="docx-preview" ref="docxPreview"></div>
... ...