Initial commit
This commit is contained in:
commit
3e7dfd3306
24
.gitignore
vendored
Normal file
24
.gitignore
vendored
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
# Logs
|
||||||
|
logs
|
||||||
|
*.log
|
||||||
|
npm-debug.log*
|
||||||
|
yarn-debug.log*
|
||||||
|
yarn-error.log*
|
||||||
|
pnpm-debug.log*
|
||||||
|
lerna-debug.log*
|
||||||
|
|
||||||
|
node_modules
|
||||||
|
dist
|
||||||
|
dist-ssr
|
||||||
|
*.local
|
||||||
|
|
||||||
|
# Editor directories and files
|
||||||
|
.vscode/*
|
||||||
|
!.vscode/extensions.json
|
||||||
|
.idea
|
||||||
|
.DS_Store
|
||||||
|
*.suo
|
||||||
|
*.ntvs*
|
||||||
|
*.njsproj
|
||||||
|
*.sln
|
||||||
|
*.sw?
|
||||||
3
.vscode/extensions.json
vendored
Normal file
3
.vscode/extensions.json
vendored
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
{
|
||||||
|
"recommendations": ["Vue.volar"]
|
||||||
|
}
|
||||||
10
auto-imports.d.ts
vendored
Normal file
10
auto-imports.d.ts
vendored
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
/* eslint-disable */
|
||||||
|
/* prettier-ignore */
|
||||||
|
// @ts-nocheck
|
||||||
|
// noinspection JSUnusedGlobalSymbols
|
||||||
|
// Generated by unplugin-auto-import
|
||||||
|
// biome-ignore lint: disable
|
||||||
|
export {}
|
||||||
|
declare global {
|
||||||
|
|
||||||
|
}
|
||||||
15
components.d.ts
vendored
Normal file
15
components.d.ts
vendored
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
/* eslint-disable */
|
||||||
|
// @ts-nocheck
|
||||||
|
// Generated by unplugin-vue-components
|
||||||
|
// Read more: https://github.com/vuejs/core/pull/3399
|
||||||
|
export {}
|
||||||
|
|
||||||
|
/* prettier-ignore */
|
||||||
|
declare module 'vue' {
|
||||||
|
export interface GlobalComponents {
|
||||||
|
ElInput: typeof import('element-plus/es')['ElInput']
|
||||||
|
Robot: typeof import('./src/components/robot.vue')['default']
|
||||||
|
RouterLink: typeof import('vue-router')['RouterLink']
|
||||||
|
RouterView: typeof import('vue-router')['RouterView']
|
||||||
|
}
|
||||||
|
}
|
||||||
25
eslint.config.js
Normal file
25
eslint.config.js
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
/*
|
||||||
|
* @Author: cclu 1106109051@qq.com
|
||||||
|
* @Date: 2024-11-18 11:54:00
|
||||||
|
* @LastEditors: cclu 1106109051@qq.com
|
||||||
|
* @LastEditTime: 2024-11-18 11:54:18
|
||||||
|
* @FilePath: \aiRobot\eslint.config.js
|
||||||
|
* @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
|
||||||
|
*/
|
||||||
|
module.exports = {
|
||||||
|
root: true,
|
||||||
|
env: {
|
||||||
|
node: true,
|
||||||
|
},
|
||||||
|
extends: [
|
||||||
|
'eslint:recommended',
|
||||||
|
'plugin:vue/vue3-essential',
|
||||||
|
'@vue/eslint-config-typescript/recommended',
|
||||||
|
],
|
||||||
|
parserOptions: {
|
||||||
|
ecmaVersion: 2020,
|
||||||
|
},
|
||||||
|
rules: {
|
||||||
|
// 自定义规则
|
||||||
|
},
|
||||||
|
};
|
||||||
28
index.html
Normal file
28
index.html
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
<!--
|
||||||
|
* @Author: cclu 1106109051@qq.com
|
||||||
|
* @Date: 2024-11-18 11:40:21
|
||||||
|
* @LastEditors: cclu 1106109051@qq.com
|
||||||
|
* @LastEditTime: 2024-11-19 09:33:22
|
||||||
|
* @FilePath: \aiRobot\index.html
|
||||||
|
* @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
|
||||||
|
-->
|
||||||
|
<!doctype html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8" />
|
||||||
|
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
|
<title>地图测试</title>
|
||||||
|
<base href="/map/">
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id="app"></div>
|
||||||
|
</body>
|
||||||
|
<script type="module" src="/src/main.ts"></script>
|
||||||
|
<style>
|
||||||
|
*{
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</html>
|
||||||
7774
package-lock.json
generated
Normal file
7774
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
38
package.json
Normal file
38
package.json
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
{
|
||||||
|
"name": "airobot",
|
||||||
|
"private": true,
|
||||||
|
"version": "0.0.0",
|
||||||
|
"type": "module",
|
||||||
|
"scripts": {
|
||||||
|
"dev": "vite",
|
||||||
|
"build": "vue-tsc -b && vite build",
|
||||||
|
"preview": "vite preview"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@antv/l7": "^2.22.3",
|
||||||
|
"@antv/l7-maps": "^2.22.3",
|
||||||
|
"axios": "^1.7.7",
|
||||||
|
"element-plus": "^2.8.8",
|
||||||
|
"moment": "^2.30.1",
|
||||||
|
"pinia": "^2.2.6",
|
||||||
|
"rollup": "^4.27.3",
|
||||||
|
"vue-router": "^4.4.5"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@eslint/js": "^9.15.0",
|
||||||
|
"@types/node": "^22.9.0",
|
||||||
|
"@vitejs/plugin-vue": "^5.2.0",
|
||||||
|
"@vue/eslint-config-typescript": "^14.1.3",
|
||||||
|
"eslint": "^9.15.0",
|
||||||
|
"eslint-plugin-vue": "^9.31.0",
|
||||||
|
"globals": "^15.12.0",
|
||||||
|
"less": "^4.2.0",
|
||||||
|
"less-loader": "^12.2.0",
|
||||||
|
"prettier": "^3.3.3",
|
||||||
|
"typescript": "~5.6.2",
|
||||||
|
"typescript-eslint": "^8.14.0",
|
||||||
|
"vite": "^5.4.11",
|
||||||
|
"vue": "^3.5.13",
|
||||||
|
"vue-tsc": "^2.1.8"
|
||||||
|
}
|
||||||
|
}
|
||||||
1
public/vite.svg
Normal file
1
public/vite.svg
Normal file
@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="31.88" height="32" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 257"><defs><linearGradient id="IconifyId1813088fe1fbc01fb466" x1="-.828%" x2="57.636%" y1="7.652%" y2="78.411%"><stop offset="0%" stop-color="#41D1FF"></stop><stop offset="100%" stop-color="#BD34FE"></stop></linearGradient><linearGradient id="IconifyId1813088fe1fbc01fb467" x1="43.376%" x2="50.316%" y1="2.242%" y2="89.03%"><stop offset="0%" stop-color="#FFEA83"></stop><stop offset="8.333%" stop-color="#FFDD35"></stop><stop offset="100%" stop-color="#FFA800"></stop></linearGradient></defs><path fill="url(#IconifyId1813088fe1fbc01fb466)" d="M255.153 37.938L134.897 252.976c-2.483 4.44-8.862 4.466-11.382.048L.875 37.958c-2.746-4.814 1.371-10.646 6.827-9.67l120.385 21.517a6.537 6.537 0 0 0 2.322-.004l117.867-21.483c5.438-.991 9.574 4.796 6.877 9.62Z"></path><path fill="url(#IconifyId1813088fe1fbc01fb467)" d="M185.432.063L96.44 17.501a3.268 3.268 0 0 0-2.634 3.014l-5.474 92.456a3.268 3.268 0 0 0 3.997 3.378l24.777-5.718c2.318-.535 4.413 1.507 3.936 3.838l-7.361 36.047c-.495 2.426 1.782 4.5 4.151 3.78l15.304-4.649c2.372-.72 4.652 1.36 4.15 3.788l-11.698 56.621c-.732 3.542 3.979 5.473 5.943 2.437l1.313-2.028l72.516-144.72c1.215-2.423-.88-5.186-3.54-4.672l-25.505 4.922c-2.396.462-4.435-1.77-3.759-4.114l16.646-57.705c.677-2.35-1.37-4.583-3.769-4.113Z"></path></svg>
|
||||||
|
After Width: | Height: | Size: 1.5 KiB |
28
src/App.vue
Normal file
28
src/App.vue
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
<!--
|
||||||
|
* @Author: cclu 1106109051@qq.com
|
||||||
|
* @Date: 2024-11-19 17:27:17
|
||||||
|
* @LastEditors: cclu 1106109051@qq.com
|
||||||
|
* @LastEditTime: 2024-11-19 17:29:28
|
||||||
|
* @FilePath: \aiMap\src\App.vue
|
||||||
|
* @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
|
||||||
|
-->
|
||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<router-view></router-view>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { onMounted } from "vue";
|
||||||
|
import { useRouter } from "vue-router";
|
||||||
|
|
||||||
|
const router = useRouter();
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
router.push("/map");
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
/* 样式 */
|
||||||
|
</style>
|
||||||
BIN
src/assets/ai/AiIcon.png
Normal file
BIN
src/assets/ai/AiIcon.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 12 KiB |
BIN
src/assets/ai/profileIcon.png
Normal file
BIN
src/assets/ai/profileIcon.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 3.3 KiB |
BIN
src/assets/ai/searchIconBlue.png
Normal file
BIN
src/assets/ai/searchIconBlue.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 930 B |
BIN
src/assets/ai/userIcon.png
Normal file
BIN
src/assets/ai/userIcon.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 4.5 KiB |
1
src/assets/vue.svg
Normal file
1
src/assets/vue.svg
Normal file
@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="37.07" height="36" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 198"><path fill="#41B883" d="M204.8 0H256L128 220.8L0 0h97.92L128 51.2L157.44 0h47.36Z"></path><path fill="#41B883" d="m0 0l128 220.8L256 0h-51.2L128 132.48L50.56 0H0Z"></path><path fill="#35495E" d="M50.56 0L128 133.12L204.8 0h-47.36L128 51.2L97.92 0H50.56Z"></path></svg>
|
||||||
|
After Width: | Height: | Size: 496 B |
176
src/components/map/component/RobotDialogueBox.less
Normal file
176
src/components/map/component/RobotDialogueBox.less
Normal file
@ -0,0 +1,176 @@
|
|||||||
|
.closeBox{
|
||||||
|
.closeIcon{
|
||||||
|
width: 50px;
|
||||||
|
height: 50px;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.expandBox{
|
||||||
|
.boxTop{
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
.closeIcon{
|
||||||
|
width: 50px;
|
||||||
|
height: 50px;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
.titleText{
|
||||||
|
font-family: PingFangSC, PingFang SC;
|
||||||
|
font-weight: 500;
|
||||||
|
font-size: 16px;
|
||||||
|
color: rgba(255, 255, 255, 0.85);
|
||||||
|
line-height: 26px;
|
||||||
|
text-align: left;
|
||||||
|
font-style: normal;
|
||||||
|
margin-left: 4px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.dialogBox{
|
||||||
|
padding: 12px;
|
||||||
|
color: #fff;
|
||||||
|
width: 650px;
|
||||||
|
max-height: calc(100vh - 140px);
|
||||||
|
white-space: pre-wrap;
|
||||||
|
background: rgba(56, 56, 56, 0.51);
|
||||||
|
border-radius: 8px;
|
||||||
|
border: 1px solid #5F5F5F;
|
||||||
|
margin-top: 10px;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
.dialogContent{
|
||||||
|
width: 100%;
|
||||||
|
box-sizing: border-box;
|
||||||
|
max-height: 100vh;
|
||||||
|
padding: 12px;
|
||||||
|
flex: 1;
|
||||||
|
overflow-y: auto;
|
||||||
|
.dialogueBoxItem{
|
||||||
|
width: 100%;
|
||||||
|
display: flex;
|
||||||
|
align-items: flex-start;
|
||||||
|
margin-top: 12px;
|
||||||
|
.robotIcon{
|
||||||
|
width: 28px;
|
||||||
|
height: 28px;
|
||||||
|
margin-right: 8px;
|
||||||
|
}
|
||||||
|
.dialogueTextBox{
|
||||||
|
max-width: calc(100% - 36px);
|
||||||
|
min-width: 30px;
|
||||||
|
min-height: 22px;
|
||||||
|
background: rgba(27, 27, 27, 0.51);
|
||||||
|
border-radius: 4px;
|
||||||
|
padding: 8px 12px;
|
||||||
|
.el-loading-mask{
|
||||||
|
background-color: transparent!important;
|
||||||
|
.el-loading-spinner{
|
||||||
|
transform: translateY(50%);
|
||||||
|
.circular{
|
||||||
|
width: 20px!important;
|
||||||
|
height: 20px!important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.elTable{
|
||||||
|
.el-table__inner-wrapper{
|
||||||
|
.el-table__body-wrapper{
|
||||||
|
.el-scrollbar{
|
||||||
|
.el-scrollbar__wrap{
|
||||||
|
.el-scrollbar__view{
|
||||||
|
.el-table__body{
|
||||||
|
.el-table__row--level-0{
|
||||||
|
.el-table__cell{
|
||||||
|
.cell{
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.el-table__row--level-1{
|
||||||
|
.el-table__cell{
|
||||||
|
.cell{
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
.el-table__indent{
|
||||||
|
padding-left: 0!important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.el-table__row--level-2{
|
||||||
|
.el-table__cell{
|
||||||
|
.cell{
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
.el-table__indent{
|
||||||
|
padding-left: 0!important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.el-table__row--level-3{
|
||||||
|
.el-table__cell{
|
||||||
|
.cell{
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
.el-table__indent{
|
||||||
|
padding-left: 0!important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.el-table__row--level-4{
|
||||||
|
.el-table__cell{
|
||||||
|
.cell{
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
.el-table__indent{
|
||||||
|
padding-left: 0!important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.userIcon{
|
||||||
|
width: 28px;
|
||||||
|
height: 28px;
|
||||||
|
margin-left: 8px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.inputBox{
|
||||||
|
width: 100%;
|
||||||
|
box-sizing: border-box;
|
||||||
|
padding: 12px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
.searchText{
|
||||||
|
width: calc(100% - 30px);
|
||||||
|
.el-input__wrapper{
|
||||||
|
background-color: transparent!important;
|
||||||
|
.el-input__inner{
|
||||||
|
color: #fff !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.searchIcon{
|
||||||
|
width: 24px;
|
||||||
|
height: 24px;
|
||||||
|
margin-left: 6px;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
602
src/components/map/component/RobotDialogueBox.vue
Normal file
602
src/components/map/component/RobotDialogueBox.vue
Normal file
@ -0,0 +1,602 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import { log } from "console";
|
||||||
|
import moment from "moment";
|
||||||
|
import { onMounted, reactive, ref } from "vue";
|
||||||
|
import { formatNumber, wrapTreeNode } from "../../../options/serveice";
|
||||||
|
import request from "../../../request/requestConfig";
|
||||||
|
import {
|
||||||
|
handleGetANALYSISRULEDetail,
|
||||||
|
handleTranslateSentence,
|
||||||
|
} from "../service";
|
||||||
|
import "./RobotDialogueBox.less";
|
||||||
|
|
||||||
|
// 判断是否已经展开了对话框
|
||||||
|
const showDialogBox = ref<boolean>(false);
|
||||||
|
// 对话框记录
|
||||||
|
// type: 1 机器人 2 用户 text: 对话框中显示的文字 用户的是直接赋值上去 机器人回复要用v-html出现 isFirst: 只有默认初始的第一局才是true 后面都是false true的时候要显示点击标签
|
||||||
|
// haveTable: true 时对话框显示表格 tableData 对话框显示的表格内容 columns 对话框表格 显示的列
|
||||||
|
let dialogueList = reactive<any>([]);
|
||||||
|
// 搜索的文字
|
||||||
|
const searchText = ref<string>();
|
||||||
|
// 是否让最新的对话框 是加载效果
|
||||||
|
const isNewDialogLoading = ref<boolean>(false);
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
// 默认在初始显示的
|
||||||
|
});
|
||||||
|
|
||||||
|
// 展开机器人的方法 第一次要执行默认打招呼语 如果已经有了对话记录 就只是展开
|
||||||
|
const handleGetShowDailogBox = () => {
|
||||||
|
if (dialogueList && dialogueList.length > 0) {
|
||||||
|
showDialogBox.value = true;
|
||||||
|
} else {
|
||||||
|
isNewDialogLoading.value = true;
|
||||||
|
let obj: any = {
|
||||||
|
type: 1,
|
||||||
|
text: "",
|
||||||
|
isFirst: true,
|
||||||
|
};
|
||||||
|
dialogueList.push(obj);
|
||||||
|
showDialogBox.value = true;
|
||||||
|
|
||||||
|
setTimeout(() => {
|
||||||
|
dialogueList[0].text = "猜你想了解:";
|
||||||
|
isNewDialogLoading.value = false;
|
||||||
|
}, 1000);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
// 关闭对话框
|
||||||
|
const handleCloseDialogbox = () => {
|
||||||
|
showDialogBox.value = false;
|
||||||
|
};
|
||||||
|
// 添加对话内容的方法
|
||||||
|
const handleAddDialogList = () => {
|
||||||
|
console.log("searchText", searchText.value);
|
||||||
|
let userObj: any = {
|
||||||
|
type: 2,
|
||||||
|
text: searchText.value,
|
||||||
|
isFirst: false,
|
||||||
|
};
|
||||||
|
let robotObj: any = {
|
||||||
|
type: 1,
|
||||||
|
text: "",
|
||||||
|
isFirst: false,
|
||||||
|
};
|
||||||
|
|
||||||
|
dialogueList.push(userObj);
|
||||||
|
dialogueList.push(robotObj);
|
||||||
|
isNewDialogLoading.value = true;
|
||||||
|
};
|
||||||
|
// 给最后一个对话框赋值上结果 且关闭加载效果
|
||||||
|
const handleLastUpdate = (str: any) => {
|
||||||
|
dialogueList[dialogueList.lengtg - 1].text = str;
|
||||||
|
isNewDialogLoading.value = false;
|
||||||
|
};
|
||||||
|
// 配置请求的方法
|
||||||
|
const handleConfigRequest = async (
|
||||||
|
url: any,
|
||||||
|
params: any,
|
||||||
|
config: any,
|
||||||
|
answer: any
|
||||||
|
) => {
|
||||||
|
// url 请求地址 params 参数 config 配置输出结果的格式 answer 拿到回答问题的数据
|
||||||
|
let data: any;
|
||||||
|
if (config.acceptVerbs === "get") {
|
||||||
|
data = await request.get(url, params);
|
||||||
|
} else {
|
||||||
|
data = await request.post(url, params);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (config.responseFormat === "nestingList") {
|
||||||
|
data = wrapTreeNode(data.Result_Data.List);
|
||||||
|
} else {
|
||||||
|
data = data.Result_Data.List;
|
||||||
|
}
|
||||||
|
let newRes: any;
|
||||||
|
|
||||||
|
// 根据输出结果的的配置 去处理接口返回的结果
|
||||||
|
// 先判断是单个服务区 还是多个服务区
|
||||||
|
if (answer?.ServerpartId && answer?.ServerpartId.indexOf(",") === -1) {
|
||||||
|
console.log("sdasda", answer?.ServerpartId.indexOf(",") === -1);
|
||||||
|
|
||||||
|
// 单个服务区 那么要去掉合计和片区层 只展示服务区层即以下
|
||||||
|
if (config?.serverpart) {
|
||||||
|
if (data && data.length > 0) {
|
||||||
|
data.forEach((item: any) => {
|
||||||
|
if (config?.serverpart === 1) {
|
||||||
|
newRes = [item];
|
||||||
|
} else {
|
||||||
|
if (item.children && item.children.length > 0) {
|
||||||
|
item.children.forEach((subItem: any) => {
|
||||||
|
if (config?.serverpart === 2) {
|
||||||
|
newRes = [subItem];
|
||||||
|
} else {
|
||||||
|
if (subItem.children && subItem.children.length > 0) {
|
||||||
|
subItem.children.forEach((thirdItem: any) => {
|
||||||
|
if (config?.serverpart === 3) {
|
||||||
|
newRes = [thirdItem];
|
||||||
|
} else {
|
||||||
|
if (
|
||||||
|
thirdItem.children &&
|
||||||
|
thirdItem.children.length > 0
|
||||||
|
) {
|
||||||
|
thirdItem.children.forEach((fourthItem: any) => {
|
||||||
|
if (config?.serverpart === 4) {
|
||||||
|
newRes = [fourthItem];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// 多个服务区就不做处理了
|
||||||
|
newRes = data;
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log("newRes", newRes);
|
||||||
|
// 如果接口返回的数据 子集不是用children命令的 那么就得转一下 把那个命令的 变成 children
|
||||||
|
if (config?.shopList) {
|
||||||
|
if (newRes && newRes.length > 0) {
|
||||||
|
newRes.forEach((item: any) => {
|
||||||
|
if (item[config?.shopList] && item[config?.shopList].length > 0) {
|
||||||
|
item.children = item[config?.shopList];
|
||||||
|
} else {
|
||||||
|
if (item.children && item.children.length > 0) {
|
||||||
|
item.children.forEach((subItem: any) => {
|
||||||
|
if (
|
||||||
|
subItem[config?.shopList] &&
|
||||||
|
subItem[config?.shopList].length > 0
|
||||||
|
) {
|
||||||
|
subItem.children = subItem[config?.shopList];
|
||||||
|
} else {
|
||||||
|
if (subItem.children && subItem.children.length > 0) {
|
||||||
|
subItem.children.forEach((thirdItem: any) => {
|
||||||
|
if (
|
||||||
|
thirdItem[config?.shopList] &&
|
||||||
|
thirdItem[config?.shopList].length > 0
|
||||||
|
) {
|
||||||
|
thirdItem.children = thirdItem[config?.shopList];
|
||||||
|
} else {
|
||||||
|
if (thirdItem.children && thirdItem.children.length > 0) {
|
||||||
|
thirdItem.children.forEach((fourthItem: any) => {
|
||||||
|
if (
|
||||||
|
fourthItem[config?.shopList] &&
|
||||||
|
fourthItem[config?.shopList].length > 0
|
||||||
|
) {
|
||||||
|
fourthItem.children = fourthItem[config?.shopList];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return newRes;
|
||||||
|
};
|
||||||
|
|
||||||
|
// 去解析配置项 输出结果
|
||||||
|
const handleAnalyzeConfig = async (configDetail: any, answer: any) => {
|
||||||
|
// configDetail 配置内容 answer 回答问题接口返回的内容
|
||||||
|
|
||||||
|
let newReq: any = JSON.parse(configDetail?.PARAM_TEMPLATE || ""); // 入参
|
||||||
|
let newRESPONSE_CONFIG: any = JSON.parse(configDetail?.RESPONSE_CONFIG || ""); // 出参
|
||||||
|
let newPARSING_RULES: any = JSON.parse(configDetail?.PARSING_RULES || ""); // 对应的规则
|
||||||
|
let OUTPUT_FORMAT: any = JSON.parse(configDetail?.OUTPUT_FORMAT || ""); // 输出格式
|
||||||
|
|
||||||
|
console.log("newReq", newReq);
|
||||||
|
console.log("newRESPONSE_CONFIG", newRESPONSE_CONFIG);
|
||||||
|
console.log("newPARSING_RULES", newPARSING_RULES);
|
||||||
|
console.log("OUTPUT_FORMAT", OUTPUT_FORMAT);
|
||||||
|
|
||||||
|
// 配置请求的参数
|
||||||
|
let req: any = {};
|
||||||
|
if (newReq) {
|
||||||
|
for (let key in newReq) {
|
||||||
|
let realKey: any = newPARSING_RULES[key];
|
||||||
|
if (realKey) {
|
||||||
|
let currentUser: any = {
|
||||||
|
ProvinceCode: "340000",
|
||||||
|
};
|
||||||
|
// formatType 0:数值 1:字段 2:取缓存 3:取年份 name 就是去resData里面去字段 value 非1 的时候会有值
|
||||||
|
if (realKey.formatType === 1) {
|
||||||
|
req[key] = answer[realKey.fieldName];
|
||||||
|
} else if (realKey.formatType === 0) {
|
||||||
|
req[key] = realKey.value;
|
||||||
|
} else if (realKey.formatType === 2) {
|
||||||
|
req[key] = currentUser[realKey.fieldName];
|
||||||
|
} else if (realKey.formatType === 3) {
|
||||||
|
req[key] = answer[realKey.fieldName]
|
||||||
|
? moment(answer[realKey.fieldName]).format("YYYY")
|
||||||
|
: "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
console.log("req", req);
|
||||||
|
// 配置请求
|
||||||
|
// 接口返回的结果
|
||||||
|
let result: any;
|
||||||
|
if (OUTPUT_FORMAT) {
|
||||||
|
result = await handleConfigRequest(
|
||||||
|
configDetail?.API_ENDPOINT,
|
||||||
|
req,
|
||||||
|
OUTPUT_FORMAT,
|
||||||
|
answer
|
||||||
|
);
|
||||||
|
}
|
||||||
|
// 如果返回的表格数据里面有对象格式的 需要拆开来
|
||||||
|
let newRes: any = [];
|
||||||
|
if (result && result.length > 0) {
|
||||||
|
result.forEach((item: any, index: number) => {
|
||||||
|
item.rowKey = `${index + 1}`;
|
||||||
|
if (item.children && item.children.length > 0) {
|
||||||
|
item.children.forEach((subItem: any, subIndex: number) => {
|
||||||
|
subItem.rowKey = `${index + 1}-${subIndex + 1}`;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
let obj = disasseListObj(item);
|
||||||
|
newRes.push(obj);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
console.log("newRes", newRes);
|
||||||
|
|
||||||
|
return newRes;
|
||||||
|
};
|
||||||
|
|
||||||
|
// 给一个对象 对象里面有字段的值是对象 输出拆了的对象数据到老对象中
|
||||||
|
const disasseListObj = (obj: any) => {
|
||||||
|
let old: any = {};
|
||||||
|
for (let key in obj) {
|
||||||
|
if (
|
||||||
|
typeof obj[key] === "object" &&
|
||||||
|
obj[key] !== null &&
|
||||||
|
key !== "children"
|
||||||
|
) {
|
||||||
|
let smallObj: any = obj[key];
|
||||||
|
for (let smallKey in smallObj) {
|
||||||
|
old[`${key}${smallKey}`] = smallObj[smallKey];
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
old[key] = obj[key];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
console.log("old", old);
|
||||||
|
|
||||||
|
return old;
|
||||||
|
};
|
||||||
|
|
||||||
|
// 拆解对象字段到外面那个字段里面去
|
||||||
|
const disassembleObjects = (obj: any, parentKey: any) => {
|
||||||
|
let res: any = [];
|
||||||
|
let addKey: any = {};
|
||||||
|
if (obj["name"]) {
|
||||||
|
addKey = {
|
||||||
|
key: parentKey,
|
||||||
|
name: obj["name"],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
if (obj["children"]) {
|
||||||
|
console.log("children", obj["children"]);
|
||||||
|
let list: any = handleChangeShow(obj["children"], addKey);
|
||||||
|
console.log("fdjksfjsd", list);
|
||||||
|
if (list && list.length > 0) {
|
||||||
|
list.forEach((item: any) => {
|
||||||
|
res.push(item);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (let key in obj) {
|
||||||
|
if (
|
||||||
|
key !== "name" &&
|
||||||
|
key !== "children" &&
|
||||||
|
typeof obj[key] === "object" &&
|
||||||
|
obj[key] !== null
|
||||||
|
) {
|
||||||
|
let list: any = disassembleObjects(obj[key], key);
|
||||||
|
if (list && list.length > 0) {
|
||||||
|
list.forEach((item: any) => {
|
||||||
|
res.push(item);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return res;
|
||||||
|
};
|
||||||
|
|
||||||
|
// 表格显示字段的递归处理
|
||||||
|
const handleChangeShow = (obj: any, addObj?: any) => {
|
||||||
|
// 如果是有父级的 那要区分一下prop 就是表格取的字段
|
||||||
|
let moneyList: any = [
|
||||||
|
"金额",
|
||||||
|
"营收",
|
||||||
|
"应收",
|
||||||
|
"缴款",
|
||||||
|
"费用",
|
||||||
|
"额",
|
||||||
|
"数值",
|
||||||
|
"增长值",
|
||||||
|
];
|
||||||
|
let rateList: any = ["同比", "环比", "率", "增长率", "比例"];
|
||||||
|
let columnsList: any = [];
|
||||||
|
for (let key in obj) {
|
||||||
|
// 判断是不是金钱类的 要添加千分号
|
||||||
|
let isMoney: boolean = false;
|
||||||
|
// 判断是不是名称类的 要宽一点
|
||||||
|
let isName: boolean = false;
|
||||||
|
// 判断是否需要带%
|
||||||
|
let isRate: boolean = false;
|
||||||
|
// 判断现在的这个字段是不是对象
|
||||||
|
let isObject: boolean = false;
|
||||||
|
if (typeof obj[key] === "string") {
|
||||||
|
moneyList.forEach((item: any) => {
|
||||||
|
if (obj[key].indexOf(item) !== -1) {
|
||||||
|
isMoney = true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if (obj[key].indexOf("名") !== -1) {
|
||||||
|
isName = true;
|
||||||
|
}
|
||||||
|
rateList.forEach((item: any) => {
|
||||||
|
if (obj[key].indexOf(item) !== -1 && !isMoney) {
|
||||||
|
isRate = true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else if (
|
||||||
|
typeof obj[key] === "object" &&
|
||||||
|
obj[key] !== null &&
|
||||||
|
key !== "ShopINCList" &&
|
||||||
|
key !== "children"
|
||||||
|
) {
|
||||||
|
isObject = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isObject) {
|
||||||
|
// let resObj = {
|
||||||
|
// label: key,
|
||||||
|
// children: handleChangeShow(),
|
||||||
|
// };
|
||||||
|
let resObj = disassembleObjects(obj[key], key);
|
||||||
|
console.log("resObj222", resObj);
|
||||||
|
if (resObj && resObj.length > 0) {
|
||||||
|
resObj.forEach((item: any) => {
|
||||||
|
columnsList.push(item);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// columnsList.push(resObj);
|
||||||
|
} else {
|
||||||
|
let resObj: any = {
|
||||||
|
width: isName ? 250 : 150,
|
||||||
|
label: isName
|
||||||
|
? `${obj[key] || ''}`
|
||||||
|
: `<div style="text-align: center">${
|
||||||
|
(addObj?.name ? addObj?.name + "" : "") + obj[key]
|
||||||
|
}</div>`,
|
||||||
|
prop: (addObj?.key ? addObj?.key + "" : "") + key,
|
||||||
|
// valueType: isMoney ? "digit" : "",
|
||||||
|
align: isMoney ? "right" : "",
|
||||||
|
"show-overflow-tooltip": true,
|
||||||
|
isSlot: false,
|
||||||
|
isMoney: isMoney,
|
||||||
|
isRate: isRate,
|
||||||
|
};
|
||||||
|
if (isRate) {
|
||||||
|
resObj.isSlot = true;
|
||||||
|
// resObj.formatter = (_: any, record: any) => {
|
||||||
|
// return record[key] ? record[key] + "%" : "";
|
||||||
|
// };
|
||||||
|
}
|
||||||
|
if (isMoney) {
|
||||||
|
resObj.isSlot = true;
|
||||||
|
// resObj.formatter = (_: any, record: any) => {
|
||||||
|
// return record[key] ? `<span>${formatNumber(record[key])}</span>` : "";
|
||||||
|
// };
|
||||||
|
}
|
||||||
|
columnsList.push(resObj);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return columnsList;
|
||||||
|
};
|
||||||
|
// 格式化列表单元格
|
||||||
|
const renderCell = (row: any, column: any) => {
|
||||||
|
const value = row[column.prop];
|
||||||
|
// 根据列类型格式化显示
|
||||||
|
if (column.isMoney) {
|
||||||
|
return `<span style="text-align: right">${formatNumber(value)}</span>`;
|
||||||
|
}
|
||||||
|
if (column.isRate) {
|
||||||
|
return `<span style="color: ${
|
||||||
|
value > 0 ? "green" : "red"
|
||||||
|
};text-align: right">${value}%</span>`;
|
||||||
|
}
|
||||||
|
|
||||||
|
return `<span>${value}</span>`;
|
||||||
|
};
|
||||||
|
|
||||||
|
// 配置对话框表格的样式
|
||||||
|
const handleConfigItemTable = (tableData: any, configObj: any, answer: any) => {
|
||||||
|
// 配置列表的显示列
|
||||||
|
if (configObj) {
|
||||||
|
let resObj: any = JSON.parse(configObj.RESPONSE_CONFIG);
|
||||||
|
if (resObj) {
|
||||||
|
// 处理对象格式
|
||||||
|
let columns: any = handleChangeShow(resObj);
|
||||||
|
// 已经拿到显示列 和 表格数据 直接赋值给当前对话框的最后一项即可
|
||||||
|
let obj: any = JSON.parse(
|
||||||
|
JSON.stringify(dialogueList[dialogueList.length - 1])
|
||||||
|
);
|
||||||
|
dialogueList[dialogueList.length - 1] = {
|
||||||
|
...obj,
|
||||||
|
haveTable: true,
|
||||||
|
tableData: tableData,
|
||||||
|
columns: columns,
|
||||||
|
};
|
||||||
|
isNewDialogLoading.value = false;
|
||||||
|
searchText.value = "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 调用回答问题的接口
|
||||||
|
const handleAnswerQuestions = async () => {
|
||||||
|
const req: any = {
|
||||||
|
Sentence: searchText.value,
|
||||||
|
ProvinceCode: "340000",
|
||||||
|
};
|
||||||
|
const data = await handleTranslateSentence(req);
|
||||||
|
console.log("data", data);
|
||||||
|
// 如果单独搜索服务区 会出现ServerpartInfoList返参 根据返参 来标出点位
|
||||||
|
if (data?.ServerpartInfoList && data?.ServerpartInfoList.length > 0) {
|
||||||
|
} else if (data?.RevenueAnalysis) {
|
||||||
|
//再判断这次查询是否有文字结果返回 如果有的话 再进行判断 是要根据语义 调用接口 还是 直接输出这段文字
|
||||||
|
if (data?.AnalysisRuleId) {
|
||||||
|
// 去拿到这个id的配置明细
|
||||||
|
const configDetail = await handleGetANALYSISRULEDetail({
|
||||||
|
ANALYSISRULEId: data?.AnalysisRuleId,
|
||||||
|
});
|
||||||
|
console.log("configDetail", configDetail);
|
||||||
|
// 如果拿到值就根据配置去调用接口 拿到数据 输出数据
|
||||||
|
if (configDetail) {
|
||||||
|
const tableData = await handleAnalyzeConfig(configDetail, data);
|
||||||
|
console.log("tableData", tableData);
|
||||||
|
// 如果拿到值了 就去配这个对话框显示表格的样式
|
||||||
|
if (tableData && tableData.length > 0) {
|
||||||
|
handleConfigItemTable(tableData, configDetail, data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
handleLastUpdate(data?.RevenueAnalysis);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
handleLastUpdate("小驿还无法理解,请换个说法,我会不停努力学习的!");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 提问的方法
|
||||||
|
const handleSubmit = async () => {
|
||||||
|
// 先添加对话内容
|
||||||
|
handleAddDialogList();
|
||||||
|
// 调用回答问题的接口
|
||||||
|
await handleAnswerQuestions();
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="expandBox" v-if="showDialogBox">
|
||||||
|
<!-- 展开后的顶部机器人图标和文字 -->
|
||||||
|
<div class="boxTop">
|
||||||
|
<img
|
||||||
|
class="closeIcon"
|
||||||
|
src="@/assets/ai/AiIcon.png"
|
||||||
|
@click="handleCloseDialogbox()"
|
||||||
|
/>
|
||||||
|
<span class="titleText">商业智能助理小驿,为您服务:</span>
|
||||||
|
</div>
|
||||||
|
<div class="dialogBox">
|
||||||
|
<!-- 实际的对话框方框 -->
|
||||||
|
<div class="dialogContent">
|
||||||
|
<div
|
||||||
|
class="dialogueBoxItem"
|
||||||
|
v-for="(item, index) in dialogueList"
|
||||||
|
:key="index"
|
||||||
|
:style="{
|
||||||
|
justifyContent: item.type === 1 ? 'flex-start' : 'flex-end',
|
||||||
|
}"
|
||||||
|
>
|
||||||
|
<img
|
||||||
|
v-if="item.type === 1"
|
||||||
|
class="robotIcon"
|
||||||
|
src="@/assets/ai/profileIcon.png"
|
||||||
|
/>
|
||||||
|
<div
|
||||||
|
class="dialogueTextBox"
|
||||||
|
v-loading="isNewDialogLoading && index === dialogueList.length - 1"
|
||||||
|
>
|
||||||
|
{{ item.text || "" }}
|
||||||
|
|
||||||
|
<div v-if="item.haveTable">
|
||||||
|
<el-table
|
||||||
|
:data="item.tableData"
|
||||||
|
border
|
||||||
|
:fit="true"
|
||||||
|
tree-props="treeProps"
|
||||||
|
row-key="rowKey"
|
||||||
|
class="elTable"
|
||||||
|
>
|
||||||
|
<el-table-column
|
||||||
|
v-for="(column, index) in item.columns"
|
||||||
|
:key="index"
|
||||||
|
:prop="column.prop"
|
||||||
|
:label="column.label"
|
||||||
|
:width="column.width"
|
||||||
|
>
|
||||||
|
<!-- 自定义表头内容 -->
|
||||||
|
<template #header>
|
||||||
|
<div v-html="column.label"></div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<!-- 默认的单元格内容渲染 -->
|
||||||
|
<template #default="{ row }">
|
||||||
|
<div v-if="column.isSlot">
|
||||||
|
<span v-html="renderCell(row, column)"></span>
|
||||||
|
</div>
|
||||||
|
<div v-else>
|
||||||
|
<span>{{ row[column.prop] }}</span>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
</el-table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<img
|
||||||
|
v-if="item.type === 2"
|
||||||
|
class="userIcon"
|
||||||
|
src="@/assets/ai/userIcon.png"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 输入框 -->
|
||||||
|
<div class="inputBox">
|
||||||
|
<el-input
|
||||||
|
class="searchText"
|
||||||
|
placeholder="Hi,您好!请输入您想了解的服务区..."
|
||||||
|
v-model="searchText"
|
||||||
|
@keyup.enter="handleSubmit()"
|
||||||
|
/>
|
||||||
|
<img
|
||||||
|
class="searchIcon"
|
||||||
|
src="@/assets/ai/searchIconBlue.png"
|
||||||
|
@clcik="handleSubmit()"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="closeBox" v-else>
|
||||||
|
<img
|
||||||
|
class="closeIcon"
|
||||||
|
src="@/assets/ai/AiIcon.png"
|
||||||
|
@click="handleGetShowDailogBox()"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
3769
src/components/map/component/anhuiLine.js
Normal file
3769
src/components/map/component/anhuiLine.js
Normal file
File diff suppressed because it is too large
Load Diff
24
src/components/map/index.less
Normal file
24
src/components/map/index.less
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
.mapBox{
|
||||||
|
width: 100%;
|
||||||
|
height: 100vh;
|
||||||
|
position: relative;
|
||||||
|
overflow: hidden;
|
||||||
|
.l7-control-container{
|
||||||
|
.l7-bottom{
|
||||||
|
.l7-control-logo{
|
||||||
|
.l7-control-logo-link{
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.RobotBox{
|
||||||
|
width: 600px;
|
||||||
|
position: absolute;
|
||||||
|
top: 16px;
|
||||||
|
left: 16px;
|
||||||
|
z-index: 10;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
181
src/components/map/index.vue
Normal file
181
src/components/map/index.vue
Normal file
@ -0,0 +1,181 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import "./index.less";
|
||||||
|
// @ts-ignore
|
||||||
|
import anhuiLine from "./component/anhuiLine";
|
||||||
|
import { LineLayer, PointLayer, Scene } from "@antv/l7";
|
||||||
|
import { GaodeMap } from "@antv/l7-maps";
|
||||||
|
import { onMounted, reactive, ref } from "vue";
|
||||||
|
import { getFieldEnumTree, handleGetServerpartList } from "./service";
|
||||||
|
import { ElLoading } from "element-plus";
|
||||||
|
import RobotDialogueBox from "./component/RobotDialogueBox.vue";
|
||||||
|
|
||||||
|
// 地图实例
|
||||||
|
const scene = ref<any>();
|
||||||
|
// 悬浮框实例
|
||||||
|
const hoverPoint = ref<any>();
|
||||||
|
// 所有服务区的数据
|
||||||
|
let defaultServerPartList = reactive<any>([]);
|
||||||
|
// 服务区类型的枚举
|
||||||
|
let ServerpartTypeObj = reactive<any>({});
|
||||||
|
// 判断是否有加载效果
|
||||||
|
const isShowLoading = ref<boolean>(false);
|
||||||
|
|
||||||
|
onMounted(async () => {
|
||||||
|
scene.value = new Scene({
|
||||||
|
id: "map",
|
||||||
|
map: new GaodeMap({
|
||||||
|
pitch: 0,
|
||||||
|
mapStyle: "amap://styles/dark",
|
||||||
|
center: [117.455467, 31.856928],
|
||||||
|
zoom: 6,
|
||||||
|
minZoom: 5.5,
|
||||||
|
token: "edb93fe4f1b3d313128b82082c5b3877",
|
||||||
|
mapConfig: {
|
||||||
|
logoVisible: false,
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
|
||||||
|
const loadingInstance = ElLoading.service({
|
||||||
|
fullscreen: true,
|
||||||
|
background: "#00000080",
|
||||||
|
text: "数据加载中...",
|
||||||
|
});
|
||||||
|
// 请求枚举
|
||||||
|
await handleGetEnumeration();
|
||||||
|
console.log("ServerpartTypeObj", ServerpartTypeObj);
|
||||||
|
|
||||||
|
// 请求到所有的服务区
|
||||||
|
await handleGetAllService();
|
||||||
|
// 给服务区标上点
|
||||||
|
handleAllServiceMarkedPoint();
|
||||||
|
// 标出安徽省的边界
|
||||||
|
handleGetAnHuiBoundary();
|
||||||
|
|
||||||
|
hoverPoint.value = handlePointHover();
|
||||||
|
loadingInstance.close();
|
||||||
|
});
|
||||||
|
|
||||||
|
// 标出安徽省的边界
|
||||||
|
const handleGetAnHuiBoundary = () => {
|
||||||
|
const blurLine = new LineLayer();
|
||||||
|
blurLine.name = "blurLine";
|
||||||
|
let list: any = anhuiLine;
|
||||||
|
blurLine.source(list).size(1).style({
|
||||||
|
opacity: 0.6,
|
||||||
|
sourceColor: "#b6cad7",
|
||||||
|
targetColor: "#b6cad7",
|
||||||
|
linearDir: "horizontal",
|
||||||
|
});
|
||||||
|
scene.value.addLayer(blurLine);
|
||||||
|
};
|
||||||
|
|
||||||
|
// 请求拿到所有服务区数据
|
||||||
|
const handleGetAllService = async () => {
|
||||||
|
const req: any = {
|
||||||
|
Province_Code: "340000",
|
||||||
|
ShowWeather: true, // 显示天气
|
||||||
|
};
|
||||||
|
const data = await handleGetServerpartList(req);
|
||||||
|
console.log("data", data);
|
||||||
|
defaultServerPartList = data;
|
||||||
|
return data;
|
||||||
|
};
|
||||||
|
|
||||||
|
// 给所有服务区标上圆点
|
||||||
|
const handleAllServiceMarkedPoint = async () => {
|
||||||
|
// 先判断有没有服务区 没有就去请求 有就直接拿
|
||||||
|
let list: any = [];
|
||||||
|
if (defaultServerPartList && defaultServerPartList.length > 0) {
|
||||||
|
list = defaultServerPartList;
|
||||||
|
} else {
|
||||||
|
list = await handleGetAllService();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 标点
|
||||||
|
const pointLayer = new PointLayer({});
|
||||||
|
pointLayer.name = "pointLayer";
|
||||||
|
pointLayer.source(list, {
|
||||||
|
parser: {
|
||||||
|
type: "json",
|
||||||
|
x: "SERVERPART_X",
|
||||||
|
y: "SERVERPART_Y",
|
||||||
|
},
|
||||||
|
});
|
||||||
|
pointLayer.shape("circle");
|
||||||
|
pointLayer.size(8);
|
||||||
|
pointLayer.color("SPREGIONTYPE_ID", (value) => {
|
||||||
|
return Number(value || 0) === 65 ||
|
||||||
|
Number(value || 0) === 45 ||
|
||||||
|
Number(value || 0) === 47
|
||||||
|
? "#34B6B7"
|
||||||
|
: "#CEF8D6";
|
||||||
|
});
|
||||||
|
pointLayer.style({
|
||||||
|
opacity: 0.6,
|
||||||
|
});
|
||||||
|
pointLayer.on("mousemove", (ev: any) => {
|
||||||
|
const detail: any = ev.feature;
|
||||||
|
console.log("detail", detail);
|
||||||
|
|
||||||
|
hoverPoint.value.style.top = `${ev.y}px`;
|
||||||
|
hoverPoint.value.style.left = `${ev.x}px`;
|
||||||
|
hoverPoint.value.style.display = "block";
|
||||||
|
hoverPoint.value.innerHTML = `<div>
|
||||||
|
<div>${detail?.SERVERPART_NAME || ""}${
|
||||||
|
detail?.SERVERPART_TYPE
|
||||||
|
? `(${
|
||||||
|
ServerpartTypeObj ? ServerpartTypeObj[detail?.SERVERPART_TYPE] : ""
|
||||||
|
})`
|
||||||
|
: ""
|
||||||
|
}</div>
|
||||||
|
</div>`;
|
||||||
|
});
|
||||||
|
|
||||||
|
// 鼠标移出
|
||||||
|
pointLayer.on("mouseout", (ev: any) => {
|
||||||
|
hoverPoint.value.style.display = "none";
|
||||||
|
});
|
||||||
|
|
||||||
|
scene.value.addLayer(pointLayer);
|
||||||
|
};
|
||||||
|
|
||||||
|
// 鼠标移入点触发的时间
|
||||||
|
const handlePointHover = () => {
|
||||||
|
const el = document.createElement("div");
|
||||||
|
el.style.background = "#000";
|
||||||
|
el.style.color = "#fff";
|
||||||
|
el.style.position = "absolute";
|
||||||
|
el.style.padding = "10px";
|
||||||
|
el.style.borderRadius = "10px";
|
||||||
|
el.style.zIndex = "9999";
|
||||||
|
el.style.transition = "0.5s";
|
||||||
|
el.style.display = "none";
|
||||||
|
const wrap: any = document.getElementById("map");
|
||||||
|
wrap.appendChild(el);
|
||||||
|
return el;
|
||||||
|
};
|
||||||
|
|
||||||
|
// 需要调用的枚举方法
|
||||||
|
const handleGetEnumeration = async () => {
|
||||||
|
const ServerpartTypeList = await getFieldEnumTree({
|
||||||
|
FieldExplainField: "SERVERPART_TYPE",
|
||||||
|
});
|
||||||
|
console.log("ServerpartTypeList", ServerpartTypeList);
|
||||||
|
const typeObj: any = {};
|
||||||
|
if (ServerpartTypeList && ServerpartTypeList.length > 0) {
|
||||||
|
ServerpartTypeList.forEach((item: any) => {
|
||||||
|
typeObj[item.value] = item.label;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
ServerpartTypeObj = typeObj;
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div id="map" class="mapBox">
|
||||||
|
<div class="RobotBox">
|
||||||
|
<RobotDialogueBox />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
60
src/components/map/service.ts
Normal file
60
src/components/map/service.ts
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
import { wrapTreeNode } from "../../options/serveice";
|
||||||
|
import request from "../../request/request";
|
||||||
|
import requestCode from "../../request/requestCode";
|
||||||
|
|
||||||
|
// 拿到服务区列表
|
||||||
|
export async function handleGetServerpartList(params: any) {
|
||||||
|
const data: any = await requestCode.get('/BaseInfo/GetServerpartList', params)
|
||||||
|
|
||||||
|
if (data.Result_Code !== 100) {
|
||||||
|
return {
|
||||||
|
data: [],
|
||||||
|
current: 1,
|
||||||
|
pageSize: 20,
|
||||||
|
total: 0,
|
||||||
|
success: true,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return data.Result_Data.List;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 拿到枚举列表
|
||||||
|
export async function getFieldEnumTree(params: any) {
|
||||||
|
const data: any = await request.get('/FrameWork/GetFieldEnumTree', params)
|
||||||
|
|
||||||
|
if (data.Result_Code !== 100) {
|
||||||
|
return {
|
||||||
|
data: [],
|
||||||
|
current: 1,
|
||||||
|
pageSize: 20,
|
||||||
|
total: 0,
|
||||||
|
success: true,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return wrapTreeNode(data.Result_Data.List);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// 询问问题 调用的接口
|
||||||
|
export async function handleTranslateSentence(params: any) {
|
||||||
|
const data: any = await requestCode.get('/Analysis/TranslateSentence', params)
|
||||||
|
if (data.Result_Code !== 100) {
|
||||||
|
return data
|
||||||
|
}
|
||||||
|
return data.Result_Data
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// 拿到这个问题的配置明细
|
||||||
|
export async function handleGetANALYSISRULEDetail(params: any) {
|
||||||
|
const data: any = await request.get('/Analysis/GetANALYSISRULEDetail', params)
|
||||||
|
if (data.Result_Code !== 100) {
|
||||||
|
return data
|
||||||
|
}
|
||||||
|
return data.Result_Data
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
169
src/components/robot.vue
Normal file
169
src/components/robot.vue
Normal file
@ -0,0 +1,169 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import { AxiosResponse } from "axios";
|
||||||
|
import { log } from "console";
|
||||||
|
import { onMounted, reactive, ref } from "vue";
|
||||||
|
import { wrapTreeNode } from "../options/serveice";
|
||||||
|
import { GetProjectSplitSummary } from "./service";
|
||||||
|
|
||||||
|
// 对话列表
|
||||||
|
let dialogueList = reactive<any>([]);
|
||||||
|
// 打字机的文字
|
||||||
|
let printText = ref<string>("");
|
||||||
|
// 判断当前是否为打字状态
|
||||||
|
const isVisible = ref<boolean>(false);
|
||||||
|
// 用于显示已经打印了的内容
|
||||||
|
const displayedText = ref<string>("");
|
||||||
|
// 搜索的内容
|
||||||
|
const searchText = ref<string>("");
|
||||||
|
|
||||||
|
onMounted(async () => {
|
||||||
|
await handleGetData();
|
||||||
|
|
||||||
|
dialogueList[0] = {
|
||||||
|
text: "",
|
||||||
|
type: 1,
|
||||||
|
searchType: "default",
|
||||||
|
};
|
||||||
|
printText.value =
|
||||||
|
"您好!我是服务区商业智能助理小驿。\n您想了解服务区哪些方面的信息?";
|
||||||
|
console.log("printText", printText.value);
|
||||||
|
handlePrintText();
|
||||||
|
|
||||||
|
// setTimeout(() => {
|
||||||
|
// dialogueList[0] = {
|
||||||
|
// text: "您好!我是服务区商业智能助理小驿。\n您想了解服务区哪些方面的信息?",
|
||||||
|
// type: 1,
|
||||||
|
// searchType: "default",
|
||||||
|
// };
|
||||||
|
// }, 2000);
|
||||||
|
});
|
||||||
|
|
||||||
|
// 打字机效果
|
||||||
|
const handlePrintText = () => {
|
||||||
|
let index = 0;
|
||||||
|
displayedText.value = ""; // 清空当前显示的文本
|
||||||
|
const interval = setInterval(() => {
|
||||||
|
// 如果遇到换行符,则添加 <br> 标签
|
||||||
|
if (printText.value[index] === "\n") {
|
||||||
|
displayedText.value += "<br>";
|
||||||
|
} else {
|
||||||
|
displayedText.value += printText.value[index];
|
||||||
|
}
|
||||||
|
index++;
|
||||||
|
|
||||||
|
// 当文本打印完成时停止定时器
|
||||||
|
if (index === printText.value.length) {
|
||||||
|
clearInterval(interval);
|
||||||
|
}
|
||||||
|
}, 100);
|
||||||
|
};
|
||||||
|
|
||||||
|
// 测试调用接口
|
||||||
|
const handleGetData = async () => {
|
||||||
|
let req: any = {
|
||||||
|
ServerpartId: "416",
|
||||||
|
StatisticsMonth: "202411",
|
||||||
|
};
|
||||||
|
const data: any = await GetProjectSplitSummary(req);
|
||||||
|
// let list: any = wrapTreeNode(data);
|
||||||
|
console.log("data", data);
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="main">
|
||||||
|
<div class="content">
|
||||||
|
<div
|
||||||
|
v-for="(item, index) in dialogueList"
|
||||||
|
:key="index"
|
||||||
|
:class="item.type === 1 ? 'dialogueItem1' : 'dialogueItem2'"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
v-html="index === dialogueList.length - 1 ? displayedText : item.text"
|
||||||
|
></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="InputBox">
|
||||||
|
<div class="inputContent">
|
||||||
|
<img
|
||||||
|
class="voiceIcon"
|
||||||
|
src="https://eshangtech.com/ShopICO/ahyd-BID/robot/microphone.png"
|
||||||
|
/>
|
||||||
|
<div class="input">
|
||||||
|
<el-input v-model="searchText" placeholder="有问题尽管问我~" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped lang='less'>
|
||||||
|
.main {
|
||||||
|
width: 100vw;
|
||||||
|
height: 100vh;
|
||||||
|
background-image: url("https://eshangtech.com/ShopICO/ahyd-BID/robot/robotBackground.png");
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
position: relative;
|
||||||
|
.content {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
box-sizing: border-box;
|
||||||
|
padding: 16px;
|
||||||
|
.dialogueItem1 {
|
||||||
|
max-width: 100%;
|
||||||
|
box-sizing: border-box;
|
||||||
|
padding: 12px 16px;
|
||||||
|
background: #ffffff;
|
||||||
|
border-radius: 0px 12px 12px 12px;
|
||||||
|
}
|
||||||
|
.dialogueItem2 {
|
||||||
|
max-width: 100%;
|
||||||
|
box-sizing: border-box;
|
||||||
|
padding: 8px 12px;
|
||||||
|
background: #2363ff;
|
||||||
|
border-radius: 12px 0px 12px 12px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.InputBox {
|
||||||
|
width: 100%;
|
||||||
|
height: 90px;
|
||||||
|
box-sizing: border-box;
|
||||||
|
padding-bottom: 56px;
|
||||||
|
background: #fff;
|
||||||
|
position: fixed;
|
||||||
|
bottom: 0;
|
||||||
|
left: 0;
|
||||||
|
.inputContent {
|
||||||
|
width: 100%;
|
||||||
|
height: 56px;
|
||||||
|
box-sizing: border-box;
|
||||||
|
padding: 8px 16px 4px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
.voiceIcon {
|
||||||
|
width: 24px;
|
||||||
|
height: 24px;
|
||||||
|
margin-right: 8px;
|
||||||
|
}
|
||||||
|
.input {
|
||||||
|
width: calc(100% - 32px);
|
||||||
|
height: 100%;
|
||||||
|
background: #f2f3f7;
|
||||||
|
border-radius: 22px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
box-sizing: border-box;
|
||||||
|
padding-left: 5px;
|
||||||
|
.el-input {
|
||||||
|
width: 95%;
|
||||||
|
::v-deep(.el-input__wrapper) {
|
||||||
|
background-color: transparent !important;
|
||||||
|
box-shadow: none !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
17
src/components/service.ts
Normal file
17
src/components/service.ts
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
import request from "../request/request";
|
||||||
|
|
||||||
|
export async function GetProjectSplitSummary(params: any) {
|
||||||
|
const data: any = await request.get('/BusinessProject/GetMonthSummaryList', params)
|
||||||
|
|
||||||
|
if (data.Result_Code !== 100) {
|
||||||
|
return {
|
||||||
|
data: [],
|
||||||
|
current: 1,
|
||||||
|
pageSize: 20,
|
||||||
|
total: 0,
|
||||||
|
success: true,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return data.Result_Data;
|
||||||
|
}
|
||||||
16
src/main.ts
Normal file
16
src/main.ts
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
import {
|
||||||
|
createApp
|
||||||
|
} from 'vue';
|
||||||
|
import App from './App.vue';
|
||||||
|
import router from './router';
|
||||||
|
import { createPinia } from 'pinia';
|
||||||
|
import ElementPlus from 'element-plus'
|
||||||
|
import 'element-plus/dist/index.css'
|
||||||
|
|
||||||
|
|
||||||
|
const app = createApp(App);
|
||||||
|
|
||||||
|
app.use(ElementPlus)
|
||||||
|
app.use(router);
|
||||||
|
app.use(createPinia());
|
||||||
|
app.mount('#app');
|
||||||
21
src/options/serveice.ts
Normal file
21
src/options/serveice.ts
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
export const wrapTreeNode = (data: any) => {
|
||||||
|
const wrapData: any = data.map((item: any) => {
|
||||||
|
const node = { ...item.node };
|
||||||
|
|
||||||
|
if (item.children && item.children.length > 0) {
|
||||||
|
node.children = wrapTreeNode(item.children);
|
||||||
|
}
|
||||||
|
return node
|
||||||
|
});
|
||||||
|
return wrapData;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 若有小数保留两位小数 没有小数不保留
|
||||||
|
export const formatNumber = (num: number) => {
|
||||||
|
// 判断是否是小数
|
||||||
|
if (num % 1 !== 0) {
|
||||||
|
return num.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 });
|
||||||
|
} else {
|
||||||
|
return num.toLocaleString(); // 使用千分号,不保留小数位
|
||||||
|
}
|
||||||
|
}
|
||||||
79
src/request/request.ts
Normal file
79
src/request/request.ts
Normal file
@ -0,0 +1,79 @@
|
|||||||
|
import axios, { AxiosRequestConfig, AxiosResponse } from 'axios';
|
||||||
|
import { notification } from 'antd';
|
||||||
|
import Cookies from 'js-cookie';
|
||||||
|
import moment from 'moment';
|
||||||
|
|
||||||
|
// 定义 HTTP 状态码及其描述
|
||||||
|
const codeMessage: Record<number, string> = {
|
||||||
|
200: '服务器成功返回请求的数据。',
|
||||||
|
201: '新建或修改数据成功。',
|
||||||
|
202: '一个请求已经进入后台排队(异步任务)。',
|
||||||
|
204: '删除数据成功。',
|
||||||
|
400: '发出的请求有错误,服务器没有进行新建或修改数据的操作。',
|
||||||
|
401: '用户没有权限(令牌、用户名、密码错误)。',
|
||||||
|
403: '用户得到授权,但是访问是被禁止的。',
|
||||||
|
404: '发出的请求针对的是不存在的记录,服务器没有进行操作。',
|
||||||
|
406: '请求的格式不可得。',
|
||||||
|
410: '请求的资源被永久删除,且不会再得到的。',
|
||||||
|
422: '当创建一个对象时,发生一个验证错误。',
|
||||||
|
500: '服务器发生错误,请检查服务器。',
|
||||||
|
502: '网关错误。',
|
||||||
|
503: '服务不可用,服务器暂时过载或维护。',
|
||||||
|
504: '网关超时。',
|
||||||
|
};
|
||||||
|
|
||||||
|
// 错误处理
|
||||||
|
const errorHandler = (error: any): any => {
|
||||||
|
const { response } = error;
|
||||||
|
if (response && response.status) {
|
||||||
|
const errorText = codeMessage[response.status] || response.statusText;
|
||||||
|
const { status, url } = response;
|
||||||
|
notification.error({
|
||||||
|
message: `请求错误 ${status}: ${url}`,
|
||||||
|
description: errorText,
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
notification.error({
|
||||||
|
description: '您的网络异常,无法连接到服务器。',
|
||||||
|
message: '网络异常',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return Promise.reject(error);
|
||||||
|
};
|
||||||
|
|
||||||
|
// 创建 axios 实例
|
||||||
|
const instance = axios.create({
|
||||||
|
baseURL: 'https://api.eshangtech.com/EShangApiMain', // 默认请求前缀
|
||||||
|
timeout: 10000, // 请求超时时间
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
// 请求拦截器
|
||||||
|
instance.interceptors.request.use(
|
||||||
|
(config: any) => {
|
||||||
|
return config;
|
||||||
|
},
|
||||||
|
errorHandler
|
||||||
|
);
|
||||||
|
|
||||||
|
// 响应拦截器
|
||||||
|
instance.interceptors.response.use(
|
||||||
|
(response: AxiosResponse) => {
|
||||||
|
// 每次响应,设置一个 tmp 的 Cookie
|
||||||
|
Cookies.set('tmp', moment().format());
|
||||||
|
return response.data; // 统一返回 data
|
||||||
|
},
|
||||||
|
errorHandler
|
||||||
|
);
|
||||||
|
|
||||||
|
// 封装的请求方法
|
||||||
|
const request = {
|
||||||
|
get: (url: string, params?: any) => instance.get(url, { params }),
|
||||||
|
post: (url: string, data?: any) => instance.post(url, data),
|
||||||
|
put: (url: string, data?: any) => instance.put(url, data),
|
||||||
|
delete: (url: string, params?: any) => instance.delete(url, { params }),
|
||||||
|
};
|
||||||
|
|
||||||
|
export default request;
|
||||||
79
src/request/requestCode.ts
Normal file
79
src/request/requestCode.ts
Normal file
@ -0,0 +1,79 @@
|
|||||||
|
import axios, { AxiosRequestConfig, AxiosResponse } from 'axios';
|
||||||
|
import { notification } from 'antd';
|
||||||
|
import Cookies from 'js-cookie';
|
||||||
|
import moment from 'moment';
|
||||||
|
|
||||||
|
// 定义 HTTP 状态码及其描述
|
||||||
|
const codeMessage: Record<number, string> = {
|
||||||
|
200: '服务器成功返回请求的数据。',
|
||||||
|
201: '新建或修改数据成功。',
|
||||||
|
202: '一个请求已经进入后台排队(异步任务)。',
|
||||||
|
204: '删除数据成功。',
|
||||||
|
400: '发出的请求有错误,服务器没有进行新建或修改数据的操作。',
|
||||||
|
401: '用户没有权限(令牌、用户名、密码错误)。',
|
||||||
|
403: '用户得到授权,但是访问是被禁止的。',
|
||||||
|
404: '发出的请求针对的是不存在的记录,服务器没有进行操作。',
|
||||||
|
406: '请求的格式不可得。',
|
||||||
|
410: '请求的资源被永久删除,且不会再得到的。',
|
||||||
|
422: '当创建一个对象时,发生一个验证错误。',
|
||||||
|
500: '服务器发生错误,请检查服务器。',
|
||||||
|
502: '网关错误。',
|
||||||
|
503: '服务不可用,服务器暂时过载或维护。',
|
||||||
|
504: '网关超时。',
|
||||||
|
};
|
||||||
|
|
||||||
|
// 错误处理
|
||||||
|
const errorHandler = (error: any): any => {
|
||||||
|
const { response } = error;
|
||||||
|
if (response && response.status) {
|
||||||
|
const errorText = codeMessage[response.status] || response.statusText;
|
||||||
|
const { status, url } = response;
|
||||||
|
notification.error({
|
||||||
|
message: `请求错误 ${status}: ${url}`,
|
||||||
|
description: errorText,
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
notification.error({
|
||||||
|
description: '您的网络异常,无法连接到服务器。',
|
||||||
|
message: '网络异常',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return Promise.reject(error);
|
||||||
|
};
|
||||||
|
|
||||||
|
// 创建 axios 实例
|
||||||
|
const instance = axios.create({
|
||||||
|
baseURL: 'https://api.eshangtech.com/CommercialApi', // 默认请求前缀
|
||||||
|
timeout: 10000, // 请求超时时间
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
// 请求拦截器
|
||||||
|
instance.interceptors.request.use(
|
||||||
|
(config: any) => {
|
||||||
|
return config;
|
||||||
|
},
|
||||||
|
errorHandler
|
||||||
|
);
|
||||||
|
|
||||||
|
// 响应拦截器
|
||||||
|
instance.interceptors.response.use(
|
||||||
|
(response: AxiosResponse) => {
|
||||||
|
// 每次响应,设置一个 tmp 的 Cookie
|
||||||
|
Cookies.set('tmp', moment().format());
|
||||||
|
return response.data; // 统一返回 data
|
||||||
|
},
|
||||||
|
errorHandler
|
||||||
|
);
|
||||||
|
|
||||||
|
// 封装的请求方法
|
||||||
|
const request = {
|
||||||
|
get: (url: string, params?: any) => instance.get(url, { params }),
|
||||||
|
post: (url: string, data?: any) => instance.post(url, data),
|
||||||
|
put: (url: string, data?: any) => instance.put(url, data),
|
||||||
|
delete: (url: string, params?: any) => instance.delete(url, { params }),
|
||||||
|
};
|
||||||
|
|
||||||
|
export default request;
|
||||||
79
src/request/requestConfig.ts
Normal file
79
src/request/requestConfig.ts
Normal file
@ -0,0 +1,79 @@
|
|||||||
|
import axios, { AxiosRequestConfig, AxiosResponse } from 'axios';
|
||||||
|
import { notification } from 'antd';
|
||||||
|
import Cookies from 'js-cookie';
|
||||||
|
import moment from 'moment';
|
||||||
|
|
||||||
|
// 定义 HTTP 状态码及其描述
|
||||||
|
const codeMessage: Record<number, string> = {
|
||||||
|
200: '服务器成功返回请求的数据。',
|
||||||
|
201: '新建或修改数据成功。',
|
||||||
|
202: '一个请求已经进入后台排队(异步任务)。',
|
||||||
|
204: '删除数据成功。',
|
||||||
|
400: '发出的请求有错误,服务器没有进行新建或修改数据的操作。',
|
||||||
|
401: '用户没有权限(令牌、用户名、密码错误)。',
|
||||||
|
403: '用户得到授权,但是访问是被禁止的。',
|
||||||
|
404: '发出的请求针对的是不存在的记录,服务器没有进行操作。',
|
||||||
|
406: '请求的格式不可得。',
|
||||||
|
410: '请求的资源被永久删除,且不会再得到的。',
|
||||||
|
422: '当创建一个对象时,发生一个验证错误。',
|
||||||
|
500: '服务器发生错误,请检查服务器。',
|
||||||
|
502: '网关错误。',
|
||||||
|
503: '服务不可用,服务器暂时过载或维护。',
|
||||||
|
504: '网关超时。',
|
||||||
|
};
|
||||||
|
|
||||||
|
// 错误处理
|
||||||
|
const errorHandler = (error: any): any => {
|
||||||
|
const { response } = error;
|
||||||
|
if (response && response.status) {
|
||||||
|
const errorText = codeMessage[response.status] || response.statusText;
|
||||||
|
const { status, url } = response;
|
||||||
|
notification.error({
|
||||||
|
message: `请求错误 ${status}: ${url}`,
|
||||||
|
description: errorText,
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
notification.error({
|
||||||
|
description: '您的网络异常,无法连接到服务器。',
|
||||||
|
message: '网络异常',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return Promise.reject(error);
|
||||||
|
};
|
||||||
|
|
||||||
|
// 创建 axios 实例
|
||||||
|
const instance = axios.create({
|
||||||
|
baseURL: 'https://api.eshangtech.com/', // 默认请求前缀
|
||||||
|
timeout: 10000, // 请求超时时间
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
// 请求拦截器
|
||||||
|
instance.interceptors.request.use(
|
||||||
|
(config: any) => {
|
||||||
|
return config;
|
||||||
|
},
|
||||||
|
errorHandler
|
||||||
|
);
|
||||||
|
|
||||||
|
// 响应拦截器
|
||||||
|
instance.interceptors.response.use(
|
||||||
|
(response: AxiosResponse) => {
|
||||||
|
// 每次响应,设置一个 tmp 的 Cookie
|
||||||
|
Cookies.set('tmp', moment().format());
|
||||||
|
return response.data; // 统一返回 data
|
||||||
|
},
|
||||||
|
errorHandler
|
||||||
|
);
|
||||||
|
|
||||||
|
// 封装的请求方法
|
||||||
|
const request = {
|
||||||
|
get: (url: string, params?: any) => instance.get(url, { params }),
|
||||||
|
post: (url: string, data?: any) => instance.post(url, data),
|
||||||
|
put: (url: string, data?: any) => instance.put(url, data),
|
||||||
|
delete: (url: string, params?: any) => instance.delete(url, { params }),
|
||||||
|
};
|
||||||
|
|
||||||
|
export default request;
|
||||||
15
src/router/index.ts
Normal file
15
src/router/index.ts
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
import { createRouter, createWebHistory } from 'vue-router';
|
||||||
|
|
||||||
|
const routes = [
|
||||||
|
{ path: '/', redirect: '/map' },
|
||||||
|
{ path: '/map', name: 'map', component: () => import('@/components/map/index.vue') }
|
||||||
|
// { path: '/', name: 'Home', component: Home },
|
||||||
|
// { path: '/about', name: 'About', component: () => import('../components/About.vue') },
|
||||||
|
];
|
||||||
|
|
||||||
|
const router = createRouter({
|
||||||
|
history: createWebHistory(),
|
||||||
|
routes,
|
||||||
|
});
|
||||||
|
|
||||||
|
export default router;
|
||||||
13
src/shims-vue.d.ts
vendored
Normal file
13
src/shims-vue.d.ts
vendored
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
/*
|
||||||
|
* @Author: cclu 1106109051@qq.com
|
||||||
|
* @Date: 2024-11-18 12:12:16
|
||||||
|
* @LastEditors: cclu 1106109051@qq.com
|
||||||
|
* @LastEditTime: 2024-11-18 12:12:24
|
||||||
|
* @FilePath: \aiRobot\src\shims-vue.d.ts
|
||||||
|
* @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
|
||||||
|
*/
|
||||||
|
declare module "*.vue" {
|
||||||
|
import { DefineComponent } from "vue";
|
||||||
|
const component: DefineComponent<{}, {}, any>;
|
||||||
|
export default component;
|
||||||
|
}
|
||||||
20
src/stores/counter.ts
Normal file
20
src/stores/counter.ts
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
/*
|
||||||
|
* @Author: cclu 1106109051@qq.com
|
||||||
|
* @Date: 2024-11-18 11:50:33
|
||||||
|
* @LastEditors: cclu 1106109051@qq.com
|
||||||
|
* @LastEditTime: 2024-11-18 11:51:03
|
||||||
|
* @FilePath: \aiRobot\src\stores\counter.ts
|
||||||
|
* @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
|
||||||
|
*/
|
||||||
|
import { defineStore } from 'pinia';
|
||||||
|
|
||||||
|
export const useCounterStore = defineStore('counter', {
|
||||||
|
state: () => ({
|
||||||
|
count: 0,
|
||||||
|
}),
|
||||||
|
actions: {
|
||||||
|
increment() {
|
||||||
|
this.count++;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
79
src/style.css
Normal file
79
src/style.css
Normal file
@ -0,0 +1,79 @@
|
|||||||
|
:root {
|
||||||
|
font-family: Inter, system-ui, Avenir, Helvetica, Arial, sans-serif;
|
||||||
|
line-height: 1.5;
|
||||||
|
font-weight: 400;
|
||||||
|
|
||||||
|
color-scheme: light dark;
|
||||||
|
color: rgba(255, 255, 255, 0.87);
|
||||||
|
background-color: #242424;
|
||||||
|
|
||||||
|
font-synthesis: none;
|
||||||
|
text-rendering: optimizeLegibility;
|
||||||
|
-webkit-font-smoothing: antialiased;
|
||||||
|
-moz-osx-font-smoothing: grayscale;
|
||||||
|
}
|
||||||
|
|
||||||
|
a {
|
||||||
|
font-weight: 500;
|
||||||
|
color: #646cff;
|
||||||
|
text-decoration: inherit;
|
||||||
|
}
|
||||||
|
a:hover {
|
||||||
|
color: #535bf2;
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
margin: 0;
|
||||||
|
display: flex;
|
||||||
|
place-items: center;
|
||||||
|
min-width: 320px;
|
||||||
|
min-height: 100vh;
|
||||||
|
}
|
||||||
|
|
||||||
|
h1 {
|
||||||
|
font-size: 3.2em;
|
||||||
|
line-height: 1.1;
|
||||||
|
}
|
||||||
|
|
||||||
|
button {
|
||||||
|
border-radius: 8px;
|
||||||
|
border: 1px solid transparent;
|
||||||
|
padding: 0.6em 1.2em;
|
||||||
|
font-size: 1em;
|
||||||
|
font-weight: 500;
|
||||||
|
font-family: inherit;
|
||||||
|
background-color: #1a1a1a;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: border-color 0.25s;
|
||||||
|
}
|
||||||
|
button:hover {
|
||||||
|
border-color: #646cff;
|
||||||
|
}
|
||||||
|
button:focus,
|
||||||
|
button:focus-visible {
|
||||||
|
outline: 4px auto -webkit-focus-ring-color;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card {
|
||||||
|
padding: 2em;
|
||||||
|
}
|
||||||
|
|
||||||
|
#app {
|
||||||
|
max-width: 1280px;
|
||||||
|
margin: 0 auto;
|
||||||
|
padding: 2rem;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (prefers-color-scheme: light) {
|
||||||
|
:root {
|
||||||
|
color: #213547;
|
||||||
|
background-color: #ffffff;
|
||||||
|
}
|
||||||
|
a:hover {
|
||||||
|
color: #747bff;
|
||||||
|
}
|
||||||
|
button {
|
||||||
|
background-color: #f9f9f9;
|
||||||
|
}
|
||||||
|
}
|
||||||
1
src/vite-env.d.ts
vendored
Normal file
1
src/vite-env.d.ts
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
/// <reference types="vite/client" />
|
||||||
20
tsconfig.json
Normal file
20
tsconfig.json
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"target": "ESNext",
|
||||||
|
"module": "ESNext",
|
||||||
|
"moduleResolution": "node",
|
||||||
|
"jsx": "preserve",
|
||||||
|
"esModuleInterop": true,
|
||||||
|
"skipLibCheck": true,
|
||||||
|
"allowSyntheticDefaultImports": true,
|
||||||
|
"strict": true,
|
||||||
|
"outDir": "./dist", // 确保所有编译的文件都输出到 dist 目录
|
||||||
|
"rootDir": "./src",
|
||||||
|
},
|
||||||
|
"include": [
|
||||||
|
"src/**/*.ts",
|
||||||
|
"src/**/*.d.ts",
|
||||||
|
"src/**/*.tsx",
|
||||||
|
"src/**/*.vue"
|
||||||
|
]
|
||||||
|
}
|
||||||
1
tsconfig.tsbuildinfo
Normal file
1
tsconfig.tsbuildinfo
Normal file
@ -0,0 +1 @@
|
|||||||
|
{"root":["./src/main.ts","./src/shims-vue.d.ts","./src/vite-env.d.ts","./src/components/service.ts","./src/components/map/service.ts","./src/options/serveice.ts","./src/request/request.ts","./src/request/requestcode.ts","./src/request/requestconfig.ts","./src/router/index.ts","./src/stores/counter.ts","./src/app.vue","./src/components/robot.vue","./src/components/map/index.vue","./src/components/map/component/robotdialoguebox.vue"],"version":"5.6.3"}
|
||||||
33
vite.config.ts
Normal file
33
vite.config.ts
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
/*
|
||||||
|
* @Author: cclu 1106109051@qq.com
|
||||||
|
* @Date: 2024-11-18 11:40:21
|
||||||
|
* @LastEditors: cclu 1106109051@qq.com
|
||||||
|
* @LastEditTime: 2024-11-20 13:59:51
|
||||||
|
* @FilePath: \aiRobot\vite.config.ts
|
||||||
|
* @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
|
||||||
|
*/
|
||||||
|
import { defineConfig } from 'vite';
|
||||||
|
import vue from '@vitejs/plugin-vue';
|
||||||
|
import path from 'path';
|
||||||
|
|
||||||
|
export default defineConfig({
|
||||||
|
plugins: [
|
||||||
|
vue(),
|
||||||
|
],
|
||||||
|
base: '/map',
|
||||||
|
build: {
|
||||||
|
outDir: 'dist', // 打包输出目录
|
||||||
|
assetsDir: 'assets', // 静态资源目录
|
||||||
|
rollupOptions: {
|
||||||
|
input: '/index.html', // 指定入口文件
|
||||||
|
},
|
||||||
|
},
|
||||||
|
resolve: {
|
||||||
|
alias: {
|
||||||
|
'@': path.resolve(__dirname, 'src'), // 将 @ 映射到 src 目录
|
||||||
|
},
|
||||||
|
},
|
||||||
|
server: {
|
||||||
|
host: '0.0.0.0',
|
||||||
|
}
|
||||||
|
});
|
||||||
Loading…
x
Reference in New Issue
Block a user