wangxinping 3 months ago
parent
commit
d3f9c44bfa
  1. 52
      ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysUserMenuConfigController.java
  2. 2
      ruoyi-framework/src/main/java/com/ruoyi/framework/web/service/SysRegisterService.java
  3. 63
      ruoyi-system/src/main/java/com/ruoyi/system/domain/SysUserMenuConfig.java
  4. 35
      ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysUserMenuConfigMapper.java
  5. 30
      ruoyi-system/src/main/java/com/ruoyi/system/service/ISysUserMenuConfigService.java
  6. 55
      ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysUserMenuConfigServiceImpl.java
  7. 58
      ruoyi-system/src/main/resources/mapper/system/SysUserMenuConfigMapper.xml
  8. 23
      ruoyi-ui/src/api/system/userMenuConfig.js
  9. 2
      ruoyi-ui/src/permission.js
  10. 180
      ruoyi-ui/src/views/cesiumMap/index.vue
  11. 18
      ruoyi-ui/src/views/childRoom/TopHeader.vue
  12. 110
      ruoyi-ui/src/views/childRoom/index.vue
  13. 45
      ruoyi-ui/src/views/dialogs/ScaleDialog.vue
  14. 7
      ruoyi-ui/src/views/login.vue

52
ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysUserMenuConfigController.java

@ -0,0 +1,52 @@
package com.ruoyi.web.controller.system;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.system.domain.SysUserMenuConfig;
import com.ruoyi.system.service.ISysUserMenuConfigService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.Map;
/**
* 用户左侧菜单配置当前登录用户自己的配置
*
* @author ruoyi
*/
@RestController
@RequestMapping("/system/user/menuConfig")
public class SysUserMenuConfigController extends BaseController {
@Autowired
private ISysUserMenuConfigService menuConfigService;
/**
* 获取当前用户的左侧菜单配置
*/
@GetMapping
public AjaxResult getMyConfig() {
Long userId = getUserId();
SysUserMenuConfig config = menuConfigService.selectByUserId(userId);
if (config == null) {
return success(null);
}
return success(config);
}
/**
* 保存当前用户的左侧菜单配置
* 请求体: { "menuItems": "[{...}]", "position": "left" }
*/
@PutMapping
public AjaxResult saveMyConfig(@RequestBody Map<String, Object> body) {
Long userId = getUserId();
String menuItems = body != null && body.get("menuItems") != null ? body.get("menuItems").toString() : null;
String position = body != null && body.get("position") != null ? body.get("position").toString() : "left";
if (menuItems == null) {
return error("菜单项不能为空");
}
int rows = menuConfigService.saveConfig(userId, menuItems, position, getUsername());
return toAjax(rows);
}
}

2
ruoyi-framework/src/main/java/com/ruoyi/framework/web/service/SysRegisterService.java

