【类 型】:fix

【原  因】:地图添加更新
【过  程】:
【影  响】:
This commit is contained in:
air 2025-09-23 18:10:18 +08:00
parent 2d44b5f54f
commit cf093c0d47
3 changed files with 159 additions and 99 deletions

View File

@ -1213,9 +1213,11 @@ const store = new Vuex.Store({
if (res.data.status === 1) { if (res.data.status === 1) {
const host = rootState.settings.host const host = rootState.settings.host
const list = res.data.mapStyleList.map(style => { const list = res.data.mapStyleList.map(style => {
const tiles = Array.isArray(style.tiles) ? style.tiles : JSON.parse(style.tiles) // 使用 url 字段,并包装成数组
const tiles = style.url ? [style.url] : (Array.isArray(style.tiles) ? style.tiles : [])
const sourceKey = 'default' const sourceKey = 'default'
const spriteUrl = style.sprite && String(style.sprite).trim() ? style.sprite : `${host}/Public/map/sprite` const spriteUrl = style.sprite && String(style.sprite).trim() ? style.sprite : `${host}/Public/map/sprite`
const glyphs = style.glyphs || 'mapbox://fonts/mapbox/{fontstack}/{range}.pbf'
return { return {
// 附带原始字段,便于管理端展示和操作 // 附带原始字段,便于管理端展示和操作
@ -1224,13 +1226,13 @@ const store = new Vuex.Store({
sort_order: Number(style.sort_order ?? 0), sort_order: Number(style.sort_order ?? 0),
name: style.name, name: style.name,
sprite: spriteUrl, sprite: spriteUrl,
glyphs: 'mapbox://fonts/mapbox/{fontstack}/{range}.pbf', glyphs: glyphs,
version: 8, version: 8,
sources: { sources: {
[sourceKey]: { [sourceKey]: {
type: 'raster', type: 'raster',
tileSize: 256, tileSize: 256,
tiles, tiles: tiles,
attribution: '' attribution: ''
} }
}, },
@ -1238,7 +1240,13 @@ const store = new Vuex.Store({
id: `${sourceKey}Layer`, id: `${sourceKey}Layer`,
type: 'raster', type: 'raster',
source: sourceKey source: sourceKey
}] }],
// 保存原始URL用于编辑
_original: {
url: style.url || (tiles.length > 0 ? tiles[0] : ''),
sprite: style.sprite,
glyphs: style.glyphs
}
} }
}) })
commit('setMapStyleList', list) commit('setMapStyleList', list)
@ -1307,6 +1315,84 @@ const store = new Vuex.Store({
} }
return Promise.reject(new Error('用户取消删除')) return Promise.reject(new Error('用户取消删除'))
} }
},
/**
* @description: 添加地图样式
* @param {Object} form 地图样式表单数据
* @param {string} form.name 样式名称
* @param {string} form.url 样式URL
* @param {string} form.thumbnail 缩略图URL
* @param {number} form.sort_order 排序值
* @return {Promise} 返回包含服务器响应的Promise
*/
async addMapStyle ({ dispatch }, form) {
// 参数验证
if (!form || typeof form !== 'object') {
throw new Error('无效的表单数据')
}
if (!form.name || !form.name.trim()) {
throw new Error('样式名称不能为空')
}
if (!form.url || !form.url.trim()) {
throw new Error('样式URL不能为空')
}
// 处理form参数为URLSearchParams格式
const params = new URLSearchParams()
params.append('name', form.name)
params.append('sprite', form.sprite || '')
params.append('glyphs', form.glyphs || 'mapbox://fonts/mapbox/{fontstack}/{range}.pbf')
params.append('url', form.url)
params.append('is_active', form.is_active ? 1 : 0)
params.append('sort_order', form.sort_order || 0)
// 发送请求
const res = await api.post('addMapStyle', params, 'Plane')
// 检查响应状态
if (res.data.status === 1) {
await dispatch('fetchMapStyleList') // 刷新列表
Message.success(res.data.msg)
} else {
Message.error(res.data.msg)
}
return res
},
async saveMapStyle ({ dispatch }, form) {
// 参数验证
if (!form || typeof form !== 'object') {
throw new Error('无效的表单数据')
}
if (!form.id) {
throw new Error('缺少样式ID')
}
// 处理form参数为URLSearchParams格式
const params = new URLSearchParams()
params.append('id', form.id)
if (form.name !== undefined) params.append('name', form.name)
if (form.sprite !== undefined) params.append('sprite', form.sprite)
if (form.glyphs !== undefined) params.append('glyphs', form.glyphs)
if (form.url !== undefined) params.append('url', form.url)
if (form.is_active !== undefined) params.append('is_active', form.is_active ? 1 : 0)
if (form.sort_order !== undefined) params.append('sort_order', form.sort_order)
// 发送请求
const res = await api.post('saveMapStyle', params, 'Plane')
// 检查响应状态
if (res.data.status === 1) {
await dispatch('fetchMapStyleList') // 刷新列表
Message.success(res.data.msg)
} else {
Message.error(res.data.msg)
}
return res
} }
}, },
modules: { modules: {

View File

@ -141,6 +141,10 @@ label {
padding-left: 25px !important; padding-left: 25px !important;
} }
.el-form-item__error {
left: 25px !important;
}
/* 当屏幕宽度小于等于480px时 */ /* 当屏幕宽度小于等于480px时 */
@media (max-width: 480px) { @media (max-width: 480px) {
.el-dialog { .el-dialog {

View File

@ -10,7 +10,8 @@
</div> </div>
</el-header> </el-header>
<el-main class="border p-20 m-b-20"> <el-main class="border p-20 m-b-20">
<el-form ref="formRef" :model="form" :rules="rules" label-width="120px" :label-position="$store.state.app.isWideScreen ? 'top' : 'right'" class="w-80"> <el-form ref="formRef" :model="form" :rules="rules" label-width="120px"
:label-position="$store.state.app.isWideScreen ? 'top' : 'right'" class="w-80">
<!-- 基本信息 --> <!-- 基本信息 -->
<div class="p-b-5"> <div class="p-b-5">
@ -19,11 +20,7 @@
</el-divider> </el-divider>
</div> </div>
<el-form-item label="样式名称" prop="name"> <el-form-item label="样式名称" prop="name">
<el-input v-model="form.name" placeholder="例如:谷歌卫星瓦片" /> <el-input v-model="form.name" placeholder="例如:谷歌卫星" />
</el-form-item>
<!-- 版本号固定为8不显示 -->
<el-form-item v-show="false" label="版本" prop="version">
<el-input-number v-model="form.version" :min="1" :max="8" :step="1" />
</el-form-item> </el-form-item>
<el-form-item label="是否启用" prop="is_active"> <el-form-item label="是否启用" prop="is_active">
<el-switch v-model="form.is_active" :active-value="1" :inactive-value="0" /> <el-switch v-model="form.is_active" :active-value="1" :inactive-value="0" />
@ -35,29 +32,28 @@
<!-- 资源信息 --> <!-- 资源信息 -->
<div class="p-t-10 p-b-5"> <div class="p-t-10 p-b-5">
<el-divider content-position="left"> <el-divider content-position="left">
<font class="fb f-s-18 normalFontColor">资源与源配置</font> <font class="fb f-s-18 normalFontColor">资源与源配置84坐标系</font>
</el-divider> </el-divider>
</div> </div>
<el-form-item label="sprite 路径" prop="sprite"> <el-form-item label="sprite 路径" prop="sprite">
<el-input v-model="form.sprite" :placeholder="form.sprite && form.sprite.includes('/Public/map/sprite') ? '使用默认路径 /Public/map/sprite' : '可选sprite 路径(留空则使用默认路径)'" /> <el-input v-model="form.sprite"
:placeholder="form.sprite && form.sprite.includes('/Public/map/sprite') ? '使用默认路径 /Public/map/sprite' : '可选sprite 路径(留空则使用默认路径)'" />
</el-form-item> </el-form-item>
<el-form-item label="glyphs 路径" prop="glyphs"> <el-form-item label="glyphs 路径" prop="glyphs">
<el-input v-model="form.glyphs" placeholder="可选glyphs 路径(如有)" /> <el-input v-model="form.glyphs" placeholder="可选glyphs 路径(如有)" />
</el-form-item> </el-form-item>
<!-- 固定使用默认值不显示 --> <!-- 固定使用默认值不显示 -->
<el-form-item label="瓦片URL列表" prop="tiles"> <el-form-item label="瓦片URL" prop="url"
<el-input :rules="[{ required: true, message: '请输入瓦片URL', trigger: 'blur' }]">
type="textarea" <el-input v-model="form.url"
:rows="4" placeholder="请输入瓦片URL例如http://gac-geo.googlecnapps.cn/maps/vt?lyrs=m&x={x}&y={y}&z={z}" />
v-model="tilesInput"
placeholder="每行一个URL或粘贴JSON数组例如\nhttps://server.com/tiles/{z}/{x}/{y}.png"
/>
</el-form-item> </el-form-item>
<!-- 固定使用默认值不显示 --> <!-- 固定使用默认值不显示 -->
<!-- 提交按钮 --> <!-- 提交按钮 -->
<el-form-item> <el-form-item>
<el-button type="primary" :icon="pageState === 'add' ? 'el-icon-plus' : 'el-icon-edit'" @click="handleSubmit"> <el-button type="primary" :icon="pageState === 'add' ? 'el-icon-plus' : 'el-icon-edit'"
@click="pageState === 'add' ? addMapStyle() : saveMapStyle()">
{{ pageState === 'add' ? '创建' : '更新' }} {{ pageState === 'add' ? '创建' : '更新' }}
</el-button> </el-button>
<el-button v-if="pageState === 'add'" class="iconfont icon-qingchu" @click="resetForm"> <el-button v-if="pageState === 'add'" class="iconfont icon-qingchu" @click="resetForm">
@ -71,7 +67,7 @@
</el-col> </el-col>
</el-row> </el-row>
</div> </div>
</template> </template>
<script> <script>
export default { export default {
@ -83,16 +79,15 @@ export default {
name: '', name: '',
sprite: '', sprite: '',
glyphs: 'mapbox://fonts/mapbox/{fontstack}/{range}.pbf', glyphs: 'mapbox://fonts/mapbox/{fontstack}/{range}.pbf',
version: 8, url: '', // URL
tiles: [], // tilesInput
is_active: 1, is_active: 1,
sort_order: 0 sort_order: 0
}, },
tilesInput: '', // /JSON
pageState: 'add', pageState: 'add',
mapStyleId: this.$route.params.id, mapStyleId: this.$route.params.id,
rules: { rules: {
name: [{ required: true, message: '请输入样式名称', trigger: 'blur' }] name: [{ required: true, message: '请输入样式名称', trigger: 'blur' }],
url: [{ required: true, message: '请输入瓦片URL', trigger: 'blur' }]
} }
} }
}, },
@ -107,7 +102,7 @@ export default {
try { try {
await this.$store.dispatch('fetchMapStyleList', this.$store.state.settings.host) await this.$store.dispatch('fetchMapStyleList', this.$store.state.settings.host)
item = (this.$store.state.mapStyleList || []).find(i => String(i.id) === String(this.mapStyleId)) item = (this.$store.state.mapStyleList || []).find(i => String(i.id) === String(this.mapStyleId))
} catch (e) {} } catch (e) { }
} }
if (item) { if (item) {
this.fillFormFromItem(item) this.fillFormFromItem(item)
@ -130,82 +125,54 @@ export default {
return text.split(/\r?\n/).map(s => s.trim()).filter(Boolean) return text.split(/\r?\n/).map(s => s.trim()).filter(Boolean)
}, },
fillFormFromItem (item) { fillFormFromItem (item) {
this.form.name = item.name || '' this.form = {
// id: item.id,
this.form.sprite = (item.sprite && item.sprite.includes('/Public/map/sprite')) ? '' : (item.sprite || '') name: item.name,
this.form.glyphs = item.glyphs || 'mapbox://fonts/mapbox/{fontstack}/{range}.pbf' sprite: item.sprite || '',
this.form.version = 8 glyphs: item.glyphs || 'mapbox://fonts/mapbox/{fontstack}/{range}.pbf',
// tiles JSON url: item.url || (item.sources && item.sources.default && item.sources.default.tiles &&
let tiles = [] item.sources.default.tiles.length > 0 ? item.sources.default.tiles[0] : ''),
if (Array.isArray(item.tiles)) { is_active: item.is_active,
tiles = item.tiles sort_order: item.sort_order
} else if (typeof item.tiles === 'string') { }
try {
tiles = JSON.parse(item.tiles) // _original
} catch (e) { if (item._original) {
tiles = item.tiles.split('\n').filter(Boolean) this.form.url = item._original.url || ''
} this.form.sprite = item._original.sprite || ''
this.form.glyphs = item._original.glyphs || 'mapbox://fonts/mapbox/{fontstack}/{range}.pbf'
} }
this.form.tiles = tiles
this.tilesInput = Array.isArray(tiles) ? tiles.join('\n') : tiles
this.form.is_active = Number(item.is_active ?? 1)
this.form.sort_order = Number(item.sort_order ?? 0)
}, },
resetForm () { resetForm () {
this.$refs.formRef && this.$refs.formRef.resetFields() this.$refs.formRef.resetFields()
this.tilesInput = '' this.form = {
this.form.version = 8 id: null,
this.form.is_active = 1 name: '',
this.form.sort_order = 0 sprite: '',
glyphs: 'mapbox://fonts/mapbox/{fontstack}/{range}.pbf',
url: '',
is_active: 1,
sort_order: 0
}
}, },
handleSubmit () { /**
this.$refs.formRef.validate(valid => { * @description: 创建地图样式
if (valid) { */
// tiles async addMapStyle () {
this.form.tiles = this.parseTilesInput(this.tilesInput) const res = await this.$store.dispatch('addMapStyle', this.form)
if (this.form.tiles.length === 0) { if (res.data.status === 1) {
this.$message.warning('请至少输入一个瓦片URL') this.$router.push('/mapstyle/index')
return }
} },
/**
// * @description: 更新地图样式
const submitData = { */
name: this.form.name, async saveMapStyle () {
// sprite使 this.form.id = this.mapStyleId
sprite: this.form.sprite || '/Public/map/sprite', const res = await this.$store.dispatch('saveMapStyle', this.form)
glyphs: this.form.glyphs, if (res.data.status === 1) {
tiles: this.form.tiles, this.$router.push('/mapstyle/index')
is_active: this.form.is_active, }
sort_order: this.form.sort_order
}
// ID
if (this.pageState === 'edit' && this.form.id) {
submitData.id = this.form.id
}
const loading = this.$loading({ lock: true })
const action = this.pageState === 'add'
? this.$store.dispatch('addMapStyle', submitData)
: this.$store.dispatch('saveMapStyle', submitData)
action.then(res => {
if (res.data.status === 1) {
this.$message.success(res.data.msg)
this.$router.push('/layout/mapstyle')
} else {
this.$message.error(res.data.msg || '操作失败')
}
}).catch(e => {
this.$message.error(e.message || '请求出错')
}).finally(() => {
loading.close()
})
} else {
this.$message.warning('请正确填写表单')
return false
}
})
} }
} }
} }
@ -213,5 +180,8 @@ export default {
<style lang="scss" scoped> <style lang="scss" scoped>
@import "@/styles/theme.scss"; @import "@/styles/theme.scss";
.w-80 { max-width: 880px; }
.w-80 {
max-width: 880px;
}
</style> </style>