首页、菜单、登录页、地图初步绘制

master
贾肃 5 months ago
parent 5a33147f56
commit d50b03199d
  1. 2
      package.json
  2. BIN
      src/assets/images/v2_rxo8qp.png
  3. 2
      src/components/Breadcrumb/index.vue
  4. 97
      src/components/Hamburger/index.vue
  5. 55
      src/layout/components/Navbar.vue
  6. 1
      src/layout/index.vue
  7. 6
      src/main.js
  8. 2
      src/router/index.js
  9. 4
      src/settings.js
  10. 1037
      src/views/index.vue
  11. 1062
      src/views/index_old.vue
  12. 82
      src/views/login.vue
  13. 11
      src/views/system/base/list.vue
  14. 58
      src/views/system/base/map.vue
  15. 12
      src/views/system/base/mapMarkers.vue

@ -17,10 +17,12 @@
},
"dependencies": {
"@element-plus/icons-vue": "2.3.1",
"@icon-park/vue-next": "^1.4.2",
"@vuemap/vue-amap": "^2.1.1",
"@vueup/vue-quill": "1.2.0",
"@vueuse/core": "10.6.1",
"axios": "0.27.2",
"babel-plugin-import": "^1.13.8",
"echarts": "5.4.3",
"element-plus": "2.4.3",
"file-saver": "2.0.5",

Binary file not shown.

After

Width:  |  Height:  |  Size: 821 KiB

@ -20,7 +20,7 @@ function getBreadcrumb() {
const first = matched[0]
//
if (!isDashboard(first)) {
matched = [{ path: '/index', meta: { title: '首页' } }].concat(matched)
matched = [{ path: '/index', meta: { title: '概览' } }].concat(matched)
}
levelList.value = matched.filter(item => item.meta && item.meta.title && item.meta.breadcrumb !== false)

@ -1,15 +1,34 @@
<template>
<div style="padding: 0 15px;" @click="toggleClick">
<svg
:class="{'is-active':isActive}"
class="hamburger"
viewBox="0 0 1024 1024"
xmlns="http://www.w3.org/2000/svg"
width="64"
height="64"
>
<path d="M408 442h480c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8H408c-4.4 0-8 3.6-8 8v56c0 4.4 3.6 8 8 8zm-8 204c0 4.4 3.6 8 8 8h480c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8H408c-4.4 0-8 3.6-8 8v56zm504-486H120c-4.4 0-8 3.6-8 8v56c0 4.4 3.6 8 8 8h784c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8zm0 632H120c-4.4 0-8 3.6-8 8v56c0 4.4 3.6 8 8 8h784c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8zM142.4 642.1L298.7 519a8.84 8.84 0 0 0 0-13.9L142.4 381.9c-5.8-4.6-14.4-.5-14.4 6.9v246.3a8.9 8.9 0 0 0 14.4 7z" />
</svg>
<div style="padding: 0 15px;">
<i-menu-unfold-one @contextmenu.prevent.stop="toggleClick" @click="showDrawer = !showDrawer" class="hamburger"
:class="{'is-active':isActive}" theme="outline" size="22" fill="#FFFFFF"/>
<div>
<el-drawer v-model="showDrawer" direction="ltr" append-to-body style="top: 50px" :z-index="165"
:with-header="false">
<div>
<div class="classify" style="margin-top: 0;">
<i-system theme="outline" size="24" fill="#333"/>
<el-link style="color: #000000 !important;font-size: 16px" @click="openRouter('/index')"></el-link>
</div>
<div v-for="item in menuList" :key="item.label">
<div class="classify">
<i-system theme="outline" size="24" fill="#333"/>
{{ item.label }}
</div>
<div class="children">
<el-row v-if="item.children" :gutter="20">
<el-col v-for="child in item.children" :key="child.label" :span="8">
<div class="children-item">
<el-link @click="openRouter(child.href)">{{ child.label }}</el-link>
</div>
</el-col>
</el-row>
</div>
</div>
</div>
</el-drawer>
</div>
</div>
</template>
@ -21,9 +40,49 @@ defineProps({
}
})
const emit = defineEmits()
const emit = defineEmits(['toggleClick'])
const showDrawer = ref(false)
const menuList = ref([
{
label: '基础数据管理', children: [
{label: '育种基地管理'},
{label: '数据采集设备管理'},
{label: '作物品种管理'},
]
},
{
label: '环境数据', children: [
{label: '基地地图',href:'/system/base/map'},
{label: '地块管理'},
{label: '土壤数据'},
{label: '气象数据'},
{label: '监控数据'},
]
},
{
label: '表型数据', children: [
{label: '原始数据管理'},
{label: '表型数据管理'},
{label: '植株表型数据'},
]
},
{
label: '基因型数据', children: [
{label: '基因型数据管理'},
]
},
])
const router = useRouter();
const openRouter = (href) => {
if (href){
router.push(href)
showDrawer.value = false
}
}
const toggleClick = () => {
if (import.meta.env.VITE_APP_ENV === 'development') {
emit('toggleClick');
}
}
</script>
@ -38,4 +97,18 @@ const toggleClick = () => {
.hamburger.is-active {
transform: rotate(180deg);
}
/*菜单样式*/
.classify {
display: flex;
align-items: center;
margin-top: 20px;
.i-icon {
margin-right: 5px;
}
}
.children-item {
margin-top: 10px;
}
</style>

@ -2,13 +2,18 @@
<div class="navbar">
<hamburger id="hamburger-container" :is-active="appStore.sidebar.opened" class="hamburger-container" @toggleClick="toggleSideBar" />
<div style="float: left;line-height: 50px;">{{title}}</div>
<breadcrumb id="breadcrumb-container" class="breadcrumb-container" v-if="!settingsStore.topNav" />
<breadcrumb id="breadcrumb-container" class="breadcrumb-container" v-if="!settingsStore.topNav && false" />
<top-nav id="topmenu-container" class="topmenu-container" v-if="settingsStore.topNav" />
<div class="right-menu">
<template v-if="appStore.device !== 'mobile'">
<header-search id="header-search" class="right-menu-item" />
<el-tooltip content="显示大屏" effect="dark" placement="bottom">
<i-tv class="right-menu-item" theme="outline" size="24" fill="#FFFFFF"/>
</el-tooltip>
<div class="right-menu-item">
<i-remind theme="outline" size="22" fill="#FFFFFF"/>
</div>
<el-tooltip v-if="false" content="源码地址" effect="dark" placement="bottom">
<ruo-yi-git id="ruoyi-git" class="right-menu-item hover-effect" />
</el-tooltip>
@ -19,19 +24,12 @@
<screenfull id="screenfull" class="right-menu-item hover-effect" />
<el-tooltip content="布局大小" effect="dark" placement="bottom">
<el-tooltip v-if="false" content="布局大小" effect="dark" placement="bottom">
<size-select id="size-select" class="right-menu-item hover-effect" />
</el-tooltip>
</template>
<div class="avatar-container">
<div class="user-name">
<el-icon><User /></el-icon>
<div>{{userStore.name}}</div>
<el-button @click="logout" style="margin-left: 10px">
退出
</el-button>
</div>
<el-dropdown v-if="false" @command="handleCommand" class="right-menu-item hover-effect" trigger="click">
<el-dropdown v-if="settingsStore.showSettings" @command="handleCommand" class="right-menu-item hover-effect" trigger="click">
<div class="avatar-wrapper">
<img :src="userStore.avatar" class="user-avatar" />
<el-icon><caret-bottom /></el-icon>
@ -41,7 +39,7 @@
<router-link to="/user/profile">
<el-dropdown-item>个人中心</el-dropdown-item>
</router-link>
<el-dropdown-item command="setLayout" v-if="settingsStore.showSettings">
<el-dropdown-item command="setLayout">
<span>布局设置</span>
</el-dropdown-item>
<el-dropdown-item divided command="logout">
@ -50,6 +48,13 @@
</el-dropdown-menu>
</template>
</el-dropdown>
<div class="right-menu-item" v-else>
<i-me theme="outline" size="24" fill="#FFF"/>
<div style="margin-left: 3px">{{userStore.name}}</div>
<div @click="logout" class="logout-button">
退出
</div>
</div>
</div>
</div>
</div>
@ -111,12 +116,14 @@ function setLayout() {
<style lang='scss' scoped>
.navbar {
z-index: 170;
height: 50px;
overflow: hidden;
position: relative;
background: #fff;
box-shadow: 0 1px 4px rgba(0, 21, 41, 0.08);
background: #567722;
color: #FFF;
.hamburger-container {
line-height: 46px;
height: 100%;
@ -147,19 +154,19 @@ function setLayout() {
.right-menu {
float: right;
height: 100%;
line-height: 50px;
//line-height: 50px;
display: flex;
&:focus {
outline: none;
}
.right-menu-item {
display: inline-block;
padding: 0 8px;
display: flex;
align-items: center;
padding: 0 5px;
height: 100%;
font-size: 18px;
color: #5a5e66;
color: #FFFFFF;
vertical-align: text-bottom;
&.hover-effect {
@ -196,9 +203,15 @@ function setLayout() {
}
}
}
.user-name{
display: flex;
align-items: center;
.logout-button{
margin-left: 10px;
border: 1px solid #FFFFFF;
border-radius: 5px;
font-size: 14px;
line-height: 20px;
padding: 2px 10px;
//
cursor: pointer;
}
}
</style>

@ -34,6 +34,7 @@ const classObj = computed(() => ({
hideSidebar: !sidebar.value.opened,
openSidebar: sidebar.value.opened,
withoutAnimation: sidebar.value.withoutAnimation,
// mobile: device.value === 'mobile'
mobile: true
}))

@ -7,7 +7,9 @@ import 'element-plus/dist/index.css'
import locale from 'element-plus/es/locale/lang/zh-cn'
import '@/assets/styles/index.scss' // global css
// iconpark样式
import {install} from '@icon-park/vue-next/es/all';
import '@icon-park/vue-next/styles/index.css';
import App from './App'
import store from './store'
import router from './router'
@ -56,6 +58,8 @@ initAMapApiLoader({
// version: '2.0.0'
//} // 如果需要使用loca组件库需要加载Loca
})
install(app, 'i'); // use custom prefix 'i', eg: icon is People, name is i-people.
// 全局方法挂载
app.config.globalProperties.useDict = useDict
app.config.globalProperties.download = download

@ -66,7 +66,7 @@ export const constantRoutes = [
path: '/index',
component: () => import('@/views/index'),
name: 'Index',
meta: { title: '首页', icon: 'dashboard', affix: true }
meta: { title: '概览', icon: 'dashboard', affix: true }
}
]
},

@ -10,7 +10,7 @@ export default {
/**
* 是否系统布局配置
*/
showSettings: true,
showSettings: false,
/**
* 是否显示顶部导航
@ -35,7 +35,7 @@ export default {
/**
* 是否显示动态标题
*/
dynamicTitle: false,
dynamicTitle: true,
/**
* @type {string | array} 'production' | ['production', 'development']

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

@ -1,7 +1,8 @@
<template>
<div class="login">
<div class="login" :class="loginClass">
<el-form ref="loginRef" :model="loginForm" :rules="loginRules" class="login-form">
<h3 class="title">甘蔗育种大数据平台</h3>
<el-divider content-position="center">欢迎登录</el-divider>
<el-form-item prop="username">
<el-input
v-model="loginForm.username"
@ -10,7 +11,9 @@
auto-complete="off"
placeholder="账号"
>
<template #prefix><svg-icon icon-class="user" class="el-input__icon input-icon" /></template>
<template #prefix>
<svg-icon icon-class="user" class="el-input__icon input-icon"/>
</template>
</el-input>
</el-form-item>
<el-form-item prop="password">
@ -19,10 +22,13 @@
type="password"
size="large"
auto-complete="off"
show-password
placeholder="密码"
@keyup.enter="handleLogin"
>
<template #prefix><svg-icon icon-class="password" class="el-input__icon input-icon" /></template>
<template #prefix>
<svg-icon icon-class="password" class="el-input__icon input-icon"/>
</template>
</el-input>
</el-form-item>
<el-form-item prop="code" v-if="captchaEnabled">
@ -34,15 +40,18 @@
style="width: 63%"
@keyup.enter="handleLogin"
>
<template #prefix><svg-icon icon-class="validCode" class="el-input__icon input-icon" /></template>
<template #prefix>
<svg-icon icon-class="validCode" class="el-input__icon input-icon"/>
</template>
</el-input>
<div class="login-code">
<img :src="codeUrl" @click="getCode" class="login-code-img"/>
</div>
</el-form-item>
<el-checkbox v-model="loginForm.rememberMe" style="margin:0px 0px 25px 0px;"></el-checkbox>
<el-form-item style="width:100%;">
<el-form-item style="width:60%;margin: 20px auto">
<el-button
round
:loading="loading"
size="large"
type="primary"
@ -59,22 +68,28 @@
</el-form>
<!-- 底部 -->
<div class="el-login-footer">
<span>Copyright © 2018-2024 ruoyi.vip All Rights Reserved.</span>
<span>中国科学院计算技术研究所 研制</span>
</div>
</div>
</template>
<script setup>
import { getCodeImg } from "@/api/login";
import {getCodeImg} from "@/api/login";
import Cookies from "js-cookie";
import { encrypt, decrypt } from "@/utils/jsencrypt";
import {encrypt, decrypt} from "@/utils/jsencrypt";
import useUserStore from '@/store/modules/user'
import useAppStore from "@/store/modules/app.js";
import {useWindowSize} from "@vueuse/core";
const userStore = useUserStore()
const route = useRoute();
const router = useRouter();
const { proxy } = getCurrentInstance();
const {proxy} = getCurrentInstance();
const {width, height} = useWindowSize();
const WIDTH = 992; // refer to Bootstrap's responsive design
const loginClass = computed(() => ({
desktop: width.value - 1 > WIDTH
}))
const loginForm = ref({
username: "admin",
password: "admin123",
@ -84,9 +99,9 @@ const loginForm = ref({
});
const loginRules = {
username: [{ required: true, trigger: "blur", message: "请输入您的账号" }],
password: [{ required: true, trigger: "blur", message: "请输入您的密码" }],
code: [{ required: true, trigger: "change", message: "请输入验证码" }]
username: [{required: true, trigger: "blur", message: "请输入您的账号"}],
password: [{required: true, trigger: "blur", message: "请输入您的密码"}],
code: [{required: true, trigger: "change", message: "请输入验证码"}]
};
const codeUrl = ref("");
@ -99,7 +114,7 @@ const redirect = ref(undefined);
watch(route, (newRoute) => {
redirect.value = newRoute.query && newRoute.query.redirect;
}, { immediate: true });
}, {immediate: true});
function handleLogin() {
proxy.$refs.loginRef.validate(valid => {
@ -107,9 +122,9 @@ function handleLogin() {
loading.value = true;
// cookie
if (loginForm.value.rememberMe) {
Cookies.set("username", loginForm.value.username, { expires: 30 });
Cookies.set("password", encrypt(loginForm.value.password), { expires: 30 });
Cookies.set("rememberMe", loginForm.value.rememberMe, { expires: 30 });
Cookies.set("username", loginForm.value.username, {expires: 30});
Cookies.set("password", encrypt(loginForm.value.password), {expires: 30});
Cookies.set("rememberMe", loginForm.value.rememberMe, {expires: 30});
} else {
//
Cookies.remove("username");
@ -125,7 +140,7 @@ function handleLogin() {
}
return acc;
}, {});
router.push({ path: redirect.value || "/", query: otherQueryParams });
router.push({path: redirect.value || "/", query: otherQueryParams});
}).catch(() => {
loading.value = false;
//
@ -168,11 +183,24 @@ getCookie();
justify-content: center;
align-items: center;
height: 100%;
background-image: url("../assets/images/login-background.jpg");
//
background-position: center;
//
background-image: url("../assets/images/v2_rxo8qp.png") ;
background-size: cover;
}
//pc
.desktop {
justify-content: flex-end;
.el-form {
position: absolute;
right: 10%;
}
}
.title {
margin: 0px auto 30px auto;
font-weight: 700;
margin: 20px auto 50px auto;
text-align: center;
color: #707070;
}
@ -182,46 +210,56 @@ getCookie();
background: #ffffff;
width: 400px;
padding: 25px 25px 5px 25px;
.el-input {
height: 40px;
input {
height: 40px;
}
}
.input-icon {
height: 39px;
width: 14px;
margin-left: 0px;
}
}
.login-tip {
font-size: 13px;
text-align: center;
color: #bfbfbf;
}
.login-code {
width: 33%;
height: 40px;
float: right;
img {
cursor: pointer;
vertical-align: middle;
}
}
.el-login-footer {
height: 40px;
line-height: 40px;
position: fixed;
bottom: 0;
bottom: 10px;
font-weight: 600;
width: 100%;
text-align: center;
color: #fff;
font-family: Arial;
font-size: 12px;
font-size: 18px;
letter-spacing: 1px;
}
.login-code-img {
height: 40px;
padding-left: 12px;
}
</style>

@ -0,0 +1,11 @@
<script setup>
</script>
<template>
</template>
<style scoped lang="scss">
</style>

@ -1,13 +1,45 @@
<script setup>
import {ElAmap, useGeolocation ,lazyAMapApiLoaderInstance} from "@vuemap/vue-amap";
const maxHeight = ref(window.innerHeight - 100);
const zoom = ref(12);
const zoom = ref(13);
const center = ref(null);
const created = ref(false)
const amapMouseType = ref('polyline')
const polygonList = ref([])
const markerPosition = ref(null)
// 1 2
const showType = ref(1)
//
const clickBase = ref(null)
const draw = (value) => {
polygonList.value.push(value)
polygonList.value.push({
edit:false,
path:value
})
console.log(value);
created.value = false
}
onBeforeMount(() => {
lazyAMapApiLoaderInstance.then(() => {
useGeolocation({
enableHighAccuracy: true,
needAddress: true
}).then(res => {
const {getCurrentPosition, getCityInfo} = res;
getCurrentPosition().then(currentPosition => {
center.value = currentPosition.position.toArray();
markerPosition.value = currentPosition.position.toArray();
console.log('currentPosition: ', currentPosition)
});
// getCityInfo().then(cityResult => {
// console.log('cityResult: ', cityResult)
// })
})
})
})
//
const selectPoi = ({poi}) => {
center.value = poi.location.toArray()
}
</script>
@ -23,7 +55,7 @@ const draw = (value) => {
<!--卫星云图-->
<el-amap-layer-satellite :visible="true" />
<!--定位控件-->
<el-amap-control-geolocation :visible="true"/>
<el-amap-control-geolocation :visible="false"/>
<!--鼠标工具-->
<el-amap-mouse-tool
v-if="created"
@ -31,12 +63,28 @@ const draw = (value) => {
:auto-clear="true"
@draw="draw"
/>
<!--地图缩放控件-->
<el-amap-control-tool-bar :visible="true" />
<!--比例尺-->
<el-amap-control-scale :visible="true" />
<!--多边形-->
<el-amap-polygon
v-for="(polygon, index) in polygonList"
:path="polygon"
:path="polygon.path"
:visible="true"
:editable="true"
:editable="polygon.edit"
/>
<!-- 点标记-->
<el-amap-marker
:position="markerPosition"
title="当前位置"
label="当前位置"
/>
<!--搜索控件-->
<el-amap-search-box
:visible="showType===1"
:debounce="1000"
@select="selectPoi"
/>
</el-amap>
</div>

@ -0,0 +1,12 @@
<!--基地点坐标-->
<script setup>
</script>
<template>
</template>
<style scoped lang="scss">
</style>
Loading…
Cancel
Save