Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
P
pptist
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
viitto
pptist
Commits
d1c5929d
Commit
d1c5929d
authored
Feb 05, 2024
by
罗超
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
完成地图脚本功能
parent
83b2495b
Hide whitespace changes
Inline
Side-by-side
Showing
7 changed files
with
238 additions
and
9 deletions
+238
-9
.env.development
.env.development
+1
-1
components.d.ts
components.d.ts
+3
-0
MapScriptForm.vue
src/components/Maps/MapScriptForm.vue
+159
-0
index.vue
src/components/Maps/index.vue
+43
-1
useMap.ts
src/components/Maps/useMap.ts
+14
-1
icon.ts
src/plugins/icon.ts
+5
-2
index.vue
src/views/Editor/EditorHeader/index.vue
+13
-4
No files found.
.env.development
View file @
d1c5929d
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
components.d.ts
View file @
d1c5929d
...
...
@@ -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'
]
...
...
src/components/Maps/MapScriptForm.vue
0 → 100644
View file @
d1c5929d
<
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
>
src/components/Maps/index.vue
View file @
d1c5929d
...
...
@@ -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
(
'地图导出后无法继续编辑,是否确认导出'
,
'提示'
,{
...
...
src/components/Maps/useMap.ts
View file @
d1c5929d
...
...
@@ -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
)
{
...
...
src/plugins/icon.ts
View file @
d1c5929d
...
...
@@ -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
{
...
...
src/views/Editor/EditorHeader/index.vue
View file @
d1c5929d
...
...
@@ -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
;
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment