wujingjing
2024-07-18 eb0460fbc34fda7906f2949d7dce0f08542e3c8c
地图展示
已修改6个文件
已添加2个文件
158 ■■■■■ 文件已修改
src/components/chat/Chat.vue 11 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/chat/chatComponents/common.ts 5 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/chat/chatComponents/mapCom/MapCom.vue 35 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/chat/chatComponents/mapCom/img/monitor-point.svg 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/chat/chatComponents/mapCom/types.ts 18 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/chat/chatComponents/summaryCom/SummaryCom.vue 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/chat/model/types.ts 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/model/map/GaoDeMap.ts 82 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/chat/Chat.vue
@@ -15,7 +15,7 @@
                        alt=""
                        srcset=""
                    />
                    <div class="flex-auto flex" :class="{'justify-end':item.role===RoleEnum.user}">
                    <div class="flex-auto flex" :class="{ 'justify-end': item.role === RoleEnum.user }">
                        <div class="inline-flex flex-col" :class="{ 'w-full': item.role === RoleEnum.assistant }">
                            <div class="relative w-full" v-if="item.content?.values">
                                <div
@@ -23,7 +23,7 @@
                                    :style="{ backgroundColor: item.role === RoleEnum.user ? 'rgb(197 224 255)' : 'white' }"
                                >
                                    <div v-if="item.content.errCode === ErrorCode.Message" class="text-red-500 w-full">{{ item.content.msg }}</div>
                                    <component v-else :is="answerTypeMapCom[item.content.type]" :data="item.content.values" />
                                    <component v-else :is="answerTypeMapCom[item.content.type]" :data="item.content.values" :originData="item"/>
                                </div>
                                <div v-if="item.role === RoleEnum.assistant" class="absolute flex items-center right-0 mr-2 mt-2 space-x-2">
