This commit is contained in:
13713575202 2025-04-16 17:12:20 +08:00
commit 2d5b692ad5
13 changed files with 334 additions and 346 deletions

View File

@ -23,12 +23,11 @@ if (process.env.npm_config_preview || rawArgv.includes('--preview')) {
}) })
) )
app.listen(port, function () { app.listen(port, function() {
console.log(chalk.green(`> Preview at http://localhost:${port}${publicPath}`)) console.log(chalk.green(`> Preview at http://localhost:${port}${publicPath}`))
if (report) { if (report) {
console.log(chalk.green(`> Report at http://localhost:${port}${publicPath}report.html`)) console.log(chalk.green(`> Report at http://localhost:${port}${publicPath}report.html`))
} }
}) })
} else { } else {
run(`vue-cli-service build ${args}`) run(`vue-cli-service build ${args}`)

View File

@ -20,3 +20,6 @@ export default {
}, },
}; };
</script> </script>
<style>
@import url('./fonts/font.css');
</style>

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.0 MiB

Binary file not shown.

BIN
src/fonts/DingTalk Sans.ttf Normal file

Binary file not shown.

15
src/fonts/font.css Normal file
View File

@ -0,0 +1,15 @@
@font-face {
font-family: 'JinBuTi';
/* 自定义字体名称 */
src: url('./DingTalk JinBuTi.ttf') format('truetype');
font-weight: normal;
font-style: normal;
}
@font-face {
font-family: 'Sans';
/* 自定义字体名称 */
src: url('./DingTalk Sans.ttf') format('truetype');
font-weight: normal;
font-style: normal;
}

View File

@ -15,6 +15,6 @@ const getters = {
topbarRouters: (state) => state.permission.topbarRouters, topbarRouters: (state) => state.permission.topbarRouters,
defaultRoutes: (state) => state.permission.defaultRoutes, defaultRoutes: (state) => state.permission.defaultRoutes,
sidebarRouters: (state) => state.permission.sidebarRouters, sidebarRouters: (state) => state.permission.sidebarRouters,
isAdmin: (state) => (state.user.roles.includes('admin') || state.user.roles.includes('tenantadmin') ? true : false), // isAdmin: (state) => (state.user.roles.includes('admin') || state.user.roles.includes('tenantadmin') ? true : false),
}; };
export default getters; export default getters;

View File

