dev_xd
姜玉琦 2025-05-23 00:23:22 +08:00
commit 2b2969e256
20 changed files with 1090 additions and 715 deletions

View File

@ -9,7 +9,8 @@ import safety from "./safety";
import tower from "./tower";
import powerIot from "./powerIot";
import aiWarning from "./aiWarning";
import planSchedule from './planSchedule';
import planSchedule from "./planSchedule";
import labor from "./labor";
export default {
http: axios,
downFile: download,
@ -24,4 +25,5 @@ export default {
powerIot,
aiWarning,
planSchedule,
labor,
};

View File

@ -0,0 +1,74 @@
import request from "@/utils/request";
/**
* 分组统计人员年龄省份统计信息
* @param {*} type
* @param {*} prjId
* @returns
*/
const groupByWorker = (type, prjId) => {
return request({
url: `/manage/bgscreen/labor/groupByWorker/${type}/${prjId}`,
method: "get",
});
};
/**
* 劳务人员七天出勤趋势
* @param {*} type
* @param {*} prjId
* @returns
*/
const groupAttendanceLastWeek = (type, prjId) => {
return request({
url: `/manage/bgscreen/labor/groupAttendanceLastWeek/${type}/${prjId}`,
method: "get",
});
};
/**
* 劳务人员工种占比
* @param {*} type
* @param {*} prjId
* @returns
*/
const getWorkerCountGroupByType = (type, prjId) => {
return request({
url: `/manage/bgscreen/labor/getWorkerCountGroupByType/${type}/${prjId}`,
method: "get",
});
};
/**
* 实时考勤进出
* @param {*} type
* @param {*} prjId
* @returns
*/
const getRealAttendance = (type, prjId) => {
return request({
url: `/manage/bgscreen/labor/getRealAttendance/${type}/${prjId}`,
method: "get",
});
};
/**
* 考勤预警
* @param {*} type
* @param {*} prjId
* @returns
*/
const getAttendanceAlert = (type, prjId) => {
return request({
url: `/manage/bgscreen/labor/getAttendanceAlert/${type}/${prjId}`,
method: "get",
});
};
export default {
groupByWorker,
groupAttendanceLastWeek,
getWorkerCountGroupByType,
groupAttendanceLastWeek,
getRealAttendance,
getAttendanceAlert,
};

View File

@ -174,6 +174,7 @@ export default {
legend: [
{
right: 10,
data: legendData,
align: 'left',
...opt,

View File

@ -539,7 +539,7 @@ export default {
left: '5%',
right: '5%',
bottom: '0%',
top: '15%',
top: '5%',
containLabel: true,
},
tooltip: {

View File

@ -2,330 +2,509 @@
<div class="project-labor main-page">
<el-col :span="6" class="h100">
<module-one-1-1 label="劳务人员概况">
<img src="images/icon2001.png" class="img-openwin" />
<div class="attendance-info warning-info">
<div class="attendance-info-title warning-info-title">
<div :class="attendanceNav == 0 ? 'active' : ''" @click="doAttendanceNav(0, '在岗人员')">在岗人员</div>
<div :class="attendanceNav == 1 ? 'active' : ''" @click="doAttendanceNav(1, '今日出勤')">今日出勤</div>
</div>
<el-row>
<el-col :span="8" class="attendance-tag">
<div class="survey_content">
<div class="survey_content_img">
<img
:src="
attendanceNav == 0
? 'images/survey_icon_4.png'
: 'images/survey_icon_5.png'
"
/>
</div>
</div>
<div class="survey_content_number labour-survey_content_number">
<div class="survey_content_value">
<span>{{ attendanceTotal }}</span>
</div>
<p>{{ attendanceNav == 0 ? "在岗人员" : "今日出勤" }}</p>
</div>
</el-col>
<el-col :span="16">
<staffSurveyChart :key="chartKey" :height="$dpi() == '1K' ? '220px' : $dpi() == '2K' ? '330px' : '550px'" :data="attendanceData" :width="140"></staffSurveyChart>
</el-col>
</el-row>
</div>
</module-one-1-1>
<module-one-1-1 label="劳务人员七天出勤趋势">
<my-chart :key="chartKey" id="prj_labor_chart2" width="100%" height="100%" :render="renderChart2"></my-chart>
</module-one-1-1>
<module-one-1-1 label="劳务人员年龄分布">
<my-chart :key="chartKey" id="prj_labor_chart3" width="100%" height="100%" :render="renderChart3"></my-chart>
</module-one-1-1>
<module-one-1-1 label="劳务人员七天出勤趋势"></module-one-1-1>
<module-one-1-1 label="劳务人员年龄分布"></module-one-1-1>
</el-col>
<el-col :span="12" class="h100">
<module-one-2-2 label class="no-title no-border">
<my-chart :key="chartKey" id="prj-labor-map" width="100%" height="100%" :render="renderMap"></my-chart>
</module-one-2-2>
<module-one-1-2 label="实时进出" class="prj-plan"></module-one-1-2>
<module-one-1-2 label="实时进出" class="prj-labor-real">
<div class="real-item" v-for="(item, index) in realList" :key="index">
<div class="real-item-type" :class="'is-'+item.inOutType">{{ item.inOutType==='out'?'出':'进' }}</div>
<el-image class="real-item-img" fit="cover" :src="item.img" :preview-src-list="[item.img]"></el-image>
<div class="real-item-name">{{ item.name }}</div>
<div class="real-item-work-type">
<span>{{ item.workType }}</span>
</div>
<div class="real-item-time">
<span>{{item.inOutType==='in'?'进场时间:':'出场时间:'}} {{ item.inoutDate }}</span>
</div>
</div>
</module-one-1-2>
</el-col>
<el-col :span="6" class="h100">
<module-one-1-1 label="工种占比分布"></module-one-1-1>
<module-one-1-1 label="人员地区分布"></module-one-1-1>
<module-one-1-1 label="人员预期"></module-one-1-1>
<module-one-1-1 label="工种占比分布" class="chart-module4">
<project-overview-chart
:htmlShow="true"
:key="'ai4' + overview+chartKey"
:sp="''"
:fn="changeChart4"
:maintitle="workerTotal"
:legend-opt="legendOpt"
:typedata="workerGroupList"
:text="'总人数'"
:height="chart4Height"
></project-overview-chart>
</module-one-1-1>
<module-one-1-1 label="人员地区分布">
<my-chart :key="chartKey" id="prj_labor_chart5" width="100%" height="100%" :render="renderChart5"></my-chart>
</module-one-1-1>
<module-one-1-1 label="人员预警" class="prj-labor-alert">
<div class="alert-list scroll">
<table>
<thead>
<tr>
<th>姓名</th>
<th>单位</th>
<th>缺勤天数</th>
</tr>
</thead>
<tbody>
<tr v-for="(item, index) in alertList" :key="index">
<td>{{ item.name }}</td>
<td>{{ item.companyName }}</td>
<td>{{ item.id }}</td>
</tr>
</tbody>
</table>
</div>
</module-one-1-1>
</el-col>
</div>
</template>
<script>
import debounce from 'lodash.debounce'
import mapbg from '@/assets/images/map-bg.png'
import staffSurveyChart from '@/components/staffSurveyChart.vue'
export default {
components: { staffSurveyChart },
data() {
return {
dpi: '',
chartKey: 0,
chart4Height: 230,
chart2Height: 230,
selProject: null,
attendanceNav: 0,
attendanceTotal: 0,
attendanceData: [
{ text: '普通工种', value: 0, id: 0 },
{ text: '特殊工种', value: 0, id: 0 },
{ text: '管理人员', value: 0, id: 0 },
],
legendOpt: {},
overviewDatas: [],
nativeList: [],
ageList: [],
weekData: [],
workerTotal: 0,
workerGroupList: [],
realList: [],
alertList: [],
}
},
methods: {
changeChart4(opt) {
if (this.$dpi() == '1K') {
opt.legend[0].left = 200
return opt
} else if (this.$dpi() == '2K') {
opt.legend[0].left = 360
return opt
} else {
opt.legend[0].left = 500
return opt
}
},
setOpts() {
let is1K = this.$dpi() == '1K'
let is2K = this.$dpi() == '2K'
this.legendOpt = {
icon: 'rect',
orient: 'vertical',
itemWidth: '50%',
left: 240,
right: '10%',
itemWidth: 20,
itemGap: 20,
itemHeight: 20,
type: 'scroll',
pageTextStyle: {
color: '#c3dbfd',
},
scroll: {
y: is1K ? 300 : is2K ? 500 : 600,
bar: {
show: true,
width: 5,
height: 10,
},
},
textStyle: {
padding: [0, 0, 0, 0],
fontSize: is1K ? 10 : is2K ? 14 : 16,
color: '#c3dbfd',
align: 'center',
rich: {
name: {
fontSize: is1K ? 10 : is2K ? 14 : 16,
color: '#c3dbfd',
padding: [5, 2, 5, 2],
},
percent: {
fontSize: is1K ? 10 : is2K ? 14 : 16,
color: '#4676FD',
padding: [0, 2, 0, 2],
},
},
},
}
},
init() {
if (!this.selProject) {
return
}
this.loadAttendanceData()
this.getGroupByWorker()
this.groupAttendanceLastWeek()
this.getWorkerCountGroupByType()
this.getRealAttendance()
this.getAttendanceAlert()
},
resize() {
let is1K = this.$dpi() == '1K'
let is2K = this.$dpi() == '2K'
this.chart4Height = is1K ? 230 : is2K ? 360 : 595
this.chart2Height = is1K ? 567 : is2K ? 800 : 1250
this.chartKey++
},
getAttendanceAlert() {
this.$api.labor.getAttendanceAlert(this.selProject.vendorsCode, this.selProject.id).then((d) => {
this.alertList = d.data.map((it) => {
return it
})
})
},
getRealAttendance() {
this.$api.labor.getRealAttendance(this.selProject.vendorsCode, this.selProject.id).then((d) => {
this.realList = d.data.map((it) => {
it.name = it.workerName
it.workType = it.workTypeName
it.img = it.scanPhoto
if (it.attendanceOutTime) {
it.inOutType = 'out'
it.inoutDate = it.attendanceInTime
} else {
it.inOutType = 'in'
it.inoutDate = it.attendanceTime
}
return it
})
})
},
getWorkerCountGroupByType() {
this.$api.labor.getWorkerCountGroupByType(this.selProject.vendorsCode, this.selProject.id).then((d) => {
let sum = 0
d.data.forEach((item) => {
sum += item.id ? item.id : 0
})
this.workerTotal = sum
this.workerGroupList = d.data.map((item) => {
return {
name: item.workTypeName,
value: item.id ? item.id : 0,
}
})
})
},
groupAttendanceLastWeek() {
this.$api.labor.groupAttendanceLastWeek(this.selProject.vendorsCode, this.selProject.id).then((d) => {
this.weekData = d.data.map((it) => {
return {
name: it.dt.substring(5).replace('-', '.'),
value: it.cnt,
//value: it.cnt + parseInt(Math.random() * 100),
}
})
})
},
getGroupByWorker() {
this.$api.labor.groupByWorker(this.selProject.vendorsCode, this.selProject.id).then((d) => {
this.nativeList = (d.data.native || []).map((it) => {
it.name = it.nativePlace
it.value = it.count
return it
})
this.ageList = (d.data.age || []).map((it) => {
it.name = ['', '18~30', '30~40', '40~55', '55岁以上'][it.age]
it.value = it.count
return it
})
this.chartKey++
})
},
renderChart2(opt) {
const areaOption = {
grid: {
left: '5%',
right: '5%',
bottom: '0%',
top: '15%',
containLabel: true,
},
tooltip: {
trigger: 'axis',
axisPointer: {
type: 'shadow',
label: {
backgroundColor: '#6a7985',
},
},
},
xAxis: {
type: 'category',
data: this.weekData.map((item) => item.name),
axisLabel: {
textStyle: {
color: '#0df2c8',
},
},
},
yAxis: {
type: 'value',
minInterval: 1,
axisLabel: {
textStyle: {
color: '#0df2c8',
},
},
},
series: [
{
name: '出勤人数',
type: 'line',
areaStyle: {
color: 'rgba(13, 204, 242,0.5)', //
},
label: {
show: true,
position: 'top', // 线
textStyle: {
color: '#0df2c8', //
},
},
data: this.weekData.map((item) => item.value),
},
],
}
return areaOption
},
renderChart3(opt) {
let pieOption = {
tooltip: {
trigger: 'item',
formatter: '{b} 岁 <br/> {c} 人 ({d}%)',
},
legend: {
orient: 'vertical',
left: 'left',
top: 'center',
data: this.ageList.map((it) => it.name),
textStyle: {
color: '#19c0e6',
},
},
series: [
{
type: 'pie',
radius: '55%',
center: ['50%', '60%'],
data: this.ageList,
label: {
normal: {
formatter: '{b}\n{c}',
textStyle: {
color: '#0df2c8',
},
},
emphasis: {
formatter: '{b}\n{c}',
textStyle: {
color: '#0df2c8',
},
},
},
emphasis: {
itemStyle: {
shadowBlur: 10,
shadowOffsetX: 0,
},
},
},
],
}
return pieOption
},
renderChart5(opt) {
const pieOption = {
tooltip: {
trigger: 'item',
formatter: '{b}: {c} ({d}%)',
},
series: [
{
type: 'pie',
radius: ['50%', '70%'], //
avoidLabelOverlap: false,
label: {
normal: {
formatter: '{b}\n{c}',
textStyle: {
color: '#0df2c8',
},
},
emphasis: {
formatter: '{b}\n{c}',
textStyle: {
color: '#0df2c8',
},
},
},
emphasis: {
label: {
show: true,
fontSize: '30',
fontWeight: 'bold',
},
},
data: this.nativeList,
},
],
}
return pieOption
},
doAttendanceNav(n) {
this.attendanceNav = n
this.loadAttendanceData()
},
loadJhAttendanceData() {
let data = {
id: this.attendanceNav,
projectId: this.selProject.id,
attendanceTime: this.$dt(new Date()).format('YYYY-MM-DD'),
}
let ajax = this.$api.detail.groupByComany
if (this.attendanceNav != 1) {
ajax = this.$api.detail.groupAllByComany
}
ajax(data).then((d) => {
let tmps = d.data || []
const func = (ids) => {
let sum = 0
tmps.filter((it) => ids.includes(it.companyTypeId))
.map((it) => it.id)
.forEach((it) => {
sum += it * 1
})
return sum
}
this.attendanceTotal = 0
this.attendanceData = [
{ text: '劳务人员', value: func(['0', '2', '3', '4', '5']) },
{ text: '监理人员', value: func(['8']) },
{ text: '总包人员', value: func(['1', '6']) },
]
this.attendanceData.forEach((it) => {
this.attendanceTotal += it.value
})
})
},
loadUniAttendanceData() {
let ajax = this.$api.detail.groupByCraftType
let posData = {
comId: this.selProject.comId,
projectId: this.selProject.id,
}
if (this.attendanceNav == 1) {
ajax = this.$api.detail.groupByCraftTypeByAttendance
posData.createTime = this.$dt(new Date()).format('YYYY-MM-DD')
//posData.createTime = '2024-10-13'
}
ajax(posData).then((d) => {
this.attendanceData = (d.data || []).map((it) => {
return {
text: it.createBy,
value: it.id || 0,
id: it.craftType,
}
})
let count = 0
this.attendanceData.forEach((it) => {
count += it.value
})
this.attendanceTotal = count
})
},
renderMap(opt, myChart) {
var name_title = '中国人民大学2017年各省市计划录取人数'
var subname = '数据爬取自千栀网\n\n上海、浙江无文理科录取人数'
var nameColor = ' rgb(55, 75, 113)'
var name_fontFamily = '等线'
var subname_fontSize = 15
var name_fontSize = 18
var mapName = 'china'
var data = [
{ name: '北京', value: 177 },
{ name: '天津', value: 42 },
{ name: '河北', value: 102 },
{ name: '山西', value: 81 },
{ name: '内蒙古', value: 47 },
{ name: '辽宁', value: 67 },
{ name: '吉林', value: 82 },
{ name: '黑龙江', value: 66 },
{ name: '上海', value: 24 },
{ name: '江苏', value: 92 },
{ name: '浙江', value: 114 },
{ name: '安徽', value: 109 },
{ name: '福建', value: 116 },
{ name: '江西', value: 91 },
{ name: '山东', value: 119 },
{ name: '河南', value: 137 },
{ name: '湖北', value: 0 },
{ name: '湖南', value: 114 },
{ name: '重庆', value: 91 },
{ name: '四川', value: 125 },
{ name: '贵州', value: 62 },
{ name: '云南', value: 83 },
{ name: '西藏', value: 9 },
{ name: '陕西', value: 80 },
{ name: '甘肃', value: 56 },
{ name: '青海', value: 10 },
{ name: '宁夏', value: 18 },
{ name: '新疆', value: 67 },
{ name: '广东', value: 123 },
{ name: '广西', value: 59 },
{ name: '海南', value: 14 },
]
var geoCoordMap = {}
var toolTipData = [
{
name: '北京',
value: [
{ name: '文科', value: 95 },
{ name: '理科', value: 82 },
],
},
{
name: '天津',
value: [
{ name: '文科', value: 22 },
{ name: '理科', value: 20 },
],
},
{
name: '河北',
value: [
{ name: '文科', value: 60 },
{ name: '理科', value: 42 },
],
},
{
name: '山西',
value: [
{ name: '文科', value: 40 },
{ name: '理科', value: 41 },
],
},
{
name: '内蒙古',
value: [
{ name: '文科', value: 23 },
{ name: '理科', value: 24 },
],
},
{
name: '辽宁',
value: [
{ name: '文科', value: 39 },
{ name: '理科', value: 28 },
],
},
{
name: '吉林',
value: [
{ name: '文科', value: 41 },
{ name: '理科', value: 41 },
],
},
{
name: '黑龙江',
value: [
{ name: '文科', value: 35 },
{ name: '理科', value: 31 },
],
},
{
name: '上海',
value: [
{ name: '文科', value: 12 },
{ name: '理科', value: 12 },
],
},
{
name: '江苏',
value: [
{ name: '文科', value: 47 },
{ name: '理科', value: 45 },
],
},
{
name: '浙江',
value: [
{ name: '文科', value: 57 },
{ name: '理科', value: 57 },
],
},
{
name: '安徽',
value: [
{ name: '文科', value: 57 },
{ name: '理科', value: 52 },
],
},
{
name: '福建',
value: [
{ name: '文科', value: 59 },
{ name: '理科', value: 57 },
],
},
{
name: '江西',
value: [
{ name: '文科', value: 49 },
{ name: '理科', value: 42 },
],
},
{
name: '山东',
value: [
{ name: '文科', value: 67 },
{ name: '理科', value: 52 },
],
},
{
name: '河南',
value: [
{ name: '文科', value: 69 },
{ name: '理科', value: 68 },
],
},
{
name: '湖北',
value: [
{ name: '文科', value: 60 },
{ name: '理科', value: 56 },
],
},
{
name: '湖南',
value: [
{ name: '文科', value: 62 },
{ name: '理科', value: 52 },
],
},
{
name: '重庆',
value: [
{ name: '文科', value: 47 },
{ name: '理科', value: 44 },
],
},
{
name: '四川',
value: [
{ name: '文科', value: 65 },
{ name: '理科', value: 60 },
],
},
{
name: '贵州',
value: [
{ name: '文科', value: 32 },
{ name: '理科', value: 30 },
],
},
{
name: '云南',
value: [
{ name: '文科', value: 42 },
{ name: '理科', value: 41 },
],
},
{
name: '西藏',
value: [
{ name: '文科', value: 5 },
{ name: '理科', value: 4 },
],
},
{
name: '陕西',
value: [
{ name: '文科', value: 38 },
{ name: '理科', value: 42 },
],
},
{
name: '甘肃',
value: [
{ name: '文科', value: 28 },
{ name: '理科', value: 28 },
],
},
{
name: '青海',
value: [
{ name: '文科', value: 5 },
{ name: '理科', value: 5 },
],
},
{
name: '宁夏',
value: [
{ name: '文科', value: 10 },
{ name: '理科', value: 8 },
],
},
{
name: '新疆',
value: [
{ name: '文科', value: 36 },
{ name: '理科', value: 31 },
],
},
{
name: '广东',
value: [
{ name: '文科', value: 63 },
{ name: '理科', value: 60 },
],
},
{
name: '广西',
value: [
{ name: '文科', value: 29 },
{ name: '理科', value: 30 },
],
},
{
name: '海南',
value: [
{ name: '文科', value: 8 },
{ name: '理科', value: 6 },
],
},
]
let mapName = 'china'
let data = this.nativeList
let geoCoordMap = {}
/*获取地图数据*/
var mapFeatures = echarts.getMap(mapName).geoJson.features
let mapFeatures = echarts.getMap(mapName).geoJson.features
let allData = []
mapFeatures.forEach(function (v) {
//
var name = v.properties.name
//
geoCoordMap[name] = v.properties.cp
allData.push({
name: name,
value: 0,
})
})
// console.log("============geoCoordMap===================")
// console.log(geoCoordMap)
// console.log("================data======================")
//console.log(data)
//console.log(toolTipData)
var max = 480,
min = 9 // todo
var maxSize4Pin = 100,
let max = 880,
min = 3 // todo
let maxSize4Pin = 80,
minSize4Pin = 20
var convertData = function (data, lbl) {
var res = []
for (var i = 0; i < data.length; i++) {
var geoCoord = geoCoordMap[data[i].name]
let convertData = function (data, lbl) {
let res = []
if (lbl == 1) {
data = allData
}
for (let i = 0; i < data.length; i++) {
let geoCoord = geoCoordMap[data[i].name]
if (geoCoord) {
res.push({
name: data[i].name,
@ -339,63 +518,6 @@ export default {
return res.filter((d) => d.value[2] > 0)
}
let option = {
title: {
show: false,
text: name_title,
subtext: subname,
x: 'center',
textStyle: {
color: nameColor,
fontFamily: name_fontFamily,
fontSize: name_fontSize,
},
subtextStyle: {
fontSize: subname_fontSize,
fontFamily: name_fontFamily,
},
},
tooltip: {
show: false,
trigger: 'item',
formatter: function (params) {
if (typeof params.value[2] == 'undefined') {
var toolTiphtml = ''
for (var i = 0; i < toolTipData.length; i++) {
if (params.name == toolTipData[i].name) {
toolTiphtml += toolTipData[i].name + ':<br>'
for (var j = 0; j < toolTipData[i].value.length; j++) {
toolTiphtml += toolTipData[i].value[j].name + ':' + toolTipData[i].value[j].value + '<br>'
}
}
}
console.log(toolTiphtml)
// console.log(convertData(data))
return toolTiphtml
} else {
var toolTiphtml = ''
for (var i = 0; i < toolTipData.length; i++) {
if (params.name == toolTipData[i].name) {
toolTiphtml += toolTipData[i].name + ':<br>'
for (var j = 0; j < toolTipData[i].value.length; j++) {
toolTiphtml += toolTipData[i].value[j].name + ':' + toolTipData[i].value[j].value + '<br>'
}
}
}
console.log(toolTiphtml)
// console.log(convertData(data))
return toolTiphtml
}
},
},
// legend: {
// orient: 'vertical',
// y: 'bottom',
// x: 'right',
// data: ['credit_pm2.5'],
// textStyle: {
// color: '#fff'
// }
// },
visualMap: {
show: false,
min: 0,
@ -420,20 +542,6 @@ export default {
// color: ['#00467F', '#A5CC82'] // 绿
},
},
/*工具按钮组*/
// toolbox: {
// show: true,
// orient: 'vertical',
// left: 'right',
// top: 'center',
// feature: {
// dataView: {
// readOnly: false
// },
// restore: {},
// saveAsImage: {}
// }
// },
geo: {
show: true,
map: mapName,
@ -530,8 +638,16 @@ export default {
}
return option
},
loadAttendanceData() {
if (this.selProject.vendorsCode != 'uni') {
this.loadJhAttendanceData()
} else {
this.loadUniAttendanceData()
}
},
},
mounted() {
window.plApp = this
this.$store.dispatch('ChangeNav', 102)
this.$bus.$on(
'projectChange',
@ -546,12 +662,93 @@ export default {
window.addEventListener('resize', () => {
if (this.dpi != this.$dpi()) {
this.dpi = this.$dpi()
this.chartKey++
this.resize()
}
})
this.setOpts()
},
}
</script>
<style>
<style lang="less">
.project-labor {
.chart-module4 {
.chart-gif {
left: 50px;
}
.chart-text {
top: 63px;
left: 50px;
}
}
.prj-labor-real {
.module-ctx {
position: relative;
display: flex;
flex-direction: column;
flex-wrap: wrap;
font-size: 12px;
.real-item {
height: 100%;
width: 25%;
position: relative;
overflow: hidden;
.real-item-type {
position: absolute;
font-size: 20px;
font-weight: bold;
z-index: 10;
&.is-in {
color: #00ffd0;
}
&.is-out {
color: #cc6933;
}
}
.real-item-img {
height: calc(100% - 60px);
padding: 0px 40px;
.el-image__inner {
width: unset;
}
}
.real-item-name {
text-align: center;
}
.real-item-work-type {
text-align: center;
line-height: 30px;
span {
color: #33b7bd;
border: solid 1px #33b7bd;
border-radius: 5px;
padding: 0 10px;
}
}
.real-item-time {
font-size: 10px;
text-align: center;
color: #33b7bd;
}
}
}
}
.prj-labor-alert {
.module-ctx {
height: calc(100% - 40px);
line-height: 30px;
.alert-list {
height: 100%;
overflow-y: auto;
th {
color: #00ffd0;
}
td {
font-size: 12px;
text-align: center;
}
}
}
}
}
</style>

View File

@ -41,8 +41,8 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
select dtpc.id,
dtpc.project_id,
dtpc.com_id,
sp.project_name as projectName,
sd.dept_name as com_name, dtpc.dept_id
sp.dept_name as projectName,
sd.dept_name as com_name, dtpc.dept_id,
dtpc.device_sn,
dtpc.device_name,
dtpc.device_source,

View File

@ -397,10 +397,11 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
pi.floor_area, pi.total_output_value, pi.planned_completion_time, pi.scheduled_start_time, pi.actual_operating_time, pi.actual_completion_time,
pi.contract_amount, pi.paid_amount, pi.on_account_amount, pi.project_schedule, pi.project_summarize, pi.project_qr_code, pi.project_status,
pi.project_sort, pi.is_del, pi.create_by, pi.create_time, pi.update_by, pi.update_time, pi.remark,
ps.id ps_id,ps.org_name ps_org_name,ps.org_logo ps_org_logo,ps.org_image ps_org_image,ps.org_video ps_org_video,ps.org_plane ps_org_plane
ps.id ps_id,ps.org_name ps_org_name,ps.org_logo ps_org_logo,ps.org_image ps_org_image,ps.org_video ps_org_video,ps.org_plane ps_org_plane,cfg.vendors_code
from pro_project_info pi
left join pro_project_info_setting ps on pi.id=ps.project_id
left join sys_dept sd on pi.com_id=sd.dept_id
left join attendance_cfg cfg on cfg.project_id=pi.id
left join sys_dict_data sdd1 on sdd1.dict_value = pi.project_type and sdd1.dict_type='pro_project_type'
<if test="currentUserId != null "> left join pro_project_info_subdepts_users psu on psu.project_id = pi.id </if>
<where>

View File

@ -653,7 +653,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
from (
select DISTINCT workerId, date(ifnull(attendance_time,attendance_out_time)) dt
from sur_project_attendance_data_${year} where
is_del !=1 and state=0
is_del !=1
and projectid=#{prjId}
AND (date(attendance_time) &gt;= date(#{dateStart}) or date(attendance_out_time) &gt;= date(#{dateStart}))
AND (date(attendance_time) &lt;= date(#{dateEnd}) or date(attendance_out_time) &lt;= date(#{dateEnd}))
@ -664,10 +664,15 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
</select>
<select id="getRealAttendance" resultMap="SurProjectAttendanceDataResult">
<!--
select * from sur_project_attendance_data_${year}
where date(attendance_time)=date(now()) or date(attendance_out_time)=date(now())
and is_del!=1
and projectid=#{prjId} and state=0
and projectid=#{prjId}
order by ifnull(attendance_time,attendance_out_time) DESC
LIMIT 4-->
select * from yanzhu_jh.sur_project_attendance_data_2024
where (date(attendance_time)='2024-03-22' or date(attendance_out_time)='2024-03-22')
order by ifnull(attendance_time,attendance_out_time) DESC
LIMIT 4
</select>

View File

@ -817,7 +817,8 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<select id="getWorkerCountGroupByType" resultMap="SurProjectAttendanceUserResult">
select workTypeName,count(1) id from sur_project_attendance_user
where cfgid in (select id from attendance_cfg where project_id= #{projectId}) and is_del!=1 and state=0
where cfgid in (select id from attendance_cfg where project_id= #{projectId})
and is_del!=1 and state=0
group by workTypeName
order by count(1) DESC
@ -826,6 +827,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<select id="getAttendanceAlert" resultMap="SurProjectAttendanceUserResult">
<!--
select u.*,TIMESTAMPDIFF(Day, att.dt,now()) id
from (
select su.workerId,su.name,pi.project_name companyName, pdept.sub_dept_name teamName
@ -846,5 +848,28 @@ and cfg.project_id=#{projectId} ) u
GROUP BY workerId
order by max(ifnull(attendance_time,attendance_out_time))
) att on u.workerId=att.workerId
-->
select u.*,TIMESTAMPDIFF(Day, att.dt,now()) id
from (
select su.workerId,su.name,pi.project_name companyName, pdept.sub_dept_name teamName
from ( select 11 cfgid, name,workerId
from yanzhu_jh.sur_project_attendance_user where cfgId=1) su
left join attendance_cfg cfg on su.cfgId=cfg.ID
left join pro_project_info pi on pi.id = cfg.project_id
join pro_project_info_subdepts pdept on cfg.dept_id=pdept.id
) u
join
(
select workerId,max(ifnull(attendance_time,attendance_out_time)) dt
from yanzhu_jh.sur_project_attendance_data_2024
where projectid=644 and is_del!=1
GROUP BY workerId
order by max(ifnull(attendance_time,attendance_out_time))
) att on u.workerId=att.workerId
LIMIT 10
</select>
</mapper>

View File

@ -120,12 +120,12 @@ public class ProVideoMonitorController extends BaseController
String key="YS_Token__"+ proVideoMonitor.getAppkey()+"_"+proVideoMonitor.getSecret();
JSONObject jo=redisService.getCacheObject(key);
String token="";
if(jo!=null){
long expireTime= jo.getLong("expireTime");
if(expireTime> System.currentTimeMillis()+1000*60){
token=jo.getString("accessToken");
return AjaxResult.success(token);
}
if (jo != null) {
long expireTime = jo.getLong("expireTime");
if (expireTime > System.currentTimeMillis() + 1000 * 60) {
token = jo.getString("accessToken");
return AjaxResult.success(token);
}
}
String postData="appKey="+proVideoMonitor.getAppkey()+"&appSecret="+proVideoMonitor.getSecret();
String url="https://open.ys7.com/api/lapp/token/get";

View File

@ -28,7 +28,7 @@ import java.util.List;
* -
*/
@RestController
@RequestMapping("/bgscreen/tower")
@RequestMapping("/bgscreen/labor")
public class LaborController extends BaseController {
@Autowired

View File

@ -1752,7 +1752,7 @@ public class ProProjectInfoSubdeptsUsersServiceImpl implements IProProjectInfoSu
JSONObject jo=new JSONObject();
jo.put("age",k);
jo.put("count",v.size());
arrNav.add(jo);
arrAge.add(jo);
});
joOut.put("age",arrAge);
return joOut;

View File

@ -353,7 +353,7 @@ public class SurProjectAttendanceUserServiceImpl implements ISurProjectAttendanc
JSONObject jo=new JSONObject();
jo.put("age",k);
jo.put("count",v.size());
arrNav.add(jo);
arrAge.add(jo);
});
joOut.put("age",arrAge);
return joOut;

View File

@ -8,6 +8,9 @@
name="viewport"
content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no"
/>
<script>
window.yanzhuAppTitle = "数字建安施工";
</script>
<link rel="icon" href="/favicon.ico" />
<title>数字建安施工</title>
<script
@ -217,5 +220,8 @@
</div>
</div>
<script type="module" src="/src/main.js"></script>
<script>
window.document.body.title = window.yanzhuAppTitle;
</script>
</body>
</html>

View File

@ -0,0 +1,55 @@
const fs = require("fs");
const path = require("path");
const config = [
{
name: "app1",
title: "建安施工管理平台",
dirPath: "app1",
},
{
name: "app2",
title: "数字项管+",
dirPath: "app2",
},
];
config.forEach((item) => {
// 在 dist 目录下创建 app 目录
const appDirPath = path.join(__dirname, "dist", item.dirPath);
fs.mkdir(appDirPath, { recursive: true }, (err) => {
if (err) {
console.error("创建目录时出错:", err);
return;
}
console.log("目录创建成功或已存在");
});
const xdAppPath = path.join(__dirname, "dist", "xd");
// 源文件路径
const sourceFilePath = path.join(xdAppPath, "index.html");
// 目标文件路径
const targetFilePath = path.join(appDirPath, "index.html");
// 读取源文件内容
fs.readFile(sourceFilePath, "utf8", (err, data) => {
if (err) {
console.error("读取文件时出错:", err);
return;
}
// 替换文本
const newData = data
.replace(/数字建安施工/g, item.title)
.replaceAll(`src="./`, `src = "/xd/`)
.replaceAll(`href="./`, `href = "/xd/`);
// 将替换后的内容写入目标文件
fs.writeFile(targetFilePath, newData, "utf8", (err) => {
if (err) {
console.error("写入文件时出错:", err);
return;
}
console.log("文件复制并替换成功");
});
});
});

View File

@ -8,8 +8,9 @@
"scripts": {
"dev": "vite",
"dev:prod": "vite --mode production",
"build:prod": "vite build",
"build:prod": "vite build && npm run pkg",
"build:stage": "vite build --mode staging",
"pkg":"node make.cjs",
"preview": "vite preview"
},
"repository": {

View File

@ -1,16 +1,16 @@
<template>
<div class="sidebar-logo-container" :class="{ 'collapse': collapse }" :style="{ backgroundColor: sideTheme === 'theme-dark' ? variables.menuBackground : variables.menuLightBackground }">
<transition name="sidebarLogoFade">
<router-link v-if="collapse" key="collapse" class="sidebar-logo-link" to="/">
<img v-if="logo" :src="logo" class="sidebar-logo" />
<h1 v-else class="sidebar-title" :style="{ color: sideTheme === 'theme-dark' ? variables.logoTitleColor : variables.logoLightTitleColor }">{{ title }}</h1>
</router-link>
<router-link v-else key="expand" class="sidebar-logo-link" to="/">
<img v-if="logo" :src="logo" class="sidebar-logo" />
<h1 class="sidebar-title" :style="{ color: sideTheme === 'theme-dark' ? variables.logoTitleColor : variables.logoLightTitleColor }">{{ title }}</h1>
</router-link>
</transition>
</div>
<div class="sidebar-logo-container" :class="{ 'collapse': collapse }" :style="{ backgroundColor: sideTheme === 'theme-dark' ? variables.menuBackground : variables.menuLightBackground }">
<transition name="sidebarLogoFade">
<router-link v-if="collapse" key="collapse" class="sidebar-logo-link" to="/">
<img v-if="logo" :src="logo" class="sidebar-logo" />
<h1 v-else class="sidebar-title" :style="{ color: sideTheme === 'theme-dark' ? variables.logoTitleColor : variables.logoLightTitleColor }">{{ title }}</h1>
</router-link>
<router-link v-else key="expand" class="sidebar-logo-link" to="/">
<img v-if="logo" :src="logo" class="sidebar-logo" />
<h1 class="sidebar-title" :style="{ color: sideTheme === 'theme-dark' ? variables.logoTitleColor : variables.logoLightTitleColor }">{{ title }}</h1>
</router-link>
</transition>
</div>
</template>
<script setup>
@ -19,63 +19,63 @@ import logo from '@/assets/logo/logo.png'
import useSettingsStore from '@/store/modules/settings'
defineProps({
collapse: {
type: Boolean,
required: true
}
collapse: {
type: Boolean,
required: true,
},
})
const title = import.meta.env.VITE_APP_TITLE;
const settingsStore = useSettingsStore();
const sideTheme = computed(() => settingsStore.sideTheme);
const title = window.yanzhuAppTitle
const settingsStore = useSettingsStore()
const sideTheme = computed(() => settingsStore.sideTheme)
</script>
<style lang="scss" scoped>
.sidebarLogoFade-enter-active {
transition: opacity 1.5s;
transition: opacity 1.5s;
}
.sidebarLogoFade-enter,
.sidebarLogoFade-leave-to {
opacity: 0;
opacity: 0;
}
.sidebar-logo-container {
position: relative;
width: 100%;
height: 50px;
line-height: 50px;
background: #2b2f3a;
text-align: center;
overflow: hidden;
& .sidebar-logo-link {
height: 100%;
position: relative;
width: 100%;
height: 50px;
line-height: 50px;
background: #2b2f3a;
text-align: center;
overflow: hidden;
& .sidebar-logo {
width: 32px;
height: 32px;
vertical-align: middle;
margin-right: 12px;
& .sidebar-logo-link {
height: 100%;
width: 100%;
& .sidebar-logo {
width: 32px;
height: 32px;
vertical-align: middle;
margin-right: 12px;
}
& .sidebar-title {
display: inline-block;
margin: 0;
color: #fff;
font-weight: 600;
line-height: 50px;
font-size: 14px;
font-family: Avenir, Helvetica Neue, Arial, Helvetica, sans-serif;
vertical-align: middle;
}
}
& .sidebar-title {
display: inline-block;
margin: 0;
color: #fff;
font-weight: 600;
line-height: 50px;
font-size: 14px;
font-family: Avenir, Helvetica Neue, Arial, Helvetica, sans-serif;
vertical-align: middle;
&.collapse {
.sidebar-logo {
margin-right: 0px;
}
}
}
&.collapse {
.sidebar-logo {
margin-right: 0px;
}
}
}
</style>

View File

@ -2,11 +2,11 @@ export default {
/**
* 网页标题
*/
title: import.meta.env.VITE_APP_TITLE,
title: window.yanzhuAppTitle,
/**
* 侧边栏主题 深色主题theme-dark浅色主题theme-light
*/
sideTheme: 'theme-dark',
sideTheme: "theme-dark",
/**
* 是否系统布局配置
*/
@ -43,5 +43,5 @@ export default {
* The default is only used in the production env
* If you want to also use it in dev, you can pass ['production', 'development']
*/
errorLog: 'production'
}
errorLog: "production",
};

View File

@ -1,289 +1,294 @@
<template>
<div class="login main-login">
<el-form ref="loginRef" :model="loginForm" :rules="loginRules" class="login-form">
<h3 class="title">数字建安</h3>
<el-form-item prop="username" style="margin-top:60px;">
<el-input v-model="loginForm.username" type="text" size="large" auto-complete="off" placeholder="账号">
<template #prefix><svg-icon icon-class="user" class="el-input__icon input-icon" /></template>
</el-input>
</el-form-item>
<el-form-item prop="password">
<el-input v-model="loginForm.password" type="password" size="large" auto-complete="off" placeholder="密码"
@keyup.enter="handleLogin">
<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">
<el-input v-model="loginForm.code" size="large" auto-complete="off" placeholder="验证码" style="width: 63%"
@keyup.enter="handleLogin">
<template #prefix><svg-icon icon-class="validCode" class="el-input__icon input-icon" /></template>
</el-input>
<div class="login-code">
<div class="login-code-bg"></div>
<img :src="codeUrl" @click="getCode" class="login-code-img" />
<div class="login main-login">
<el-form ref="loginRef" :model="loginForm" :rules="loginRules" class="login-form">
<h3 class="title">{{title}}</h3>
<el-form-item prop="username" style="margin-top:60px;">
<el-input v-model="loginForm.username" type="text" size="large" auto-complete="off" placeholder="账号">
<template #prefix>
<svg-icon icon-class="user" class="el-input__icon input-icon" />
</template>
</el-input>
</el-form-item>
<el-form-item prop="password">
<el-input v-model="loginForm.password" type="password" size="large" auto-complete="off" placeholder="密码" @keyup.enter="handleLogin">
<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">
<el-input v-model="loginForm.code" size="large" auto-complete="off" placeholder="验证码" style="width: 63%" @keyup.enter="handleLogin">
<template #prefix>
<svg-icon icon-class="validCode" class="el-input__icon input-icon" />
</template>
</el-input>
<div class="login-code">
<div class="login-code-bg"></div>
<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-button :loading="loading" class="btn-login" size="large" type="primary" style="width:100%;" @click.prevent="handleLogin">
<span v-if="!loading"> </span>
<span v-else> ...</span>
</el-button>
<div style="float: right;" v-if="register">
<router-link class="link-type" :to="'/register'">立即注册</router-link>
</div>
</el-form-item>
<div class="login-form-bg"></div>
</el-form>
<!-- 底部 -->
<div class="el-login-footer">
<span>Copyright © 2023-2024 陕西研筑信息科技有限公司 All Rights Reserved.</span>
</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-button :loading="loading" class="btn-login" size="large" type="primary" style="width:100%;"
@click.prevent="handleLogin">
<span v-if="!loading"> </span>
<span v-else> ...</span>
</el-button>
<div style="float: right;" v-if="register">
<router-link class="link-type" :to="'/register'">立即注册</router-link>
</div>
</el-form-item>
<div class="login-form-bg"></div>
</el-form>
<!-- 底部 -->
<div class="el-login-footer">
<span>Copyright © 2023-2024 陕西研筑信息科技有限公司 All Rights Reserved.</span>
</div>
</div>
</template>
<script setup>
import { getCodeImg } from "@/api/login";
import Cookies from "js-cookie";
import { encrypt, decrypt } from "@/utils/jsencrypt";
import { getCodeImg } from '@/api/login'
import Cookies from 'js-cookie'
import { encrypt, decrypt } from '@/utils/jsencrypt'
import useUserStore from '@/store/modules/user'
const userStore = useUserStore()
const router = useRouter();
const router = useRouter()
const route = useRoute()
const { proxy } = getCurrentInstance();
const { proxy } = getCurrentInstance()
let title = ref('系统登录')
title.value = window.yanzhuAppTitle
const loginForm = ref({
username: "",
password: "",
rememberMe: false,
code: "",
uuid: ""
});
username: '',
password: '',
rememberMe: false,
code: '',
uuid: '',
})
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("");
const loading = ref(false);
const codeUrl = ref('')
const loading = ref(false)
//
const captchaEnabled = ref(true);
const captchaEnabled = ref(true)
//
const register = ref(false);
const redirect = ref(undefined);
const register = ref(false)
const redirect = ref(undefined)
function handleLogin() {
proxy.$refs.loginRef.validate(valid => {
if (valid) {
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 });
} else {
//
Cookies.remove("username");
Cookies.remove("password");
Cookies.remove("rememberMe");
}
// action
userStore.login(loginForm.value).then(() => {
if (route.query?.redirect) {
location.href = route.query.redirect;
} else {
router.push({ path: "/" });
proxy.$refs.loginRef.validate((valid) => {
if (valid) {
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 })
} else {
//
Cookies.remove('username')
Cookies.remove('password')
Cookies.remove('rememberMe')
}
// action
userStore
.login(loginForm.value)
.then(() => {
if (route.query?.redirect) {
location.href = route.query.redirect
} else {
router.push({ path: '/' })
}
})
.catch(() => {
loading.value = false
//
if (captchaEnabled.value) {
getCode()
}
})
}
}).catch(() => {
loading.value = false;
//
if (captchaEnabled.value) {
getCode();
}
});
}
});
})
}
function getCode() {
getCodeImg().then(res => {
captchaEnabled.value = res.captchaEnabled === undefined ? true : res.captchaEnabled;
if (captchaEnabled.value) {
codeUrl.value = "data:image/gif;base64," + res.img;
loginForm.value.uuid = res.uuid;
}
});
getCodeImg().then((res) => {
captchaEnabled.value = res.captchaEnabled === undefined ? true : res.captchaEnabled
if (captchaEnabled.value) {
codeUrl.value = 'data:image/gif;base64,' + res.img
loginForm.value.uuid = res.uuid
}
})
}
function getCookie() {
const username = Cookies.get("username");
const password = Cookies.get("password");
const rememberMe = Cookies.get("rememberMe");
loginForm.value = {
username: username === undefined ? loginForm.value.username : username,
password: password === undefined ? loginForm.value.password : decrypt(password),
rememberMe: rememberMe === undefined ? false : Boolean(rememberMe)
};
const username = Cookies.get('username')
const password = Cookies.get('password')
const rememberMe = Cookies.get('rememberMe')
loginForm.value = {
username: username === undefined ? loginForm.value.username : username,
password: password === undefined ? loginForm.value.password : decrypt(password),
rememberMe: rememberMe === undefined ? false : Boolean(rememberMe),
}
}
getCode();
getCookie();
getCode()
getCookie()
</script>
<style lang='scss'>
.login.main-login {
display: flex;
justify-content: center;
align-items: center;
height: 100%;
background-image: url("../assets/images/loginbg.jpeg");
background-size: cover;
position: relative;
.title {
margin: 0px auto 30px auto;
text-align: center;
color: #707070;
font-size: 28px;
}
.login-form-bg {
background-image: url("../assets/images/loginbg3.png");
position: absolute;
top: 0%;
width: 80%;
display: flex;
justify-content: center;
align-items: center;
height: 100%;
background-position: center;
background-size: 100%;
background-repeat: no-repeat;
filter: opacity(0.8);
}
.login-form {
border-radius: 6px;
background-image: url("../assets/images/loginbg2.png");
background-size: 100% 100%;
width: 420px;
padding: 50px;
position: absolute;
height: 560px;
right: 10%;
.el-form-item {
position: relative;
z-index: 10;
}
.title {
position: relative;
top: -68px;
color: #336699;
font-weight: bold;
}
.el-form-item--default {
margin-bottom: 40px;
}
.el-input {
height: 30px;
.el-input__wrapper {
background: #113356;
box-shadow: 0px 0px 0px 1px #1262b5;
border-radius: 15px;
.el-input__prefix-inner {
svg {
fill: #45C4DD;
}
}
}
input {
height: 30px;
color: #fff;
}
}
.input-icon {
height: 29px;
width: 14px;
margin-left: 0px;
}
}
.login-tip {
font-size: 13px;
text-align: center;
color: #bfbfbf;
}
.login-code {
width: 33%;
height: 30px;
float: right;
background-image: url('../assets/images/loginbg.jpeg');
background-size: cover;
position: relative;
.login-code-bg {
position: absolute;
background: #113356;
box-shadow: 0px 0px 0px 1px #1262b5;
width: 70px;
height: 30px;
left: 20px;
.title {
margin: 0px auto 30px auto;
text-align: center;
color: #707070;
font-size: 28px;
}
img {
position: relative;
z-index: 10;
cursor: pointer;
vertical-align: middle;
.login-form-bg {
background-image: url('../assets/images/loginbg3.png');
position: absolute;
top: 0%;
width: 80%;
height: 100%;
background-position: center;
background-size: 100%;
background-repeat: no-repeat;
filter: opacity(0.8);
}
}
.el-checkbox__inner {
background: #113356;
border: solid 1px #1262b5;
}
.login-form {
border-radius: 6px;
background-image: url('../assets/images/loginbg2.png');
background-size: 100% 100%;
width: 420px;
padding: 50px;
position: absolute;
height: 560px;
right: 10%;
.el-checkbox__input+.el-checkbox__label {
color: #aaa;
}
.el-form-item {
position: relative;
z-index: 10;
}
.el-checkbox__input.is-checked+.el-checkbox__label {
color: var(--el-checkbox-checked-text-color) !important;
}
.title {
position: relative;
top: -90px;
color: #336699;
font-weight: bold;
}
.btn-login {
background: #113356;
border: solid 1px #1262b5;
height: 36px;
line-height: 36px;
}
.el-form-item--default {
margin-bottom: 40px;
}
.el-login-footer {
height: 40px;
line-height: 40px;
position: fixed;
bottom: 0;
width: 100%;
text-align: center;
color: #fff;
font-family: Arial;
font-size: 12px;
letter-spacing: 1px;
}
.el-input {
height: 30px;
.login-code-img {
height: 30px;
padding-left: 12px;
}
.el-input__wrapper {
background: #113356;
box-shadow: 0px 0px 0px 1px #1262b5;
border-radius: 15px;
.el-input__prefix-inner {
svg {
fill: #45c4dd;
}
}
}
input {
height: 30px;
color: #fff;
}
}
.input-icon {
height: 29px;
width: 14px;
margin-left: 0px;
}
}
.login-tip {
font-size: 13px;
text-align: center;
color: #bfbfbf;
}
.login-code {
width: 33%;
height: 30px;
float: right;
position: relative;
.login-code-bg {
position: absolute;
background: #113356;
box-shadow: 0px 0px 0px 1px #1262b5;
width: 70px;
height: 30px;
left: 20px;
}
img {
position: relative;
z-index: 10;
cursor: pointer;
vertical-align: middle;
}
}
.el-checkbox__inner {
background: #113356;
border: solid 1px #1262b5;
}
.el-checkbox__input + .el-checkbox__label {
color: #aaa;
}
.el-checkbox__input.is-checked + .el-checkbox__label {
color: var(--el-checkbox-checked-text-color) !important;
}
.btn-login {
background: #113356;
border: solid 1px #1262b5;
height: 36px;
line-height: 36px;
}
.el-login-footer {
height: 40px;
line-height: 40px;
position: fixed;
bottom: 0;
width: 100%;
text-align: center;
color: #fff;
font-family: Arial;
font-size: 12px;
letter-spacing: 1px;
}
.login-code-img {
height: 30px;
padding-left: 12px;
}
}
</style>

View File

@ -1,27 +1,27 @@
import { defineConfig, loadEnv } from 'vite'
import path from 'path'
import createVitePlugins from './vite/plugins'
import { defineConfig, loadEnv } from "vite";
import path from "path";
import createVitePlugins from "./vite/plugins";
// https://vitejs.dev/config/
export default defineConfig(({ mode, command }) => {
const env = loadEnv(mode, process.cwd())
const { VITE_APP_ENV } = env
const env = loadEnv(mode, process.cwd());
const { VITE_APP_ENV } = env;
return {
// 部署生产环境和开发环境下的URL。
// 默认情况下vite 会假设你的应用是被部署在一个域名的根路径上
// 例如 https://www.ruoyi.vip/。如果应用被部署在一个子路径上,你就需要用这个选项指定这个子路径。例如,如果你的应用被部署在 https://www.ruoyi.vip/admin/,则设置 baseUrl 为 /admin/。
base: VITE_APP_ENV === 'production' ? '/xd/' : '/xd/',
plugins: createVitePlugins(env, command === 'build'),
base: VITE_APP_ENV === "production" ? "/xd/" : "/xd/",
plugins: createVitePlugins(env, command === "build"),
resolve: {
// https://cn.vitejs.dev/config/#resolve-alias
alias: {
// 设置路径
'~': path.resolve(__dirname, './'),
"~": path.resolve(__dirname, "./"),
// 设置别名
'@': path.resolve(__dirname, './src')
"@": path.resolve(__dirname, "./src"),
},
// https://cn.vitejs.dev/config/#resolve-extensions
extensions: ['.mjs', '.js', '.ts', '.jsx', '.tsx', '.json', '.vue']
extensions: [".mjs", ".js", ".ts", ".jsx", ".tsx", ".json", ".vue"],
},
// vite 相关配置
server: {
@ -30,56 +30,59 @@ export default defineConfig(({ mode, command }) => {
open: true,
proxy: {
"/prod-api": {
//target: "http://localhost:8080",
target: 'http://62.234.3.186',
changeOrigin: true,
pathRewrite: {
"^/prod-api": "/",
},
},
// https://cn.vitejs.dev/config/#server-proxy
'/dev-api': {
target: 'http://localhost:8080',
//target: "http://localhost:8080",
target: "http://62.234.3.186",
changeOrigin: true,
rewrite: (p) => p.replace(/^\/dev-api/, '')
pathRewrite: {
"^/prod-api": "/",
},
},
'/statics': {
target: VITE_APP_ENV === 'production'?'http://62.234.3.186':`http://localhost:9300`,
// https://cn.vitejs.dev/config/#server-proxy
"/dev-api": {
target: "http://localhost:8080",
changeOrigin: true,
rewrite: (p) => p.replace(/^\/dev-api/, ""),
},
"/statics": {
target:
VITE_APP_ENV === "production"
? "http://62.234.3.186"
: `http://localhost:9300`,
//target: 'http://62.234.3.186',
changeOrigin: true,
pathRewrite: {
"^/statics": "/",
},
},
}
},
},
//fix:error:stdin>:7356:1: warning: "@charset" must be the first rule in the file
css: {
postcss: {
plugins: [
{
postcssPlugin: 'internal:charset-removal',
postcssPlugin: "internal:charset-removal",
AtRule: {
charset: (atRule) => {
if (atRule.name === 'charset') {
if (atRule.name === "charset") {
atRule.remove();
}
}
}
}
]
}
},
},
},
},
],
},
},
optimizeDeps: {
include: ['@/lib/vform/designer.umd.js'] //此处路径必须跟main.js中import路径完全一致
},
build: {
include: ["@/lib/vform/designer.umd.js"], //此处路径必须跟main.js中import路径完全一致
},
build: {
outDir: "dist/xd/",
/* 其他build生产打包配置省略 */
//...
commonjsOptions: {
include: /node_modules|lib/ //这里记得把lib目录加进来否则生产打包会报错
}
}
}
})
include: /node_modules|lib/, //这里记得把lib目录加进来否则生产打包会报错
},
},
};
});