@@ -157,6 +157,12 @@
                values: res.url,
            };
            break;
        case AnswerType.Map:
            content = {
                type: AnswerType.Map,
                values: res.values,
            };
            break;
        default:
            content = {
                type: AnswerType.Text,
@@ -167,6 +173,7 @@
    content.askMoreList = _.orderBy(res.context_history, [(item) => Number(item.radio)], ['desc']);
    content.errCode = res?.err_code;
    content.msg = res?.json_msg;
    content.origin = res;
    return content;
};
//#region ====================== æŸ¥è¯¢è¿›åº¦ ======================
src/components/chat/chatComponents/common.ts
@@ -47,6 +47,9 @@
export const chatComProps = buildProps({
    data: {
        type: Object as PropType<any>,
    }
    },
    originData: {
        type: Object as PropType<any>,
    },
} as const);
export type ChatComPropsType = ExtractPropTypes<typeof chatComProps>;
src/components/chat/chatComponents/mapCom/MapCom.vue
@@ -4,18 +4,45 @@
<script setup lang="ts">
import { onMounted, ref } from 'vue';
import { GaoDeMap } from '/@/model/map/GaoDeMap';
import { chatComProps } from '../common';
import type { MapData } from './types';
import type { GaoDePosition, LabelMarkerData } from '/@/model/map/GaoDeMap';
import { GaoDeMap } from '/@/model/map/GaoDeMap';
import monitorPointPic from './img/monitor-point.svg';
let gaoDeMap = new GaoDeMap();
const containerRef = ref<HTMLDivElement>(null);
const props = defineProps(chatComProps);
const props = defineProps(chatComProps) as {
    data: MapData;
};
const addMarkerLayer = () => {
    const dataList = (props.data?.values ?? []).map<LabelMarkerData>((item) => ({
        position: [item.posx, item.posy],
        textColor: item.color,
        extData: item,
        title: item.title,
    }));
    gaoDeMap.addMarkerLayer(dataList, {
        markerOpt: {
            icon: {
                url: monitorPointPic,
                size: 30,
            },
        },
        layerOpt: {
            // allowCollision:false
        },
    });
};
onMounted(async () => {
    await gaoDeMap.init({
        container: containerRef.value,
    });
    gaoDeMap.zoomToRect([116.319665, 39.855919], [116.468324, 39.9756]);
    const southWest: GaoDePosition = [props.data.minx, props.data.miny];
    const northEast: GaoDePosition = [props.data.maxx, props.data.maxy];
    gaoDeMap.zoomToRect(southWest, northEast);
    gaoDeMap.applyBasicPlugins();
    addMarkerLayer();
});
</script>
<style scoped lang="scss"></style>
src/components/chat/chatComponents/mapCom/img/monitor-point.svg
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1721287703583" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2874" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><path d="M512 816.3c-82.2 0-159.4-32-217.5-90.1-58.1-58.1-90.1-135.3-90.1-217.5 0-75.1 27.3-147.4 77-203.6l48 42.4c-39.3 44.5-61 101.7-61 161.2 0 134.3 109.3 243.6 243.6 243.6S755.6 643 755.6 508.7c0-59.5-21.7-116.9-61.1-161.4l47.9-42.4c49.8 56.2 77.2 128.6 77.2 203.8 0 82.2-32 159.4-90.1 217.5-58.1 58.1-135.3 90.1-217.5 90.1z" fill="#1c86ff" p-id="2875"></path><path d="M544 417.1V207.7h-64v209.4c-40.1 13.4-69.1 51.3-69.1 95.9 0 55.8 45.4 101.1 101.1 101.1S613.1 568.8 613.1 513c0-44.5-29-82.5-69.1-95.9z m-32 133.1c-20.5 0-37.1-16.7-37.1-37.1S491.6 476 512 476s37.1 16.7 37.1 37.1-16.6 37.1-37.1 37.1z" fill="#1c86ff" p-id="2876"></path><path d="M510 957.5c-60.3 0-118.7-11.8-173.8-35.1-53.2-22.5-100.9-54.7-141.9-95.7S121.1 738 98.6 684.8C75.3 629.7 63.5 571.3 63.5 511s11.8-118.7 35.1-173.8c22.5-53.2 54.7-100.9 95.7-141.9s88.7-73.2 141.9-95.7C391.3 76.3 449.7 64.5 510 64.5s118.7 11.8 173.8 35.1c53.2 22.5 100.9 54.7 141.9 95.7s73.2 88.7 95.7 141.9c23.3 55.1 35.1 113.5 35.1 173.8s-11.8 118.7-35.1 173.8c-22.5 53.2-54.7 100.9-95.7 141.9s-88.7 73.2-141.9 95.7c-55.1 23.3-113.5 35.1-173.8 35.1z m0-829c-210.9 0-382.5 171.6-382.5 382.5S299.1 893.5 510 893.5 892.5 721.9 892.5 511 720.9 128.5 510 128.5z" fill="#1c86ff" p-id="2877"></path></svg>
src/components/chat/chatComponents/mapCom/types.ts
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,18 @@
export interface MapData {
    type: string
    title: string
    minx: number
    maxx: number
    miny: number
    maxy: number
    values: MapDataValue[]
  }
  export interface MapDataValue {
    type: string
    posx: number
    posy: number
    color: string
    title: string
  }
src/components/chat/chatComponents/summaryCom/SummaryCom.vue
@@ -27,6 +27,9 @@
                <!-- <HTMLCom data="http://101.133.133.173:8019/ai_html/views/demo/html/MonthlyPay.html" v-for="(item, index) in urlList" :key="index"></HTMLCom> -->
                <HTMLCom :data="item.url" v-for="(item, index) in urlList" :key="index"></HTMLCom>
            </div>
            <div v-if="mapList && mapList.length > 0" class="w-full">
                <MapCom :data="item" v-for="(item, index) in mapList" :key="index"></MapCom>
            </div>
        </template>
    </div>