@ -96,7 +96,7 @@ public class SysRegisterService
String level = registerBody.getUserLevel();
if ("1".equals(level)) {
roleIds[0] = 1L; // 管理员角色ID
roleIds[0] = 101L; // 管理员角色ID
} else if ("2".equals(level)) {
roleIds[0] = 100L; // 主持人角色ID
} else {

63
ruoyi-system/src/main/java/com/ruoyi/system/domain/SysUserMenuConfig.java

@ -0,0 +1,63 @@
package com.ruoyi.system.domain;
import javax.validation.constraints.Size;
import com.ruoyi.common.annotation.Excel;
import com.ruoyi.common.core.domain.BaseEntity;
/**
* 用户左侧菜单配置对象 sys_user_menu_config
*
* @author ruoyi
*/
public class SysUserMenuConfig extends BaseEntity {
private static final long serialVersionUID = 1L;
/** 配置主键 */
private Long configId;
/** 用户ID */
@Excel(name = "用户ID")
private Long userId;
/** 菜单项JSON数组 */
@Excel(name = "菜单项")
private String menuItems;
/** 菜单位置 left/top/bottom */
@Excel(name = "菜单位置")
@Size(max = 20)
private String position;
public Long getConfigId() {
return configId;
}
public void setConfigId(Long configId) {
this.configId = configId;
}
public Long getUserId() {
return userId;
}
public void setUserId(Long userId) {
this.userId = userId;
}
public String getMenuItems() {
return menuItems;
}
public void setMenuItems(String menuItems) {
this.menuItems = menuItems;
}
public String getPosition() {
return position;
}
public void setPosition(String position) {
this.position = position;
}
}

35
ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysUserMenuConfigMapper.java

@ -0,0 +1,35 @@
package com.ruoyi.system.mapper;
import com.ruoyi.system.domain.SysUserMenuConfig;
/**
* 用户左侧菜单配置 数据层
*
* @author ruoyi
*/
public interface SysUserMenuConfigMapper {
/**
* 根据用户ID查询配置
*
* @param userId 用户ID
* @return 配置信息
*/
SysUserMenuConfig selectByUserId(Long userId);
/**
* 新增配置
*
* @param config 配置信息
* @return 结果
*/
int insertConfig(SysUserMenuConfig config);
/**
* 更新配置
*
* @param config 配置信息
* @return 结果
*/
int updateConfig(SysUserMenuConfig config);
}

30
ruoyi-system/src/main/java/com/ruoyi/system/service/ISysUserMenuConfigService.java

@ -0,0 +1,30 @@
package com.ruoyi.system.service;
import com.ruoyi.system.domain.SysUserMenuConfig;
/**
* 用户左侧菜单配置 服务层
*
* @author ruoyi
*/
public interface ISysUserMenuConfigService {
/**
* 根据当前登录用户ID查询配置
*
* @param userId 用户ID
* @return 配置信息无则返回 null
*/
SysUserMenuConfig selectByUserId(Long userId);
/**
* 保存当前用户的菜单配置有则更新无则新增
*
* @param userId 用户ID
* @param menuItems 菜单项JSON字符串
* @param position 菜单位置
* @param operator 操作人createBy/updateBy
* @return 结果
*/
int saveConfig(Long userId, String menuItems, String position, String operator);
}

55
ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysUserMenuConfigServiceImpl.java

@ -0,0 +1,55 @@
package com.ruoyi.system.service.impl;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.system.domain.SysUserMenuConfig;
import com.ruoyi.system.mapper.SysUserMenuConfigMapper;
import com.ruoyi.system.service.ISysUserMenuConfigService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
/**
* 用户左侧菜单配置 服务层实现
*
* @author ruoyi
*/
@Service
public class SysUserMenuConfigServiceImpl implements ISysUserMenuConfigService {
@Autowired
private SysUserMenuConfigMapper menuConfigMapper;
@Override
public SysUserMenuConfig selectByUserId(Long userId) {
if (userId == null) {
return null;
}
return menuConfigMapper.selectByUserId(userId);
}
@Override
public int saveConfig(Long userId, String menuItems, String position, String operator) {
if (userId == null) {
return 0;
}
SysUserMenuConfig existing = menuConfigMapper.selectByUserId(userId);
if (existing != null) {
existing.setMenuItems(menuItems);
if (StringUtils.isNotEmpty(position)) {
existing.setPosition(position);
}
if (StringUtils.isNotEmpty(operator)) {
existing.setUpdateBy(operator);
}
return menuConfigMapper.updateConfig(existing);
} else {
SysUserMenuConfig config = new SysUserMenuConfig();
config.setUserId(userId);
config.setMenuItems(menuItems);
config.setPosition(StringUtils.isEmpty(position) ? "left" : position);
if (StringUtils.isNotEmpty(operator)) {
config.setCreateBy(operator);
}
return menuConfigMapper.insertConfig(config);
}
}
}

58
ruoyi-system/src/main/resources/mapper/system/SysUserMenuConfigMapper.xml

@ -0,0 +1,58 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.ruoyi.system.mapper.SysUserMenuConfigMapper">
<resultMap type="com.ruoyi.system.domain.SysUserMenuConfig" id="SysUserMenuConfigResult">
<id property="configId" column="config_id" />
<result property="userId" column="user_id" />
<result property="menuItems" column="menu_items" />
<result property="position" column="position" />
<result property="createBy" column="create_by" />
<result property="createTime" column="create_time" />
<result property="updateBy" column="update_by" />
<result property="updateTime" column="update_time" />
<result property="remark" column="remark" />
</resultMap>
<sql id="selectVo">
select config_id, user_id, menu_items, position, create_by, create_time, update_by, update_time, remark
from sys_user_menu_config
</sql>
<select id="selectByUserId" parameterType="Long" resultMap="SysUserMenuConfigResult">
<include refid="selectVo"/>
where user_id = #{userId} limit 1
</select>
<insert id="insertConfig" parameterType="com.ruoyi.system.domain.SysUserMenuConfig">
insert into sys_user_menu_config (
user_id,
menu_items,
position,
<if test="createBy != null and createBy != ''">create_by,</if>
<if test="remark != null and remark != ''">remark,</if>
create_time
) values (
#{userId},
#{menuItems},
#{position},
<if test="createBy != null and createBy != ''">#{createBy},</if>
<if test="remark != null and remark != ''">#{remark},</if>
sysdate()
)
</insert>
<update id="updateConfig" parameterType="com.ruoyi.system.domain.SysUserMenuConfig">
update sys_user_menu_config
<set>
<if test="menuItems != null">menu_items = #{menuItems},</if>
<if test="position != null and position != ''">position = #{position},</if>
<if test="updateBy != null and updateBy != ''">update_by = #{updateBy},</if>
<if test="remark != null">remark = #{remark},</if>
update_time = sysdate()
</set>
where user_id = #{userId}
</update>
</mapper>

23
ruoyi-ui/src/api/system/userMenuConfig.js

@ -0,0 +1,23 @@
import request from '@/utils/request'
/**
* 获取当前用户的左侧菜单配置
*/
export function getMenuConfig() {
return request({
url: '/system/user/menuConfig',
method: 'get'
})
}
/**
* 保存当前用户的左侧菜单配置
* @param {Object} data - { menuItems: string (JSON), position: string }
*/
export function saveMenuConfig(data) {
return request({
url: '/system/user/menuConfig',
method: 'put',
data: data
})
}

2
ruoyi-ui/src/permission.js

@ -9,7 +9,7 @@ import { isRelogin } from '@/utils/request'
NProgress.configure({ showSpinner: false })
const whiteList = ['/login', '/register', '/selectRoom', '/childRoom']
const whiteList = ['/login', '/register', '/selectRoom']
const isWhiteList = (path) => {
return whiteList.some(pattern => isPathMatch(pattern, path))

180
ruoyi-ui/src/views/cesiumMap/index.vue

@ -46,7 +46,7 @@
<!-- 地图右下角比例尺 + 经纬度 -->
<div class="map-info-panel">
<div class="scale-bar">
<div class="scale-bar" @click="handleScaleClick">
<span class="scale-bar-text">{{ scaleBarText }}</span>
<div class="scale-bar-line" :style="{ width: scaleBarWidthPx + 'px' }">
<span class="scale-bar-tick scale-bar-tick-left"></span>
@ -89,6 +89,15 @@ export default {
type: String,
default: 'airspace' // 'airspace' or 'ranging'
},
scaleConfig: {
type: Object,
default: () => ({
scaleNumerator: 1,
scaleDenominator: 1000,
unit: 'km',
position: 'bottom-right'
})
}
},
watch: {
drawDomClick: {
@ -99,6 +108,14 @@ export default {
// this.initMap()
}
}
},
scaleConfig: {
deep: true,
handler(newVal) {
if (newVal) {
this.updateScaleFromConfig(newVal)
}
}
}
},
data() {
@ -149,6 +166,10 @@ export default {
//
scaleBarText: '--',
scaleBarWidthPx: 80,
useCustomScale: false,
customScaleText: '',
currentScaleUnit: 'm',
isApplyingScale: false,
//
locateDialogVisible: false
}
@ -174,6 +195,102 @@ export default {
this.destroyViewer()
},
methods: {
updateScaleFromConfig(config) {
if (!config || !this.viewer) return
const { scaleNumerator, scaleDenominator, unit } = config
if (!scaleDenominator || scaleDenominator <= 0) return
let displayValue = ''
let metersPerPixel = 0
const standardDPI = 96
const pixelsPerCm = standardDPI * 0.393701
const scaleFactor = scaleDenominator / scaleNumerator
switch (unit) {
case 'm':
displayValue = `1:${scaleDenominator}`
metersPerPixel = scaleFactor / pixelsPerCm
break
case 'km':
displayValue = `1:${scaleDenominator}`
metersPerPixel = (scaleFactor * 1000) / pixelsPerCm
break
default:
displayValue = `1:${scaleDenominator}`
metersPerPixel = scaleFactor / pixelsPerCm
}
console.log('比例尺设置:', displayValue, '每像素米数:', metersPerPixel.toFixed(4))
this.isApplyingScale = true
this.useCustomScale = true
this.customScaleText = displayValue
this.currentScaleUnit = unit
this.applyScaleToCamera(metersPerPixel)
this.updateScaleBar()
this.$forceUpdate()
setTimeout(() => {
this.isApplyingScale = false
}, 1000)
},
applyScaleToCamera(metersPerPixel) {
if (!this.viewer || !this.viewer.camera) return
const canvas = this.viewer.scene.canvas
const width = canvas.clientWidth
const height = canvas.clientHeight
if (width <= 0 || height <= 0) return
const camera = this.viewer.camera
const scene = this.viewer.scene
if (scene.mode === Cesium.SceneMode.SCENE2D) {
const frustumWidth = width * metersPerPixel
camera.frustum.right = frustumWidth / 2
camera.frustum.left = -frustumWidth / 2
const frustumHeight = height * metersPerPixel
camera.frustum.top = frustumHeight / 2
camera.frustum.bottom = -frustumHeight / 2
} else {
const cameraPosition = camera.positionCartographic
const groundWidth = width * metersPerPixel
const fov = camera.frustum.fov || Cesium.Math.PI_OVER_THREE
const aspectRatio = width / height
const verticalFov = fov / aspectRatio
const targetHeight = (groundWidth / 2) / Math.tan(fov / 2)
const destination = Cesium.Cartesian3.fromRadians(
cameraPosition.longitude,
cameraPosition.latitude,
targetHeight
)
camera.flyTo({
destination: destination,
duration: 0.5,
orientation: {
heading: camera.heading,
pitch: camera.pitch,
roll: camera.roll
}
})
}
},
handleScaleClick() {
this.$emit('scale-click', {
useCustomScale: this.useCustomScale,
customScaleText: this.customScaleText
})
},
preventContextMenu(e) {
e.preventDefault();
},
@ -2926,6 +3043,10 @@ export default {
initScaleBar() {
const that = this
const update = () => {
if (!that.isApplyingScale) {
that.useCustomScale = false
that.customScaleText = ''
}
that.updateScaleBar()
}
update()
@ -2966,9 +3087,10 @@ export default {
if (leftCartesian && rightCartesian) {
const rawMeters = Cesium.Cartesian3.distance(leftCartesian, rightCartesian)
if (rawMeters > 0) {
const metersPerPx = rawMeters / barPx
const niceMeters = this.niceScaleValue(rawMeters)
const widthPx = Math.round((niceMeters / rawMeters) * barPx)
const text = niceMeters >= 1000 ? `${(niceMeters / 1000).toFixed(0)} 公里` : `${Math.round(niceMeters)}`
const text = this.formatScaleText(niceMeters)
return { text, widthPx, niceMeters }
}
}
@ -2982,8 +3104,8 @@ export default {
const rawMeters = metersPerPx * barPx
const niceMeters = this.niceScaleValue(rawMeters)
const widthPx = Math.round(niceMeters / metersPerPx)
const text = niceMeters >= 1000 ? `${(niceMeters / 1000).toFixed(0)} 公里` : `${Math.round(niceMeters)}`
return { text, widthPx: Math.min(120, Math.max(40, widthPx)), niceMeters }
const text = this.formatScaleText(niceMeters)
return { text, widthPx, niceMeters }
}
}
// 2D ->
@ -2994,12 +3116,31 @@ export default {
const rawMeters = metersPerPx * barPx
const niceMeters = this.niceScaleValue(rawMeters)
const widthPx = Math.round(niceMeters / metersPerPx)
const text = niceMeters >= 1000 ? `${(niceMeters / 1000).toFixed(0)} 公里` : `${Math.round(niceMeters)}`
return { text, widthPx: Math.min(120, Math.max(40, widthPx)), niceMeters }
const text = this.formatScaleText(niceMeters)
return { text, widthPx, niceMeters }
}
}
return null
},
/** 计算比例尺比例 */
calculateScaleRatio(metersPerPx) {
const standardDPI = 96
const pixelsPerCm = standardDPI * 0.393701
const metersPerCm = metersPerPx * pixelsPerCm
let scaleRatio = 0
if (this.currentScaleUnit === 'km') {
scaleRatio = Math.round(metersPerCm / 1000)
} else {
scaleRatio = Math.round(metersPerCm)
}
return scaleRatio
},
/** 获取1厘米对应的像素数 */
getPixelsPerCm() {
const standardDPI = 96
const pixelsPerCm = standardDPI * 0.393701
return pixelsPerCm
},
/** 将实际距离圆整为易读的刻度值(米) */
niceScaleValue(meters) {
const candidates = [10, 20, 50, 100, 200, 500, 1000, 2000, 5000, 10000, 20000, 50000, 100000, 200000, 500000]
@ -3009,14 +3150,29 @@ export default {
}
return best
},
/** 格式化比例尺文本 */
formatScaleText(meters) {
if (meters >= 1000) {
const kmValue = (meters / 1000).toFixed(0)
return `${kmValue}km`
} else {
return `${meters}m`
}
},
updateScaleBar() {
const info = this.getScaleBarInfo()
if (info) {
this.scaleBarText = info.text
this.scaleBarWidthPx = Math.min(120, Math.max(40, info.widthPx))
if (this.useCustomScale && this.customScaleText) {
this.scaleBarText = `${this.customScaleText}${this.currentScaleUnit}`
const pixelsPerCm = this.getPixelsPerCm()
this.scaleBarWidthPx = Math.min(120, Math.max(40, Math.round(pixelsPerCm)))
} else {
this.scaleBarText = '--'
this.scaleBarWidthPx = 80
const info = this.getScaleBarInfo()
if (info) {
this.scaleBarText = info.text
this.scaleBarWidthPx = Math.min(120, Math.max(40, info.widthPx))
} else {
this.scaleBarText = '--'
this.scaleBarWidthPx = 80
}
}
this.$nextTick()
},

18
ruoyi-ui/src/views/childRoom/TopHeader.vue

@ -334,6 +334,14 @@ export default {
isIconEditMode: {
type: Boolean,
default: false
},
currentScaleConfig: {
type: Object,
default: () => ({
scaleNumerator: 1,
scaleDenominator: 1000,
unit: 'm'
})
}
},
data() {
@ -366,6 +374,16 @@ export default {
]
}
},
watch: {
currentScaleConfig: {
deep: true,
handler(newVal) {
if (newVal) {
this.currentScale = { ...newVal }
}
}
}
},
methods: {
selectTopNav(item) {
this.$emit('select-nav', item)

110
ruoyi-ui/src/views/childRoom/index.vue

@ -6,8 +6,10 @@
<!-- cesiummap组件 -->
<cesiumMap ref="cesiumMap" :drawDomClick="drawDom || airspaceDrawDom"
:tool-mode="drawDom ? 'ranging' : (airspaceDrawDom ? 'airspace' : 'airspace')"
:scaleConfig="scaleConfig"
@draw-complete="handleMapDrawComplete"
@open-waypoint-dialog="handleOpenWaypointEdit"
@scale-click="handleScaleClick" />
@open-route-dialog="handleOpenRouteEdit" />
<div class="map-overlay-text">
<i class="el-icon-location-outline text-3xl mb-2 block"></i>
@ -67,6 +69,7 @@
:can-set-k-time="canSetKTime"
:user-avatar="userAvatar"
:is-icon-edit-mode="isIconEditMode"
:current-scale-config="scaleConfig"
@select-nav="selectTopNav"
@set-k-time="openKTimeSetDialog"
@save-plan="savePlan"
@ -269,6 +272,7 @@
v-model="showScaleDialog"
:scale="currentScale"
@save="saveScale"
@unit-change="handleScaleUnitChange"
/>
<!-- 外部参数弹窗 -->
@ -331,6 +335,7 @@ import { listRoutes, getRoutes, addRoutes, updateRoutes, delRoutes } from "@/api
import { updateWaypoints } from "@/api/system/waypoints";
import { listLib,addLib,delLib} from "@/api/system/lib";
import { getRooms, updateRooms } from "@/api/system/rooms";
import { getMenuConfig, saveMenuConfig } from "@/api/system/userMenuConfig";
import PlatformImportDialog from "@/views/dialogs/PlatformImportDialog.vue";
export default {
name: 'MissionPlanningView',
@ -367,7 +372,16 @@ export default {
showPowerZoneDialog: false,
currentPowerZone: {},
showScaleDialog: false,
currentScale: {},
currentScale: {
scaleNumerator: 1,
scaleDenominator: 1000,
unit: 'm'
},
scaleConfig: {
scaleNumerator: 1,
scaleDenominator: 1000,
unit: 'm'
},
showExternalParamsDialog: false,
currentExternalParams: {},
showPageLayoutDialog: false,
@ -528,10 +542,12 @@ export default {
isAdmin() {
const roles = this.$store.getters.roles || [];
const id = this.$store.getters.id;
const userLevel = String(this.$store.getters.userLevel);
return (
roles.includes('admin') ||
String(id) === '1' ||
(Array.isArray(roles) && roles.some(r => String(r).toLowerCase() === 'admin'))
id === '1' || // ID
userLevel === '1' || // user_level
roles.includes('admin') || //
roles.includes('manager') //
);
},
canSetKTime() {
@ -544,8 +560,9 @@ export default {
this.isMenuHidden = true;
//
this.isRightPanelHidden = true;
//
//
this.menuItems = [...this.defaultMenuItems];
this.loadUserMenuConfig();
//
this.updateTime();
@ -1110,6 +1127,10 @@ export default {
return `${y}-${m}-${day} ${h}:${min}:${s}`;
},
openKTimeSetDialog() {
console.log("当前登录 ID (myId):", this.$store.getters.id);
console.log("当前房间 ownerId:", this.roomDetail ? this.roomDetail.ownerId : '无房间信息');
console.log("当前房间 userLevel:", this.$store.getters.userLevel);
console.log("当前角色 roles:", this.$store.getters.roles);
if (!this.canSetKTime) {
this.$message.info('仅房主或管理员可设定或修改 K 时');
return;
@ -1224,8 +1245,14 @@ export default {
this.isIconEditMode = false
},
handleResetMenuItems() {
async handleResetMenuItems() {
this.menuItems = [...this.defaultMenuItems]
try {
await saveMenuConfig({
menuItems: JSON.stringify(this.menuItems),
position: this.menuPosition || 'left'
})
} catch (e) { /* 未登录时仅本地恢复默认 */ }
},
updateMenuItems(newItems) {
@ -1303,8 +1330,43 @@ export default {
}
},
handleSaveMenuItems(savedItems) {
async handleSaveMenuItems(savedItems) {
this.menuItems = [...savedItems]
//
try {
await saveMenuConfig({
menuItems: JSON.stringify(this.menuItems),
position: this.menuPosition || 'left'
})
} catch (e) {
// LeftMenu
if (e && e.response && e.response.status === 401) {
this.$message.info('当前未登录,配置仅在本页有效;登录后保存可同步到账号')
}
}
},
/** 加载当前用户的左侧菜单配置(登录且有过保存时生效) */
async loadUserMenuConfig() {
try {
const res = await getMenuConfig()
const data = res && res.data
if (!data) return
if (data.menuItems) {
let arr = []
try {
arr = typeof data.menuItems === 'string' ? JSON.parse(data.menuItems) : data.menuItems
} catch (e) { /* 解析失败保留默认 */ }
if (Array.isArray(arr) && arr.length > 0) {
this.menuItems = arr
}
}
if (data.position && ['left', 'top', 'bottom'].includes(data.position)) {
this.menuPosition = data.position
}
} catch (e) {
// 使
}
},
attributeEdit() {
@ -1349,10 +1411,36 @@ export default {
saveScale(scale) {
console.log('保存比例尺:', scale)
this.scaleConfig = {
scaleNumerator: scale.scaleNumerator,
scaleDenominator: scale.scaleDenominator,
unit: scale.unit
}
if (this.$refs.cesiumMap) {
this.$refs.cesiumMap.updateScaleFromConfig(this.scaleConfig)
}
const scaleText = `${scale.scaleNumerator}:${scale.scaleDenominator}`
this.$message.success(`比例尺 "${scaleText}" 保存成功`);
},
handleScaleClick(scaleInfo) {
this.currentScale = {
scaleNumerator: this.scaleConfig.scaleNumerator,
scaleDenominator: this.scaleConfig.scaleDenominator,
unit: this.scaleConfig.unit
}
this.showScaleDialog = true
},
handleScaleUnitChange(unit) {
this.scaleConfig.unit = unit
if (this.$refs.cesiumMap) {
this.$refs.cesiumMap.currentScaleUnit = unit
}
},
//
loadTerrain() {
this.$message.success('加载/切换地形');
@ -1413,9 +1501,15 @@ export default {
this.$message.success('外部参数保存成功');
},
savePageLayout(position) {
async savePageLayout(position) {
this.menuPosition = position;
this.$message.success(`菜单位置已设置为:${this.getPositionLabel(position)}`);
try {
await saveMenuConfig({
menuItems: JSON.stringify(this.menuItems),
position: this.menuPosition || 'left'
})
} catch (e) { /* 未登录时仅本地生效 */ }
},
getPositionLabel(position) {

45
ruoyi-ui/src/views/dialogs/ScaleDialog.vue

@ -30,17 +30,6 @@
<el-select v-model="formData.unit" placeholder="请选择单位" style="width: 100%;">
<el-option label="米" value="m"></el-option>
<el-option label="千米" value="km"></el-option>
<el-option label="英尺" value="ft"></el-option>
<el-option label="英里" value="mi"></el-option>
</el-select>
</el-form-item>
<el-form-item label="显示位置" prop="position">
<el-select v-model="formData.position" placeholder="请选择显示位置" style="width: 100%;">
<el-option label="左下角" value="bottom-left"></el-option>
<el-option label="右下角" value="bottom-right"></el-option>
<el-option label="左上角" value="top-left"></el-option>
<el-option label="右上角" value="top-right"></el-option>
</el-select>
</el-form-item>
</el-form>
@ -71,9 +60,8 @@ export default {
return {
formData: {
scaleNumerator: 1,
scaleDenominator: 1000,
unit: 'km',
position: 'bottom-right'
scaleDenominator: 20,
unit: 'km'
},
rules: {
scaleNumerator: [
@ -84,9 +72,6 @@ export default {
],
unit: [
{ required: true, message: '请选择单位', trigger: 'change' }
],
position: [
{ required: true, message: '请选择显示位置', trigger: 'change' }
]
}
};
@ -101,15 +86,19 @@ export default {
if (this.value && newVal) {
this.initFormData();
}
},
'formData.unit'(newVal) {
if (this.value) {
this.$emit('unit-change', newVal);
}
}
},
methods: {
initFormData() {
this.formData = {
scaleNumerator: this.scale.scaleNumerator || 1,
scaleDenominator: this.scale.scaleDenominator || 1000,
unit: this.scale.unit || 'km',
position: this.scale.position || 'bottom-right'
scaleDenominator: this.scale.scaleDenominator || 20,
unit: this.scale.unit || 'km'
};
},
closeDialog() {
@ -151,7 +140,7 @@ export default {
border-radius: 8px;
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.15);
width: 90%;
max-width: 500px;
max-width: 400px;
max-height: 90vh;
overflow-y: auto;
animation: dialog-fade-in 0.3s ease;
@ -173,7 +162,7 @@ export default {
display: flex;
align-items: center;
justify-content: space-between;
padding: 16px 20px;
padding: 12px 16px;
border-bottom: 1px solid #e8e8e8;
}
@ -196,7 +185,17 @@ export default {
}
.dialog-body {
padding: 20px;
padding: 16px;
}
.quick-scale-buttons {
display: flex;
flex-wrap: wrap;
gap: 8px;
}
.quick-scale-buttons .el-button {
margin: 0;
}
.scale-inputs {

7
ruoyi-ui/src/views/login.vue

@ -154,9 +154,9 @@
v-model="form.role"
class="form-select"
>
<option value="user">普通用户</option>
<option value="manager">管理员</option>
<option value="host">主持人</option>
<option value="admin">管理员</option>
<option value="user">普通用户</option>
</select>
</div>
@ -252,7 +252,8 @@ export default {
// 2.
const roleMap = {
'admin': '1',
'manager': '1',
'admin':'1',
'host': '2',
'user': '3'
};

Loading…
Cancel
Save