@ -1,5 +1,5 @@
import Vue from 'vue'; import Vue from 'vue';
let color = Vue.prototype.$colorList; const color = Vue.prototype.$colorList;
export function pie(option, unit = '%') { export function pie(option, unit = '%') {
return { return {
color: color, color: color,
@ -146,19 +146,19 @@ export function barColumn(option, unit = '个') {
} }
export function autoHover(myChart, option, time) { export function autoHover(myChart, option, time) {
let app = { const app = {
currentIndex: -1, currentIndex: -1,
}; };
var timeTicket = setInterval(function () { var timeTicket = setInterval(function () {
let dataLen = option.series[0].data.length; const dataLen = option.series[0].data.length;
// 取消之前高亮的图形 // 取消之前高亮的图形
myChart.dispatchAction({ myChart.dispatchAction({
type: 'downplay', type: 'downplay',
seriesIndex: 0, //要展示的series数据索引 seriesIndex: 0, // 要展示的series数据索引
dataIndex: app.currentIndex, dataIndex: app.currentIndex,
}); });
app.currentIndex = (app.currentIndex + 1) % dataLen; app.currentIndex = (app.currentIndex + 1) % dataLen;
//console.log(app.currentIndex); // console.log(app.currentIndex);
// 高亮当前图形 // 高亮当前图形
myChart.dispatchAction({ myChart.dispatchAction({
type: 'highlight', type: 'highlight',
@ -174,7 +174,7 @@ export function autoHover(myChart, option, time) {
}, time); }, time);
myChart.on('mouseover', function (params) { myChart.on('mouseover', function (params) {
//停止并显示当前的高亮和tooltip // 停止并显示当前的高亮和tooltip
clearInterval(timeTicket); clearInterval(timeTicket);
myChart.dispatchAction({ myChart.dispatchAction({
type: 'downplay', type: 'downplay',
@ -195,7 +195,7 @@ export function autoHover(myChart, option, time) {
myChart.on('mouseout', function () { myChart.on('mouseout', function () {
timeTicket && clearInterval(timeTicket); timeTicket && clearInterval(timeTicket);
timeTicket = setInterval(function () { timeTicket = setInterval(function () {
let dataLen = option.series[0].data.length; const dataLen = option.series[0].data.length;
// 取消之前高亮的图形 // 取消之前高亮的图形
myChart.dispatchAction({ myChart.dispatchAction({
type: 'downplay', type: 'downplay',
@ -203,7 +203,7 @@ export function autoHover(myChart, option, time) {
dataIndex: app.currentIndex, dataIndex: app.currentIndex,
}); });
app.currentIndex = (app.currentIndex + 1) % dataLen; app.currentIndex = (app.currentIndex + 1) % dataLen;
//console.log(app.currentIndex); // console.log(app.currentIndex);
// 高亮当前图形 // 高亮当前图形
myChart.dispatchAction({ myChart.dispatchAction({
type: 'highlight', type: 'highlight',

View File

@ -1,9 +1,9 @@
<template> <template>
<div class="dataScreen-container" :style="{ width: `${style.width}px`, height: `${style.height}px`, transform: `${style.transform}` }"> <div class="dataScreen-container" :style="{ width: `${style.width}px`, height: `${style.height}px`, transform: `${style.transform}` }">
<div class="boxTop"> <div class="boxTop">
<img src="./img/leftTitle.png" alt="" class="img1" /> <img src="./img/leftTitle.png" alt="" class="img1">
<div class="boxTopRight"> <div class="boxTopRight">
<div class="index_animation__s5UDk"></div> <div class="index_animation__s5UDk" />
<ul v-for="(item, index) in titleList" :key="index"> <ul v-for="(item, index) in titleList" :key="index">
<li <li
:style="{ :style="{
@ -17,18 +17,18 @@
</ul> </ul>
</div> </div>
</div> </div>
<component :baseId="baseId" :is="key"></component> <component :is="key" :base-id="baseId" />
<base-select v-model="baseId" :type="2"></base-select> <base-select v-model="baseId" :type="2" />
</div> </div>
</template> </template>
<script> <script>
// import './flexible' // import './flexible'
import pageOne from './pageOne'; import pageOne from './pageOne'
import pageTwo from './pageTwo'; import pageTwo from './pageTwo'
import pageThree from './pageThree'; import pageThree from './pageThree'
import pageFour from './pageFour'; import pageFour from './pageFour'
import pageFive from './pageFive'; import pageFive from './pageFive'
export default { export default {
name: '', name: '',
components: { components: {
@ -36,14 +36,14 @@ export default {
pageTwo, pageTwo,
pageThree, pageThree,
pageFour, pageFour,
pageFive, pageFive
}, },
provide() { provide() {
return { return {
getType: () => this.key, getType: () => this.key,
getX: () => this.scale.x, getX: () => this.scale.x,
getY: () => this.scale.y, getY: () => this.scale.y
}; }
}, },
data() { data() {
return { return {
@ -53,48 +53,48 @@ export default {
{ name: '科技支撑', type: 'pageTwo' }, { name: '科技支撑', type: 'pageTwo' },
{ name: '产业基地', type: 'pageThree' }, { name: '产业基地', type: 'pageThree' },
{ name: '全维监测', type: 'pageFour' }, { name: '全维监测', type: 'pageFour' },
{ name: '朔源追朔', type: 'pageFive' }, { name: '朔源追朔', type: 'pageFive' }
], ],
titleImg1: require('./img/1.png'), titleImg1: require('./img/1.png'),
titleImg2: require('./img/2.png'), titleImg2: require('./img/2.png'),
style: { style: {
width: '1920', width: '1920',
height: '1080', height: '1080',
transform: 'scaleY(1) scaleX(1) translate(-50%, -50%)', transform: 'scaleY(1) scaleX(1) translate(-50%, -50%)'
}, },
current: 0, current: 0,
key: 'pageOne', key: 'pageOne',
scale: {}, scale: {}
}; }
}, },
mounted() { mounted() {
this.setScale(); this.setScale()
/*窗口改变事件*/ /* 窗口改变事件*/
window.onresize = () => { window.onresize = () => {
this.setScale(); this.setScale()
}; }
}, },
methods: { methods: {
handleTabs(item, index) { handleTabs(item, index) {
window.addEventListener('resize', () => { window.addEventListener('resize', () => {
this.setScale(); this.setScale()
}); })
if (index != this.current) { if (index != this.current) {
this.current = index; this.current = index
this.key = item.type; this.key = item.type
} }
}, },
getScale() { getScale() {
const w = window.innerWidth / this.style.width; const w = window.innerWidth / this.style.width
const h = window.innerHeight / this.style.height; const h = window.innerHeight / this.style.height
return { x: w, y: h }; return { x: w, y: h }
}, },
setScale() { setScale() {
this.scale = this.getScale(); this.scale = this.getScale()
this.style.transform = 'scaleY(' + this.scale.y + ') scaleX(' + this.scale.x + ') translate(-50%, -50%)'; this.style.transform = 'scaleY(' + this.scale.y + ') scaleX(' + this.scale.x + ') translate(-50%, -50%)'
}, }
}, }
}; }
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
.dataScreen-container { .dataScreen-container {

View File

@ -1,51 +1,51 @@
<template> <template>
<div id="screen" :style="{ 'background-image': `url(${bg})`, 'background-size': '100% 100%' }"> <div id="screen" :style="{ 'background-image': `url(${bg})`, 'background-size': '100% 100%' }">
<div <div
id="indexMap"
v-if="type == 'pageThree'" v-if="type == 'pageThree'"
id="indexMap"
v-loading="loading" v-loading="loading"
element-loading-background="#263840" element-loading-background="#263840"
element-loading-text="地图加载中" element-loading-text="地图加载中"
element-loading-spinner="el-icon-loading" element-loading-spinner="el-icon-loading"
:style="{ height: '100vh', width: '100vw', transform: `${scale}` }" :style="{ height: '100vh', width: '100vw', transform: `${scale}` }"
></div> />
<div class="boxTop"></div> <div class="boxTop" />
<div class="boxCentLeft" v-if="type != 'pageThree' && type != 'pageFive'"> <div v-if="type != 'pageThree' && type != 'pageFive'" class="boxCentLeft">
<slot name="one"></slot> <slot name="one" />
</div> </div>
<div class="boxRightTop"> <div class="boxRightTop">
<div class="title">{{ title[0] }}</div> <div class="title">{{ title[0] }}</div>
<div class="content"> <div class="content">
<slot name="two"></slot> <slot name="two" />
</div> </div>
</div> </div>
<div class="boxRightBom"> <div class="boxRightBom">
<div class="title">{{ title[1] }}</div> <div class="title">{{ title[1] }}</div>
<div class="content"> <div class="content">
<slot name="three"></slot> <slot name="three" />
</div> </div>
</div> </div>
<div class="boxBomLeft" v-if="type != 'pageFive' && type != 'pageFour'"> <div v-if="type != 'pageFive' && type != 'pageFour'" class="boxBomLeft">
<div class="title">{{ title[2] }}</div> <div class="title">{{ title[2] }}</div>
<div class="content"> <div class="content">
<slot name="four"></slot> <slot name="four" />
</div> </div>
</div> </div>
<div class="boxBomCent" v-if="type != 'pageFive' && type != 'pageFour'"> <div v-if="type != 'pageFive' && type != 'pageFour'" class="boxBomCent">
<div class="title">{{ title[3] }}</div> <div class="title">{{ title[3] }}</div>
<div class="content"> <div class="content">
<slot name="five"></slot> <slot name="five" />
</div> </div>
</div> </div>
<div class="boxBomRight"> <div class="boxBomRight">
<div class="title">{{ title[4] }}</div> <div class="title">{{ title[4] }}</div>
<div class="content"> <div class="content">
<slot name="six"></slot> <slot name="six" />
</div> </div>
</div> </div>
<div class="left" v-if="type == 'pageFive' || type == 'pageFour'"> <div v-if="type == 'pageFive' || type == 'pageFour'" class="left">
<div class="content"> <div class="content">
<slot name="seven"></slot> <slot name="seven" />
</div> </div>
</div> </div>
</div> </div>
@ -56,13 +56,13 @@ import mapMixin from './map';
export default { export default {
name: '', name: '',
mixins: [mapMixin], mixins: [mapMixin],
inject: ['getType', 'getX', 'getY'],
props: { props: {
bg: String, bg: String,
title: Array, title: Array,
baseId: Number, baseId: Number,
}, },
inject: ['getType', 'getX', 'getY'], // TODO:使eventBus
//TODO:使eventBus
computed: { computed: {
type() { type() {
return this.getType(); return this.getType();

View File

@ -1,6 +1,6 @@
import { listDevice } from '@/api/iot/device'; import { listDevice } from '@/api/iot/device'
import { listLand } from '@/api/agriculture/land'; import { listLand } from '@/api/agriculture/land'
import { getDicts } from '@/api/system/dict/data'; import { getDicts } from '@/api/system/dict/data'
const mapMixin = { const mapMixin = {
data() { data() {
return { return {
@ -9,66 +9,66 @@ const mapMixin = {
baseUrl: process.env.VUE_APP_BASE_API, baseUrl: process.env.VUE_APP_BASE_API,
loading: false, loading: false,
landType: [], landType: [],
deviceType: [], deviceType: []
}; }
}, },
watch: { watch: {
baseId: { baseId: {
handler: async function (n) { handler: async function(n) {
if (n) { if (n) {
await this.$nextTick(); await this.$nextTick()
if (this.type == 'pageThree') { if (this.type == 'pageThree') {
this.loading = true; this.loading = true
//获去地块数据 // 获去地块数据
let res = await listLand({ baseId: this.baseId }); const res = await listLand({ baseId: this.baseId })
this.area = res.rows; this.area = res.rows
//获取设备数据 // 获取设备数据
let res1 = await listDevice({ baseId: this.baseId }); const res1 = await listDevice({ baseId: this.baseId })
this.device = res1.rows.map((item) => ({ this.device = res1.rows.map((item) => ({
...item, ...item,
imgUrl: item.imgUrl.split(',').length > 1 ? item.imgUrl.split(',')[1] : item.imgUrl, imgUrl: item.imgUrl.split(',').length > 1 ? item.imgUrl.split(',')[1] : item.imgUrl
})); }))
this.initMap(); this.initMap()
getDicts('agriculture_land_type').then((response) => { getDicts('agriculture_land_type').then((response) => {
this.landType = response.data; this.landType = response.data
}); })
getDicts('iot_device_status').then((response) => { getDicts('iot_device_status').then((response) => {
this.deviceType = response.data; this.deviceType = response.data
}); })
} }
} }
}, },
immediate: true, immediate: true
}, }
}, },
async mounted() {}, async mounted() {},
methods: { methods: {
/** 初始化map */ /** 初始化map */
async initMap() { async initMap() {
this.map = new this.AMap.Map('indexMap', { this.map = new this.AMap.Map('indexMap', {
//设置地图容器id // 设置地图容器id
mapStyle: 'amap://styles/grey', mapStyle: 'amap://styles/grey',
zoom: 16, //初始化地图级别 zoom: 16, // 初始化地图级别
// center: baseCoordinate, //初始化地图中心点位置 // center: baseCoordinate, //初始化地图中心点位置
doubleClickZoom: false, doubleClickZoom: false
}); })
await this.createAreaPolygon(); await this.createAreaPolygon()
await this.createDevicePoint(); await this.createDevicePoint()
this.map.setFitView(); this.map.setFitView()
}, },
/** 绘制地块 */ /** 绘制地块 */
createAreaPolygon() { createAreaPolygon() {
let label = [], const label = []
overlayGroup = []; const overlayGroup = []
this.area.forEach((item) => { this.area.forEach((item) => {
if (item.landPath) { if (item.landPath) {
let path = [], const path = []
pointList = []; const pointList = []
item.landPath.split('|').forEach((point) => { item.landPath.split('|').forEach((point) => {
path.push(new this.AMap.LngLat(point.split(',')[0], point.split(',')[1])); path.push(new this.AMap.LngLat(point.split(',')[0], point.split(',')[1]))
pointList.push([Number(point.split(',')[0]), Number(point.split(',')[1])]); pointList.push([Number(point.split(',')[0]), Number(point.split(',')[1])])
}); })
let polygon = new this.AMap.Polygon({ const polygon = new this.AMap.Polygon({
path: path, path: path,
fillColor: item.fillColor, fillColor: item.fillColor,
fillOpacity: item.fillOpacity, fillOpacity: item.fillOpacity,
@ -76,14 +76,14 @@ const mapMixin = {
strokeWeight: item.strokeWeight, strokeWeight: item.strokeWeight,
strokeOpacity: item.strokeOpacity, strokeOpacity: item.strokeOpacity,
extData: { extData: {
...item, ...item
}, }
}); })
polygon.on('click', (e) => { polygon.on('click', (e) => {
this.createInfoWindow(e); this.createInfoWindow(e)
}); })
overlayGroup.push(polygon); overlayGroup.push(polygon)
//添加地块名称 // 添加地块名称
label.push( label.push(
new this.AMap.Text({ new this.AMap.Text({
text: item.landName, text: item.landName,
@ -93,119 +93,119 @@ const mapMixin = {
background: 'transparent', background: 'transparent',
color: '#fff', color: '#fff',
border: 'none', border: 'none',
fontSize: '16px', fontSize: '16px'
}, }
}) })
); )
} }
}); })
this.map.add(new this.AMap.OverlayGroup(label)); this.map.add(new this.AMap.OverlayGroup(label))
this.map.add(new this.AMap.OverlayGroup(overlayGroup)); this.map.add(new this.AMap.OverlayGroup(overlayGroup))
}, },
/** 创建设备marker点 */ /** 创建设备marker点 */
createDevicePoint() { createDevicePoint() {
let devicePointList = []; const devicePointList = []
this.device.forEach((device) => { this.device.forEach((device) => {
if ((device.longitude, device.latitude)) { if ((device.longitude, device.latitude)) {
let marker = new this.AMap.Marker({ const marker = new this.AMap.Marker({
icon: new this.AMap.Icon({ icon: new this.AMap.Icon({
image: this.baseUrl + device.imgUrl, image: this.baseUrl + device.imgUrl,
imageSize: new this.AMap.Size(32, 32), imageSize: new this.AMap.Size(32, 32)
}), }),
position: [device.longitude, device.latitude], position: [device.longitude, device.latitude],
title: device.deviceName, title: device.deviceName,
anchor: 'bottom-center', anchor: 'bottom-center',
extData: { extData: {
...device, ...device
}, }
}); })
marker.on('click', (e) => { marker.on('click', (e) => {
this.createInfoWindow2(e); this.createInfoWindow2(e)
}); })
devicePointList.push(marker); devicePointList.push(marker)
} }
}); })
this.map.add(new this.AMap.OverlayGroup(devicePointList)); this.map.add(new this.AMap.OverlayGroup(devicePointList))
this.loading = false; this.loading = false
}, },
/** 获取地块中心点 */ /** 获取地块中心点 */
getAreaCenter(location) { getAreaCenter(location) {
var total = location.length; var total = location.length
var X = 0, var X = 0
Y = 0, var Y = 0
Z = 0; var Z = 0
location.forEach((lnglat) => { location.forEach((lnglat) => {
var lng = (lnglat[0] * Math.PI) / 180; var lng = (lnglat[0] * Math.PI) / 180
var lat = (lnglat[1] * Math.PI) / 180; var lat = (lnglat[1] * Math.PI) / 180
var x, y, z; var x, y, z
x = Math.cos(lat) * Math.cos(lng); x = Math.cos(lat) * Math.cos(lng)
y = Math.cos(lat) * Math.sin(lng); y = Math.cos(lat) * Math.sin(lng)
z = Math.sin(lat); z = Math.sin(lat)
X += x; X += x
Y += y; Y += y
Z += z; Z += z
}); })
X = X / total; X = X / total
Y = Y / total; Y = Y / total
Z = Z / total; Z = Z / total
var Lng = Math.atan2(Y, X); var Lng = Math.atan2(Y, X)
var Hyp = Math.sqrt(X * X + Y * Y); var Hyp = Math.sqrt(X * X + Y * Y)
var Lat = Math.atan2(Z, Hyp); var Lat = Math.atan2(Z, Hyp)
return [parseFloat((Lng * 180) / Math.PI), parseFloat((Lat * 180) / Math.PI)]; return [parseFloat((Lng * 180) / Math.PI), parseFloat((Lat * 180) / Math.PI)]
}, },
/** 信息窗体 */ /** 信息窗体 */
createInfoWindow(e) { createInfoWindow(e) {
var info = document.createElement('div'); var info = document.createElement('div')
info.className = 'InfoBox'; info.className = 'InfoBox'
var title = document.createElement('div'); var title = document.createElement('div')
title.className = 'title'; title.className = 'title'
title.innerHTML = `${e.target._opts.extData.landName}`; title.innerHTML = `${e.target._opts.extData.landName}`
var type = document.createElement('div'); var type = document.createElement('div')
var typeName = ''; var typeName = ''
this.landType.forEach((item) => { this.landType.forEach((item) => {
if (item.dictValue == e.target._opts.extData.landType) { if (item.dictValue == e.target._opts.extData.landType) {
typeName = item.dictLabel; typeName = item.dictLabel
} }
}); })
type.className = 'type'; type.className = 'type'
type.innerHTML = `<div class="item">类型:<div class="tag">${typeName}</div></div> type.innerHTML = `<div class="item">类型:<div class="tag">${typeName}</div></div>
<div class="item">面积${e.target._opts.extData.landArea}</div>`; <div class="item">面积${e.target._opts.extData.landArea}</div>`
info.appendChild(title); info.appendChild(title)
info.appendChild(type); info.appendChild(type)
let infoWindow = new this.AMap.InfoWindow({ const infoWindow = new this.AMap.InfoWindow({
anchor: 'bottom-center', anchor: 'bottom-center',
content: info, //使用默认信息窗体框样式,显示信息内容 content: info // 使用默认信息窗体框样式,显示信息内容
}); })
infoWindow.open(this.map, new this.AMap.LngLat(e.lnglat.getLng(), e.lnglat.getLat())); infoWindow.open(this.map, new this.AMap.LngLat(e.lnglat.getLng(), e.lnglat.getLat()))
}, },
createInfoWindow2(e) { createInfoWindow2(e) {
var info = document.createElement('div'); var info = document.createElement('div')
info.className = 'InfoBox'; info.className = 'InfoBox'
var title = document.createElement('div'); var title = document.createElement('div')
title.className = 'title'; title.className = 'title'
title.innerHTML = `${e.target._opts.extData.deviceName}`; title.innerHTML = `${e.target._opts.extData.deviceName}`
var num = document.createElement('div'); var num = document.createElement('div')
num.className = 'num'; num.className = 'num'
num.innerHTML = `<div>编号:${e.target._opts.extData.serialNumber}</div>`; num.innerHTML = `<div>编号:${e.target._opts.extData.serialNumber}</div>`
var tips = document.createElement('div'); var tips = document.createElement('div')
tips.className = 'tips'; tips.className = 'tips'
var statusName = ''; var statusName = ''
this.deviceType.forEach((item) => { this.deviceType.forEach((item) => {
if (item.dictValue == e.target._opts.extData.status) { if (item.dictValue == e.target._opts.extData.status) {
statusName = item.dictLabel; statusName = item.dictLabel
} }
}); })
tips.innerHTML = `${statusName}`; tips.innerHTML = `${statusName}`
info.appendChild(title); info.appendChild(title)
info.appendChild(num); info.appendChild(num)
info.appendChild(tips); info.appendChild(tips)
let infoWindow = new this.AMap.InfoWindow({ const infoWindow = new this.AMap.InfoWindow({
anchor: 'bottom-center', anchor: 'bottom-center',
content: info, //使用默认信息窗体框样式,显示信息内容 content: info // 使用默认信息窗体框样式,显示信息内容
}); })
infoWindow.open(this.map, new this.AMap.LngLat(e.lnglat.getLng(), e.lnglat.getLat())); infoWindow.open(this.map, new this.AMap.LngLat(e.lnglat.getLng(), e.lnglat.getLat()))
}, }
}, }
}; }
export default mapMixin; export default mapMixin

View File

@ -1,65 +1,52 @@
<template> <template>
<div class="login"> <div class="login">
<el-row> <section class="system_name">数字农业平台</section>
<el-col :span="14"> <div class="login_content">
<div class="left"> <section class="login_text">登录</section>
<div class="login-title">{{ loginTitle }}</div> <div>
<div class="login-subTitle">专注于农业面向未来自主创新</div> <el-form label-position="top">
<div class="login-bgImage"> <el-form ref="loginForm" :model="loginForm" :rules="loginRules">
<img src="@/assets/images/loginBg.svg" alt="" /> <el-form-item label="账号" prop="username">
</div> <el-input v-model="loginForm.username" prefix-icon="el-icon-user" placeholder="请输入用户名"></el-input>
</div> </el-form-item>
</el-col> <el-form-item label="密码" prop="password">
<el-col :span="10"> <el-input v-model="loginForm.password" prefix-icon="el-icon-lock" type="password" placeholder="请输入密码" show-password></el-input>
<div class="right"> </el-form-item>
<div class="loginForm-title">系统登录</div> <el-form-item label="验证码" prop="code" v-if="captchaOnOff">
<div class="loginForm-subTitle">SYSTEM LOGIN</div> <el-row class="login-captchaBox">
<div class="loginForm-form"> <el-col :span="15">
<el-form label-position="top"> <el-input
<el-form ref="loginForm" :model="loginForm" :rules="loginRules"> v-model="loginForm.code"
<el-form-item label="账号" prop="username"> auto-complete="off"
<el-input v-model="loginForm.username" prefix-icon="el-icon-user" placeholder="请输入用户名"></el-input> placeholder="验证码"
</el-form-item> prefix-icon="el-icon-circle-check"
<el-form-item label="密码" prop="password"> @keyup.enter.native="handleLogin"
<el-input v-model="loginForm.password" prefix-icon="el-icon-lock" type="password" placeholder="请输入密码" show-password></el-input> />
</el-form-item> </el-col>
<el-form-item label="验证码" prop="code" v-if="captchaOnOff"> <el-col :span="8" :offset="1" style="display: flex">
<el-row class="login-captchaBox"> <div class="login-code">
<el-col :span="15"> <img :src="codeUrl" @click="getCode" />
<el-input </div>
v-model="loginForm.code" </el-col>
auto-complete="off" </el-row>
placeholder="验证码" </el-form-item>
prefix-icon="el-icon-circle-check"
@keyup.enter.native="handleLogin"
/>
</el-col>
<el-col :span="8" :offset="1" style="display: flex">
<div class="login-code">
<img :src="codeUrl" @click="getCode" />
</div>
</el-col>
</el-row>
</el-form-item>
<el-checkbox v-model="loginForm.rememberMe" style="margin: 0px 0px 25px 0px; color: #000">记住密码</el-checkbox> <el-checkbox v-model="loginForm.rememberMe" style="margin: 0px 0px 25px 25px; color: #000; transform: scale(1.6)">记住密码</el-checkbox>
<el-form-item style="width: 100%"> <el-form-item class="login_btn" style="width: 100%">
<el-button v-if="!bindAccount" :loading="loading" type="primary" style="width: 100%" @click.native.prevent="handleLogin"> <el-button v-if="!bindAccount" :loading="loading" type="primary" style="width: 100%" @click.native.prevent="handleLogin">
<span v-if="!loading"> </span> <span v-if="!loading"> </span>
<span v-else> 中...</span> <span v-else> 中...</span>
</el-button> </el-button>
<el-button v-else :loading="loading" type="primary" style="width: 100%" @click.native.prevent="handleLogin"> <el-button v-else :loading="loading" type="primary" style="width: 100%" @click.native.prevent="handleLogin">
<span v-if="!loading">绑定</span> <span v-if="!loading">绑定</span>
<span v-else> 中...</span> <span v-else> 中...</span>
</el-button> </el-button>
</el-form-item> </el-form-item>
</el-form> </el-form>
</el-form> </el-form>
</div> </div>
</div> </div>
</el-col>
</el-row>
</div> </div>
</template> </template>
@ -266,73 +253,61 @@ export default {
<style lang="scss" scoped> <style lang="scss" scoped>
.login { .login {
.left { padding: 14vh 6vw 0;
height: 100vh; display: flex;
background: #109b5e; justify-content: space-between;
overflow: hidden; width: 100vw;
.login-title { height: 100vh;
display: flex; overflow: hidden;
align-items: center; background: url('../assets/login/loginBG.png') no-repeat fixed center / cover;
justify-content: center; .system_name {
padding-bottom: 26px; padding-top: 8vh;
color: #fff; font-size: 100px;
letter-spacing: 11px; font-weight: bold;
font-size: 50px; color: #fff;
font-weight: 500; font-family: 'JinBuTi', sans-serif;
margin-top: 15vh; transform: skew(-12deg);
}
.login-subTitle {
display: flex;
align-items: center;
justify-content: center;
padding-bottom: 26px;
color: #fff;
font-size: 20px;
}
.login-bgImage {
display: flex;
align-items: center;
justify-content: center;
margin-top: 15vh;
img {
width: 75%;
}
}
} }
.right { .login_content {
height: 100vh; .login_text {
margin: 0 auto 60px;
width: 128px;
height: 78px;
font-family: 'JinBuTi', sans-serif;
font-size: 64px;
color: #fff;
background-size: 100% 100%;
}
padding: 60px 40px;
width: 640px;
height: 72vh;
background-color: rgba(0, 0, 0, 0.2);
backdrop-filter: blur(18px);
overflow: hidden; overflow: hidden;
border-radius: 40px;
.loginForm-title { .loginForm-title {
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
font-size: 30px; font-size: 30px;
font-weight: bold; font-weight: bold;
margin-top: 20vh;
}
.loginForm-subTitle {
display: flex;
align-items: center;
justify-content: center;
color: rgba(22, 23, 26, 0.1);
font-size: 23px;
white-space: nowrap;
letter-spacing: 2px;
margin-top: -10px;
}
.loginForm-form {
padding: 0 25%;
}
.login-captchaBox {
display: flex;
img {
height: 50px;
}
} }
// //
::v-deep { ::v-deep {
.el-form-item {
margin-bottom: 40px;
}
.el-form-item__label {
color: #fff;
}
.login_btn {
margin-top: 40px;
span {
font-family: 'Sans';
font-weight: bold;
}
}
.el-input__inner { .el-input__inner {
height: 50px; height: 50px;
border-radius: 25px; border-radius: 25px;

View File

@ -15,7 +15,7 @@ module.exports = {
// 部署生产环境和开发环境下的URL。 // 部署生产环境和开发环境下的URL。
// 默认情况下Vue CLI 会假设你的应用是被部署在一个域名的根路径上 // 默认情况下Vue CLI 会假设你的应用是被部署在一个域名的根路径上
// 例如 https://www.ruoyi.vip/。如果应用被部署在一个子路径上,你就需要用这个选项指定这个子路径。例如,如果你的应用被部署在 https://www.ruoyi.vip/admin/,则设置 baseUrl 为 /admin/。 // 例如 https://www.ruoyi.vip/。如果应用被部署在一个子路径上,你就需要用这个选项指定这个子路径。例如,如果你的应用被部署在 https://www.ruoyi.vip/admin/,则设置 baseUrl 为 /admin/。
publicPath: process.env.NODE_ENV === "production" ? "/" : "/", publicPath: process.env.NODE_ENV === 'production' ? '/' : '/',
// 在npm run build 或 yarn build 时 生成文件的目录名称要和baseUrl的生产环境路径一致默认dist // 在npm run build 或 yarn build 时 生成文件的目录名称要和baseUrl的生产环境路径一致默认dist
outputDir: 'dist', outputDir: 'dist',
// 用于放置生成的静态资源 (js、css、img、fonts) 的;(项目打包之后,静态资源会放在这个文件夹下) // 用于放置生成的静态资源 (js、css、img、fonts) 的;(项目打包之后,静态资源会放在这个文件夹下)
@ -38,13 +38,13 @@ module.exports = {
['^' + process.env.VUE_APP_BASE_API]: '' ['^' + process.env.VUE_APP_BASE_API]: ''
} }
}, },
['/api/v4']: { '/api/v4': {
target: process.env.VUE_APP_EMQX_API_URL, target: process.env.VUE_APP_EMQX_API_URL,
changeOrigin: true, changeOrigin: true
// logLevel: 'debug', // logLevel: 'debug',
}, }
}, },
https:false, https: false,
disableHostCheck: true disableHostCheck: true
}, },
configureWebpack: { configureWebpack: {
@ -53,17 +53,14 @@ module.exports = {
alias: { alias: {
'@': resolve('src') '@': resolve('src')
} }
}, }
}, },
chainWebpack(config) { chainWebpack(config) {
config.plugins.delete('preload') // TODO: need test config.plugins.delete('preload') // TODO: need test
config.plugins.delete('prefetch') // TODO: need test config.plugins.delete('prefetch') // TODO: need test
// set svg-sprite-loader // set svg-sprite-loader
config.module config.module.rule('svg').exclude.add(resolve('src/assets/icons')).end()
.rule('svg')
.exclude.add(resolve('src/assets/icons'))
.end()
config.module config.module
.rule('icons') .rule('icons')
.test(/\.svg$/) .test(/\.svg$/)
@ -76,47 +73,46 @@ module.exports = {
}) })
.end() .end()
config config.when(process.env.NODE_ENV !== 'development', (config) => {
.when(process.env.NODE_ENV !== 'development', config
config => { .plugin('ScriptExtHtmlWebpackPlugin')
config .after('html')
.plugin('ScriptExtHtmlWebpackPlugin') .use('script-ext-html-webpack-plugin', [
.after('html')
.use('script-ext-html-webpack-plugin', [{
// `runtime` must same as runtimeChunk name. default is `runtime`
inline: /runtime\..*\.js$/
}])
.end()
config
.optimization.splitChunks({
chunks: 'all',
cacheGroups: {
libs: {
name: 'chunk-libs',
test: /[\\/]node_modules[\\/]/,
priority: 10,
chunks: 'initial' // only package third parties that are initially dependent
},
elementUI: {
name: 'chunk-elementUI', // split elementUI into a single package
priority: 20, // the weight needs to be larger than libs and app or it will be packaged into libs or app
test: /[\\/]node_modules[\\/]_?element-ui(.*)/ // in order to adapt to cnpm
},
commons: {
name: 'chunk-commons',
test: resolve('src/components'), // can customize your rules
minChunks: 3, // minimum common number
priority: 5,
reuseExistingChunk: true
}
}
})
config.optimization.runtimeChunk('single'),
{ {
from: path.resolve(__dirname, './public/robots.txt'), //防爬虫文件 // `runtime` must same as runtimeChunk name. default is `runtime`
to: './' //到根目录下 inline: /runtime\..*\.js$/
}
])
.end()
config.optimization.splitChunks({
chunks: 'all',
cacheGroups: {
libs: {
name: 'chunk-libs',
test: /[\\/]node_modules[\\/]/,
priority: 10,
chunks: 'initial' // only package third parties that are initially dependent
},
elementUI: {
name: 'chunk-elementUI', // split elementUI into a single package
priority: 20, // the weight needs to be larger than libs and app or it will be packaged into libs or app
test: /[\\/]node_modules[\\/]_?element-ui(.*)/ // in order to adapt to cnpm
},
commons: {
name: 'chunk-commons',
test: resolve('src/components'), // can customize your rules
minChunks: 3, // minimum common number
priority: 5,
reuseExistingChunk: true
} }
} }
) })
// eslint-disable-next-line no-sequences
config.optimization.runtimeChunk('single'),
{
from: path.resolve(__dirname, './public/robots.txt'), // 防爬虫文件
to: './' // 到根目录下
}
})
} }
} }