</template>
@@ -44,6 +47,7 @@
import { axisLabelFormatter } from '/@/utils/chart';
import { usePageDisplay } from '/@/hooks/usePageDisplay';
import { debounce } from '/@/utils/util';
import MapCom from '../mapCom/MapCom.vue';
const props = defineProps(chatComProps);
const selectChartType = ref<ChartTypeEnum>(ChartTypeEnum.Line);
@@ -86,6 +90,7 @@
const recordSetList = computed(() => props.data.filter((item) => item.type === AnswerType.RecordSet));
const summaryList = computed(() => props.data.filter((item) => item.type === AnswerType.Summary));
const urlList = computed(() => props.data.filter((item) => item.type === AnswerType.Url));
const mapList = computed(() => props.data.filter((item) => item.type === AnswerType.Map));
const drawAllChart = () => {
    chartInstanceList.value.map((item, index) => {
src/components/chat/model/types.ts
@@ -45,6 +45,7 @@
    msg?: string;
    askMoreList?:ContextHistory[];
    errCode?:string;
    origin?:any;
};
export interface ChatMessage {
src/model/map/GaoDeMap.ts
@@ -1,6 +1,5 @@
import AMapLoader from '@amap/amap-jsapi-loader';
import _ from 'lodash';
export type AMapInstance = typeof AMap;
export type GaoDePosition = [number, number];
export type GaoDeMapOption = {
@@ -9,6 +8,25 @@
    plugins?: string[];
    container: string | HTMLDivElement;
    aMapOption?: Partial<AMap.MapOptions>;
};
export type GaoDeMarkerOption = {
    icon: {
        url: string;
        size: number;
    };
};
export type LabelMarkerData = {
    position: GaoDePosition;
    title?: string;
    textColor?: string;
    extData?: any;
};
export type MarkerLayerOption = {
    // è®¾ç½® allowCollision:true,可以让标注避让用户的标注
    layerOpt?: AMap.LabelsLayerOptions;
    markerOpt: GaoDeMarkerOption;
};
export class GaoDeMap {
@@ -57,11 +75,61 @@
        this.map.setBounds(this.viewBound);
    }
    applyBasicPlugins() {
        // const scale = new AMap.Scale();
        // this.map.addControl(scale)
        // const toolbar = new AMap.ToolBar();
        // this.map.addControl(toolbar)
    }
    applyBasicPlugins(){
        // const scale = new AMap.Scale();
        // this.map.addControl(scale)
        // const toolbar = new AMap.ToolBar();
        // this.map.addControl(toolbar)
    }
    addMarkerLayer(dataList: LabelMarkerData[], option: MarkerLayerOption) {
        const markerLayerOption = _.defaultsDeep(option, {
            layerOpt: {
                zooms: [3, 20],
                zIndex: 1000,
                allowCollision: false,
            },
        } as MarkerLayerOption) as MarkerLayerOption;
        const layer = new AMap.LabelsLayer(markerLayerOption.layerOpt);
        let convertData = (dataList ?? []).map<AMap.LabelMarkerOptions>((item) => {
            const {
                markerOpt: { icon },
            } = markerLayerOption;
            return {
                // name: '自提点9',
                position: item.position,
                zIndex: 2,
                opacity: 1,
                icon: {
                    // å›¾æ ‡ç±»åž‹ï¼ŒçŽ°é˜¶æ®µåªæ”¯æŒ image ç±»åž‹
                    type: 'image',
                    // å›¾ç‰‡ url
                    image: icon.url,
                    // å›¾ç‰‡å°ºå¯¸
                    size: [icon.size, icon.size],
                    // å›¾ç‰‡ç›¸å¯¹ position çš„锚点,默认为 bottom-center
                    anchor: 'center',
                },
                text: {
                    content: item.title,
                    direction: 'right',
                    offset: [-5, -5],
                    style: {
                        fontSize: 10,
                        fontWeight: 'normal',
                        fillColor: item.textColor,
                        strokeColor: '#fff',
                        strokeWidth: 2,
                        fold: true,
                        padding: '2, 5',
                    },
                },
                extData: item.extData,
            };
        });
        const markerList = convertData.map((item) => new AMap.LabelMarker(item));
        layer.add(markerList);
        this.map.add(layer);
    }
}