Browse Source

feat:固件上传

dev
zhaobing’ 1 year ago
parent
commit
d51d8f28f1
  1. 7
      api/.vscode/launch.json
  2. 366
      api/app/lib/controllers/firmwareUpgrade/index.js
  3. 29
      api/app/lib/routes/firmwareUpgrade/index.js
  4. 5
      api/app/lib/utils/dataRange.js
  5. 11
      api/config.js
  6. 1
      web/client/src/layout/actions/global.js
  7. 2
      web/client/src/layout/reducers/global.js
  8. 103
      web/client/src/sections/service/actions/firmwareUpgrade.js
  9. 3
      web/client/src/sections/service/actions/index.js
  10. 152
      web/client/src/sections/service/components/addFirmwareModal.jsx
  11. 2
      web/client/src/sections/service/components/cycAddmodal.jsx
  12. 86
      web/client/src/sections/service/components/firmwareListModal.jsx
  13. 4
      web/client/src/sections/service/components/maintenanceRecordModal.jsx
  14. 2
      web/client/src/sections/service/components/recordModal.jsx
  15. 246
      web/client/src/sections/service/containers/deviceManagement.jsx
  16. 135
      web/client/src/sections/service/containers/firmwareLibrary.jsx
  17. 5
      web/client/src/sections/service/containers/index.js
  18. 2
      web/client/src/sections/service/containers/serviceRecord.jsx
  19. 9
      web/client/src/sections/service/nav-item.jsx
  20. 19
      web/client/src/sections/service/routes.js
  21. 17
      web/client/src/utils/webapi.js
  22. 7
      web/config.js
  23. 2
      web/package.json
  24. 3
      web/routes/attachment/index.js

7
api/.vscode/launch.json

@ -40,8 +40,10 @@
//
// "--apiEmisUrl http://10.8.30.161:1111",
// "--apiEmisUrl http://10.8.30.161:31111/",
// "--apiEmisUrl https://pepca-demo.anxinyun.cn/_api",
"--apiEmisUrl http://localhost:14000",
"--apiEmisUrl https://pepca-demo.anxinyun.cn/_api",
// "--apiEmisUrl https://pep-ca.anxinyun.cn/_api",
// "--apiEmisUrl http://localhost:14000",
"--apiVcmpUrl http://localhost:4000",
"--apiIotAuth http://localhost:4200",
"--godUrl https://restapi.amap.com/v3",
@ -106,6 +108,7 @@
"--confirmAlarmAnxinUserId 1",
"--vcmpAppId 5048b08d-c449-4d7f-b1ec-f741012aefe8",
"--vcmpAppSecret 5ba8c0ab-9fbd-4f07-9817-c48017c3cbad",
"--apiCrawUrl http://218.3.126.49:30555/v1" //
]
},
{

366
api/app/lib/controllers/firmwareUpgrade/index.js

@ -0,0 +1,366 @@
'use strict';
const request = require('superagent');
const moment = require('moment')
const http = require('http');
const ApiTable = {
getFirmwares:'firmwareupgrade/getPkg',
firmwareUpgrade:'firmwareupgrade',
getThingMessages:'firmwareupgrade/getThingMessages',
distributeConfiguration:'firmwareupgrade/redisSet'
}
//设备维护记录
async function getDeviceType (ctx) {
try {
// const { models } = ctx.fs.dc
// const sequelize = ctx.fs.dc.ORM
const { clickHouse } = ctx.app.fs
const rlst = await clickHouse.iot.query(`
SELECT id,model FROM DeviceMeta
WHERE model in ('FS-YTSW','FS-YTDZ-GD','FS-iFWL-ZXSJ','ZSJ-iVW08','FS-Q90-NHB1-HC','FS-RTU-P4-SL','FS-RTU-SL','FS-V08','FS-M24','FS-LPWAN08')
`).toPromise()
ctx.body=rlst||[]
ctx.status=200
}catch(error){
ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`)
ctx.status = 400
ctx.body = {
message: `查询设备型号失败`
}
}
}
//查询结构物
async function getStruc (ctx) {
try {
const { clickHouse } = ctx.app.fs
// const { models } = ctx.fs.dc
// const sequelize = ctx.fs.dc.ORM
const { pepProjectId, keywordTarget, keyword} = ctx.query
const { utils: {anxinStrucIdRange } } = ctx.app.fs
let anxinStruc = await anxinStrucIdRange({
ctx, pepProjectId, keywordTarget, keyword
})
// console.log('anxinStruc1',anxinStruc)
let thingIds=new Set()
if(anxinStruc&&anxinStruc.length){
anxinStruc.map(item=>thingIds.add(item.thingId))
}
let deviceType= thingIds.size ?
await clickHouse.iot.query(`
SELECT distinct dm.id id,dm.model model,dc.thingId thingId
FROM Device dc
INNER JOIN DeviceMeta dm
ON dm.id=dc.deviceMetaId
WHERE dc.thingId in (${[...thingIds].map(id => `'${id}'`).join(',')},'-000')`
).toPromise() :[]
let rslt=[]
if(deviceType&&deviceType.length&&anxinStruc&&anxinStruc.length){
rslt= anxinStruc.map(item=>{
item.deviceType=deviceType.filter(child=>child.thingId===item.thingId)
return item
})
}
// //返回数据结构示例
// // [ {strucId: s.strucId,
// // strucName: s.strucName,
// // projectId: s.projectId,
// // project: [{ id: s.projectId,}],
// // pomsProject: [],
// // deviceType:[{}]
// // }]
ctx.body=rslt||[]
ctx.status=200
}catch(error){
ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`)
ctx.status = 400
ctx.body = {
message: `查询结构物以及设备类型失败`
}
}
}
async function getFirmwares (ctx) {
const query = ctx.query
// console.log('query1',query)
try{
const res=await ctx.app.fs.craw.get(ApiTable.getFirmwares,{query})
// console.log('666x1111',res)
let rslt=[]
if(res){
if( JSON.parse(res).msg){
JSON.parse(JSON.parse(res).msg)&&JSON.parse(JSON.parse(res).msg).length?JSON.parse(JSON.parse(res).msg).map(item=>{
// console.log('xxxx',item)
rslt.push(
{device_meta_id:item.device_meta_id,
deviceMetaName:item.device_meta_name,
versionNo:item.version,
firmwareName:item.filename,
filepath:item.filepath,
uploader:item.userid,
comment:item.comment,
uploadTime:moment(item.UpdatedTime).format('YYYY-MM-DD'),
fileObj:item.Bin
})
}):[]
}
}
ctx.body=rslt
ctx.status=200
}catch(error){
ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`)
ctx.status = 400
ctx.body = {
message: `查询固件包列表失败`
}
}
}
function getFileAsBuffer(remoteFileUrl) {
return new Promise((resolve, reject) => {
// 发起 HTTP 请求
http.get(remoteFileUrl, (response) => {
if (response.statusCode !== 200) {
reject(new Error(`HTTP请求失败,状态码:${response.statusCode}`));
return;
}
const buffers = [];
// 监听数据流
response.on('data', (chunk) => {
buffers.push(chunk);
});
// 数据传输完成
response.on('end', () => {
// 将文件数据合并为一个 Buffer
const fileData = Buffer.concat(buffers);
// 返回文件内容的 Buffer
resolve(fileData);
});
// 处理请求错误
response.on('error', (error) => {
reject(error);
});
});
});
}
//增加/覆盖固件包
async function firmwareUpgrades (ctx) {
try{
const {qiniu,version,tokenup,device_meta_id,wholeFile} = ctx.query
const {deviceMetaName,filePath,userId,fileObj,comment} = ctx.request.body
const url=qiniu+'/'+wholeFile
// 发起 GET 请求以获取文件
// console.log('url1',url)
// var data = fs.readFileSync(url, "utf-8");
// console.log('xxxx111',data)
request.get(url).responseType('blob').end((err, response) => {
if (err) {
console.error('Superagent request error:', err);
return;
}
if (response.ok) {
const blobData = response.body
// console.log('xxxxx1',response)
request.post('http://218.3.126.49:30555/v1/firmwareupgrade')
// .set('Content-Type','application/octet-stream')
.attach('file',blobData,fileObj.name||'')
.field('filePath', filePath||'')
.field('userId', userId||'')
.field('comment',comment||'')
.field('device_meta_name',deviceMetaName||'')
.query({ version,device_meta_id,token:tokenup})
.then((resolve, reject) => {
return (err, res) => {
if (err) {
reject(err);
} else {
resolve(res);
}
};
})
}
})
// const ressss= await request.get(url).end(function(err, sourceResponse) {
// console.log('xxx2',sourceResponse)
// if (err) {
// console.error('文件获取失败:', err);
// return;
// }
// 从响应中获取文件内容
// const fileContent = sourceResponse.body;
// // 创建一个 POST 请求以上传文件
// request
// .post(ApiTable.firmwareUpgrade)
// .field('caption', 'My cats') // 其他表单字段
// .attach('file', fileContent, 'file.jpeg') // 将文件添加为表单字段
// .end(function(err, targetResponse) {
// if (err) {
// console.error('上传失败:', err);
// return;
// }
// // 处理目标服务器的响应
// console.log('上传成功');
// console.log(targetResponse.text);
// });
// });
// console.log('xxx1',ressss)
// console.log('query1111', ctx.query)
// const fileObj=await getFileAsBuffer(qiniu+'/'+wholeFile)
// console.log('xx1',fileObj)
// const file=qiniu+'/'+wholeFile
// console.log('xxxx666',deviceMetaName)
// const {files}=await parse(fileObjq)
// const file=files[0]
// const res=await ctx.app.fs.craw.post(ApiTable.firmwareUpgrade,
// {query:{version,token:tokenup,device_meta_id},
// data:{deviceMetaName,filePath,userId,fileObjq},
// header:{ 'Content-Type':'multipart/form-data'}})
// const formData = new FormData(ApiTable.firmwareUpgrade,{query:{version,token:tokenup,device_meta_id},data:{deviceMetaName,filePath,userId,file},header:{
// 'Content-Type':'multipart/form-data; boundary=--------------------------033155845889797072451758'
// }});
// // 添加普通字段到 FormData
// // formData.append('device_meta_name', device_meta_name);
// // formData.append('filePath', filePath);
// // formData.append('userId', userId)
// // formData.append('file', fileObj);
// // console.log('fileObj',formData)
// // const body= ctx.request.body
// // const fileData = await getFileAsBase64(qiniu+'/'+wholeFile);
// // const res=await ctx.app.fs.craw.post1(ApiTable.firmwareUpgrade,userId,filePath,{query:{version:version,token:tokenup,device_meta_id:device_meta_id},data:fileObj})
ctx.body={}
ctx.status=200
}catch(error){
// console.log('xx1111',error)
ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`)
ctx.status = 400
ctx.body = {
message: `增加/覆盖固件包失败`
}
}
}
async function deleteFirmware(ctx){
const {version,device_meta_id,tokenup}=ctx.query
try{
await ctx.app.fs.craw.delete(ApiTable.firmwareUpgrade,{query:{version,device_meta_id,token:tokenup}})
ctx.status=204
}catch(eror){
ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`)
ctx.status = 400
ctx.body = {
message: `删除固件包失败`
}
}
}
async function getThingMessages(ctx){
try{
const {thingIds,device_meta_id,searchVal}=ctx.query
const res= await ctx.app.fs.craw.get(ApiTable.getThingMessages,{query:{thingIds,device_meta_id}})
// console.log('xxxxxx',res)
let rslt=[]
if(res){
JSON.parse(res).data&&JSON.parse(res).data.length?JSON.parse(res).data.map(item=>{
if( item.devices&& item.devices.length){
item.devices.map(child=>{
// console.log('childx',child)
rslt.push({
key:child.id,
thingId:item.thingId,
devicemetaId:child.deviceMetaId||'',
deviceType:JSON.parse(child.properties).productType||'',
deviceName:child.name||'',
firmwareName:child.fileName||'',
firmwareNo:child.updateVersion||'',
status:child.updateState||'',
updatePercentage:child.updatePercentage||'',
switchStatus:JSON.parse(child.properties).switch||false,
deviceId:child.id
})
// console.log('xxxx2',child.properties)
// console.log('xxxx2',child)
})
}
// console.log('xxxx1',item)
}):[]
}
let result
if(searchVal&&rslt&&rslt.length){
result= rslt.filter(item=>item.deviceName===searchVal)
}
if(!searchVal){
result=rslt
}
ctx.body=result
ctx.status=200
}catch(error){
ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`)
ctx.status = 400
ctx.body = {
message: `查询结构物状态失败`
}
}
}
async function distributeConfiguration(ctx){
try{
const {version,device_meta_id,tokenup}=ctx.query
const res= await ctx.app.fs.craw.post(ApiTable.distributeConfiguration,{query:{version,device_meta_id,token:tokenup},data:JSON.stringify(ctx.request.body)})
if(res){
ctx.body=JSON.parse(res)
ctx.status=200
}else{
ctx.status=400
ctx.body = {
message: `下发配置失败`
}
}
}catch(error){
ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`)
ctx.status = 400
ctx.body = {
message: `下发配置失败`
}
}
}
module.exports = {
getDeviceType,
getStruc,
getFirmwares,
firmwareUpgrades,
deleteFirmware,
getThingMessages,
distributeConfiguration
};

29
api/app/lib/routes/firmwareUpgrade/index.js

@ -0,0 +1,29 @@
'use strict';
const firmwareUpgrade = require('../../controllers/firmwareUpgrade');
module.exports = function (app, router, opts) {
app.fs.api.logAttr['GET/deviceType'] = { content: '获取设备型号', visible: true }
router.get('/deviceType', firmwareUpgrade.getDeviceType)
app.fs.api.logAttr['GET/structure'] = { content: '获取结构物相关', visible: true }
router.get('/structure', firmwareUpgrade.getStruc)
app.fs.api.logAttr['GET/firmware'] = { content: '获取固件包列表', visible: true }
router.get('/firmware', firmwareUpgrade.getFirmwares)
// app.fs.api.logAttr['POST/upgradeFirmware'] = { content: '增加/覆盖固件包', visible: true }
// router.post('/upgradeFirmware', firmwareUpgrade.firmwareUpgrades)
app.fs.api.logAttr['DELETE/deleteFirmware'] = { content: '删除固件包', visible: true }
router.delete('/deleteFirmware', firmwareUpgrade.deleteFirmware)
app.fs.api.logAttr['GET/getThingMessages'] = { content: '获取设备信息', visible: true }
router.get('/getThingMessages', firmwareUpgrade.getThingMessages)
app.fs.api.logAttr['POST/distributeConfiguration'] = { content: '下发配置(单个或批量)', visible: true }
router.post('/distributeConfiguration', firmwareUpgrade.distributeConfiguration)
}

5
api/app/lib/utils/dataRange.js

@ -90,6 +90,7 @@ module.exports = function (app, opts) {
async function anxinStrucIdRange ({ ctx, pepProjectId, keywordTarget, keyword }) {
const { clickHouse } = ctx.app.fs
const { pepProjectRes, bindRes, } = await pomsWithPepRangeParams({ ctx, pepProjectId, keywordTarget, keyword })
// 获取不重复的 安心云项目 id
@ -124,6 +125,7 @@ module.exports = function (app, opts) {
t_project.id AS projectId,
t_structure.id AS strucId,
t_structure.name AS strucName,
t_structure.iota_thing_id as thingId,
project_state
FROM
t_project
@ -175,7 +177,8 @@ module.exports = function (app, opts) {
project: [{
id: s.projectId,
}],
pomsProject: []
pomsProject: [],
thingId:s.thingId
}
undelStruc.push(corStruc)
}

11
api/config.js

@ -61,6 +61,9 @@ args.option('caiyunKey', '彩云天气 apiKey');
args.option('vcmpAppId', '视频平台 应用 id')
args.option('vcmpAppSecret', '视频平台 应用秘钥')
//设备升级
args.option('apiCrawUrl', '设备升级')
const flags = args.parse(process.argv);
const POMS_DB = process.env.POMS_DB || flags.pg;
@ -90,6 +93,9 @@ const API_EMIS_URL = process.env.API_EMIS_URL || flags.apiEmisUrl;
const API_VCMP_URL = process.env.API_VCMP_URL || flags.apiVcmpUrl;
// iot鉴权平台 api
const API_IOT_AUTH = process.env.API_IOT_AUTH || flags.apiIotAuth;
//设备升级
const API_CRAW_URL = process.env.API_CRAW_URL || flags.apiCrawUrl;
// 高德地图的参数
const GOD_URL = process.env.GOD_URL || flags.godUrl || 'https://restapi.amap.com/v3';
@ -153,6 +159,7 @@ const requireParams = {
// CLICKHOUST_CAM_WORKFLOW,
CONFIRM_ALARM_ANXIN_USER_ID,
VCMP_APP_ID, VCMP_APP_SECRET,
API_CRAW_URL
}
Object.keys(requireParams).forEach(key => {
@ -260,6 +267,10 @@ const product = {
pssaRequest: [{// name 会作为一个 request 出现在 ctx.app.fs
name: 'axyRequest',
root: API_ANXINYUN_URL
},{
name:'craw',
root:API_CRAW_URL,
dataWord:'text'
}, {
name: 'emisRequest',
root: API_EMIS_URL

1
web/client/src/layout/actions/global.js

@ -50,6 +50,7 @@ export function initApiRoot () {
qiniu: res.qiniu,
webEmis: res.webEmis,
webOa: res.webOa,
crawapi:res.crawapi
}
})
});

2
web/client/src/layout/reducers/global.js

@ -20,6 +20,7 @@ function global (state = {
pomsEs: '',
pomsNotebook: '',
dcWeb: '',
crawapi:'',
qiniu: {}
}, action) {
const payload = action.payload;
@ -52,6 +53,7 @@ function global (state = {
qiniu: payload.qiniu,
webEmis: payload.webEmis,
webOa: payload.webOa,
crawapi:payload.crawapi
}).toJS();
case PEPPROJECTID:
return Immutable.fromJS(state).merge({

103
web/client/src/sections/service/actions/firmwareUpgrade.js

@ -0,0 +1,103 @@
'use strict';
import { ApiTable, basicAction } from '$utils'
export function getDeviceType(query) { //获取设备型号
return dispatch => basicAction({
type: 'get',
dispatch: dispatch,
query,
actionType: 'GET_DEVICE_TYPE',
url: `${ApiTable.getDeviceType}`,
msg: { option: '获取设备型号' },
reducer: {
name: "deviceType",
params: { noClear: true }
}
});
}
export function getStruc(query) { //获取结构物以及设备类型
return dispatch => basicAction({
type: 'get',
dispatch: dispatch,
query,
actionType: 'GET_STRUC',
url: `${ApiTable.getStruc}`,
msg: { option: '获取结构物以及设备类型' },
reducer: {
name: "structAndDeviceType",
params: { noClear: true }
}
});
}
export function getFirmware(query) { //获取固件包
return dispatch => basicAction({
type: 'get',
dispatch: dispatch,
query,
actionType: 'GET_FIRMWARE',
url: `${ApiTable.getFirmware}`,
msg: { option: '获取固件包' },
reducer: {
name: "firmware",
params: { noClear: true }
}
});
}
export function upgradeFirmware(query,data) { //增加/覆盖固件包
return dispatch => basicAction({
type: 'post',
dispatch: dispatch,
query,
data,
actionType: 'UPGRADE_FIRMWARE',
url: `${ApiTable.upgradeFirmware}`,
msg: { option: '增加/覆盖固件包' },
});
}
export function deleteFirmware(query) { //删除固件包
return dispatch => basicAction({
type: 'delete',
dispatch: dispatch,
query,
actionType: 'DELETE_FIRMWARE',
url: `${ApiTable.deleteFirmware}`,
msg: { option: '删除固件包' },
});
}
export function getThingMessages(query) { //获取固件包信息
return dispatch => basicAction({
type: 'get',
dispatch: dispatch,
query,
actionType: 'GET_THING_MESSAGES',
url: `${ApiTable.getThingMessages}`,
msg: { option: '获取设备信息' },
});
}
export function distributeConfiguration(query,data) { //下发配置
return dispatch => basicAction({
type: 'post',
dispatch: dispatch,
query,
data,
actionType: 'DISTRIBUTE_CONNFIGURATION',
url: `${ApiTable.distributeConfiguration}`,
msg: { option: '下发配置'},
});
}

3
web/client/src/sections/service/actions/index.js

@ -4,6 +4,7 @@ import * as emPush from './emPush'
import * as redcord from './record'
import * as maintenancePlan from './maintenancePlan'
import * as equipment from './equipment'
import * as firmwareUpgrade from './firmwareUpgrade'
export default {
...emPush, ...redcord, ...maintenancePlan, ...equipment
...emPush, ...redcord, ...maintenancePlan, ...equipment,...firmwareUpgrade
}

152
web/client/src/sections/service/components/addFirmwareModal.jsx

@ -0,0 +1,152 @@
import React, { useState, useEffect, useRef } from 'react'
import { connect } from 'react-redux';
import moment from 'moment'
import { Button, Table, Modal, Form,Notification,Upload } from '@douyinfe/semi-ui';
import { IconUpload } from '@douyinfe/semi-icons';
import request from 'superagent';
const AddFirmwareModal = (props) => {
const {modalVis,onCancel,crawapi,recordRow,actions,dispatch,qiniu} =props
const api = useRef();
const {domain}=qiniu //
const {service}=actions
const [uploadData, setUploadData] = useState({})
const [options,setOptions]=useState([])//
const [fileObj,setFileObj]=useState({})//
const [fileUrl,setFileUrl]=useState()//
const userId = JSON.parse(sessionStorage.getItem('pomsUser'))?.id
const [removeFlag,setRemoveFlag]=useState(false)//
useEffect(()=>{
//
dispatch(service.getDeviceType()).then((res) => {
setOptions( res.payload.data?.map(item=> {
return {
label:item.model,
value:item.id
}
}))
})
},[])
// console.log('xxxx1111',recordRow)
// console.log('xxxx11112',fileUrl)
const okHandler= ()=>{
// console.log('fileObj',fileObj)
api.current.validate().then(async (res)=>{
// console.log('ressss',res)
// const query = {
// version:res?.versionNo,
// qiniu:domain,
// device_meta_id: res?.deviceName,
// tokenup: '22767e1f-db8d-4a1d-87d4-56347cf21247',
// wholeFile:fileUrl,
// }
// const body={
// filePath:fileUrl,
// userId:userId,
// comment:res?.remark,
// deviceMetaName:options?.find(item=>item.value===res?.deviceName)?.label,
// fileObj:fileObj
// }
// dispatch(service.upgradeFirmware(query,body)).then(res=>{
// })
const responseData=await request.get(qiniu+'/'+fileUrl).responseType('blob')
const blobData = responseData.body;
request.post(crawapi+'/firmwareupgrade')
// .set('Content-Type','application/octet-stream')
.attach('file',blobData,fileObj?.name||'')
.field('filePath',removeFlag?fileUrl:recordRow?recordRow.filepath:fileUrl)
.field('userId', userId||'')
.field('comment',res?.remark||'')
.field('device_meta_name', options?.find(item=>item.value===res?.deviceName)?.label||'')
.query({ version:res?.versionNo,device_meta_id: res?.deviceName,token:'22767e1f-db8d-4a1d-87d4-56347cf21247'})
.end((err, response) => {
if(response?.ok){
setRemoveFlag(false)
onCancel()
}else{
console.error('Superagent request failed:');
}
})
})
}
// function readFileAsBlob(file) {
// return new Promise((resolve, reject) => {
// const reader = new FileReader();
// reader.onload = () => {
// const blob = new Blob([reader.result], { type: file.type });
// resolve(blob);
// };
// reader.onerror = (error) => {
// reject(error);
// };
// reader.readAsArrayBuffer(file);
// });
// }
return <>
<Modal visible={modalVis} onCancel={onCancel} title='固件上传' onOk={okHandler} >
<Form initValues={{
'firmwareName':recordRow?.firmwareName,
'deviceName':recordRow?.device_meta_id,
'versionNo':recordRow?.versionNo,
'files':recordRow?[{ url: `${domain}/${recordRow?.filepath}`, name: recordRow?.firmwareName }]:[],
'remark':recordRow?.remark
}} getFormApi={formApi => api.current = formApi} labelCol={{ span: 7,offset:1}} wrapperCol={{span: 15,offset:1}} labelPosition='left' >
<Form.Input field='firmwareName' label='固件版本名称:' style={{with:'80%'}} rules={[{ required: true, message: '固件版本名称必填' }]}></Form.Input>
<Form.Select field='deviceName' label='设备型号:' placeholder='请选择设备型号' optionList={options} rules={[{ required: true, message: '设备型号必填' }]}></Form.Select>
<Form.Input field='versionNo' label='版本号:' rules={[{ required: true, message: '版本号必填' }]}></Form.Input>
<Form.Upload limit={1}
action={`/_upload/attachments`}
field='files' label='文件上传'
rules={[{ required: true, message: '文件上传必填' }]}
onRemove={() => {
setUploadData({})
setRemoveFlag(true)
}}
onSuccess={ async(responseBody, file,all) => {
// console.log('file111',file)
setFileObj(file)
setFileUrl(responseBody?.uploaded)
setUploadData({
name: file.name,
size: file.size,
url: responseBody?.uploaded,
uploadTime: moment().format("YYYY-MM-DD HH:mm:ss")
})
}}
>
<Button icon={<IconUpload />} theme="light">
点击上传
</Button>
</Form.Upload>
<Form.TextArea field='remark' label='备注:' placeholder='请输入项目介绍'></Form.TextArea>
</Form>
</Modal>
</>
}
function mapStateToProps (state) {
const { auth, global } = state;
return {
user: auth.user,
actions: global.actions,
crawapi: global.crawapi,
qiniu:global.qiniu,
};
}
export default connect(mapStateToProps)(AddFirmwareModal)

2
web/client/src/sections/service/components/cycAddmodal.jsx

@ -15,7 +15,7 @@ const AddModal = (props) => {
//
const okHandler = () => {
api.current.validate().then((res) => {
console.log(111, res, respondRecordData?.map(v => ({ value: v.id, label: v.sketch })));
// console.log(111, res, respondRecordData?.map(v => ({ value: v.id, label: v.sketch })));
const query = {
id: recordRow?.id,
actualFinishTime: res.realityTime,

86
web/client/src/sections/service/components/firmwareListModal.jsx

@ -0,0 +1,86 @@
import React, { useState, useEffect, useRef } from 'react'
import { connect } from 'react-redux';
import moment from 'moment'
import { Button, Table, Modal, Form } from '@douyinfe/semi-ui';
import { IconUpload } from '@douyinfe/semi-icons';
const firmwareListModal = (props) => {
const {modalVis,onCancel,apiRoot,recordRow,versionData,vData,actions,dispatch} =props
const api = useRef();
const [uploadData, setUploadData] = useState({})
const [data,setData]=useState()
const {service}=actions
const okHandler=()=>{
api.current.validate().then((res)=>{
const query = {
version:res?.type,
device_meta_id:data[0]?.device_meta_id,
tokenup: '22767e1f-db8d-4a1d-87d4-56347cf21247',
}
const body=[{thing_id:data[0]?.thing_id,device_ids:data?.map(item=>item.deviceId)}]
dispatch(service.distributeConfiguration(query,body)).then((res)=>{
if(res.success) onCancel()
})
// console.log('rexxxx',res)
})
}
useEffect(()=>{
// console.log('versionData',vData,versionData)
if(recordRow&&recordRow.length&&versionData&&versionData.length&&vData&&vData.length){
//id
const res= versionData?.filter(item=>recordRow?.some(p=>p.deviceId===item.deviceId))?.map(child=>{
return {
device_meta_id:child.devicemetaId,
deviceId:child.deviceId,
thing_id:child.thingId,
firmwareNo:child.firmwareNo,
firmwareName:child.firmwareName,
versionList:vData.filter(n=>n.device_meta_id==child.devicemetaId)
}
})
setData(res)
}
},[recordRow,versionData,vData])
// console.log('recordRow1',recordRow,data)
return <>
<Modal visible={modalVis} onCancel={onCancel} title='固件升级' onOk={okHandler}>
<Form initValues={{
}}
getFormApi={formApi => api.current = formApi}
labelCol={{ span: 7}}
wrapperCol={{span: 15}}
labelPosition='left' >
<Form.RadioGroup field="type" label='固件包' direction='vertical' rules={[{ required: true, message: '版本号必填' }]}>
{data&&data.length&&data[0].versionList&&data[0].versionList.length?
data[0].versionList.map((item,index)=><Form.Radio key={index} value={item.versionNo}>{`版本名称:${item.firmwareName}-版本号:${item.versionNo}`}</Form.Radio>)
:''}
</Form.RadioGroup>
</Form>
</Modal>
</>
}
function mapStateToProps (state) {
const { auth, global } = state;
return {
user: auth.user,
actions: global.actions,
apiRoot: global.apiRoot
};
}
export default connect(mapStateToProps)(firmwareListModal)

4
web/client/src/sections/service/components/maintenanceRecordModal.jsx

@ -15,14 +15,14 @@ const MaintenanceRecordModal = (props) => {
const api = useRef();
useEffect(() => {
console.log('recordRow', recordRow);
// console.log('recordRow', recordRow);
}, [recordRow]);
const cancelHandler = () => {
onClose();
};
const okHandler = () => {
api.current.validate().then((res) => {
console.log('res1', res)
// console.log('res1', res)
const query = {
id: recordRow?.id,
projectId:res.projectName,

2
web/client/src/sections/service/components/recordModal.jsx

@ -164,7 +164,7 @@ const RecordModal = (props) => {
}
function mapStateToProps (state) {
const { auth, global, members, webSocket, addRecord } = state;
console.log(addRecord);
// console.log(addRecord);
return {
addRecord: addRecord.isRequesting,
// user: auth.user,

246
web/client/src/sections/service/containers/deviceManagement.jsx

@ -0,0 +1,246 @@
import React, { useEffect, useState } from 'react';
import { connect } from 'react-redux';
import { Button, Table, Popconfirm, Pagination,Select,Input,Switch,Notification,Progress } from '@douyinfe/semi-ui';
import moment from 'moment'
import FirmwareListModal from '../components/firmwareListModal';
const DeviceManagement = (props) => {
const {actions,dispatch,pepProjectId,user}=props
const {service}=actions
const [updataButtonDisabled,setUpdataButtonDisabled]=useState(true)//
const [firmwareModalVis,setFirmwareModalVis]=useState(false)
const [strucAndDeviceType,setStrucAndDeviceType]=useState([])//
const [struc,setStruc]=useState([])//
const [deviceType,setDeviceType]=useState([])//optionList
const [data,setData]=useState([])//
const [thingIds,setThingIds]=useState([])//id
const [defaultVal,setDefaultVal]=useState('')//id
const [thingId,setThingId]=useState()//id
const [searchVal,setSearchVal]=useState()//
const [recordRow,setRecordRow]=useState()
const [selectedRows,setSelectedRows]=useState([])//key
const [selectdR,setSelectedR]=useState([])//
const [vData,setVData]=useState([])//
const getData=(query)=>{
dispatch(service.getThingMessages(query)).then((res)=>{
if(res.success) {
setData(res.payload.data)
}
})
dispatch(service.getFirmware(query)).then(res=>{
if(res.success) setVData(res.payload.data)
})
}
useEffect(()=>{
//
dispatch(service.getStruc({pepProjectId})).then((res)=>{
if(res.success) {
setStrucAndDeviceType( res.payload.data)
setStruc( res.payload.data?.map(item=>{
return {label:item.strucName,value:item.thingId}
}))
setThingIds(res.payload.data?.map(item=>item.thingId)?.join(',')||'')
}
})
// console.log('xxxx111',user)
},[])
useEffect(()=>{
const query={thingIds}
getData(query)
},[thingIds])
const structChange =value => {
clearSelectedRows()
setUpdataButtonDisabled(true)
const deviceTypeList= strucAndDeviceType?.find(item=>item.thingId==value)?.deviceType?.map(child=>{
return {
label:child.model,
value:child.id
}
})||[]
setDefaultVal('')
// console.log('event',deviceTypeList)
setDeviceType(deviceTypeList)
setThingId(value)
const query={thingIds:value,device_meta_id:defaultVal}
getData(query)
};
const deviceTypeChange=value=>{
setUpdataButtonDisabled(true)
clearSelectedRows()
setDefaultVal(value)
const query={thingIds:thingId,device_meta_id:value}
getData(query)
// console.log(value,'event')
}
//
const clearHandler=()=>{
setUpdataButtonDisabled(true)
clearSelectedRows()
const query={thingIds}
getData(query)
}
//
const cleartypeHandler=()=>{
setUpdataButtonDisabled(true)
clearSelectedRows()
setDefaultVal(null)
const query={thingIds:thingId}
getData(query)
}
//
const searchHandler=()=>{
if(!thingId&&!defaultVal){
const query={thingIds}
getData(query)
}else{
const query={thingIds:thingId,device_meta_id:defaultVal,searchVal}
getData(query)
}
}
const clearSelectedRows = () => {
setSelectedRows([]);
};
const rowSelection = {
selectedRowKeys: selectedRows, // keys
getCheckboxProps: record => ({
name: record.name,
}),
// onSelect: (record, selected) => {
// console.log(`select row: ${selected}`, record);
// },
onSelectAll: (selected, selectedRows) => {
setUpdataButtonDisabled(!selectedRows.every(item=>selectedRows[0]?.deviceType===item.deviceType))
},
onChange: (selectedRowKeys, selectedRows) => {
setSelectedR(selectedRows)
setSelectedRows(selectedRowKeys)
// console.log('xxxx',selectedRows)
//
if(selectedRows&&selectedRows.length===0){
setUpdataButtonDisabled(true)
}
//
if(selectedRows&&selectedRows.length>0){
setUpdataButtonDisabled(!selectedRows.every(item=>selectedRows[0].deviceType===item.deviceType))
}
},
};
let columns=[{
title: '序号',
render: (t, r, i) => {
return i + 1;
}
},{
title: '设备名称',
dataIndex: 'deviceName'
},{
title: '设备型号',
dataIndex: 'deviceType'
},
{
title: '固件名称',
dataIndex: 'firmwareName'
},
{
title: '固件版本号',
dataIndex: 'firmwareNo'
},
{
title: '升级状态',
render:(_,record)=>{
return record.status!=='未升级'&&record.status!=='升级成功'?<Progress percent={parseFloat(record.updatePercentage||0)} showInfo></Progress>:record.status
}
},
{
title: '升级开关状态',
dataIndex: 'switchStatus' ,
render:(_,record)=>{
return <Switch disabled defaultChecked={record.switchStatus}></Switch>
}
},
{
title: '操作',
render:(_,record)=>{
return <div>
<Button type="secondary" onClick={()=>{
if(record.switchStatus){
setFirmwareModalVis(true)
setRecordRow([record])
}else{
Notification.info({
title: '提示',
content: '请到安心云平台打开升级开关后进行升级。',
duration: 3,
})
}
if(record.status!=='未升级'&&record.status!=='升级成功'){
Notification.info({
title: '提示',
content: '该设备仍在升级中,请在完成升级后再操作。',
duration: 3,
})
}
}}>固件升级</Button>
</div>
}
}
]
return <><div style={{ background: '#FFFFFF', margin: '8px 12px', padding: '20px 20px 0px 20px' }}>
<div style={{ display: 'flex', alignItems: 'center' }}>
<div style={{ display: 'flex', alignItems: 'center',marginRight:30 }}>
<div style={{ width: 0, height: 20, borderLeft: '3px solid #005ABD', borderTop: '3px solid transparent', borderBottom: '3px solid transparent' }}></div>
<div style={{ fontFamily: "YouSheBiaoTiHei", fontSize: 24, color: '#101531', marginLeft: 8 }}>设备管理</div>
<div style={{ marginLeft: 6, fontSize: 12, color: '#969799', fontFamily: "DINExp", }}>Device Management</div>
</div>
<Select placeholder='请选择结构物' optionList={struc} filter showClear
onChange={structChange}
onClear={clearHandler}
style={{ width:300,marginRight:10}}>
</Select>
<Select placeholder='请选择设备型号' value={defaultVal} optionList={deviceType}
onClear={cleartypeHandler}
onChange={deviceTypeChange}
filter
showClear
style={{ width:300,marginRight:10}}></Select>
<Button style={{marginRight:10}} type="secondary" disabled={updataButtonDisabled} onClick={()=>{
setFirmwareModalVis(true);
setRecordRow(selectdR)
}}>固件升级</Button>
<Input placeholder='请输入设备名称' style={{ width:300,marginRight:10}} onChange={(e)=>{setSearchVal(e)}}></Input>
<Button style={{marginRight:10}} type="secondary" theme='solid'
onClick={searchHandler}
>查询</Button>
</div>
<div style={{marginTop:10}}>
<Table columns={columns} rowSelection={rowSelection} dataSource={data}></Table>
<FirmwareListModal vData={vData} versionData={data} modalVis={firmwareModalVis} recordRow={recordRow} onCancel={()=>{setFirmwareModalVis(false);setRecordRow(null)}}></FirmwareListModal>
</div>
</div>
</>
}
function mapStateToProps (state) {
const { auth, global, getPush } = state;
return {
loading: getPush.isRequesting,
user: auth.user,
actions: global.actions,
pepProjectId:global.pepProjectId
};
}
export default connect(mapStateToProps)(DeviceManagement);

135
web/client/src/sections/service/containers/firmwareLibrary.jsx

@ -0,0 +1,135 @@
import React, { useEffect, useState } from 'react';
import { connect } from 'react-redux';
import { Button, Table, Popconfirm, Pagination,Input,Toast } from '@douyinfe/semi-ui';
import moment from 'moment'
import AddFirmwareModal from '../components/addFirmwareModal'
const FirmwareLibrary = (props) => {
const {actions,dispatch}=props
const [modalVis,setModalVis]=useState(false)//
const [recordRow,setRecordRow]=useState()
const [data,setData]=useState([])//
const [searchVal,setSearchVal]=useState('')//
const [users,setUsers]=useState([])//
const {service}=actions
// console.log(data,'data1111')
const getData=(query)=>{
dispatch(service.getFirmware(query)).then(res=>{
if(res.success)setData(res.payload.data)
})
}
useEffect(()=>{
//
getData()
//
dispatch(service.getOrganizationUsers()).then(res=>{
setUsers(res.payload.data)
})
},[])
const searchHandler=()=>{
const query={version:searchVal}
getData(query)
}
const onConfirm = (record) => {
const query={version:record?.versionNo,device_meta_id:record?.device_meta_id,tokenup:'22767e1f-db8d-4a1d-87d4-56347cf21247'}
dispatch(service.deleteFirmware(query)).then(res=>{
if(res.success) {
getData()
// Toast.success('');
}
})
};
const onCancel = () => {
Toast.warning('取消删除');
};
let columns=[{
title: '序号',
render: (t, r, i) => {
return i + 1;
}
},{
title: '固件名称',
dataIndex: 'firmwareName'
},{
title: '设备型号',
dataIndex: 'deviceMetaName'
},
{
title: '版本号',
dataIndex: 'versionNo'
},
{
title: '上传时间',
dataIndex: 'uploadTime'
},
{
title: '上传人',
render:(_,record)=>{
return <span>{users?.find(item=>item.id==record.uploader)?.name||''}</span>
}
},
{
title: '备注',
dataIndex: 'comment'
},
{
title: '操作',
render:(_,record)=>{
return <div> <Popconfirm
title="确定是否要删除?"
onConfirm={()=>onConfirm(record)}
onCancel={onCancel}
>
<Button type="danger" theme='light'>删除</Button>
</Popconfirm>
<Button type="secondary" theme='solid' onClick={()=>{
setModalVis(true);
setRecordRow(record)
}}>编辑</Button>
</div>
}
}
]
return <><div style={{ background: '#FFFFFF', margin: '8px 12px', padding: '20px 20px 0px 20px' }}>
<div style={{ display: 'flex', alignItems: 'center' }}>
<div style={{ display: 'flex', alignItems: 'center',marginRight:30 }}>
<div style={{ width: 0, height: 20, borderLeft: '3px solid #005ABD', borderTop: '3px solid transparent', borderBottom: '3px solid transparent' }}></div>
<div style={{ fontFamily: "YouSheBiaoTiHei", fontSize: 24, color: '#101531', marginLeft: 8 }}>固件库</div>
<div style={{ marginLeft: 6, fontSize: 12, color: '#969799', fontFamily: "DINExp", }}>Firmware Library</div>
</div>
<Input placeholder='请输入名称版本号' style={{ width:300,marginRight:10}} onChange={(e)=>{setSearchVal(e)}}></Input>
<Button style={{marginRight:10}} type="secondary" theme='solid' onClick={searchHandler}>查询</Button>
<Button type="secondary" theme='solid' onClick={()=>{setModalVis(true)}}>上传</Button>
</div>
<div style={{marginTop:10}}>
<Table columns={columns} pagination dataSource={data} ></Table>
<AddFirmwareModal modalVis={modalVis} recordRow={recordRow} onCancel={()=>{getData({version:searchVal});setModalVis(false);setRecordRow(null)}}></AddFirmwareModal>
</div>
</div>
</>
}
function mapStateToProps (state) {
const { auth, global, getPush } = state;
// console.log('state1',state)
return {
loading: getPush.isRequesting,
user: auth.user,
actions: global.actions,
};
}
export default connect(mapStateToProps)(FirmwareLibrary);

5
web/client/src/sections/service/containers/index.js

@ -8,5 +8,6 @@ import AppPush from './appPush';
import MaintenanceModel from './maintenanceModel';
import ServiceRecord from './serviceRecord';
import MaintenanceRecords from './maintenanceRecords';
export { ReportManagement, CyclePlan, TemporaryResponse, EmPush, AppPush, MaintenanceModel, ServiceRecord, MaintenanceRecords };
import FirmwareLibrary from './firmwareLibrary'
import DeviceManagement from './deviceManagement';
export { ReportManagement, CyclePlan, TemporaryResponse, EmPush, AppPush, MaintenanceModel, ServiceRecord, MaintenanceRecords,DeviceManagement,FirmwareLibrary };

2
web/client/src/sections/service/containers/serviceRecord.jsx

@ -65,7 +65,7 @@ const Server = (props) => {
const query = {
sTime, eTime
}
console.log('sTime', sTime, eTime)
// console.log('sTime', sTime, eTime)
dispatch(service.calculability(query)).then((res) => {
if (res.success) setCalculability((Math.round(res.payload.data * 10000)) / 100 + '%'); // console.log(res.payload.data,'dateee')
})

9
web/client/src/sections/service/nav-item.jsx

@ -57,6 +57,15 @@ export function getNavItem (user, dispatch) {
icon: <iconpark-icon style={{ width: 20, height: 20 }} name="iconjianshezhong"></iconpark-icon>,
to: '/service/serviceRecord/MaintenanceRecords',
items: [{ itemKey:'MaintenanceRecords',to:'/service/serviceRecord/MaintenanceRecords',text:'维修记录'}]
},
{
itemKey: 'firmwareUpgrade',
text: '固件升级',
icon: <iconpark-icon style={{ width: 20, height: 20 }} name="iconjianshezhong"></iconpark-icon>,
to: '/service/firmwareUpgrade/FirmwareLibrary',
items: [{ itemKey:'FirmwareLibrary',to:'/service/firmwareUpgrade/FirmwareLibrary',text:'固件库'},
{ itemKey:'DeviceManagement',to:'/service/firmwareUpgrade/DeviceManagement',text:'设备管理'}
]
}
]
},

19
web/client/src/sections/service/routes.js

@ -1,4 +1,4 @@
import { ReportManagement, CyclePlan, TemporaryResponse, EmPush, AppPush, MaintenanceModel, ServiceRecord, MaintenanceRecords } from './containers';
import { ReportManagement, CyclePlan, TemporaryResponse, EmPush, AppPush, MaintenanceModel, ServiceRecord, MaintenanceRecords,FirmwareLibrary,DeviceManagement } from './containers';
export default [{
type: 'inner',
@ -73,6 +73,23 @@ export default [{
component: MaintenanceRecords,
breadcrumb: '维护记录',
}]
},
{
path: '/firmwareUpgrade',
key: 'firmwareUpgrade',
breadcrumb: '固件升级',
childRoutes: [{
path: '/FirmwareLibrary',
key: 'firmwareLibrary',
component: FirmwareLibrary,
breadcrumb: '固件库',
},{
path: '/DeviceManagement',
key: 'deviceManagement',
component: DeviceManagement,
breadcrumb: '设备管理',
}]
}
]
}
}];

17
web/client/src/utils/webapi.js

@ -147,7 +147,21 @@ export const ApiTable = {
respondRecord: 'respond-record',
//待办工单
workOrders:'unfinished'
workOrders:'unfinished',
//获取设备型号
getDeviceType:'deviceType',
//结构物和对应设备类型
getStruc:'structure',
//获取固件包列表
getFirmware:'firmware',
//增加/覆盖固件包
upgradeFirmware:'upgradeFirmware',
//删除固件包
deleteFirmware:'deleteFirmware',
//获取设备信息
getThingMessages:'getThingMessages',
//下发配置(批量单个)
distributeConfiguration:'distributeConfiguration'
};
// 项企的接口
@ -170,6 +184,7 @@ export const EmisApiTable = {
}
export const RouteTable = {
apiRoot: "/api/root",
fileUpload: "/_upload/new",

7
web/config.js

@ -27,6 +27,8 @@ args.option('pomsEs', 'es监控 web');
args.option('pomsNotebook', 'notebook web');
args.option('dcWeb', '报表中心web');
//硬件升级
args.option('crawapi','硬件升级')
// 七牛
args.option('qnak', 'qiniuAccessKey');
@ -51,7 +53,7 @@ const POMS_PGHERO = process.env.POMS_PGHERO || flags.pomsPghero;
const POMS_ES = process.env.POMS_ES || flags.pomsEs;
const POMS_NOTEBOOK = process.env.POMS_NOTEBOOK || flags.pomsNotebook;
const DC_WEB = process.env.DC_WEB || flags.dcWeb;
const CRAW_API=process.env.CRAW_API || flags.crawapi;
// 七牛
const ANXINCLOUD_QINIU_AK = process.env.ANXINCLOUD_QINIU_ACCESSKEY || flags.qnak;
const ANXINCLOUD_QINIU_SK = process.env.ANXINCLOUD_QINIU_SECRETKEY || flags.qnsk;
@ -60,7 +62,7 @@ const ANXINCLOUD_QINIU_DOMAIN_QNDMN_RESOURCE = process.env.ANXINCLOUD_QINIU_DOMA
if (
!API_URL
!API_URL|| !CRAW_API
|| !API_EMIS_URL || !WEB_EMIS_URL || !WEB_OA_URL
|| !API_ANXINYUN_URL
|| !POMS_MONITOR || !DC_WEB
@ -119,6 +121,7 @@ const product = {
pomsNotebook: POMS_NOTEBOOK,
dcWeb: DC_WEB,
staticRoot: './client',
crawapi:CRAW_API,
qiniu: {
fetchUrl: '/_file-server',

2
web/package.json

@ -7,7 +7,7 @@
"test": "mocha",
"start-vite": "cross-env NODE_ENV=developmentVite npm run start-params",
"start": "cross-env NODE_ENV=development npm run start-params",
"start-params": "node server -p 5600 -u http://localhost:4600 --apiPomsUrl http://localhost:4600 --apiAnxinyunUrl http://10.8.30.112:4100 --apiEmisUrl http://localhost:14000 --webEmisUrl http://localhost:5000 --webOaUrl http://10.8.30.161:8668 --qnak 5XrM4wEB9YU6RQwT64sPzzE6cYFKZgssdP5Kj3uu --qnsk w6j2ixR_i-aelc6I7S3HotKIX-ukMzcKmDfH6-M5 --qnbkt anxinyun-test --qndmn http://test.resources.anxinyun.cn --iotVcmpWeb https://mediaconsole.ngaiot.com --pomsMonitor http://monitor.anxinyun.cn/goto/PaEDLE84z?orgId=1 --pomsKubesphere https://k8sadmin.anxinyun.cn/ --pomsAmbari https://ambari.anxinyun.cn/ --pomsKowl https://kafka.anxinyun.cn/ --pomsPghero https://pghero.anxinyun.cn/ --pomsEs https://esc.anxinyun.cn/ --pomsNotebook https://inotebook.anxinyun.cn/ --dcWeb https://fsiot-oamss.anxinyun.cn",
"start-params": "node server -p 5600 -u http://localhost:4600 --apiPomsUrl http://localhost:4600 --apiAnxinyunUrl http://10.8.30.112:4100 --apiEmisUrl http://localhost:14000 --webEmisUrl http://localhost:5000 --webOaUrl http://10.8.30.161:8668 --qnak 5XrM4wEB9YU6RQwT64sPzzE6cYFKZgssdP5Kj3uu --qnsk w6j2ixR_i-aelc6I7S3HotKIX-ukMzcKmDfH6-M5 --qnbkt anxinyun-test --qndmn http://test.resources.anxinyun.cn --iotVcmpWeb https://mediaconsole.ngaiot.com --pomsMonitor http://monitor.anxinyun.cn/goto/PaEDLE84z?orgId=1 --pomsKubesphere https://k8sadmin.anxinyun.cn/ --pomsAmbari https://ambari.anxinyun.cn/ --pomsKowl https://kafka.anxinyun.cn/ --pomsPghero https://pghero.anxinyun.cn/ --pomsEs https://esc.anxinyun.cn/ --pomsNotebook https://inotebook.anxinyun.cn/ --crawapi http://218.3.126.49:30555/v1 --dcWeb https://fsiot-oamss.anxinyun.cn",
"deploy": "export NODE_ENV=production&& npm run build && node server",
"build-dev": "cross-env NODE_ENV=development&&webpack --config webpack.config.js",
"build": "cross-env NODE_ENV=production&&webpack --config webpack.config.prod.js"

3
web/routes/attachment/index.js

@ -19,7 +19,7 @@ module.exports = {
entry: function (app, router, opts) {
const getApiRoot = async function (ctx) {
const { apiUrl, iotVcmpWeb, pomsMonitor, pomsKubesphere, pomsAmbari, pomsKowl, pomsPghero, pomsEs, pomsNotebook, dcWeb, qiniu, webEmis, webOa } = opts;
const { apiUrl, iotVcmpWeb, pomsMonitor, pomsKubesphere, pomsAmbari, pomsKowl, pomsPghero, pomsEs, pomsNotebook, dcWeb, qiniu, webEmis, webOa,crawapi } = opts;
ctx.status = 200;
ctx.body = {
@ -36,6 +36,7 @@ module.exports = {
qiniu: qiniu,
webEmis,
webOa,
crawapi
};
};

Loading…
Cancel
Save