Commit d1c5929d authored by 罗超's avatar 罗超

完成地图脚本功能

parent 83b2495b
VUE_APP_API_URL = 'http://192.168.10.214/api/common/post'
VUE_APP_API_URL = 'http://reborn.oytour.com/api/common/post'
VUE_APP_UPLOADURLAPI_URL = 'http://192.168.10.214:8120'
VUE_APP_SHARE_URL = 'http://127.0.0.1:8080'
\ No newline at end of file
......@@ -20,6 +20,7 @@ declare module 'vue' {
Divider: typeof import('./src/components/Divider.vue')['default']
Drawer: typeof import('./src/components/Drawer.vue')['default']
EditableInput: typeof import('./src/components/ColorPicker/EditableInput.vue')['default']
ElAutocomplete: typeof import('element-plus/es')['ElAutocomplete']
ElButton: typeof import('element-plus/es')['ElButton']
ElButtonGroup: typeof import('element-plus/es')['ElButtonGroup']
ElCheckbox: typeof import('element-plus/es')['ElCheckbox']
......@@ -40,6 +41,7 @@ declare module 'vue' {
ElPagination: typeof import('element-plus/es')['ElPagination']
ElResult: typeof import('element-plus/es')['ElResult']
ElRow: typeof import('element-plus/es')['ElRow']
ElScrollbar: typeof import('element-plus/es')['ElScrollbar']
ElSelect: typeof import('element-plus/es')['ElSelect']
ElTable: typeof import('element-plus/es')['ElTable']
ElTableColumn: typeof import('element-plus/es')['ElTableColumn']
......@@ -59,6 +61,7 @@ declare module 'vue' {
LineAttributes: typeof import('./src/components/Maps/MapAttributes/LineAttributes.vue')['default']
MapAttributes: typeof import('./src/components/Maps/MapAttributes/index.vue')['default']
Maps: typeof import('./src/components/Maps/index.vue')['default']
MapScriptForm: typeof import('./src/components/Maps/MapScriptForm.vue')['default']
MarkAttributes: typeof import('./src/components/Maps/MapAttributes/MarkAttributes.vue')['default']
MenuContent: typeof import('./src/components/Contextmenu/MenuContent.vue')['default']
Message: typeof import('./src/components/Message.vue')['default']
......
<template>
<div class="script-form bg-white rounded">
<div class="q-pa-md">
<div class="text-h6">行程表单</div>
<div class="text-small q-mt-lg">你需要的国家:</div>
<el-select class="full-width" size="large" collapse-tags multiple filterable v-model="attrs.selectedCountries"
placeholder="请选择">
<el-option :label="item.label" :value="item.value" v-for="(item, index) in attrs.countriesData"
:key="index" />
</el-select>
<div class="text-small q-mt-lg">你需要的城市:</div>
</div>
<el-scrollbar class="q-pa-md full-width" max-height="50vh">
<el-autocomplete v-for="(x, i) in attrs.cities" v-model="x.label" size="large" class="full-width q-mb-md"
label="label" value-key="label" :fetch-suggestions="querySearchAsync" placeholder="请输入城市名称"
@select="(item: Record<string, any>) => citySelectHandler(item, i)">
<template #suffix>
<div class="row items-center">
<el-icon class="el-input__icon cusor-pointer" size="20px" title="上移" v-if="i > 0"
@click.stop="() => changePoiHandler(i, 'up')">
<Top />
</el-icon>
<el-icon class="el-input__icon cusor-pointer" size="18px" title="下移"
v-if="i < attrs.cities.length - 1" @click.stop="() => changePoiHandler(i, 'down')">
<Bottom />
</el-icon>
<el-icon class="el-input__icon cusor-pointer" color="#409eff" size="16px" title="新增"
@click.stop="() => createNewCity(i + 1)">
<Plus />
</el-icon>
<el-icon class="el-input__icon cusor-pointer" color="#d14424" size="16px" title="删除"
@click.stop="() => removeHandler(i)" v-if="attrs.cities.length > 1">
<Delete />
</el-icon>
</div>
</template>
<template #prefix>
<div class="text-small">{{ i + 1 }}</div>
</template>
</el-autocomplete>
</el-scrollbar>
<div class="q-pa-md q-mt-lg text-right">
<el-button link size="small" class="q-mr-md" @click="closeHandler">取消</el-button>
<el-button type="primary" size="small" :loading="loading" @click="()=>finishHandler()">开始创建</el-button>
</div>
</div>
</template>
<script setup lang="ts">
import { reactive, ref } from "vue";
import { useMapStore } from "@/store/index";
import { storeToRefs } from "pinia";
import MapService from "@/services/MapService";
import { Plus, Top, Bottom, Delete } from "@element-plus/icons-vue";
import { ElMessage } from "element-plus";
const attrs = reactive({
selectedCountries: [],
countriesData: [] as any[],
cities: [] as { label: string; data: any }[],
} as any);
const emit = defineEmits<{
(event: 'close'): void,
(event: 'finish',playload:any): void
}>()
const mapStore = useMapStore();
const { allCountries } = storeToRefs(mapStore);
const loading = ref(false)
const resolveCountries = () => {
attrs.countriesData = [];
if (allCountries.value) {
Object.keys(allCountries.value).forEach(function (key: string) {
attrs.countriesData.push({
value: key,
label: allCountries.value![key],
});
});
}
};
const querySearchAsync = async (
queryString: string,
cb: (arg: any) => void
) => {
let response = await MapService.queryPlaceInfoAsync(queryString);
cb(response);
};
const citySelectHandler = (item: Record<string, any>, i: number) => {
console.log(item);
attrs.cities[i].data = item;
};
const createNewCity = (index = -1) => {
let city = {
label: "",
data: null,
};
if (index == -1) {
attrs.cities.push(city);
} else {
attrs.cities.splice(index, 0, city);
}
};
const removeHandler = (index: number) => {
attrs.cities.splice(index, 1);
};
const changePoiHandler = (index: number, align: string) => {
let targetIndex = align == "up" ? index - 1 : index + 1;
let tempData = JSON.parse(JSON.stringify(attrs.cities[targetIndex]));
attrs.cities[targetIndex] = JSON.parse(JSON.stringify(attrs.cities[index]));
attrs.cities[index] = tempData;
};
const closeHandler= ()=>{
emit('close')
}
const finishHandler = ()=>{
if(!loading.value){
loading.value=true
let msg = ''
if(!attrs.selectedCountries||attrs.selectedCountries.length==0){
msg = '至少应该选择一个国家'
} else {
let index = attrs.cities.findIndex((x:any)=>x.label=='' || !x.data)
msg = index==-1?'':`请完善或删除第${index+1}个城市`
}
if(msg!=''){
ElMessage.error({
message: msg,
})
}else{
let r = {
countries:attrs.selectedCountries,
cities:attrs.cities
}
console.log(r)
emit('finish',r)
}
loading.value=false
}
}
createNewCity();
resolveCountries();
</script>
<style>
.script-form {
position: absolute;
z-index: 9;
top: 5px;
right: 5px;
width: 320px;
max-height: 80vh;
overflow-y: auto;
}
.cusor-pointer {
cursor: pointer;
}
</style>
......@@ -4,6 +4,8 @@
<div class="row items-center">
<div class="text-title col">地图创作</div>
<el-button link type="primary" size="mini" v-if="ConfigId" @click="loadTripMap"><el-icon style="margin-right: 5px;font-size: 16px;"><Loading /></el-icon>行程渲染</el-button>
<el-button link size="mini" @click="createScriptHandler"><el-icon style="margin-right: 5px;font-size: 16px;"><MapLocation /></el-icon>行程表单</el-button>
<el-button link size="mini" @click="exportMapImage"><el-icon style="margin-right: 5px;font-size: 16px;"><Download /></el-icon>生成</el-button>
<el-button link size="mini" @click="closed"><el-icon style="margin-right: 5px;font-size: 16px;"><Close /></el-icon>退出</el-button>
</div>
......@@ -13,6 +15,7 @@
<tools></tools>
<map-line v-if="operaIndex==2 && createLineStatus && canOpera" :parent="mapRef" :position="mouse" @success="createLineStatus=false"></map-line>
<map-attributes></map-attributes>
<MapScriptForm v-if="formVisable" @close="()=>formVisable=false" @finish="(result:any)=>createScriptMap(result)"></MapScriptForm>
</div>
</el-dialog>
......@@ -21,14 +24,16 @@
<script setup lang="ts">
import tools from './Tools.vue'
import MapAttributes from './MapAttributes/index.vue';
import MapScriptForm from './MapScriptForm.vue'
import mapLine from './Line.vue'
import { onMounted, provide, ref, watch } from 'vue';
import useMap from './useMap'
import { useMapStore,useScreenStore } from '@/store/index'
import { storeToRefs } from 'pinia';
import LineService from '@/services/LineService';
import { Loading,Download,Close } from '@element-plus/icons-vue'
import { Loading,Download,Close, MapLocation } from '@element-plus/icons-vue'
import { ElMessage, ElMessageBox } from 'element-plus';
import { result } from 'lodash';
const props = defineProps({
visible:{
......@@ -48,6 +53,7 @@ const mouse = ref<{x:number,y:number}>({
x:0,
y:0
})
const formVisable = ref(false)
const mapStore = useMapStore()
const createLineStatus = ref(false)
const loadingStatus = ref(true)
......@@ -124,6 +130,42 @@ const loadTripMap = async () =>{
dataLoadingStatus.value=false
}
const createScriptMap = (r:any)=>{
formVisable.value=false
disposeAll()
initMap()
setCountry(r.countries)
let points:{latitude:number,longitude:number}[][] = []
let cities = r.cities.map((x:any,i:number)=> {
let city = {
name:x.Label,
lat:x.data.center[1],
lng:x.data.center[0]
}
if(i>0){
let t = r.cities[i-1]
let p = [
{
latitude: t.data.center[1],
longitude: t.data.center[0]
},
{
latitude:city.lat,
longitude:city.lng
}
]
points.push(p)
}
return city
})
setMarks(cities)
setLines(points)
}
const createScriptHandler = ()=>{
formVisable.value= true
}
const exportMapImage = () => {
ElMessageBox.confirm('地图导出后无法继续编辑,是否确认导出','提示',{
......
......@@ -8,6 +8,7 @@ import { storeToRefs } from 'pinia';
import am4geodata_data_countries from "@amcharts/amcharts4-geodata/data/countries";
import am5geodata_lang_cn_ZH from "@amcharts/amcharts4-geodata/lang/cn_ZH";
import AliyunUpload from '@/utils/upload/aliyun';
export default (MapDOM: Ref<HTMLElement | undefined>, loadingStatus: Ref<boolean>) => {
......@@ -109,7 +110,14 @@ export default (MapDOM: Ref<HTMLElement | undefined>, loadingStatus: Ref<boolean
}
const exportPng = (): Promise<string> => {
const tt = map.config
console.log(tt)
countrySeries.exporting.getJSON("json").then(async r=>{
r = decodeURIComponent(r.replace('data:application/json;charset=utf-8,',''))
const blob = new Blob([r],{ type: 'application/json;charset=utf-8' });
await AliyunUpload.UploadAsync(blob,"tripfmap/1/temp.json")
})
loadingStatus.value = true
let tempBack = back.isShowing
let tempAdd = addButton.isShowing
......@@ -294,6 +302,11 @@ export default (MapDOM: Ref<HTMLElement | undefined>, loadingStatus: Ref<boolean
id: key,
name: allCountries![key]
});
}else if(names.includes(key)){
countriesData.push({
id: key,
name: allCountries![key]
});
}
})
if (countriesData && countriesData.length > 0) {
......
......@@ -2,6 +2,7 @@
import type { App } from 'vue'
import {
PlayOne,
FullScreenPlay,
Lock,
......@@ -124,7 +125,8 @@ import {
Info,
Earth,
RotationHorizontal,
RotationVertical
RotationVertical,
AssemblyLine
} from '@icon-park/vue-next'
export interface Icons {
......@@ -254,7 +256,8 @@ export const icons: Icons = {
IconInfo: Info,
IconEarth: Earth,
IconRotationHorizontal: RotationHorizontal,
IconRotationVertical: RotationVertical
IconRotationVertical: RotationVertical,
IconAssemblyLine: AssemblyLine
}
export default {
......
......@@ -37,10 +37,10 @@
<div class="title">
<Input
class="title-input"
ref="titleInputRef"
v-model:value="titleValue"
@blur="handleUpdateTitle()"
@blur="handleUpdateTitle()"
maxlength="250"
v-if="editingTitle"
></Input>
<div
......@@ -642,6 +642,10 @@ watch(()=>autoSave.value,(newVal)=>{
justify-content: center;
align-items: center;
}
.left{
flex:1;
justify-content:left !important;
}
.menu-item {
height: 30px;
display: flex;
......@@ -686,16 +690,21 @@ watch(()=>autoSave.value,(newVal)=>{
height: 32px;
margin-left: 2px;
font-size: 13px;
flex:1;
min-width: 0;
width: 0;
.title-input {
width: 200px;
// width: 200px;
height: 100%;
padding-left: 0;
padding-right: 0;
// max-width: 100%;
}
.title-text {
min-width: 20px;
max-width: 400px;
max-width: 100%;
line-height: 32px;
padding: 0 6px;
border-radius: $borderRadius;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment