@@ -31,9 +31,6 @@ VUE_CLI_BABEL_TRANSPILE_MODULES = true | |||
# 多租户的开关 | |||
VUE_APP_TENANT_ENABLE = true | |||
# 验证码的开关 | |||
VUE_APP_CAPTCHA_ENABLE = true | |||
# 文档的开关 | |||
VUE_APP_DOC_ENABLE = true | |||
@@ -14,9 +14,6 @@ VUE_CLI_BABEL_TRANSPILE_MODULES = true | |||
# 多租户的开关 | |||
VUE_APP_TENANT_ENABLE = true | |||
# 验证码的开关 | |||
VUE_APP_CAPTCHA_ENABLE = true | |||
# 文档的开关 | |||
VUE_APP_DOC_ENABLE = true | |||
@@ -28,9 +28,6 @@ VUE_APP_APP_NAME ='yudao-admin' | |||
# 多租户的开关 | |||
VUE_APP_TENANT_ENABLE = true | |||
# 验证码的开关 | |||
VUE_APP_CAPTCHA_ENABLE = true | |||
# 文档的开关 | |||
VUE_APP_DOC_ENABLE = false | |||
@@ -15,9 +15,6 @@ PUBLIC_PATH = 'http://static.yudao.iocoder.cn/' | |||
# 多租户的开关 | |||
VUE_APP_TENANT_ENABLE = true | |||
# 验证码的开关 | |||
VUE_APP_CAPTCHA_ENABLE = true | |||
# 文档的开关 | |||
VUE_APP_DOC_ENABLE = false | |||
@@ -17,9 +17,6 @@ VUE_APP_APP_NAME ='/admin-ui-vue2/' | |||
# 多租户的开关 | |||
VUE_APP_TENANT_ENABLE = true | |||
# 验证码的开关 | |||
VUE_APP_CAPTCHA_ENABLE = true | |||
# 文档的开关 | |||
VUE_APP_DOC_ENABLE = true | |||
@@ -187,19 +187,6 @@ export function getTenantEnable() { | |||
return process.env.VUE_APP_TENANT_ENABLE || true; | |||
} | |||
/** | |||
* 获得验证码功能是否开启 | |||
*/ | |||
export function getCaptchaEnable() { | |||
if (process.env.VUE_APP_CAPTCHA_ENABLE === "true") { | |||
return true; | |||
} | |||
if (process.env.VUE_APP_CAPTCHA_ENABLE === "false") { | |||
return false; | |||
} | |||
return process.env.VUE_APP_CAPTCHA_ENABLE || true; | |||
} | |||
/** | |||
* 获得文档是否开启 | |||
*/ | |||
@@ -0,0 +1,228 @@ | |||
<!-- | |||
filename: chart.vue | |||
author: liubin | |||
date: 2023-11-29 09:03:01 | |||
description: | |||
--> | |||
<template> | |||
<div class="analysis-chart"> | |||
<!-- tt ct 选择 --> | |||
<el-button | |||
v-for="(item, index) in ['设备CT', '设备TT', '产线CT', '产线TT']" | |||
:key="index" | |||
:class="[index == activeIndex ? 'activeButton' : '']" | |||
@click="activeIndex = index"> | |||
{{ item }} | |||
</el-button> | |||
<!-- chart --> | |||
<div id="chart" ref="chartDiv" class="chart" style="margin-top: 12px" /> | |||
</div> | |||
</template> | |||
<script> | |||
import * as echarts from 'echarts'; | |||
export default { | |||
name: 'AnalysisChart', | |||
components: {}, | |||
props: ['daterange', 'tableData'], | |||
data() { | |||
return { | |||
activeIndex: 0, | |||
chart: null, | |||
templateOption: { | |||
tooltip: { | |||
trigger: 'axis', | |||
}, | |||
legend: { | |||
icon: 'roundRect', | |||
itemWidth: 12, | |||
itemHeight: 12, | |||
}, | |||
grid: { | |||
top: '12%', | |||
left: '6%', | |||
right: '6%', | |||
bottom: '12%', | |||
}, | |||
xAxis: { | |||
name: '时间', | |||
axisLabel: { | |||
margin: 12, | |||
rotate: -8, | |||
}, | |||
axisTicks: { | |||
show: false, | |||
}, | |||
data: this.daterange || [ | |||
'2020-01-02', | |||
'2020-02-02', | |||
'2020-03-02', | |||
'2020-04-02', | |||
], | |||
}, | |||
yAxis: { | |||
name: ['设备CT', '设备TT', '产线CT', '产线TT'][this.activeIndex], | |||
nameLocation: 'end', | |||
nameGap: 28, | |||
nameTextStyle: { | |||
fontSize: 14, | |||
align: 'right', | |||
}, | |||
axisLine: { | |||
show: true, | |||
lineStyle: { | |||
color: '#333', | |||
opacity: 0.6, | |||
}, | |||
}, | |||
}, | |||
series: [ | |||
{ | |||
name: 'der Hund', | |||
type: 'line', | |||
data: [15, undefined, 36, 11], | |||
}, | |||
{ | |||
name: 'die Katze', | |||
type: 'line', | |||
data: [5, 2, 6, 3], | |||
}, | |||
{ | |||
name: 'die Maus', | |||
type: 'line', | |||
data: [11, 12, 13, 10], | |||
}, | |||
], | |||
}, | |||
}; | |||
}, | |||
mounted() { | |||
this.initChart(); | |||
}, | |||
deactivated() {}, | |||
watch: { | |||
activeIndex(val) { | |||
this.initChart(val); | |||
}, | |||
}, | |||
methods: { | |||
/** | |||
* | |||
* @param {object} row 表格的每一列 | |||
* @param {string} key 表格列prop的后缀 | |||
*/ | |||
getListFromTableRow(row, key = '_eq_ct') { | |||
const list = []; | |||
for (const prop of Object.keys(row).sort()) { | |||
if (prop.endsWith(key)) { | |||
list.push(row[prop]); | |||
} | |||
} | |||
return list; | |||
}, | |||
/** 初始化/设置 图表 */ | |||
initChart(val) { | |||
console.log('tableData', this.tableData); | |||
if (!this.chart) this.chart = echarts.init(this.$refs.chartDiv); | |||
switch (val) { | |||
case 0: | |||
const eqCt = this.tableData.map((row) => ({ | |||
name: row.equName, | |||
type: 'line', | |||
symbol: 'circle', | |||
symbolSize: 8, | |||
data: this.getListFromTableRow(row, '_eq_ct'), | |||
})); | |||
this.chart.setOption({ | |||
...this.templateOption, | |||
yAxis: { ...this.templateOption.yAxis, name: '设备CT' }, | |||
series: eqCt, | |||
}); | |||
break; | |||
case 1: | |||
const eqTt = this.tableData.map((row) => ({ | |||
name: row.equName, | |||
type: 'line', | |||
symbol: 'circle', | |||
symbolSize: 8, | |||
data: this.getListFromTableRow(row, '_eq_tt'), | |||
})); | |||
this.chart.setOption({ | |||
...this.templateOption, | |||
yAxis: { ...this.templateOption.yAxis, name: '设备TT' }, | |||
series: eqTt, | |||
}); | |||
break; | |||
case 2: | |||
const plCt = this.tableData.map((row) => ({ | |||
name: row.equName, | |||
type: 'line', | |||
symbol: 'circle', | |||
symbolSize: 8, | |||
data: this.getListFromTableRow(row, '_pl_ct'), | |||
})); | |||
this.chart.setOption({ | |||
...this.templateOption, | |||
yAxis: { ...this.templateOption.yAxis, name: '产线CT' }, | |||
series: plCt, | |||
}); | |||
break; | |||
case 3: | |||
const plTt = this.tableData.map((row) => ({ | |||
name: row.equName, | |||
type: 'line', | |||
symbol: 'circle', | |||
symbolSize: 8, | |||
data: this.getListFromTableRow(row, '_pl_tt'), | |||
})); | |||
this.chart.setOption({ | |||
...this.templateOption, | |||
yAxis: { ...this.templateOption.yAxis, name: '产线TT' }, | |||
series: plTt, | |||
}); | |||
break; | |||
default: | |||
const eqCt2 = this.tableData.map((row) => ({ | |||
name: row.equName, | |||
type: 'line', | |||
symbol: 'circle', | |||
symbolSize: 8, | |||
data: this.getListFromTableRow(row, '_eq_ct'), | |||
})); | |||
this.chart.setOption({ | |||
...this.templateOption, | |||
yAxis: { ...this.templateOption.yAxis, name: '设备CT' }, | |||
series: eqCt2, | |||
}); | |||
} | |||
}, | |||
}, | |||
}; | |||
</script> | |||
<style scoped> | |||
.analysis-chart { | |||
width: 100%; | |||
height: 100%; | |||
} | |||
.analysis-chart >>> .el-button { | |||
background: #f1f1f1; | |||
color: #333; | |||
transition: all 0.3s; | |||
border: none; | |||
&.activeButton, | |||
&:hover { | |||
background: #0b58ff; | |||
color: #fff; | |||
} | |||
} | |||
#chart { | |||
height: 100%; | |||
/* background: #ccc; */ | |||
} | |||
</style> |
@@ -1,51 +1,56 @@ | |||
<template> | |||
<div class="app-container"> | |||
<div class="app-container" style="flex: 1; height: 1px"> | |||
<search-bar | |||
:formConfigs="formConfig" | |||
ref="searchBarForm" | |||
@headBtnClick="handleSearchBarBtnClick" /> | |||
<!-- <div v-if="tableData.length"> --> | |||
<el-tabs | |||
v-model="activeName" | |||
@tab-click="handleTabClick" | |||
style="height: 100%"> | |||
<el-tab-pane :label="'\u2002数据列表\u2002'" name="table"> | |||
<!-- @emitFun="handleEmitFun"> --> | |||
<base-table | |||
v-if="activeName == 'table'" | |||
:span-method="mergeColumnHandler" | |||
:page="1" | |||
:limit="999" | |||
:table-props="tableProps" | |||
:table-data="tableData" /> | |||
</el-tab-pane> | |||
<el-tab-pane :label="'\u3000产线平衡分析图\u3000'" name="graph"> | |||
<div class="graph" style="height: 100%"> | |||
<!-- graph --> | |||
<!-- <Graph | |||
<div class="custom-tabs" style=""> | |||
<el-tabs | |||
v-model="activeName" | |||
@tab-click="handleTabClick" | |||
style="height: 100%"> | |||
<el-tab-pane :label="'\u2002数据列表\u2002'" name="table"> | |||
<base-table | |||
v-if="activeName == 'table' && ready" | |||
:span-method="mergeRow" | |||
:page="1" | |||
:limit="999" | |||
:table-props="tableProps" | |||
:table-data="tableData" /> | |||
<div v-if="tableData.length == 0" class="no-data-bg"></div> | |||
</el-tab-pane> | |||
<el-tab-pane :label="'\u3000产线平衡分析图\u3000'" name="graph"> | |||
<div class="graph" style="height: 800px"> | |||
<!-- graph --> | |||
<AnalysisChart | |||
v-if="activeName == 'graph'" | |||
:table-data="tableData" | |||
:daterange="dateArr"></AnalysisChart> | |||
<!-- <div v-else class="no-data-bg"></div> --> | |||
<!-- <Graph | |||
v-if="list.length" | |||
:equipment-list="list" | |||
:render="renderKey" /> --> | |||
<!-- <BalanceChart ref="lineChart" /> --> | |||
<div v-if="list.length == 0" class="no-data-bg"></div> | |||
</div> | |||
</el-tab-pane> | |||
</el-tabs> | |||
<!-- <SearchBar :formConfigs="[{ label: '产线平衡分析图', type: 'title' }]" /> --> | |||
<!-- </div> | |||
<div v-else class="no-data-bg"></div> --> | |||
<!-- <BalanceChart ref="lineChart" /> --> | |||
<!-- <div v-if="list.length == 0" class="no-data-bg"></div> --> | |||
</div> | |||
</el-tab-pane> | |||
</el-tabs> | |||
</div> | |||
</div> | |||
</template> | |||
<script> | |||
import BalanceChart from '../balanceChart'; | |||
import basicPageMixin from '@/mixins/lb/basicPageMixin'; | |||
import AnalysisChart from './chart.vue'; | |||
export default { | |||
components: { | |||
BalanceChart, | |||
AnalysisChart, | |||
}, | |||
mixins: [basicPageMixin], | |||
data() { | |||
@@ -98,6 +103,13 @@ export default { | |||
startTime: null, | |||
endTime: null, | |||
}, | |||
sectionMap: {}, | |||
lastSection: null, | |||
currRowIndex: 0, | |||
spanArr: [], | |||
// 保存时间列表 | |||
dateArr: [], | |||
ready: false, | |||
}; | |||
}, | |||
@@ -156,11 +168,19 @@ export default { | |||
const { data, nameData } = await this.getCT(); | |||
await this.buildProps(nameData); | |||
await this.buildTableData(data); | |||
const xxxx = this.tableData; | |||
debugger; | |||
this.tableData = this.tableData.sort((a, b) => { | |||
if (a.sectionName < b.sectionName) return -1; | |||
return 1; | |||
}); | |||
// const p = this.tableProps | |||
// const d = this.tableData | |||
// debugger; | |||
this.ready = true; | |||
}, | |||
buildProps(nameData) { | |||
this.initTableProps(); | |||
this.dateArr = []; | |||
return new Promise((resolve, reject) => { | |||
try { | |||
const dateArr = Array.from( | |||
@@ -199,7 +219,7 @@ export default { | |||
], | |||
}); | |||
}); | |||
this.dateArr = dateArr; | |||
resolve(); | |||
} catch (err) { | |||
reject(err); | |||
@@ -208,38 +228,68 @@ export default { | |||
}, | |||
async buildTableData(data) { | |||
/** 处理 工段 分组 */ | |||
const sectionList = data.map((item) => {}); | |||
}, | |||
this.tableData = []; | |||
const sectionArr = Array.from( | |||
new Set(data.map((item) => item.sectionName)) | |||
).sort(); | |||
setRowSpan(arr) { | |||
let count = 0; | |||
arr.forEach((item, index) => { | |||
if (index === 0) { | |||
this.spanArr.push(1); | |||
} else { | |||
if (item === arr[index - 1]) { | |||
this.spanArr[count] += 1; | |||
this.spanArr.push(0); | |||
} else { | |||
count = index; | |||
this.spanArr.push(1); | |||
} | |||
const sectionMap = sectionArr.reduce( | |||
(sum, curr) => ({ ...sum, [curr]: 0 }), | |||
{} | |||
); | |||
console.log('sectionArr', sectionArr); | |||
console.log('sectionMap', sectionMap); | |||
let spanArr = Array.from(sectionArr, () => 0); | |||
return new Promise((resolve, reject) => { | |||
/** 处理 工段 分组 */ | |||
data.map((item) => { | |||
sectionMap[item.sectionName]++; | |||
/** 处理 设备 */ | |||
const row = { | |||
equName: item.equName, | |||
sectionName: item.sectionName, | |||
}; | |||
item.data.forEach((eq) => { | |||
const date = eq.dynamicName; | |||
eq.children.forEach((sub) => { | |||
if (sub.dynamicName == '设备CT') | |||
row[date + '_eq_ct'] = sub.dynamicValue; | |||
if (sub.dynamicName == '设备TT') | |||
row[date + '_eq_tt'] = sub.dynamicValue; | |||
if (sub.dynamicName == '产线CT') | |||
row[date + '_pl_ct'] = sub.dynamicValue; | |||
if (sub.dynamicName == '产线TT') | |||
row[date + '_pl_tt'] = sub.dynamicValue; | |||
}); | |||
}); | |||
this.tableData.push(row); | |||
}); | |||
/** 生成span数组 */ | |||
const tmp = [...spanArr]; | |||
for (const [index, key] of sectionArr.entries()) { | |||
tmp[index + 1] = tmp[index] + sectionMap[key]; | |||
} | |||
console.log('tep', tmp); | |||
spanArr = tmp; | |||
this.sectionMap = sectionMap; | |||
this.spanArr = spanArr; | |||
resolve(); | |||
}); | |||
}, | |||
/** 合并table列的规则 */ | |||
mergeColumnHandler({ row, column, rowIndex, columnIndex }) { | |||
if (columnIndex == 0) { | |||
if (this.spanArr[rowIndex]) { | |||
return [ | |||
this.spanArr[rowIndex], // row span | |||
1, // col span | |||
]; | |||
} else { | |||
return [0, 0]; | |||
mergeRow({ row, column, rowIndex, columnIndex }) { | |||
if (columnIndex == 1) { | |||
const span = this.sectionMap[row.sectionName]; | |||
if (this.spanArr.includes(rowIndex)) { | |||
console.log('span...'); | |||
return [span, 1]; | |||
} | |||
return [0, 0]; | |||
} | |||
}, | |||
@@ -319,6 +369,7 @@ export default { | |||
// this.dataListLoading = false; | |||
}); | |||
}, | |||
handleSearchBarBtnClick(btn) { | |||
switch (btn.btnName) { | |||
case 'search': | |||
@@ -381,3 +432,23 @@ export default { | |||
}, | |||
}; | |||
</script> | |||
<style scoped> | |||
.custom-tabs >>> .el-tabs__header { | |||
margin-bottom: 8px; | |||
display: inline-block; | |||
transform: translateY(-12px); | |||
} | |||
.custom-tabs >>> .el-tabs__item { | |||
padding-left: 0px !important; | |||
padding-right: 0px !important; | |||
line-height: 36px !important; | |||
height: 36px; | |||
} | |||
.custom-tabs >>> .el-tabs__content { | |||
height: calc(100% - 42px); | |||
} | |||
.custom-tabs >>> .el-tab-pane { | |||
height: 100%; | |||
} | |||
</style> |
@@ -80,6 +80,8 @@ | |||
<el-select | |||
v-if="open" | |||
style="width: 100%" | |||
filterable | |||
clearable | |||
v-model="queryParams.equipmentId" | |||
placeholder="请选择一个设备"> | |||
<el-option | |||
@@ -80,13 +80,6 @@ | |||
<!-- 表单 --> | |||
<div class="form-cont"> | |||
<el-tabs | |||
class="form" | |||
v-model="loginForm.loginType" | |||
style="float: none"> | |||
<el-tab-pane label="账号密码登录" name="uname"></el-tab-pane> | |||
<el-tab-pane label="短信验证码登录" name="sms"></el-tab-pane> | |||
</el-tabs> | |||
<div style=""> | |||
<el-form | |||
ref="loginForm" | |||
@@ -106,7 +99,7 @@ | |||
</el-input> | |||
</el-form-item> | |||
<!-- 账号密码登录 --> | |||
<div v-if="loginForm.loginType === 'uname'"> | |||
<div> | |||
<el-form-item prop="username"> | |||
<el-input | |||
v-model="loginForm.username" | |||
@@ -139,56 +132,6 @@ | |||
</el-checkbox> | |||
</div> | |||
<!-- 短信验证码登录 --> | |||
<div v-if="loginForm.loginType === 'sms'"> | |||
<el-form-item prop="mobile"> | |||
<el-input | |||
v-model="loginForm.mobile" | |||
type="text" | |||
auto-complete="off" | |||
placeholder="请输入手机号"> | |||
<!-- <svg-icon | |||
slot="prefix" | |||
icon-class="phone" | |||
class="el-input__icon input-icon" /> --> | |||
</el-input> | |||
</el-form-item> | |||
<el-form-item prop="mobileCode"> | |||
<el-input | |||
v-model="loginForm.mobileCode" | |||
type="text" | |||
auto-complete="off" | |||
placeholder="短信验证码" | |||
class="sms-login-mobile-code-prefix" | |||
@keyup.enter.native="handleLogin"> | |||
<!-- <template> | |||
<svg-icon | |||
slot="prefix" | |||
icon-class="password" | |||
class="el-input__icon input-icon" /> | |||
</template> --> | |||
<template slot="suffix"> | |||
<span | |||
v-if="mobileCodeTimer <= 0" | |||
class="getMobileCode" | |||
@click="getSmsCode" | |||
style=" | |||
cursor: pointer; | |||
color: #0b58ff; | |||
font-size: calc(12 * 0.12vh); | |||
line-height: calc(54 * 0.12vh); | |||
padding-right: calc(10 * 0.12vh); | |||
"> | |||
获取验证码 | |||
</span> | |||
<span v-if="mobileCodeTimer > 0" class="getMobileCode"> | |||
{{ mobileCodeTimer }}秒后可重新获取 | |||
</span> | |||
</template> | |||
</el-input> | |||
</el-form-item> | |||
</div> | |||
<!-- 下方的登录按钮 --> | |||
<el-form-item | |||
id="button-form-item" | |||
@@ -227,13 +170,6 @@ | |||
</div> | |||
</div> | |||
</div> | |||
<!-- 图形验证码 --> | |||
<Verify | |||
ref="verify" | |||
:captcha-type="'blockPuzzle'" | |||
:img-size="{ width: '400px', height: '200px' }" | |||
@success="handleLogin" /> | |||
</div> | |||
</template> | |||
@@ -241,7 +177,7 @@ | |||
import { sendSmsCode, socialAuthRedirect } from '@/api/login'; | |||
import { getTenantIdByName } from '@/api/system/tenant'; | |||
import { SystemUserSocialTypeEnum } from '@/utils/constants'; | |||
import { getCaptchaEnable, getTenantEnable } from '@/utils/ruoyi'; | |||
import { getTenantEnable } from '@/utils/ruoyi'; | |||
import { | |||
getPassword, | |||
getRememberMe, | |||
@@ -269,7 +205,7 @@ export default { | |||
data() { | |||
return { | |||
codeUrl: '', | |||
captchaEnable: true, | |||
captchaEnable: false, | |||
tenantEnable: true, | |||
mobileCodeTimer: 0, | |||
loginForm: { | |||
@@ -347,8 +283,6 @@ export default { | |||
} | |||
}); | |||
} | |||
// 验证码开关 | |||
this.captchaEnable = getCaptchaEnable(); | |||
// 重定向地址 | |||
this.redirect = this.$route.query.redirect | |||
? decodeURIComponent(this.$route.query.redirect) | |||
@@ -360,15 +294,7 @@ export default { | |||
}, | |||
methods: { | |||
getCode() { | |||
// 情况一,未开启:则直接登录 | |||
if (!this.captchaEnable) { | |||
this.handleLogin({}); | |||
return; | |||
} | |||
// 情况二,已开启:则展示验证码;只有完成验证码的情况,才进行登录 | |||
// 弹出验证码 | |||
this.$refs.verify.show(); | |||
this.handleLogin({}); | |||
}, | |||
getCookie() { | |||
const username = getUsername(); | |||
@@ -522,4 +448,7 @@ export default { | |||
top: 22%; | |||
} | |||
} | |||
.form-cont { | |||
padding-top: 40px; | |||
} | |||
</style> |
@@ -115,12 +115,12 @@ export default { | |||
vm.$set( | |||
vm.searchBarFormConfig[0], | |||
'defaultSelect', | |||
to.params.equipmentCode | |||
to.params.equipmentName | |||
); | |||
vm.$set( | |||
vm.searchBarFormConfig[1], | |||
'defaultSelect', | |||
to.params.equipmentName | |||
to.params.equipmentCode | |||
); | |||
vm.handleQuery(); | |||
}); | |||
@@ -33,7 +33,7 @@ | |||
:data-value="fc.id" | |||
class="factory-list__item" | |||
:class="{ 'is-current': fc.id == currentFactory?.id }"> | |||
<span> | |||
<span :data-value="fc.id"> | |||
{{ fc.label }} | |||
</span> | |||
<svg-icon | |||
@@ -98,9 +98,7 @@ | |||
</base-table> | |||
</el-tab-pane> | |||
<el-tab-pane :label="'\u3000柱状图\u3000'" name="graph"> | |||
<div | |||
class="graph" | |||
style="height: 100%;"> | |||
<div class="graph" style="height: 100%"> | |||
<!-- graph --> | |||
<Graph | |||
v-if="list.length" | |||