20251213:数据中心-历史记录-设备-导出历史数据

This commit is contained in:
George 2025-12-13 19:33:12 +08:00
parent d965eab5d6
commit d0526b4e46
18 changed files with 315 additions and 69 deletions

View File

@ -158,11 +158,23 @@ public class DeviceDebugLogAspect {
if (msg instanceof byte[]) {
sourceData = ByteBufUtil.hexDump((byte[]) msg);
} else {
sourceData = msg.toString();
String msgStr = msg.toString();
// 如果dataType是ascii,需要将ASCII字符串转换为HEX格式用于显示
if ("ascii".equalsIgnoreCase(deviceMessage.getDataType())) {
// ASCII字符串转HEX
sourceData = asciiToHex(msgStr);
} else {
// 其他情况直接使用原字符串(可能是HEX格式)
sourceData = msgStr;
}
}
}
} catch (Exception ex) {
log.warn("处理原始数据失败: {}", ex.getMessage());
// 如果转换失败,至少保存原始字符串
if (deviceMessage.getMessage() != null) {
sourceData = deviceMessage.getMessage().toString();
}
}
String errorMsg = e.getMessage();
@ -395,6 +407,37 @@ public class DeviceDebugLogAspect {
}
}
/**
* 将ASCII字符串转换为HEX字符串
* @param asciiStr ASCII字符串
* @return HEX字符串(大写,每两个字符一组,用空格分隔)
*/
private String asciiToHex(String asciiStr) {
if (StringUtils.isEmpty(asciiStr)) {
return "";
}
try {
StringBuilder hex = new StringBuilder();
for (int i = 0; i < asciiStr.length(); i++) {
char c = asciiStr.charAt(i);
String hexByte = Integer.toHexString(c & 0xFF).toUpperCase();
if (hexByte.length() == 1) {
hex.append("0");
}
hex.append(hexByte);
// 每两个字节之间加一个空格,便于阅读
if (i < asciiStr.length() - 1) {
hex.append(" ");
}
}
return hex.toString();
} catch (Exception e) {
log.warn("ASCII转HEX失败: {}, ASCII字符串: {}", e.getMessage(),
StringUtils.isNotEmpty(asciiStr) ? StringUtils.substring(asciiStr, 0, 50) : "");
return "";
}
}
/**
* 将16进制字符串转换为ASCII字符串
* @param hexStr 16进制字符串(可能包含空格)

View File

@ -159,8 +159,9 @@ public class DataCenterController {
return;
}
// 获取变量名称映射(identifier -> modelName)
// 获取变量名称映射(identifier -> modelName)和数据类型映射(identifier -> datatype)
Map<String, String> identifierNameMap = new LinkedHashMap<>();
Map<String, String> identifierTypeMap = new LinkedHashMap<>(); // 存储identifier到数据类型的映射
List<String> headerList = new ArrayList<>();
if (deviceHistoryParam.getIdentifierList() != null && !deviceHistoryParam.getIdentifierList().isEmpty()) {
@ -169,7 +170,7 @@ public class DataCenterController {
.map(DeviceHistoryParam.IdentifierVO::getIdentifier)
.collect(Collectors.toList());
// 查询物模型获取中文名称
// 查询物模型获取中文名称和数据类型
if (deviceHistoryParam.getDeviceId() != null) {
List<ThingsModelDTO> thingsModelList = deviceService.listThingsModel(deviceHistoryParam.getDeviceId());
Map<String, ThingsModelDTO> thingsModelMap = thingsModelList.stream()
@ -180,6 +181,12 @@ public class DataCenterController {
String headerName = thingsModel != null && StringUtils.isNotEmpty(thingsModel.getModelName())
? thingsModel.getModelName() : identifier;
identifierNameMap.put(identifier, headerName);
// 获取数据类型
String dataType = "string"; // 默认字符串类型
if (thingsModel != null && thingsModel.getDatatype() != null && StringUtils.isNotEmpty(thingsModel.getDatatype().getType())) {
dataType = thingsModel.getDatatype().getType();
}
identifierTypeMap.put(identifier, dataType);
headerList.add(headerName);
}
} else {
@ -187,6 +194,7 @@ public class DataCenterController {
headerList.addAll(identifierList);
for (String identifier : identifierList) {
identifierNameMap.put(identifier, identifier);
identifierTypeMap.put(identifier, "string"); // 默认字符串类型
}
}
} else if (!dataList.isEmpty()) {
@ -204,7 +212,7 @@ public class DataCenterController {
}
}
// 查询物模型获取中文名称
// 查询物模型获取中文名称和数据类型
if (deviceHistoryParam.getDeviceId() != null) {
List<ThingsModelDTO> thingsModelList = deviceService.listThingsModel(deviceHistoryParam.getDeviceId());
Map<String, ThingsModelDTO> thingsModelMap = thingsModelList.stream()
@ -215,6 +223,12 @@ public class DataCenterController {
String headerName = thingsModel != null && StringUtils.isNotEmpty(thingsModel.getModelName())
? thingsModel.getModelName() : identifier;
identifierNameMap.put(identifier, headerName);
// 获取数据类型
String dataType = "string"; // 默认字符串类型
if (thingsModel != null && thingsModel.getDatatype() != null && StringUtils.isNotEmpty(thingsModel.getDatatype().getType())) {
dataType = thingsModel.getDatatype().getType();
}
identifierTypeMap.put(identifier, dataType);
headerList.add(headerName);
}
} else {
@ -222,6 +236,7 @@ public class DataCenterController {
headerList.addAll(identifierSet);
for (String identifier : identifierSet) {
identifierNameMap.put(identifier, identifier);
identifierTypeMap.put(identifier, "string"); // 默认字符串类型
}
}
}
@ -246,11 +261,19 @@ public class DataCenterController {
}
}
// 按照identifierNameMap的顺序添加数据
// 按照identifierNameMap的顺序添加数据,并根据数据类型转换
for (Map.Entry<String, String> entry : identifierNameMap.entrySet()) {
String identifier = entry.getKey();
Object value = valueMap.get(identifier);
rowData.add(value != null ? value : "");
// 根据数据类型转换值
if (value != null) {
String dataType = identifierTypeMap.getOrDefault(identifier, "string");
Object convertedValue = convertValueByType(value, dataType);
rowData.add(convertedValue);
} else {
rowData.add("");
}
}
}
exportDataList.add(rowData);
@ -280,4 +303,87 @@ public class DataCenterController {
excelWriter.finish();
}
/**
* 根据数据类型转换值
* @param value 原始值
* @param dataType 数据类型(integer、decimal、string、bool、enum等)
* @return 转换后的值
*/
private Object convertValueByType(Object value, String dataType) {
if (value == null) {
return "";
}
try {
switch (dataType) {
case "integer":
// 整数类型:转换为Integer
if (value instanceof Number) {
return ((Number) value).intValue();
} else if (value instanceof String) {
String str = ((String) value).trim();
if (str.isEmpty()) {
return "";
}
// 尝试解析为整数
try {
// 如果是小数,先转double再转int
if (str.contains(".")) {
return (int) Double.parseDouble(str);
}
return Integer.parseInt(str);
} catch (NumberFormatException e) {
// 如果无法解析,返回原值
return value;
}
}
return value;
case "decimal":
// 小数类型:转换为Double
if (value instanceof Number) {
return ((Number) value).doubleValue();
} else if (value instanceof String) {
String str = ((String) value).trim();
if (str.isEmpty()) {
return "";
}
try {
return Double.parseDouble(str);
} catch (NumberFormatException e) {
// 如果无法解析,返回原值
return value;
}
}
return value;
case "bool":
// 布尔类型:转换为Boolean或字符串
if (value instanceof Boolean) {
return value;
} else if (value instanceof Number) {
return ((Number) value).intValue() != 0;
} else if (value instanceof String) {
String str = ((String) value).trim().toLowerCase();
if ("true".equals(str) || "1".equals(str) || "yes".equals(str)) {
return true;
} else if ("false".equals(str) || "0".equals(str) || "no".equals(str)) {
return false;
}
return value;
}
return value;
case "string":
case "enum":
default:
// 字符串类型和其他类型:保持原样或转为字符串
return value.toString();
}
} catch (Exception e) {
// 转换失败时返回原值
return value;
}
}
}

View File

@ -1,6 +1,6 @@
# 开发环境配置
# 页面标题
VUE_APP_TITLE = FastBee物联网平台
VUE_APP_TITLE = 岩安测控数据平台
# 开发服务器端口
port = 80

View File

@ -1,5 +1,5 @@
# 页面标题
VUE_APP_TITLE = FastBee物联网系统
VUE_APP_TITLE = 岩安测控数据平台
# 生产环境配置
ENV = 'production'

View File

@ -1,5 +1,5 @@
# 页面标题
VUE_APP_TITLE = FastBee物联网系统
VUE_APP_TITLE = 岩安测控数据平台
NODE_ENV = production

View File

@ -1,7 +1,7 @@
{
"name": "fastbee",
"version": "3.8.5",
"description": "FastBee物联网平台",
"description": "岩安测控数据平台",
"author": "kerwincui",
"license": "AGPL3.0",
"scripts": {

View File

@ -112,7 +112,7 @@
"home.disk": "System disk usage rate",
"home.diskStatus": "Disk status G",
"home.available": "available",
"views.index.394840-0": "FastBee IoT Platform",
"views.index.394840-0": "YAN AN CE KONG IoT Platform",
"views.index.394840-1": "The open source version adopts the AGPL-3.0 license agreement, and commercial use requires authorization",
"views.index.394840-2": "Open source version:",
"views.index.394840-3": "Can be used for personal learning and use, non-commercial purposes",

View File

@ -36,11 +36,11 @@
"login.989807-34": "微信登录",
"login.989807-35": "注册账号",
"login.989807-36": "注册绑定账号",
"login.989807-37": "蜂信物联",
"login.989807-38": "FastBee开源物联网平台,简单易用,更适合中小企业和个人学习使用的物联网平台。",
"login.989807-39": "FastBee系统采用国内流行度最高的技术栈,帮助更多的企业实现设备联网控制和监测。",
"login.989807-37": "岩安测控数据平台",
"login.989807-38": "岩安测控数据平台,简单易用,更适合中小企业和个人学习使用的物联网平台。",
"login.989807-39": "岩安测控数据平台采用国内流行度最高的技术栈,帮助更多的企业实现设备联网控制和监测。",
"register.974236-0": "账号注册",
"register.974236-1": "蜂信物联",
"register.974236-1": "岩安测控",
"register.974236-2": "手机号码",
"register.974236-3": "确认密码",
"register.974236-4": "注 册",
@ -50,7 +50,7 @@
"register.974236-8": "查看文档",
"register.974236-9": "账号登录",
"register.974236-10": "绑定中...",
"register.974236-11": "FastBee开源物联网平台,简单易用,更适合中小企业和个人学习使用的物联网平台。",
"register.974236-11": "岩安测控数据平台,简单易用,更适合中小企业和个人学习使用的物联网平台。",
"register.974236-12": "两次输入的密码不一致",
"register.974236-13": "用户账号长度必须介于 2 和 20 之间",
"register.974236-14": "请输入您的手机号码",
@ -112,7 +112,7 @@
"home.disk": "系统盘使用率",
"home.diskStatus": "磁盘状态 G",
"home.available": "可用",
"views.index.394840-0": "FastBee物联网平台",
"views.index.394840-0": "岩安测控数据平台",
"views.index.394840-1": "开源版本采用AGPL-3.0许可协议,商用需要获得授权",
"views.index.394840-2": "开源版本:",
"views.index.394840-3": "可用于个人学习和使用,非商业用途",
@ -127,7 +127,7 @@
"views.index.394840-12": "系统源码",
"views.index.394840-13": "Gitee源码",
"views.index.394840-14": "Github源码",
"views.index.394840-15": "蜂信物联",
"views.index.394840-15": "岩安测控",
"views.index.394840-16": "登录用户数量",
"views.index.394840-17": "项目文档",
"tagsView.refresh": "刷新",

View File

@ -35,7 +35,7 @@ export default {
},
data() {
return {
title: 'FastBee',
title: '岩安测控',
logo: logoImg,
};
},

View File

@ -10,7 +10,7 @@
<div class="guang"></div>
<div class="d-flex jc-center">
<div class="title">
<span class="title-text">FastBee物联网平台</span>
<span class="title-text">岩安测控数据平台</span>
</div>
</div>
<div class="timers ">

View File

@ -583,8 +583,9 @@ export default {
return;
}
}
// 有效的Excel文件,直接下载
const fileName = `设备历史数据_${moment().format('YYYYMMDDHHmmss')}.xlsx`;
// 有效的Excel文件,直接下载 - 使用设备编号作为文件名
const deviceSerialNumber = devices.serialNumber || '设备数据';
const fileName = `${deviceSerialNumber}_${moment().format('YYYYMMDDHHmmss')}.xlsx`;
saveAs(res, fileName);
this.$message.success('导出成功');
} else {

View File

@ -882,11 +882,11 @@ export default {
}
return res;
};
option = {
option = {
title: {
text: this.$t('home.onlineDevice') + this.deviceList.filter((x) => x.status == 3).length + ')',
subtext: 'Fastbee open source iot platform',
sublink: 'https://iot.fastbee.cn',
subtext: '岩安测控数据平台',
sublink: 'https://iot.fastbee.cn', // todo 替换为延安测控的官网
target: '_blank',
textStyle: {
color: '#333',

View File

@ -5,13 +5,13 @@
<div class="head">
<span style="color: #909399">{{ $t('device.instruction-parsing.830424-0') }}</span>
<span>{{ device.serialNumber }}</span>
<el-dropdown style="margin-left: auto">
<el-dropdown style="margin-left: auto" @command="handleFormatChange">
<span class="el-dropdown-link">
{{ format }}
<i class="el-icon-arrow-down el-icon--right"></i>
</span>
<el-dropdown-menu slot="dropdown">
<el-dropdown-item v-for="(item, index) in formatList" :key="index">{{ item }}</el-dropdown-item>
<el-dropdown-item v-for="(item, index) in formatList" :key="index" :command="item">{{ item }}</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
</div>
@ -31,16 +31,19 @@
</div>
<div class="item-content">
<div class="content-value">
<!-- 显示HEX格式 -->
<div v-if="item.value" class="data-format-item">
<!-- 根据format选择显示HEX或ASCII格式 -->
<div v-if="format === 'Hex' && item.value" class="data-format-item">
<span class="format-label">HEX:</span>
<span class="hex-value">{{ item.value }}</span>
</div>
<!-- 显示ASCII格式 -->
<div v-if="item.valueAscii" class="data-format-item ascii-item">
<div v-if="format === 'ASCII' && item.valueAscii" class="data-format-item ascii-item">
<span class="format-label">ASCII:</span>
<pre class="ascii-value">{{ item.valueAscii }}</pre>
</div>
<div v-if="format === 'JSON'" class="data-format-item">
<span class="format-label">JSON:</span>
<pre class="json-value">{{ formatJsonValue(item.value, item.valueAscii) }}</pre>
</div>
</div>
</div>
<div class="analysis-data" v-if="item.type != 0 && item.analysis">
@ -63,10 +66,11 @@
</div>
</div>
<div class="bottom">
<el-input :placeholder="$t('device.instruction-parsing.830424-10')" v-model="sendVal" class="input-with-select" size="medium">
<el-input :placeholder="$t('device.instruction-parsing.830424-10')" v-model="sendVal" class="input-with-select" size="medium" @keyup.enter.native="sendMessage">
<el-select v-model="dataType" slot="prepend" :placeholder="$t('device.instruction-parsing.830424-11')">
<el-option label="hex" value="hex"></el-option>
<el-option label="json" value="json"></el-option>
<el-option label="ascii" value="ascii"></el-option>
</el-select>
</el-input>
<el-button round type="primary" class="send-btn" size="mini" @click.stop="sendMessage">{{ $t('device.instruction-parsing.830424-14') }}</el-button>
@ -411,7 +415,7 @@ export default {
//选中的格式
format: 'Hex',
//格式列表
formatList: ['Hex', 'JSON', 'Plaintext'],
formatList: ['Hex', 'JSON', 'ASCII'],
//数据列表
logList: [],
//发送的命令
@ -499,6 +503,68 @@ export default {
};
},
methods: {
/**处理updateData事件 */
handleUpdateData(params) {
const { serialNumber, productId, data } = params;
if (serialNumber == this.device.serialNumber) {
this.logList.push({
//0是下发,1是回复,2是上报
type: 2,
time: formatDate(new Date()),
value: data.sources, // HEX格式
valueAscii: data.sourcesAscii || '', // ASCII格式
loading: false,
analysis: false,
//解析的数据数组
analysisList: data.message,
});
}
},
/**处理格式切换 */
handleFormatChange(command) {
this.format = command;
},
/**格式化JSON值 */
formatJsonValue(hexValue, asciiValue) {
// 优先尝试从ASCII值解析JSON
if (asciiValue) {
try {
const json = JSON.parse(asciiValue);
return JSON.stringify(json, null, 2);
} catch (e) {
// ASCII不是JSON,继续尝试HEX
}
}
// 尝试从HEX值解析JSON
if (hexValue) {
try {
// 先尝试直接解析
const json = JSON.parse(hexValue);
return JSON.stringify(json, null, 2);
} catch (e) {
// 如果不是JSON字符串,尝试将HEX转为字符串再解析
try {
const hexStr = hexValue.replace(/\s+/g, '');
let jsonStr = '';
for (let i = 0; i < hexStr.length; i += 2) {
const hexByte = hexStr.substr(i, 2);
const charCode = parseInt(hexByte, 16);
if (charCode >= 32 && charCode <= 126) {
jsonStr += String.fromCharCode(charCode);
}
}
if (jsonStr) {
const json = JSON.parse(jsonStr);
return JSON.stringify(json, null, 2);
}
} catch (e2) {
// 转换失败
}
}
}
// 如果都不是JSON,返回提示信息
return '数据不是有效的JSON格式';
},
/**打开编辑框 */
openEdit() {
this.resetCreateForm();
@ -847,24 +913,14 @@ export default {
},
mounted() {
this.resetCreateForm();
this.$busEvent.$on('updateData', (params) => {
const { serialNumber, productId, data } = params;
if (serialNumber == this.device.serialNumber) {
this.logList.push({
//0是下发,1是回复,2是上报
type: 2,
time: formatDate(new Date()),
value: data.sources, // HEX格式
valueAscii: data.sourcesAscii || '', // ASCII格式
loading: false,
analysis: false,
//解析的数据数组
analysisList: data.message,
});
}
});
// 先移除旧的监听器,避免重复绑定
this.$busEvent.$off('updateData', this.handleUpdateData);
// 绑定新的监听器
this.$busEvent.$on('updateData', this.handleUpdateData);
},
beforeDestroy() {
// 移除所有事件监听器
this.$busEvent.$off('updateData', this.handleUpdateData);
this.$busEvent.$off('updateMqttMessage');
},
};
@ -1076,7 +1132,8 @@ $right-btn-color: #1890ff;
font-family: 'Courier New', monospace;
}
.ascii-value {
.ascii-value,
.json-value {
margin: 0;
padding: 8px;
background-color: #f5f7fa;

View File

@ -643,7 +643,7 @@ export default {
// 对象类型
for (let n = 0; n < this.deviceInfo.thingsModels[k].datatype.params.length; n++) {
if (this.deviceInfo.thingsModels[k].datatype.params[n].id == data[j].id) {
this.deviceInfo.thingsModels[k].datatype.params[n].shadow = msg.value;
this.deviceInfo.thingsModels[k].datatype.params[n].shadow = data[j].value;
isComplete = true;
break;
}
@ -656,7 +656,7 @@ export default {
for (let n = 0; n < this.deviceInfo.thingsModels[k].datatype.arrayParams.length; n++) {
for (let m = 0; m < this.deviceInfo.thingsModels[k].datatype.arrayParams[n].length; m++) {
if (this.deviceInfo.thingsModels[k].datatype.arrayParams[n][m].id == data[j].id) {
this.deviceInfo.thingsModels[k].datatype.arrayParams[n][m].shadow = msg.value;
this.deviceInfo.thingsModels[k].datatype.arrayParams[n][m].shadow = data[j].value;
isComplete = true;
break;
}
@ -672,7 +672,7 @@ export default {
let index = n > 9 ? String(n) : '0' + k;
let prefix = 'array_' + index + '_';
if (this.deviceInfo.thingsModels[k].datatype.arrayParams[n][m].id == prefix + data[j].id) {
this.deviceInfo.thingsModels[k].datatype.arrayParams[n][m].shadow = msg.value;
this.deviceInfo.thingsModels[k].datatype.arrayParams[n][m].shadow = data[j].value;
}
}
}
@ -681,7 +681,7 @@ export default {
// 整数、小数和字符串类型数组
for (let n = 0; n < this.deviceInfo.thingsModels[k].datatype.arrayModel.length; n++) {
if (this.deviceInfo.thingsModels[k].datatype.arrayModel[n].id == data[j].id) {
this.deviceInfo.thingsModels[k].datatype.arrayModel[n].shadow = msg.value;
this.deviceInfo.thingsModels[k].datatype.arrayModel[n].shadow = data[j].value;
break;
}
}
@ -693,24 +693,43 @@ export default {
if (this.deviceInfo.chartList[k].id.indexOf('array_') == 0) {
// 数组类型匹配,例如:array_00_gateway_temperature
if (this.deviceInfo.chartList[k].id == data[j].id) {
// let shadows = msg[j].value.split(",");
this.deviceInfo.chartList[k].shadow = msg.value;
this.deviceInfo.chartList[k].shadow = data[j].value;
// 更新图表
for (let m = 0; m < this.monitorChart.length; m++) {
if (data[j].id == this.monitorChart[m].data.id) {
let data = [
// 更新数据对象
this.monitorChart[m].data.value = data[j].value;
// 确保数值是数字类型
const numValue = Number(data[j].value) || 0;
// 构建图表数据
const chartData = [
{
value: msg.value,
value: numValue,
name: this.monitorChart[m].data.name,
},
];
// 更新图表配置,包括detail部分
this.monitorChart[m].chart.setOption({
series: [
{
data: data,
data: chartData,
detail: {
formatter: '{value}' + ' ' + (this.deviceInfo.chartList[k].datatype.unit || ''),
},
},
],
}, false); // false表示不合并,完全替换
// 强制刷新图表
this.$nextTick(() => {
if (this.monitorChart[m] && this.monitorChart[m].chart) {
this.monitorChart[m].chart.resize();
}
});
break;
}
}
@ -718,23 +737,43 @@ export default {
} else {
// 普通类型匹配
if (this.deviceInfo.chartList[k].id == data[j].id) {
this.deviceInfo.chartList[k].shadow = msg.value;
this.deviceInfo.chartList[k].shadow = data[j].value;
// 更新图表
for (let m = 0; m < this.monitorChart.length; m++) {
if (data[j].id == this.monitorChart[m].data.id) {
let data = [
// 更新数据对象
this.monitorChart[m].data.value = data[j].value;
// 确保数值是数字类型
const numValue = Number(data[j].value) || 0;
// 构建图表数据
const chartData = [
{
value: msg.value,
value: numValue,
name: this.monitorChart[m].data.name,
},
];
// 更新图表配置,包括detail部分
this.monitorChart[m].chart.setOption({
series: [
{
data: data,
data: chartData,
detail: {
formatter: '{value}' + ' ' + (this.deviceInfo.chartList[k].datatype.unit || ''),
},
},
],
}, false); // false表示不合并,完全替换
// 强制刷新图表
this.$nextTick(() => {
if (this.monitorChart[m] && this.monitorChart[m].chart) {
this.monitorChart[m].chart.resize();
}
});
break;
}
}

View File

@ -154,7 +154,7 @@
<div class="switch__container" id="switch-c2" :class="{ 'is-hidden': isC2Hidden }">
<div style="display: flex; align-items: center">
<img src="../assets/logo/fastbee.png" alt="logo" style="width: 60px" />
<h2 class="switch__title title" style="margin-left: 10px">FastBee</h2>
<h2 class="switch__title title" style="margin-left: 10px">岩安测控</h2>
</div>
<p class="switch__description description">{{ $t('login.989807-39') }}</p>
<img src="../assets/images/login7.jpeg" alt="logo" style="width: 220px; height: 220px" />

View File

@ -7,10 +7,10 @@
<div style="font-size: 42px; padding-top: 40px; width: 300px; margin: 0 auto">
<img :src="logo" alt="logo" style="width: 100px; height: 100px; float: left" />
<div style="float: left; margin-top: 13px; width: 200px; text-align: left">
<div>FastBee</div>
<div>岩安测控</div>
<div
style="letter-spacing: 1.5px; font-size: 20px; font-weight: 600; margin-top: -8px; margin-left: 3px">
开源物联网平台</div>
岩安测控数据平台</div>
</div>
</div>
</div>

View File

@ -9,10 +9,10 @@
<div style="font-size: 42px; padding-top: 40px; width: 300px; margin: 0 auto">
<img :src="logo" alt="logo" style="width: 100px; height: 100px; float: left" />
<div style="float: left; margin-top: 13px; width: 200px; text-align: left">
<div>FastBee</div>
<div>岩安测控</div>
<div
style="letter-spacing: 1.5px; font-size: 20px; font-weight: 600; margin-top: -8px; margin-left: 3px">
开源物联网平台</div>
岩安测控数据平台</div>
</div>
</div>
</div>

View File

@ -8,7 +8,7 @@ function resolve(dir) {
const CompressionPlugin = require('compression-webpack-plugin');
const MonacoWebpackPlugin = require('monaco-editor-webpack-plugin');
const name = process.env.VUE_APP_TITLE || 'FastBee物联网平台'; // 网页标题
const name = process.env.VUE_APP_TITLE || '岩安测控数据平台'; // 网页标题
const port = process.env.port || process.env.npm_config_port || 80; // 端口