Browse Source

巡检项目发布

master
wenlele 1 year ago
parent
commit
6d35bc3649
  1. 0
      api/app/lib/controllers/projectManagement/projectBind.js
  2. 238
      api/app/lib/controllers/projectManagement/projectPublish.js
  3. 37
      api/app/lib/controllers/projectRegime/projectSituation.js
  4. 105
      api/app/lib/models/project_user.js
  5. 43
      api/app/lib/models/project_user_token.js
  6. 19
      api/app/lib/routes/projectBind/index.js
  7. 33
      api/app/lib/routes/projectManagement/index.js
  8. 52
      api/log/development.log
  9. 46
      script/2.1/schema/1.porject_user.sql
  10. 3
      web/client/src/layout/actions/global.js
  11. 91
      web/client/src/layout/reducers/global.js
  12. 4
      web/client/src/sections/projectManagement/actions/index.js
  13. 71
      web/client/src/sections/projectManagement/actions/projectPublish.js
  14. 128
      web/client/src/sections/projectManagement/components/projectModel.js
  15. 199
      web/client/src/sections/projectManagement/containers/projectPublish.js
  16. 1
      web/client/src/sections/projectRegime/actions/projectSituation.js
  17. 32
      web/client/src/utils/webapi.js
  18. 155
      web/config.js
  19. 279
      web/log/development.txt
  20. 218
      web/package.json
  21. 441
      web/routes/attachment/index.js

0
api/app/lib/controllers/projectBind/projectBind.js → api/app/lib/controllers/projectManagement/projectBind.js

238
api/app/lib/controllers/projectManagement/projectPublish.js

@ -0,0 +1,238 @@
'use strict'
const moment = require('moment')
const { QueryTypes } = require('sequelize');
const Hex = require('crypto-js/enc-hex');
const MD5 = require('crypto-js/md5');
let axyTokenCache = {
token: null,
orgId: null,
expireTime: null, //过期时间
}
async function getAnxinyunToken (ctx) {
try {
if (!axyTokenCache.token || moment() > moment(axyTokenCache.expireTime)) {
if (ctx.app.fs.opts.axyProject.split('/').length === 3) {
const dataToAxy = {
domain: ctx.app.fs.opts.axyProject.split('/')[0],
username: ctx.app.fs.opts.axyProject.split('/')[1],
password: ctx.app.fs.opts.axyProject.split('/')[2],
}
const axyResponse = await ctx.app.fs.anxinyun.post('login', { data: dataToAxy })
if (axyResponse.authorized) {
axyTokenCache.token = axyResponse.token //放进缓存
axyTokenCache.orgId = axyResponse.orgId //放进缓存
axyTokenCache.expireTime = moment().add(1, 'hour').format('YYYY-MM-DD HH:mm:ss')
}
}
}
return axyTokenCache
} catch (error) {
ctx.fs.logger.error(`sechedule: laborAttendance, error: ${error}`)
}
}
//调用安心云结构物接口
async function findAnxinyunProject (ctx, next) {
try {
let { type, url, params = {} } = ctx.request.body
let data = await getAnxinyunToken(ctx)
if (url && url.indexOf('{orgId}') != -1) {
url = url.replace(`{orgId}`, data.orgId)
}
const res = await ctx.app.fs.anxinyun[type](`${url}?token=${data.token}`, {
data: params.data || {},
query: params.query || {},
})
ctx.status = 200
ctx.body = res
} catch (error) {
ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`)
ctx.status = 400
ctx.body = {
message: '查询安心云项目失败',
}
}
}
async function addorEditRelation (ctx, next) {
let err = ''
const { axyProjectId, structrueId, id } = ctx.request.body
try {
const models = ctx.fs.dc.models
//编辑
if (id) {
const res = await models.ProjectBind.findOne({ where: { id, axyProjectId, structureId: structrueId } })
if (res) {
err = '所选安心云结构物和巡检结构物重复!!!'
throw '所选安心云结构物和巡检结构物重复!!!'
}
await models.ProjectBind.update({ axyProjectId, structureId: structrueId }, { where: { id } })
ctx.status = 204
ctx.body = {
message: '编辑成功!!',
}
} else {
//新增
const res = await models.ProjectBind.findOne({ where: { axyProjectId, structureId: structrueId } })
if (res) {
err = '所选安心云结构物和巡检结构物重复!!!'
throw '所选安心云结构物和巡检结构物重复!!!'
}
await models.ProjectBind.create({ axyProjectId, structureId: structrueId })
ctx.status = 204
ctx.body = {
message: '新增成功!!',
}
}
} catch (error) {
ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`)
ctx.status = 400
ctx.body = {
message: err ? err : id ? '编辑失败' : '新增失败',
}
}
}
async function getRelationList (ctx, next) {
try {
const models = ctx.fs.dc.models
const { limit, page, startTime, endTime } = ctx.query
let options = {
where: {},
}
if (limit) {
options.limit = Number(limit)
}
if (page && limit) {
options.offset = Number(page) * Number(limit)
}
if (startTime && endTime) {
options.where.inspectTm = { $between: [startTime, endTime] }
}
const res = await models.ProjectBind.findAndCountAll(options)
ctx.body = res
ctx.status = 200
} catch (error) {
ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`)
ctx.status = 400
ctx.body = {
message: '查询关联关系列表失败',
}
}
}
async function deleteRelation (ctx, next) {
const { id } = ctx.params
try {
const models = ctx.fs.dc.models
const res = await models.ProjectBind.findOne({ where: { id: Number(id) } })
if (!res) {
throw 'id不存在'
}
await models.ProjectBind.destroy({ where: { id: Number(id) } })
ctx.status = 200
} catch (error) {
ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`)
ctx.status = 400
ctx.body = {
message: '关联关系列表失败',
}
}
}
async function getProjectType (ctx, next) {
try {
const models = ctx.fs.dc.models
const sequelize = ctx.fs.dc.orm;
const { } = ctx.query
const res = await sequelize.query(`select distinct type from project`, { type: QueryTypes.SELECT });
ctx.body = res
ctx.status = 200
} catch (error) {
ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`)
ctx.status = 400
ctx.body = {
message: '获取项目类型失败',
}
}
}
async function getProjectPublishList (ctx, next) {
try {
const models = ctx.fs.dc.models
const { limit, page } = ctx.query
let options = {
where: {},
}
if (limit) {
options.limit = Number(limit)
}
if (page && limit) {
options.offset = Number(page) * Number(limit)
}
const res = await models.ProjectUser.findAndCountAll(options)
ctx.body = res
ctx.status = 200
} catch (error) {
ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`)
ctx.status = 400
ctx.body = {
message: '获取项目发布列表失败',
}
}
}
async function postProjectPublish (ctx, next) {
let message = '新增项目失败'
try {
const models = ctx.fs.dc.models
const data = ctx.request.body
const { id, password } = data
if (id) {
message = '修改项目失败'
await models.ProjectUser.update(data, { where: { id } })
} else {
let passwords = Hex.stringify(MD5(password));
await models.ProjectUser.create({ ...data, password: passwords, del: false })
}
ctx.status = 204
} catch (error) {
ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`)
ctx.status = 400
ctx.body = {
message: message
}
}
}
async function delProjectPublish (ctx, next) {
try {
const models = ctx.fs.dc.models
const { id } = ctx.params
await models.ProjectUser.destroy({ where: { id } })
ctx.status = 204
} catch (error) {
ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`)
ctx.status = 400
ctx.body = {
message: '删除项目失败'
}
}
}
module.exports = {
findAnxinyunProject,
addorEditRelation,
getRelationList,
deleteRelation,
getProjectType,
getProjectPublishList,
postProjectPublish,
delProjectPublish
}

37
api/app/lib/controllers/projectRegime/projectSituation.js

@ -3,11 +3,11 @@ const request = require('superagent');
const fs = require('fs'); const fs = require('fs');
const path = require('path'); const path = require('path');
async function projectList(ctx, next) { async function projectList (ctx, next) {
try { try {
const models = ctx.fs.dc.models; const models = ctx.fs.dc.models;
let userInfo = ctx.fs.api.userInfo; let userInfo = ctx.fs.api.userInfo;
const { limit, page, name, justStructure } = ctx.query; const { limit, page, name, type, justStructure } = ctx.query;
let options = { let options = {
where: { where: {
@ -28,16 +28,19 @@ async function projectList(ctx, next) {
if (name) { if (name) {
options.where.name = { $like: `%${name}%` } options.where.name = { $like: `%${name}%` }
} }
if (name) {
let res = [] options.where.name = { $like: `%${name}%` }
}
if (type) {
options.where.type = type
}
if (justStructure) { if (justStructure) {
res = await models.Project.findAndCountAll({ options.attributes = ['id', 'name','type']
attributes: ['id', 'name'],
})
} else {
res = await models.Project.findAndCountAll(options)
} }
let res = await models.Project.findAndCountAll(options)
ctx.status = 200; ctx.status = 200;
ctx.body = res ctx.body = res
} catch (error) { } catch (error) {
@ -50,8 +53,8 @@ async function projectList(ctx, next) {
} }
async function postAddProject(ctx, next) { async function postAddProject (ctx, next) {
let errMsg = '' let errMsg = ''
try { try {
const models = ctx.fs.dc.models; const models = ctx.fs.dc.models;
let userInfo = ctx.fs.api.userInfo; let userInfo = ctx.fs.api.userInfo;
@ -92,7 +95,7 @@ async function postAddProject(ctx, next) {
} }
} }
async function delProject(ctx, next) { async function delProject (ctx, next) {
try { try {
const models = ctx.fs.dc.models; const models = ctx.fs.dc.models;
let userInfo = ctx.fs.api.userInfo; let userInfo = ctx.fs.api.userInfo;
@ -160,7 +163,7 @@ let wxAccessToken = {
time: null time: null
} }
async function addPosition(ctx, next) { async function addPosition (ctx, next) {
try { try {
const models = ctx.fs.dc.models; const models = ctx.fs.dc.models;
let userInfo = ctx.fs.api.userInfo; let userInfo = ctx.fs.api.userInfo;
@ -253,7 +256,7 @@ async function addPosition(ctx, next) {
} }
} }
async function position(ctx, next) { async function position (ctx, next) {
try { try {
const models = ctx.fs.dc.models; const models = ctx.fs.dc.models;
let userInfo = ctx.fs.api.userInfo; let userInfo = ctx.fs.api.userInfo;
@ -293,7 +296,7 @@ async function position(ctx, next) {
} }
} }
async function delPosition(ctx, next) { async function delPosition (ctx, next) {
try { try {
const models = ctx.fs.dc.models; const models = ctx.fs.dc.models;
let userInfo = ctx.fs.api.userInfo; let userInfo = ctx.fs.api.userInfo;
@ -377,7 +380,7 @@ async function delPosition(ctx, next) {
} }
async function qrCodeShow(ctx, next) { async function qrCodeShow (ctx, next) {
try { try {
const models = ctx.fs.dc.models; const models = ctx.fs.dc.models;
let userInfo = ctx.fs.api.userInfo; let userInfo = ctx.fs.api.userInfo;
@ -408,7 +411,7 @@ async function qrCodeShow(ctx, next) {
} }
async function q(ctx) { async function q (ctx) {
// let error = { // let error = {
// name: 'FindError', // name: 'FindError',
// message: "获取失败!" // message: "获取失败!"

105
api/app/lib/models/project_user.js

@ -0,0 +1,105 @@
/* eslint-disable*/
'use strict';
module.exports = dc => {
const DataTypes = dc.ORM;
const sequelize = dc.orm;
const ProjectUser = sequelize.define("projectUser", {
id: {
type: DataTypes.INTEGER,
allowNull: false,
defaultValue: null,
comment: null,
primaryKey: true,
field: "id",
autoIncrement: true
},
projectName: {
type: DataTypes.STRING,
allowNull: false,
defaultValue: null,
comment: '项目名称',
primaryKey: false,
field: "project_name",
autoIncrement: false
},
projectDescribe: {
type: DataTypes.STRING,
allowNull: true,
defaultValue: null,
comment: "项目描述",
primaryKey: false,
field: "project_describe",
autoIncrement: false
},
projectType: {
type: DataTypes.STRING,
allowNull: false,
defaultValue: null,
comment: '项目类型',
primaryKey: false,
field: "project_type",
autoIncrement: false
},
monitorObject: {
type: DataTypes.ARRAY(DataTypes.INTEGER),
allowNull: false,
defaultValue: null,
comment: "监测对象",
primaryKey: false,
field: "monitor_object",
autoIncrement: false
},
account: {
type: DataTypes.STRING,
allowNull: false,
defaultValue: null,
comment: '发布账号',
primaryKey: false,
field: "account",
autoIncrement: false
},
password: {
type: DataTypes.STRING,
allowNull: false,
defaultValue: null,
comment: "发布密码",
primaryKey: false,
field: "password",
autoIncrement: false
},
createTime: {
type: DataTypes.STRING,
allowNull: false,
defaultValue: null,
comment: '创建时间',
primaryKey: false,
field: "create_time",
autoIncrement: false
},
code: {
type: DataTypes.STRING,
allowNull: false,
defaultValue: null,
comment: "p",
primaryKey: false,
field: "code",
autoIncrement: false
},
del: {
type: DataTypes.BOOLEAN,
allowNull: false,
defaultValue: null,
comment: "",
primaryKey: false,
field: "del",
autoIncrement: false
}
}, {
tableName: "project_user",
comment: "",
indexes: []
});
dc.models.ProjectUser = ProjectUser;
return ProjectUser;
};

43
api/app/lib/models/project_user_token.js

@ -0,0 +1,43 @@
/* eslint-disable*/
'use strict';
module.exports = dc => {
const DataTypes = dc.ORM;
const sequelize = dc.orm;
const ProjectUserToken = sequelize.define("projectUserToken", {
token: {
type: DataTypes.UUIDV4,
allowNull: false,
defaultValue: null,
comment: null,
primaryKey: true,
field: "token",
autoIncrement: false,
unique: "project_user_token_uindex"
},
projectUserInfo: {
type: DataTypes.JSONB,
allowNull: false,
defaultValue: null,
comment: null,
primaryKey: false,
field: "project_user_info",
autoIncrement: false
},
expired: {
type: DataTypes.DATE,
allowNull: false,
defaultValue: null,
comment: null,
primaryKey: false,
field: "expired",
autoIncrement: false
}
}, {
tableName: "project_user_token",
comment: "",
indexes: []
});
dc.models.ProjectUserToken = ProjectUserToken;
return ProjectUserToken;
};

19
api/app/lib/routes/projectBind/index.js

@ -1,19 +0,0 @@
'use strict';
const projectBind = require('../../controllers/projectBind/projectBind');
module.exports = function (app, router, opts) {
app.fs.api.logAttr['POST/anxinyun/project/list'] = { content: '获取安心云项目列表', visible: false }
router.post('/anxinyun/project/list', projectBind.findAnxinyunProject)
app.fs.api.logAttr['POST/anxinyun/project/relation'] = { content: '新增或编辑项目映射关系', visible: false }
router.post('/anxinyun/project/relation', projectBind.addorEditRelation)
app.fs.api.logAttr['GET/anxinyun/project/relation/list'] = { content: '获取项目映射关系列表', visible: false }
router.get('/anxinyun/project/relation/list', projectBind.getRelationList)
app.fs.api.logAttr['DELETE/anxinyun/project/relation/:id'] = { content: '删除项目映射关系', visible: false }
router.delete('/anxinyun/project/relation/:id', projectBind.deleteRelation)
}

33
api/app/lib/routes/projectManagement/index.js

@ -0,0 +1,33 @@
'use strict';
const projectBind = require('../../controllers/projectManagement/projectBind');
const projectPublish = require('../../controllers/projectManagement/projectPublish');
module.exports = function (app, router, opts) {
app.fs.api.logAttr['POST/anxinyun/project/list'] = { content: '获取安心云项目列表', visible: false }
router.post('/anxinyun/project/list', projectBind.findAnxinyunProject)
app.fs.api.logAttr['POST/anxinyun/project/relation'] = { content: '新增或编辑项目映射关系', visible: false }
router.post('/anxinyun/project/relation', projectBind.addorEditRelation)
app.fs.api.logAttr['GET/anxinyun/project/relation/list'] = { content: '获取项目映射关系列表', visible: false }
router.get('/anxinyun/project/relation/list', projectBind.getRelationList)
app.fs.api.logAttr['DELETE/anxinyun/project/relation/:id'] = { content: '删除项目映射关系', visible: false }
router.delete('/anxinyun/project/relation/:id', projectBind.deleteRelation)
app.fs.api.logAttr['GET/project/type'] = { content: '获取项目类型', visible: false }
router.get('/project/type', projectPublish.getProjectType)
app.fs.api.logAttr['GET/project/publish/list'] = { content: '获取项目发布列表', visible: false }
router.get('/project/publish/list', projectPublish.getProjectPublishList)
app.fs.api.logAttr['POST/project/publish/list'] = { content: '新增或编辑项目', visible: false }
router.post('/project/publish/list', projectPublish.postProjectPublish)
app.fs.api.logAttr['DEL/project/publish/:id'] = { content: '删除项目', visible: false }
router.del('/project/publish/:id', projectPublish.delProjectPublish)
}

52
api/log/development.log

@ -4328,3 +4328,55 @@ notNull Violation: PatrolPlan.patrolCount cannot be null
2024-01-08 14:28:04.506 - info: [FS-ATTACHMENT] Inject attachment mw into router. 2024-01-08 14:28:04.506 - info: [FS-ATTACHMENT] Inject attachment mw into router.
2024-01-08 14:28:04.506 - debug: init fs.attachment and inject it into app(app.fs.attachment) and runtime ctx(ctx.fs.attachment) 2024-01-08 14:28:04.506 - debug: init fs.attachment and inject it into app(app.fs.attachment) and runtime ctx(ctx.fs.attachment)
2024-01-08 14:28:04.507 - info: [FS-AUTH] Inject auth and api mv into router. 2024-01-08 14:28:04.507 - info: [FS-AUTH] Inject auth and api mv into router.
2024-01-09 10:59:44.815 - debug: [FS-LOGGER] Init.
2024-01-09 10:59:46.192 - info: [FS-ATTACHMENT] Inject attachment mw into router.
2024-01-09 10:59:46.192 - debug: init fs.attachment and inject it into app(app.fs.attachment) and runtime ctx(ctx.fs.attachment)
2024-01-09 10:59:46.194 - info: [FS-AUTH] Inject auth and api mv into router.
2024-01-09 11:01:09.444 - error: path: /project/type, error: ReferenceError: constres is not defined
2024-01-09 11:02:25.623 - debug: [FS-LOGGER] Init.
2024-01-09 11:02:25.975 - info: [FS-ATTACHMENT] Inject attachment mw into router.
2024-01-09 11:02:25.975 - debug: init fs.attachment and inject it into app(app.fs.attachment) and runtime ctx(ctx.fs.attachment)
2024-01-09 11:02:25.976 - info: [FS-AUTH] Inject auth and api mv into router.
2024-01-09 11:25:49.079 - debug: [FS-LOGGER] Init.
2024-01-09 11:25:49.379 - info: [FS-ATTACHMENT] Inject attachment mw into router.
2024-01-09 11:25:49.379 - debug: init fs.attachment and inject it into app(app.fs.attachment) and runtime ctx(ctx.fs.attachment)
2024-01-09 11:25:49.380 - info: [FS-AUTH] Inject auth and api mv into router.
2024-01-09 11:31:01.274 - debug: [FS-LOGGER] Init.
2024-01-09 11:31:01.572 - info: [FS-ATTACHMENT] Inject attachment mw into router.
2024-01-09 11:31:01.572 - debug: init fs.attachment and inject it into app(app.fs.attachment) and runtime ctx(ctx.fs.attachment)
2024-01-09 11:31:01.573 - info: [FS-AUTH] Inject auth and api mv into router.
2024-01-09 11:32:29.303 - debug: [FS-LOGGER] Init.
2024-01-09 11:32:29.592 - info: [FS-ATTACHMENT] Inject attachment mw into router.
2024-01-09 11:32:29.593 - debug: init fs.attachment and inject it into app(app.fs.attachment) and runtime ctx(ctx.fs.attachment)
2024-01-09 11:32:29.593 - info: [FS-AUTH] Inject auth and api mv into router.
2024-01-09 13:39:20.502 - debug: [FS-LOGGER] Init.
2024-01-09 13:39:21.092 - info: [FS-ATTACHMENT] Inject attachment mw into router.
2024-01-09 13:39:21.093 - debug: init fs.attachment and inject it into app(app.fs.attachment) and runtime ctx(ctx.fs.attachment)
2024-01-09 13:39:21.093 - info: [FS-AUTH] Inject auth and api mv into router.
2024-01-09 13:40:44.437 - error: path: /project/publish/list, error: ReferenceError: startTime is not defined
2024-01-09 13:41:30.948 - debug: [FS-LOGGER] Init.
2024-01-09 13:41:31.275 - info: [FS-ATTACHMENT] Inject attachment mw into router.
2024-01-09 13:41:31.276 - debug: init fs.attachment and inject it into app(app.fs.attachment) and runtime ctx(ctx.fs.attachment)
2024-01-09 13:41:31.276 - info: [FS-AUTH] Inject auth and api mv into router.
2024-01-09 13:41:38.928 - error: path: /project/publish/list, error: TypeError: Cannot read property 'findAndCountAll' of undefined
2024-01-09 13:44:46.008 - debug: [FS-LOGGER] Init.
2024-01-09 13:44:46.364 - info: [FS-ATTACHMENT] Inject attachment mw into router.
2024-01-09 13:44:46.365 - debug: init fs.attachment and inject it into app(app.fs.attachment) and runtime ctx(ctx.fs.attachment)
2024-01-09 13:44:46.365 - info: [FS-AUTH] Inject auth and api mv into router.
2024-01-09 13:47:41.402 - debug: [FS-LOGGER] Init.
2024-01-09 13:47:41.794 - info: [FS-ATTACHMENT] Inject attachment mw into router.
2024-01-09 13:47:41.796 - debug: init fs.attachment and inject it into app(app.fs.attachment) and runtime ctx(ctx.fs.attachment)
2024-01-09 13:47:41.797 - info: [FS-AUTH] Inject auth and api mv into router.
2024-01-09 13:49:41.051 - error: path: /project/publish/list, error: SequelizeDatabaseError: 关系 "project_user" 不存在
2024-01-09 13:51:01.115 - debug: [FS-LOGGER] Init.
2024-01-09 13:51:01.394 - info: [FS-ATTACHMENT] Inject attachment mw into router.
2024-01-09 13:51:01.394 - debug: init fs.attachment and inject it into app(app.fs.attachment) and runtime ctx(ctx.fs.attachment)
2024-01-09 13:51:01.394 - info: [FS-AUTH] Inject auth and api mv into router.
2024-01-09 14:20:36.427 - debug: [FS-LOGGER] Init.
2024-01-09 14:20:36.855 - info: [FS-ATTACHMENT] Inject attachment mw into router.
2024-01-09 14:20:36.856 - debug: init fs.attachment and inject it into app(app.fs.attachment) and runtime ctx(ctx.fs.attachment)
2024-01-09 14:20:36.861 - info: [FS-AUTH] Inject auth and api mv into router.
2024-01-09 14:47:05.905 - debug: [FS-LOGGER] Init.
2024-01-09 14:47:06.230 - info: [FS-ATTACHMENT] Inject attachment mw into router.
2024-01-09 14:47:06.231 - debug: init fs.attachment and inject it into app(app.fs.attachment) and runtime ctx(ctx.fs.attachment)
2024-01-09 14:47:06.231 - info: [FS-AUTH] Inject auth and api mv into router.

46
script/2.1/schema/1.porject_user.sql

@ -0,0 +1,46 @@
create table project_user
(
id serial not null,
project_name varchar(128) not null,
project_describe varchar,
project_type varchar(128) not null,
monitor_object integer[] not null,
account varchar(128) not null,
password varchar(128) not null,
create_time timestamp not null,
code varchar(128) not null,
del boolean not null
);
comment on table project_user is '发布项目';
comment on column project_user.project_name is '项目名称';
comment on column project_user.project_describe is '项目描述';
comment on column project_user.project_type is '项目类型';
comment on column project_user.monitor_object is '监测对象';
comment on column project_user.account is '发布账号';
comment on column project_user.password is '发布密码';
comment on column project_user.create_time is '创建时间';
comment on column project_user.code is 'p';
create unique index project_user_id_uindex
on project_user (id);
alter table project_user
add constraint project_user_pk
primary key (id);
create table project_user_token
(
token uuid not null,
project_user_info jsonb not null,
expired timestamp not null
);

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

@ -36,7 +36,8 @@ export function initApiRoot () {
dispatch({ dispatch({
type: INIT_API_ROOT, type: INIT_API_ROOT,
payload: { payload: {
apiRoot: res.root apiRoot: res.root,
webScreen: res.webScreen
} }
}) })
}); });

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

@ -1,52 +1,53 @@
'use strict'; 'use strict';
import Immutable from 'immutable'; import Immutable from 'immutable';
import { INIT_LAYOUT, RESIZE } from '../actions/global'; import { INIT_LAYOUT, RESIZE, INIT_API_ROOT } from '../actions/global';
import { SET_GLOBAL_SITE_LIST, CLEAR_GLOBAL_SITE_LIST } from '../actions/site' import { SET_GLOBAL_SITE_LIST, CLEAR_GLOBAL_SITE_LIST } from '../actions/site'
function global(state = { function global (state = {
title: '', title: '',
copyright: '', copyright: '',
sections: [], sections: [],
actions: {}, actions: {},
plugins: {}, plugins: {},
clientHeight: 768, clientHeight: 768,
clientWidth: 1024, clientWidth: 1024,
sites: [] sites: [],
webScreen: ''
}, action) { }, action) {
const payload = action.payload; const payload = action.payload;
switch (action.type) { switch (action.type) {
case RESIZE: case RESIZE:
return Immutable.fromJS(state).merge({ return Immutable.fromJS(state).merge({
clientHeight: payload.clientHeight, clientHeight: payload.clientHeight,
clientWidth: payload.clientWidth clientWidth: payload.clientWidth
}).toJS(); }).toJS();
case INIT_LAYOUT: case INIT_LAYOUT:
return { return {
title: payload.title, title: payload.title,
copyright: payload.copyright, copyright: payload.copyright,
sections: payload.sections, sections: payload.sections,
actions: payload.actions, actions: payload.actions,
plugins: payload.plugins, plugins: payload.plugins,
clientHeight: state.clientHeight, clientHeight: state.clientHeight,
detailsComponent: null, detailsComponent: null,
sites: [] sites: [],
}; };
// case INIT_RESOURCE_ROOT: case INIT_API_ROOT:
// return Immutable.fromJS(state).merge(payload).toJS(); return Immutable.fromJS(state).merge(payload).toJS();
// case INIT_PAGE_HEADER_DETAILS: // case INIT_PAGE_HEADER_DETAILS:
// return Immutable.fromJS(state).merge({ // return Immutable.fromJS(state).merge({
// detailsComponent: payload.component // detailsComponent: payload.component
// }).toJS(); // }).toJS();
case SET_GLOBAL_SITE_LIST: case SET_GLOBAL_SITE_LIST:
return Immutable.fromJS(state).merge({ return Immutable.fromJS(state).merge({
sites: payload.data sites: payload.data
}).toJS(); }).toJS();
case CLEAR_GLOBAL_SITE_LIST: case CLEAR_GLOBAL_SITE_LIST:
return Immutable.fromJS(state).merge({ return Immutable.fromJS(state).merge({
sites: [] sites: []
}).toJS(); }).toJS();
default: default:
return state; return state;
} }
} }
export default global; export default global;

4
web/client/src/sections/projectManagement/actions/index.js

@ -1,6 +1,8 @@
'use strict'; 'use strict';
import projectBinding from './projectBinding' import projectBinding from './projectBinding'
import projectPublish from './projectPublish'
export default { export default {
...projectBinding ...projectBinding,
...projectPublish
} }

71
web/client/src/sections/projectManagement/actions/projectPublish.js

@ -0,0 +1,71 @@
'use strict';
import { basicAction } from '@peace/utils'
import { ApiTable } from '$utils'
export function getProjectType () {
return dispatch => basicAction({
type: 'get',
dispatch: dispatch,
actionType: 'GET_PORJECT_TYPE',
url: `${ApiTable.projectType}`,
msg: { error: '获取项目类型失败' },
reducer: { name: 'projectType' }
});
}
export function getProjectPublishList (query = {}) {
return dispatch => basicAction({
type: 'get',
query,
dispatch: dispatch,
actionType: 'GET_PROJECT_PUBLISH_LIST',
url: `${ApiTable.projectPublishList}`,
msg: { error: '获取项目发布列表失败' },
reducer: { name: 'publishList' }
});
}
export function postProjectPublish (data = {}) {
return dispatch => basicAction({
type: 'post',
dispatch: dispatch,
data,
actionType: 'POST_PROJECT_PUBLISH',
url: `${ApiTable.projectPublishList}`,
msg: { option: data?.isCode ? '修改地址' : data?.id ? "编辑项目" : '新增项目' },
reducer: { name: 'anxinyunProject' }
});
}
// export function addorEditRelation(data) {
// return dispatch => basicAction({
// type: 'post',
// dispatch: dispatch,
// data,
// actionType: 'ADD_OR_EDIT_RELATION',
// url: `${ApiTable.addorEditRelation}`,
// msg: { option:data?.id? '编辑绑定关系':'新增绑定关系' },
// // reducer: { name: 'anxinyunProject'}
// });
// }
export function delProjectPublish (id) {
return dispatch => basicAction({
type: 'del',
dispatch: dispatch,
actionType: 'DEL_RELATION',
url: ApiTable.delProjectPublish.replace('{id}', id),
msg: { option: '删除项目' },
});
}
export default {
getProjectType,
getProjectPublishList,
postProjectPublish,
delProjectPublish
}

128
web/client/src/sections/projectManagement/components/projectModel.js

@ -0,0 +1,128 @@
import React, { useState, useEffect } from 'react';
import { connect } from 'react-redux';
import { v4 } from 'uuid';
import moment from 'moment';
import { Form, Input, Modal, Select, Row, Col, message } from 'antd';
const { TextArea } = Input;
const ProjectModel = ({ dispatch, actions, user, modelData, close, success, projectType, strucList }) => {
const { projectManagement, projectRegime } = actions
const [showBaiduMap, setShowBaiduMap] = useState(false)
const [strucData, setStrucData] = useState([])
const [form] = Form.useForm();
useEffect(() => {
if (modelData?.id) {
setStrucData(strucList?.filter(s => s.type == modelData?.projectType) || [])
}
}, [])
return (
<Modal
// className="global-modal"
title={modelData?.id ? '修改项目' : '新增项目'}
width={600}
open={true}
onOk={() => {
form.validateFields().then(v => {
if (modelData?.id || v.password == v.confirmPassword) {
dispatch(projectManagement.postProjectPublish({
...v,
id: modelData?.id,
createTime: moment(modelData?.createTime).format('YYYY-MM-DD HH:mm:ss'),
code: modelData?.code || v4()
})).then(res => {
if (res.success) {
success()
}
})
} else {
message.warning('两次输入的密码不一致');
}
})
}}
onCancel={() => close()}
>
<Form
style={{}}
form={form}
labelAlign='right'
labelCol={{ span: 4 }} wrapperCol={{ span: 18 }}
onFinish={r => {
}}
>
<Form.Item label='项目名称' name='projectName' initialValue={modelData?.projectName}
rules={[{ required: true, message: '请输入项目名称' },]}
>
<Input style={{ width: 210 }} placeholder='请输入项目名称' />
</Form.Item>
<Form.Item name='projectDescribe' label="项目描述" initialValue={modelData?.projectDescribe}
rules={[{ required: true, message: '请输入项目描述' },]}
>
<TextArea placeholder='请输入项目描述' style={{ width: 360 }} />
</Form.Item>
<Form.Item label='项目类型' name="projectType"
initialValue={modelData?.projectType}
rules={[{ required: true, message: '请选择项目类型' },]}
>
<Select allowClear options={projectType?.map(d => ({ value: d.type, label: d.type })) || []} style={{ width: 254 }} placeholder='请选择项目类型'
onSelect={d => {
form.setFieldValue('monitorObject', [])
setStrucData(strucList?.filter(s => s.type == d) || [])
}}
/>
</Form.Item>
<Form.Item label='监测对象' name="monitorObject"
initialValue={modelData?.monitorObject || []}
rules={[{ required: true, message: '请选择监测对象' },]}
>
<Select allowClear options={strucData?.map(d => ({ value: d.id, label: d.name })) || []} style={{ width: 254 }} mode='multiple' placeholder='请选择监测对象'
/>
</Form.Item>
<Form.Item label='发布账号' name='account' initialValue={modelData?.account}
rules={[{ required: true, message: '请输入发布账号' },]}
>
<Input style={{ width: 150 }} placeholder='请输入发布账号' />
</Form.Item>
{!modelData?.id &&
<>
<Form.Item label='发布密码' name='password' initialValue={modelData?.password}
rules={[{ required: true, message: '请输入发布密码' },]}
>
<Input.Password autocomplete='new-password' onPaste={e => {
e.preventDefault();
}} style={{ width: 150 }} placeholder='请输入发布密码' />
</Form.Item>
<Form.Item label='确认密码' name='confirmPassword' initialValue={modelData?.confirmPassword}
rules={[{ required: true, message: '请输入确认密码' },]}
>
<Input.Password autocomplete='new-password' style={{ width: 150 }} placeholder='请输入确认密码' />
</Form.Item>
</>
}
</Form>
</Modal>
);
};
function mapStateToProps (state) {
const { auth, global, projectType } = state;
return {
user: auth.user,
actions: global.actions,
projectType: projectType?.data || [],
};
}
export default connect(mapStateToProps)(ProjectModel);

199
web/client/src/sections/projectManagement/containers/projectPublish.js

@ -1,51 +1,60 @@
import React, { useEffect, useState } from 'react'; import React, { useEffect, useState } from 'react';
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import { Form, Input, Button, Table, Modal, Popconfirm, Tooltip } from 'antd'; import { Spin, Form, Input, Button, Table, Modal, Popconfirm, Tooltip } from 'antd';
import { SettingOutlined } from '@ant-design/icons';
import { push } from 'react-router-redux'; import { push } from 'react-router-redux';
// import ProjectAddModel from '../components/projectAddModel' import moment from 'moment';
import { v4 } from 'uuid';
import ProjectModel from '../components/projectModel'
import './style.less'; import './style.less';
const ProjectPublish = ({ dispatch, actions, user, loading }) => { const ProjectPublish = ({ dispatch, actions, user, loading, publishList, webScreen }) => {
const { projectManagement } = actions const { projectManagement, projectRegime } = actions
const [firmList, setFirmList] = useState([]) const [firmList, setFirmList] = useState([])
const [tableList, settableList] = useState([]) const [tableList, settableList] = useState([])
const [addModel, setAddModel] = useState(false) const [editModel, setEditModel] = useState(false)
const [codeEdit, setCodeEdit] = useState(false)
const [modelData, setModelData] = useState({}) const [modelData, setModelData] = useState({})
const [query, setQuery] = useState({ limit: 10, page: 0 }) const [query, setQuery] = useState({ limit: 10, page: 0 })
const [limits, setLimits] = useState() const [strucList, setStrucList] = useState([])
const [search, setSearch] = useState({}) const [search, setSearch] = useState({})
const [companyID, setCompanyId] = useState('') const [companyID, setCompanyId] = useState('')
const [code, setCode] = useState('')
useEffect(() => { useEffect(() => {
projectList(query) dispatch(projectManagement.getProjectType())
dispatch(projectRegime.getProjectList({ justStructure: true })).then(v => {
if (v.success) {
setStrucList(v.payload.data?.rows || [])
}
})
projectPublishList(query)
}, []) }, [])
const projectList = (obj) => { const projectPublishList = (data = {}) => {
// const { limit, page, name } = obj dispatch(projectManagement.getProjectPublishList(data))
// dispatch(projectManagement.getProjectList({ limit, page, name, })).then(res => {
// // console.log(res)
// if (res.success) {
// settableList(res.payload.data?.rows?.map(v => ({ ...v, key: v.id })))
// setLimits(res.payload.data?.count)
// }
// })
} }
const columns = [{ const columns = [{
title: '项目名称', title: '项目名称',
dataIndex: 'porjectName', dataIndex: 'projectName',
key: 'porjectName', key: 'projectName',
}, { }, {
title: '监测对象', title: '监测对象',
dataIndex: 'monitorObject', dataIndex: 'monitorObject',
key: 'monitorObject', key: 'monitorObject',
render: (text, record, index) => text && text.json('、') render: (text, record, index) => {
let findAll = strucList?.filter(d => text?.includes(d.id))?.map(s => s.name) || []
return findAll.join('、') || '--'
}
}, { }, {
title: '创建时间', title: '创建时间',
dataIndex: 'createTime', dataIndex: 'createTime',
@ -58,7 +67,7 @@ const ProjectPublish = ({ dispatch, actions, user, loading }) => {
render: (text, record, index) => { render: (text, record, index) => {
return (<> return (<>
<Button type="link" onClick={() => { <Button type="link" onClick={() => {
setAddModel(true) setEditModel(true)
setModelData(record) setModelData(record)
}} }}
>修改</Button> >修改</Button>
@ -66,25 +75,21 @@ const ProjectPublish = ({ dispatch, actions, user, loading }) => {
title={<div style={{ width: 180 }}>是否确认删除此项目</div>} title={<div style={{ width: 180 }}>是否确认删除此项目</div>}
position='topLeft' position='topLeft'
onConfirm={() => { onConfirm={() => {
// dispatch(projectRegime.delProject(record.id)).then(res => { dispatch(projectManagement.delProjectPublish(record.id)).then(res => {
// if (res.success) { if (res.success) {
// if ((limits > 11 && tableList.length > 1) || limits < 11) { setQuery({ limit: 10, page: 0 });
// projectList({ ...query, ...search }) projectPublishList({ limit: 10, page: 0 })
// } else { }
// projectList({ limit: query?.limit, page: query?.page - 1, ...search }) })
// setQuery({ limit: query?.limit, page: query?.page - 1 });
// }
// }
// })
}} }}
> >
<Button type="link" danger >删除</Button> <Button type="link" danger >删除</Button>
</Popconfirm> </Popconfirm>
{/* <Button type="link" danger >二维码生成</Button> */}
<Button type="link" onClick={() => { <Button type="link" onClick={() => {
dispatch(push(`/projectRegime/information/${record.id}/point`)); setCode(record?.code)
}} >点位</Button></> setModelData(record)
setCodeEdit(true)
}} >地址</Button></>
) )
} }
} }
@ -92,70 +97,108 @@ const ProjectPublish = ({ dispatch, actions, user, loading }) => {
return ( return (
<div className='global-main'> <div className='global-main'>
<Button type="primary" onClick={() => { <Button type="primary" style={{ marginBottom: 10 }} onClick={() => {
setAddModel(true) setEditModel(true)
// setModelData(record)
}} }}
>新增</Button> >新增</Button>
<Table <Spin spinning={loading}>
columns={columns} <Table
dataSource={tableList} columns={columns}
pagination={{ dataSource={publishList?.rows || []}
className: 'global-pagination', pagination={{
current: query.page + 1, className: 'global-pagination',
total: limits, current: query.page + 1,
showSizeChanger: true, total: publishList?.count || 0,
showQuickJumper: true, showSizeChanger: true,
pageSizeOptions: [10, 20, 50], showQuickJumper: true,
showTotal: (total) => { pageSizeOptions: [10, 20, 50],
return <span style={{ fontSize: 15 }}>{`${Math.ceil(total / query?.limit)}页,${total}`}</span> showTotal: (total) => {
}, return <span style={{ fontSize: 15 }}>{`${Math.ceil(total / query?.limit)}页,${total}`}</span>
onChange: (page, pageSize) => { },
setQuery({ limit: pageSize, page: page - 1 }); onChange: (page, pageSize) => {
projectList({ limit: pageSize, page: page - 1, ...search, companyId: companyID || search?.companyId }) setQuery({ limit: pageSize, page: page - 1 });
} projectPublishList({ limit: pageSize, page: page - 1 })
}} }
// rowSelection={{ }}
// selectedRowKeys: select || [], // rowSelection={{
// onChange: (selectedRowKeys, selectedRows) => { // selectedRowKeys: select || [],
// setSelect(selectedRowKeys) // onChange: (selectedRowKeys, selectedRows) => {
// console.log(selectedRowKeys, selectedRows); // setSelect(selectedRowKeys)
// } // console.log(selectedRowKeys, selectedRows);
// }} // }
rowClassName={(record, index) => { // }}
let className = 'global-light-row'; rowClassName={(record, index) => {
if (index % 2 === 1) className = 'global-dark-row'; let className = 'global-light-row';
return className; if (index % 2 === 1) className = 'global-dark-row';
}} return className;
// scroll={{ y: 590 }} }}
/> // scroll={{ y: 590 }}
/>
</Spin>
{/* {
addModel ? {
<ProjectAddModel editModel ?
firmList={firmList} <ProjectModel
strucList={strucList}
modelData={modelData} modelData={modelData}
close={() => { close={() => {
setAddModel(false) setEditModel(false)
setModelData({}) setModelData({})
}} }}
success={() => { success={() => {
setAddModel(false) setEditModel(false)
setModelData({}) setModelData({})
setQuery({ limit: 10, page: 0 }); setQuery({ limit: 10, page: 0 });
projectList({ limit: 10, page: 0, ...search, companyId: companyID || search?.companyId }) projectPublishList({ limit: 10, page: 0 })
}} }}
/> : "" /> : ""
} */} }
{
codeEdit &&
<Modal
title={'项目地址'}
width={600}
open={codeEdit}
onOk={() => {
dispatch(projectManagement.postProjectPublish({
id: modelData?.id,
code: code || v4(),
isCode: true,
})).then(res => {
if (res.success) {
setCodeEdit(false)
setCode("")
setModelData({})
}
})
}}
onCancel={() => {
setCodeEdit(false)
setCode("")
setModelData({})
}}
>
<Input
disabled={true}
addonBefore={webScreen + '?p='}
addonAfter={<div style={{ cursor: 'pointer' }} onClick={() => { setCode(v4()) }}><SettingOutlined />修改</div>}
value={code} />
</Modal>
}
</div> </div>
) )
} }
function mapStateToProps (state) { function mapStateToProps (state) {
const { auth, global } = state; const { auth, global, publishList } = state;
return { return {
user: auth.user, user: auth.user,
actions: global.actions, actions: global.actions,
loading: publishList?.isRequesting,
publishList: publishList?.data || {},
webScreen: global?.webScreen
}; };
} }

1
web/client/src/sections/projectRegime/actions/projectSituation.js

@ -12,6 +12,7 @@ export function getProjectList (query) {
actionType: 'GET_PROJEECT_LIST', actionType: 'GET_PROJEECT_LIST',
url: ApiTable.getProjectList, url: ApiTable.getProjectList,
msg: { error: '获取结构物列表失败', }, msg: { error: '获取结构物列表失败', },
reducer: { name: 'projectList'}
}); });
} }

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

@ -146,29 +146,33 @@ export const ApiTable = {
addDevice: 'device', addDevice: 'device',
modifyDevice: 'device/{id}', modifyDevice: 'device/{id}',
//报表配置相关 //报表配置相关
getReportList:'reportList', getReportList: 'reportList',
postReport:'postReport', postReport: 'postReport',
delReport: "reportList/{id}", //删除报表规则 delReport: "reportList/{id}", //删除报表规则
generateReport: "generate/report",//报表生成 generateReport: "generate/report",//报表生成
//项目映射相关 //项目映射相关
getanxinyunProject:'anxinyun/project/list', getanxinyunProject: 'anxinyun/project/list',
addorEditRelation:'anxinyun/project/relation', addorEditRelation: 'anxinyun/project/relation',
delRelation:'anxinyun/project/relation/{id}', delRelation: 'anxinyun/project/relation/{id}',
getRelation:'anxinyun/project/relation/list', getRelation: 'anxinyun/project/relation/list',
//项目发布
projectType: "project/type", //获取项目类型
projectPublishList: 'project/publish/list', //获取项目发布列表
delProjectPublish: "project/publish/{id}", //删除项目
//资讯公告 //资讯公告
getAdvisoryNotices:'advisoryNotices/list', getAdvisoryNotices: 'advisoryNotices/list',
addOrUpdateAdvisoryNotice:'advisoryNotices/addOrUpdate', addOrUpdateAdvisoryNotice: 'advisoryNotices/addOrUpdate',
delAdvisoryNotice:'advisoryNotices/{id}', delAdvisoryNotice: 'advisoryNotices/{id}',
updateAdvisoryNoticeState:'updateAdvisoryNotices/{id}', updateAdvisoryNoticeState: 'updateAdvisoryNotices/{id}',
//宽带专网 //宽带专网
getNetworks:'network', getNetworks: 'network',
addOrUpdateNetwork:'network', addOrUpdateNetwork: 'network',
delNetwork:'network/{id}', delNetwork: 'network/{id}',
}; };
export const RouteTable = { export const RouteTable = {

155
web/config.js

@ -15,6 +15,7 @@ dev && console.log('\x1B[33m%s\x1b[0m', '请遵循并及时更新 readme.md,
// // 启动参数 // // 启动参数
args.option(['p', 'port'], '启动端口'); args.option(['p', 'port'], '启动端口');
args.option(['u', 'api-url'], 'webapi的URL'); args.option(['u', 'api-url'], 'webapi的URL');
args.option('webScreen', '巡检大屏web');
args.option('qnak', 'qiniuAccessKey'); args.option('qnak', 'qiniuAccessKey');
args.option('qnsk', 'qiniuSecretKey'); args.option('qnsk', 'qiniuSecretKey');
args.option('qnbkt', 'qiniuBucket'); args.option('qnbkt', 'qiniuBucket');
@ -23,9 +24,12 @@ args.option('aliOssAccessKey', '阿里OSS AccessKey');
args.option('aliOssSecretKey', '阿里OSS SecretKey'); args.option('aliOssSecretKey', '阿里OSS SecretKey');
args.option('aliOssBucket', '阿里OSS Bucket'); args.option('aliOssBucket', '阿里OSS Bucket');
args.option('aliOssRegion', '阿里OSS Region'); args.option('aliOssRegion', '阿里OSS Region');
const flags = args.parse(process.argv); const flags = args.parse(process.argv);
const FS_UNIAPP_API = process.env.FS_UNIAPP_API || flags.apiUrl; const FS_UNIAPP_API = process.env.FS_UNIAPP_API || flags.apiUrl;
const FS_WEB_SCREEN = process.env.FS_WEB_SCREEN || flags.webScreen;
const ANXINCLOUD_QINIU_ACCESSKEY = process.env.ANXINCLOUD_QINIU_ACCESSKEY || flags.qnak; const ANXINCLOUD_QINIU_ACCESSKEY = process.env.ANXINCLOUD_QINIU_ACCESSKEY || flags.qnak;
const ANXINCLOUD_QINIU_SECRETKEY = process.env.ANXINCLOUD_QINIU_SECRETKEY || flags.qnsk; const ANXINCLOUD_QINIU_SECRETKEY = process.env.ANXINCLOUD_QINIU_SECRETKEY || flags.qnsk;
const ANXINCLOUD_QINIU_BUCKET_RESOURCE = process.env.ANXINCLOUD_QINIU_BUCKET_RESOURCE || flags.qnbkt; const ANXINCLOUD_QINIU_BUCKET_RESOURCE = process.env.ANXINCLOUD_QINIU_BUCKET_RESOURCE || flags.qnbkt;
@ -38,89 +42,90 @@ const ALI_OSS_BUCKET = process.env.ALI_OSS_BUCKET || flags.aliOssBucket;
const ALI_OSS_REGION = process.env.ALI_OSS_REGION || flags.aliOssRegion; const ALI_OSS_REGION = process.env.ALI_OSS_REGION || flags.aliOssRegion;
if (!FS_UNIAPP_API || !ANXINCLOUD_QINIU_ACCESSKEY || !ANXINCLOUD_QINIU_SECRETKEY || !ANXINCLOUD_QINIU_BUCKET_RESOURCE || !ANXINCLOUD_QINIU_DOMAIN_QNDMN_RESOURCE) { if (!FS_UNIAPP_API || !ANXINCLOUD_QINIU_ACCESSKEY || !ANXINCLOUD_QINIU_SECRETKEY || !ANXINCLOUD_QINIU_BUCKET_RESOURCE || !ANXINCLOUD_QINIU_DOMAIN_QNDMN_RESOURCE) {
console.log('缺少启动参数,异常退出'); console.log('缺少启动参数,异常退出');
args.showHelp(); args.showHelp();
process.exit(-1); process.exit(-1);
} }
const product = { const product = {
port: flags.port || 8080, port: flags.port || 8080,
staticDirs: [path.join(__dirname, './client')], staticDirs: [path.join(__dirname, './client')],
mws: [{ mws: [{
entry: require('./middlewares/proxy').entry, entry: require('./middlewares/proxy').entry,
opts: { opts: {
host: FS_UNIAPP_API, host: FS_UNIAPP_API,
match: /^\/_api\//, match: /^\/_api\//,
} }
}, { }, {
entry: require('./middlewares/attachment').entry, entry: require('./middlewares/attachment').entry,
opts: { opts: {
qiniu: { qiniu: {
accessKey: ANXINCLOUD_QINIU_ACCESSKEY, accessKey: ANXINCLOUD_QINIU_ACCESSKEY,
secretKey: ANXINCLOUD_QINIU_SECRETKEY, secretKey: ANXINCLOUD_QINIU_SECRETKEY,
bucket: ANXINCLOUD_QINIU_BUCKET_RESOURCE, bucket: ANXINCLOUD_QINIU_BUCKET_RESOURCE,
domain: ANXINCLOUD_QINIU_DOMAIN_QNDMN_RESOURCE domain: ANXINCLOUD_QINIU_DOMAIN_QNDMN_RESOURCE
}, },
maxSize: 104857600, // 100M maxSize: 104857600, // 100M
uploadPath: 'other' uploadPath: 'other'
} }
}, { }, {
entry: require('./routes').entry, entry: require('./routes').entry,
opts: { opts: {
apiUrl: FS_UNIAPP_API, apiUrl: FS_UNIAPP_API,
staticRoot: './client', staticRoot: './client',
qiniu: { webScreen: FS_WEB_SCREEN,
fetchUrl: '/_file-server', qiniu: {
domain: ANXINCLOUD_QINIU_DOMAIN_QNDMN_RESOURCE fetchUrl: '/_file-server',
}, domain: ANXINCLOUD_QINIU_DOMAIN_QNDMN_RESOURCE
aliOss: { },
fetchUrl: '/_file-ali-server', aliOss: {
accessKey: ALI_OSS_ACCESSKEY, fetchUrl: '/_file-ali-server',
secretKey: ALI_OSS_SECRETKET, accessKey: ALI_OSS_ACCESSKEY,
bucket: ALI_OSS_BUCKET, secretKey: ALI_OSS_SECRETKET,
region: ALI_OSS_REGION bucket: ALI_OSS_BUCKET,
} region: ALI_OSS_REGION
} }
}, { }
entry: require('./client').entry,// 静态信息 }, {
opts: {} entry: require('./client').entry,// 静态信息
}], opts: {}
logger: { }],
level: 'debug', logger: {
json: false, level: 'debug',
filename: path.join(__dirname, 'log', 'runtime.txt'), json: false,
colorize: true, filename: path.join(__dirname, 'log', 'runtime.txt'),
maxsize: 1024 * 1024 * 5, colorize: true,
rotationFormat: false, maxsize: 1024 * 1024 * 5,
zippedArchive: true, rotationFormat: false,
maxFiles: 10, zippedArchive: true,
prettyPrint: true, maxFiles: 10,
label: '', prettyPrint: true,
timestamp: () => moment().format('YYYY-MM-DD HH:mm:ss.SSS'), label: '',
eol: os.EOL, timestamp: () => moment().format('YYYY-MM-DD HH:mm:ss.SSS'),
tailable: true, eol: os.EOL,
depth: null, tailable: true,
showLevel: true, depth: null,
maxRetries: 1 showLevel: true,
} maxRetries: 1
}
}; };
let config; let config;
if (dev) { if (dev) {
config = { config = {
port: product.port, port: product.port,
staticDirs: product.staticDirs, staticDirs: product.staticDirs,
mws: product.mws.concat([ mws: product.mws.concat([
{ {
entry: require('./middlewares/webpack-dev').entry, entry: require('./middlewares/webpack-dev').entry,
opts: {} opts: {}
} }
]), ]),
logger: product.logger logger: product.logger
} }
config.logger.filename = path.join(__dirname, 'log', 'development.txt'); config.logger.filename = path.join(__dirname, 'log', 'development.txt');
} else { } else {
config = product; config = product;
} }
module.exports = config;//区分开发和发布 module.exports = config;//区分开发和发布

279
web/log/development.txt

@ -5645,3 +5645,282 @@
2024-01-08 13:25:12.319 - debug: [FS-LOGGER] Init. 2024-01-08 13:25:12.319 - debug: [FS-LOGGER] Init.
2024-01-08 13:25:12.322 - debug: init fs.attachment and inject it into app(app.fs.attachment) and runtime ctx(ctx.fs.attachment) 2024-01-08 13:25:12.322 - debug: init fs.attachment and inject it into app(app.fs.attachment) and runtime ctx(ctx.fs.attachment)
2024-01-08 13:25:15.341 - info: [Router] Inject api: attachment/index 2024-01-08 13:25:15.341 - info: [Router] Inject api: attachment/index
2024-01-09 11:00:43.055 - info: extNames
[
'/_file-server/project/1f19d5d5-45bc-4190-bbc0-2254e81b4dbc/5',
'JPg'
]
2024-01-09 11:02:19.821 - error: [FS-ERRHD]
{
message: 'Error: read ECONNRESET',
name: 'RequestError',
cause: { errno: 'ECONNRESET', code: 'ECONNRESET', syscall: 'read' },
error: { '$ref': '$["cause"]' },
options: {
jar: false,
url: 'http://127.0.0.1:4900/project/type?token=3947c6c4-ebfa-4eae-b097-9f5ad8fc800c',
headers: {
host: '127.0.0.1:4900',
connection: 'keep-alive',
'sec-ch-ua': '"Not_A Brand";v="8", "Chromium";v="120", "Google Chrome";v="120"',
expires: '-1',
'cache-control': 'no-cache,no-store,must-revalidate,max-age=-1,private',
'x-requested-with': 'XMLHttpRequest',
'sec-ch-ua-mobile': '?0',
'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',
'sec-ch-ua-platform': '"Windows"',
accept: '*/*',
'sec-fetch-site': 'same-origin',
'sec-fetch-mode': 'cors',
'sec-fetch-dest': 'empty',
referer: 'http://localhost:5900/projectManagement/projectPublish',
'accept-encoding': 'gzip, deflate, br',
'accept-language': 'zh-CN,zh;q=0.9',
cookie: '__51vcke__Jo4eTlZVqgx3uwqm=1fad3d39-9b32-5c9c-99eb-547dddae7232; __51vuft__Jo4eTlZVqgx3uwqm=1684920883692; __51uvsct__Jo4eTlZVqgx3uwqm=44; cookie-gray-released=new; cookie-gray-released.sig=k487rENXok_KtaXhanO3Rm1eP7I'
},
encoding: null,
followRedirect: true,
method: 'GET',
body: '[object Object]',
simple: false,
resolveWithFullResponse: true,
callback: [Function: RP$callback],
transform: undefined,
transform2xxOnly: false
},
response: undefined,
stack: 'RequestError: Error: read ECONNRESET\n' +
' at new RequestError (C:\\Users\\方式、\\Desktop\\项目资料\\巡检\\Inspection\\web\\node_modules\\request-promise-core\\lib\\errors.js:14:15)\n' +
' at Request.plumbing.callback (C:\\Users\\方式、\\Desktop\\项目资料\\巡检\\Inspection\\web\\node_modules\\request-promise-core\\lib\\plumbing.js:87:29)\n' +
' at Request.RP$callback [as _callback] (C:\\Users\\方式、\\Desktop\\项目资料\\巡检\\Inspection\\web\\node_modules\\request-promise-core\\lib\\plumbing.js:46:31)\n' +
' at self.callback (C:\\Users\\方式、\\Desktop\\项目资料\\巡检\\Inspection\\web\\node_modules\\request\\request.js:185:22)\n' +
' at Request.emit (events.js:314:20)\n' +
' at Request.onRequestError (C:\\Users\\方式、\\Desktop\\项目资料\\巡检\\Inspection\\web\\node_modules\\request\\request.js:877:8)\n' +
' at ClientRequest.emit (events.js:314:20)\n' +
' at Socket.socketErrorListener (_http_client.js:427:9)\n' +
' at Socket.emit (events.js:314:20)\n' +
' at emitErrorNT (internal/streams/destroy.js:92:8)\n' +
' at emitErrorAndCloseNT (internal/streams/destroy.js:60:3)\n' +
' at processTicksAndRejections (internal/process/task_queues.js:84:21)'
}
2024-01-09 11:02:19.901 - error: [FS-ERRHD]
{
message: 'Error: read ECONNRESET',
name: 'RequestError',
cause: { errno: 'ECONNRESET', code: 'ECONNRESET', syscall: 'read' },
error: { '$ref': '$["cause"]' },
options: {
jar: false,
url: 'http://127.0.0.1:4900/anxinyun/project/list?token=3947c6c4-ebfa-4eae-b097-9f5ad8fc800c',
headers: {
host: '127.0.0.1:4900',
connection: 'keep-alive',
'content-length': '55',
'sec-ch-ua': '"Not_A Brand";v="8", "Chromium";v="120", "Google Chrome";v="120"',
'sec-ch-ua-platform': '"Windows"',
'sec-ch-ua-mobile': '?0',
'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',
'content-type': 'application/json',
'cache-control': 'no-cache,no-store,must-revalidate,max-age=-1,private',
'x-requested-with': 'XMLHttpRequest',
expires: '-1',
accept: '*/*',
origin: 'http://localhost:5900',
'sec-fetch-site': 'same-origin',
'sec-fetch-mode': 'cors',
'sec-fetch-dest': 'empty',
referer: 'http://localhost:5900/projectManagement/projectBinding',
'accept-encoding': 'gzip, deflate, br',
'accept-language': 'zh-CN,zh;q=0.9',
cookie: '__51vcke__Jo4eTlZVqgx3uwqm=1fad3d39-9b32-5c9c-99eb-547dddae7232; __51vuft__Jo4eTlZVqgx3uwqm=1684920883692; __51uvsct__Jo4eTlZVqgx3uwqm=44; cookie-gray-released=new; cookie-gray-released.sig=k487rENXok_KtaXhanO3Rm1eP7I'
},
encoding: null,
followRedirect: true,
method: 'POST',
body: '{"url":"organizations/{orgId}/structures","type":"get"}',
simple: false,
resolveWithFullResponse: true,
callback: [Function: RP$callback],
transform: undefined,
transform2xxOnly: false
},
response: undefined,
stack: 'RequestError: Error: read ECONNRESET\n' +
' at new RequestError (C:\\Users\\方式、\\Desktop\\项目资料\\巡检\\Inspection\\web\\node_modules\\request-promise-core\\lib\\errors.js:14:15)\n' +
' at Request.plumbing.callback (C:\\Users\\方式、\\Desktop\\项目资料\\巡检\\Inspection\\web\\node_modules\\request-promise-core\\lib\\plumbing.js:87:29)\n' +
' at Request.RP$callback [as _callback] (C:\\Users\\方式、\\Desktop\\项目资料\\巡检\\Inspection\\web\\node_modules\\request-promise-core\\lib\\plumbing.js:46:31)\n' +
' at self.callback (C:\\Users\\方式、\\Desktop\\项目资料\\巡检\\Inspection\\web\\node_modules\\request\\request.js:185:22)\n' +
' at Request.emit (events.js:314:20)\n' +
' at Request.onRequestError (C:\\Users\\方式、\\Desktop\\项目资料\\巡检\\Inspection\\web\\node_modules\\request\\request.js:877:8)\n' +
' at ClientRequest.emit (events.js:314:20)\n' +
' at Socket.socketErrorListener (_http_client.js:427:9)\n' +
' at Socket.emit (events.js:314:20)\n' +
' at emitErrorNT (internal/streams/destroy.js:92:8)\n' +
' at emitErrorAndCloseNT (internal/streams/destroy.js:60:3)\n' +
' at processTicksAndRejections (internal/process/task_queues.js:84:21)'
}
2024-01-09 13:44:39.843 - error: [FS-ERRHD]
{
message: 'Error: read ECONNRESET',
name: 'RequestError',
cause: { errno: 'ECONNRESET', code: 'ECONNRESET', syscall: 'read' },
error: { '$ref': '$["cause"]' },
options: {
jar: false,
url: 'http://127.0.0.1:4900/project/publish/list?token=3947c6c4-ebfa-4eae-b097-9f5ad8fc800c&limit=10&page=0',
headers: {
host: '127.0.0.1:4900',
connection: 'keep-alive',
'sec-ch-ua': '"Not_A Brand";v="8", "Chromium";v="120", "Google Chrome";v="120"',
expires: '-1',
'cache-control': 'no-cache,no-store,must-revalidate,max-age=-1,private',
'x-requested-with': 'XMLHttpRequest',
'sec-ch-ua-mobile': '?0',
'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',
'sec-ch-ua-platform': '"Windows"',
accept: '*/*',
'sec-fetch-site': 'same-origin',
'sec-fetch-mode': 'cors',
'sec-fetch-dest': 'empty',
referer: 'http://localhost:5900/projectManagement/projectPublish',
'accept-encoding': 'gzip, deflate, br',
'accept-language': 'zh-CN,zh;q=0.9',
cookie: '__51vcke__Jo4eTlZVqgx3uwqm=1fad3d39-9b32-5c9c-99eb-547dddae7232; __51vuft__Jo4eTlZVqgx3uwqm=1684920883692; __51uvsct__Jo4eTlZVqgx3uwqm=44; cookie-gray-released=new; cookie-gray-released.sig=k487rENXok_KtaXhanO3Rm1eP7I'
},
encoding: null,
followRedirect: true,
method: 'GET',
body: '[object Object]',
simple: false,
resolveWithFullResponse: true,
callback: [Function: RP$callback],
transform: undefined,
transform2xxOnly: false
},
response: undefined,
stack: 'RequestError: Error: read ECONNRESET\n' +
' at new RequestError (C:\\Users\\方式、\\Desktop\\项目资料\\巡检\\Inspection\\web\\node_modules\\request-promise-core\\lib\\errors.js:14:15)\n' +
' at Request.plumbing.callback (C:\\Users\\方式、\\Desktop\\项目资料\\巡检\\Inspection\\web\\node_modules\\request-promise-core\\lib\\plumbing.js:87:29)\n' +
' at Request.RP$callback [as _callback] (C:\\Users\\方式、\\Desktop\\项目资料\\巡检\\Inspection\\web\\node_modules\\request-promise-core\\lib\\plumbing.js:46:31)\n' +
' at self.callback (C:\\Users\\方式、\\Desktop\\项目资料\\巡检\\Inspection\\web\\node_modules\\request\\request.js:185:22)\n' +
' at Request.emit (events.js:314:20)\n' +
' at Request.onRequestError (C:\\Users\\方式、\\Desktop\\项目资料\\巡检\\Inspection\\web\\node_modules\\request\\request.js:877:8)\n' +
' at ClientRequest.emit (events.js:314:20)\n' +
' at Socket.socketErrorListener (_http_client.js:427:9)\n' +
' at Socket.emit (events.js:314:20)\n' +
' at emitErrorNT (internal/streams/destroy.js:92:8)\n' +
' at emitErrorAndCloseNT (internal/streams/destroy.js:60:3)\n' +
' at processTicksAndRejections (internal/process/task_queues.js:84:21)'
}
2024-01-09 13:44:39.854 - error: [FS-ERRHD]
{
message: 'Error: read ECONNRESET',
name: 'RequestError',
cause: { errno: 'ECONNRESET', code: 'ECONNRESET', syscall: 'read' },
error: { '$ref': '$["cause"]' },
options: {
jar: false,
url: 'http://127.0.0.1:4900/project/type?token=3947c6c4-ebfa-4eae-b097-9f5ad8fc800c',
headers: {
host: '127.0.0.1:4900',
connection: 'keep-alive',
'sec-ch-ua': '"Not_A Brand";v="8", "Chromium";v="120", "Google Chrome";v="120"',
expires: '-1',
'cache-control': 'no-cache,no-store,must-revalidate,max-age=-1,private',
'x-requested-with': 'XMLHttpRequest',
'sec-ch-ua-mobile': '?0',
'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',
'sec-ch-ua-platform': '"Windows"',
accept: '*/*',
'sec-fetch-site': 'same-origin',
'sec-fetch-mode': 'cors',
'sec-fetch-dest': 'empty',
referer: 'http://localhost:5900/projectManagement/projectPublish',
'accept-encoding': 'gzip, deflate, br',
'accept-language': 'zh-CN,zh;q=0.9',
cookie: '__51vcke__Jo4eTlZVqgx3uwqm=1fad3d39-9b32-5c9c-99eb-547dddae7232; __51vuft__Jo4eTlZVqgx3uwqm=1684920883692; __51uvsct__Jo4eTlZVqgx3uwqm=44; cookie-gray-released=new; cookie-gray-released.sig=k487rENXok_KtaXhanO3Rm1eP7I'
},
encoding: null,
followRedirect: true,
method: 'GET',
body: '[object Object]',
simple: false,
resolveWithFullResponse: true,
callback: [Function: RP$callback],
transform: undefined,
transform2xxOnly: false
},
response: undefined,
stack: 'RequestError: Error: read ECONNRESET\n' +
' at new RequestError (C:\\Users\\方式、\\Desktop\\项目资料\\巡检\\Inspection\\web\\node_modules\\request-promise-core\\lib\\errors.js:14:15)\n' +
' at Request.plumbing.callback (C:\\Users\\方式、\\Desktop\\项目资料\\巡检\\Inspection\\web\\node_modules\\request-promise-core\\lib\\plumbing.js:87:29)\n' +
' at Request.RP$callback [as _callback] (C:\\Users\\方式、\\Desktop\\项目资料\\巡检\\Inspection\\web\\node_modules\\request-promise-core\\lib\\plumbing.js:46:31)\n' +
' at self.callback (C:\\Users\\方式、\\Desktop\\项目资料\\巡检\\Inspection\\web\\node_modules\\request\\request.js:185:22)\n' +
' at Request.emit (events.js:314:20)\n' +
' at Request.onRequestError (C:\\Users\\方式、\\Desktop\\项目资料\\巡检\\Inspection\\web\\node_modules\\request\\request.js:877:8)\n' +
' at ClientRequest.emit (events.js:314:20)\n' +
' at Socket.socketErrorListener (_http_client.js:427:9)\n' +
' at Socket.emit (events.js:314:20)\n' +
' at emitErrorNT (internal/streams/destroy.js:92:8)\n' +
' at emitErrorAndCloseNT (internal/streams/destroy.js:60:3)\n' +
' at processTicksAndRejections (internal/process/task_queues.js:84:21)'
}
2024-01-09 13:50:54.223 - error: [FS-ERRHD]
{
message: 'Error: read ECONNRESET',
name: 'RequestError',
cause: { errno: 'ECONNRESET', code: 'ECONNRESET', syscall: 'read' },
error: { '$ref': '$["cause"]' },
options: {
jar: false,
url: 'http://127.0.0.1:4900/project/publish/list?token=3947c6c4-ebfa-4eae-b097-9f5ad8fc800c&limit=10&page=0',
headers: {
host: '127.0.0.1:4900',
connection: 'keep-alive',
'sec-ch-ua': '"Not_A Brand";v="8", "Chromium";v="120", "Google Chrome";v="120"',
expires: '-1',
'cache-control': 'no-cache,no-store,must-revalidate,max-age=-1,private',
'x-requested-with': 'XMLHttpRequest',
'sec-ch-ua-mobile': '?0',
'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',
'sec-ch-ua-platform': '"Windows"',
accept: '*/*',
'sec-fetch-site': 'same-origin',
'sec-fetch-mode': 'cors',
'sec-fetch-dest': 'empty',
referer: 'http://localhost:5900/projectManagement/projectPublish',
'accept-encoding': 'gzip, deflate, br',
'accept-language': 'zh-CN,zh;q=0.9',
cookie: '__51vcke__Jo4eTlZVqgx3uwqm=1fad3d39-9b32-5c9c-99eb-547dddae7232; __51vuft__Jo4eTlZVqgx3uwqm=1684920883692; __51uvsct__Jo4eTlZVqgx3uwqm=44; cookie-gray-released=new; cookie-gray-released.sig=k487rENXok_KtaXhanO3Rm1eP7I'
},
encoding: null,
followRedirect: true,
method: 'GET',
body: '[object Object]',
simple: false,
resolveWithFullResponse: true,
callback: [Function: RP$callback],
transform: undefined,
transform2xxOnly: false
},
response: undefined,
stack: 'RequestError: Error: read ECONNRESET\n' +
' at new RequestError (C:\\Users\\方式、\\Desktop\\项目资料\\巡检\\Inspection\\web\\node_modules\\request-promise-core\\lib\\errors.js:14:15)\n' +
' at Request.plumbing.callback (C:\\Users\\方式、\\Desktop\\项目资料\\巡检\\Inspection\\web\\node_modules\\request-promise-core\\lib\\plumbing.js:87:29)\n' +
' at Request.RP$callback [as _callback] (C:\\Users\\方式、\\Desktop\\项目资料\\巡检\\Inspection\\web\\node_modules\\request-promise-core\\lib\\plumbing.js:46:31)\n' +
' at self.callback (C:\\Users\\方式、\\Desktop\\项目资料\\巡检\\Inspection\\web\\node_modules\\request\\request.js:185:22)\n' +
' at Request.emit (events.js:314:20)\n' +
' at Request.onRequestError (C:\\Users\\方式、\\Desktop\\项目资料\\巡检\\Inspection\\web\\node_modules\\request\\request.js:877:8)\n' +
' at ClientRequest.emit (events.js:314:20)\n' +
' at Socket.socketErrorListener (_http_client.js:427:9)\n' +
' at Socket.emit (events.js:314:20)\n' +
' at emitErrorNT (internal/streams/destroy.js:92:8)\n' +
' at emitErrorAndCloseNT (internal/streams/destroy.js:60:3)\n' +
' at processTicksAndRejections (internal/process/task_queues.js:84:21)'
}
2024-01-09 14:15:31.395 - debug: [FS-LOGGER] Init.
2024-01-09 14:15:31.398 - debug: init fs.attachment and inject it into app(app.fs.attachment) and runtime ctx(ctx.fs.attachment)
2024-01-09 14:15:35.753 - info: [Router] Inject api: attachment/index
2024-01-09 15:21:19.312 - debug: [FS-LOGGER] Init.
2024-01-09 15:21:19.315 - debug: init fs.attachment and inject it into app(app.fs.attachment) and runtime ctx(ctx.fs.attachment)
2024-01-09 15:21:22.590 - info: [Router] Inject api: attachment/index

218
web/package.json

@ -1,110 +1,110 @@
{ {
"name": "fs-anxincloud-4.0", "name": "fs-anxincloud-4.0",
"version": "1.0.0", "version": "1.0.0",
"description": "anxincloud-4.0", "description": "anxincloud-4.0",
"main": "server.js", "main": "server.js",
"scripts": { "scripts": {
"test": "mocha", "test": "mocha",
"start": "cross-env NODE_ENV=development npm run start-params", "start": "cross-env NODE_ENV=development npm run start-params",
"start-params": "node server -p 5900 -u http://127.0.0.1:4900 --qnak 5XrM4wEB9YU6RQwT64sPzzE6cYFKZgssdP5Kj3uu --qnsk w6j2ixR_i-aelc6I7S3HotKIX-ukMzcKmDfH6-M5 --qnbkt anxinyun-test --qndmn http://test.resources.anxinyun.cn --aliOssAccessKey LTAI5tNDfn7UhStYQcn3JBtw --aliOssSecretKey rnoXtDWQA1djJ5Xqcdn1OSEol0lVyv --aliOssBucket test-c371 --aliOssRegion oss-cn-hangzhou", "start-params": "node server -p 5900 -u http://127.0.0.1:4900 --webScreen http://localhost:5800 --qnak 5XrM4wEB9YU6RQwT64sPzzE6cYFKZgssdP5Kj3uu --qnsk w6j2ixR_i-aelc6I7S3HotKIX-ukMzcKmDfH6-M5 --qnbkt anxinyun-test --qndmn http://test.resources.anxinyun.cn --aliOssAccessKey LTAI5tNDfn7UhStYQcn3JBtw --aliOssSecretKey rnoXtDWQA1djJ5Xqcdn1OSEol0lVyv --aliOssBucket test-c371 --aliOssRegion oss-cn-hangzhou",
"deploy": "export NODE_ENV=production && npm run build && node server", "deploy": "export NODE_ENV=production && npm run build && node server",
"build-dev": "export NODE_ENV=development&&webpack --config webpack.config.js", "build-dev": "export NODE_ENV=development&&webpack --config webpack.config.js",
"build": "export NODE_ENV=production&&webpack --config webpack.config.prod.js" "build": "export NODE_ENV=production&&webpack --config webpack.config.prod.js"
}, },
"keywords": [ "keywords": [
"app" "app"
], ],
"author": "", "author": "",
"license": "ISC", "license": "ISC",
"devDependencies": { "devDependencies": {
"@babel/core": "^7.14.6", "@babel/core": "^7.14.6",
"@babel/plugin-proposal-class-properties": "^7.14.5", "@babel/plugin-proposal-class-properties": "^7.14.5",
"@babel/plugin-proposal-object-rest-spread": "^7.14.7", "@babel/plugin-proposal-object-rest-spread": "^7.14.7",
"@babel/plugin-transform-runtime": "^7.14.5", "@babel/plugin-transform-runtime": "^7.14.5",
"@babel/polyfill": "^7.12.1", "@babel/polyfill": "^7.12.1",
"@babel/preset-env": "^7.14.7", "@babel/preset-env": "^7.14.7",
"@babel/preset-react": "^7.14.5", "@babel/preset-react": "^7.14.5",
"babel-loader": "^8.2.2", "babel-loader": "^8.2.2",
"babel-polyfill": "^6.26.0", "babel-polyfill": "^6.26.0",
"babel-plugin-import": "^1.13.3", "babel-plugin-import": "^1.13.3",
"connected-react-router": "^6.8.0", "connected-react-router": "^6.8.0",
"css-loader": "^3.5.0", "css-loader": "^3.5.0",
"express": "^4.17.1", "express": "^4.17.1",
"file-loader": "^6.0.0", "file-loader": "^6.0.0",
"html-webpack-plugin": "^4.5.0", "html-webpack-plugin": "^4.5.0",
"immutable": "^4.0.0-rc.12", "immutable": "^4.0.0-rc.12",
"less": "^3.12.2", "less": "^3.12.2",
"less-loader": "^7.0.2", "less-loader": "^7.0.2",
"natty-fetch": "^2.5.3", "natty-fetch": "^2.5.3",
"nprogress": "^0.2.0", "nprogress": "^0.2.0",
"path": "^0.12.7", "path": "^0.12.7",
"path-to-regexp": "^2.4.0", "path-to-regexp": "^2.4.0",
"perfect-scrollbar": "^1.5.0", "perfect-scrollbar": "^1.5.0",
"react": "^17.0.0", "react": "^17.0.0",
"react-copy-to-clipboard": "^5.0.1", "react-copy-to-clipboard": "^5.0.1",
"react-dnd": "^10.0.2", "react-dnd": "^10.0.2",
"react-dnd-html5-backend": "^10.0.2", "react-dnd-html5-backend": "^10.0.2",
"react-dom": "^17.0.0", "react-dom": "^17.0.0",
"react-if": "^2.2.1", "react-if": "^2.2.1",
"react-jsonschema-form": "^1.8.1", "react-jsonschema-form": "^1.8.1",
"react-quill": "^1.3.5", "react-quill": "^1.3.5",
"react-redux": "^7.2.1", "react-redux": "^7.2.1",
"react-router-dom": "^5.2.0", "react-router-dom": "^5.2.0",
"react-router-redux": "^4.0.8", "react-router-redux": "^4.0.8",
"redux": "^4.0.5", "redux": "^4.0.5",
"redux-thunk": "^2.3.0", "redux-thunk": "^2.3.0",
"redux-undo": "^1.0.1", "redux-undo": "^1.0.1",
"style-loader": "^2.0.0", "style-loader": "^2.0.0",
"webpack": "^5.3.2", "webpack": "^5.3.2",
"webpack-bundle-analyzer": "^4.1.0", "webpack-bundle-analyzer": "^4.1.0",
"webpack-cli": "^4.2.0", "webpack-cli": "^4.2.0",
"webpack-dev-middleware": "^4.0.2", "webpack-dev-middleware": "^4.0.2",
"webpack-hot-middleware": "^2.25.0" "webpack-hot-middleware": "^2.25.0"
}, },
"dependencies": { "dependencies": {
"@ant-design/icons": "^4.6.2", "@ant-design/icons": "^4.6.2",
"@ant-design/pro-form": "^1.34.0", "@ant-design/pro-form": "^1.34.0",
"@ant-design/pro-table": "^2.48.0", "@ant-design/pro-table": "^2.48.0",
"@antv/g6": "^4.2.5", "@antv/g6": "^4.2.5",
"@fs/attachment": "^1.0.0", "@fs/attachment": "^1.0.0",
"@peace/components": "0.0.35", "@peace/components": "0.0.35",
"@peace/utils": "0.0.37", "@peace/utils": "0.0.37",
"ahooks": "^3.7.4", "ahooks": "^3.7.4",
"ali-oss": "^6.17.1", "ali-oss": "^6.17.1",
"antd": "^4.24.5", "antd": "^4.24.5",
"antd-theme-generator": "^1.2.8", "antd-theme-generator": "^1.2.8",
"args": "^5.0.1", "args": "^5.0.1",
"array-move": "^3.0.1", "array-move": "^3.0.1",
"bpmn-js": "^6.5.1", "bpmn-js": "^6.5.1",
"camunda-bpmn-moddle": "^4.4.0", "camunda-bpmn-moddle": "^4.4.0",
"canvas": "^2.11.0", "canvas": "^2.11.0",
"co-busboy": "^1.4.1", "co-busboy": "^1.4.1",
"cross-env": "^7.0.3", "cross-env": "^7.0.3",
"crypto-js": "^4.1.1", "crypto-js": "^4.1.1",
"echarts": "^5.4.1", "echarts": "^5.4.1",
"file-saver": "^2.0.5", "file-saver": "^2.0.5",
"form-data": "^3.0.0", "form-data": "^3.0.0",
"fs-attachment": "^1.0.0", "fs-attachment": "^1.0.0",
"fs-web-server-scaffold": "^1.0.6", "fs-web-server-scaffold": "^1.0.6",
"i": "^0.3.6", "i": "^0.3.6",
"jszip": "^3.10.1", "jszip": "^3.10.1",
"koa-better-http-proxy": "^0.2.5", "koa-better-http-proxy": "^0.2.5",
"koa-proxy": "^1.0.0-alpha.3", "koa-proxy": "^1.0.0-alpha.3",
"koa-view": "^2.1.4", "koa-view": "^2.1.4",
"mini-dynamic-antd-theme": "^0.5.3", "mini-dynamic-antd-theme": "^0.5.3",
"moment": "^2.22.0", "moment": "^2.22.0",
"npm": "^7.20.6", "npm": "^7.20.6",
"qrcode": "^1.5.1", "qrcode": "^1.5.1",
"qs": "^6.10.1", "qs": "^6.10.1",
"react-dnd": "^7", "react-dnd": "^7",
"react-dnd-html5-backend": "^7", "react-dnd-html5-backend": "^7",
"react-color": "^2.19.3", "react-color": "^2.19.3",
"react-router-breadcrumbs-hoc": "^4.0.1", "react-router-breadcrumbs-hoc": "^4.0.1",
"react-sortable-hoc": "^2.0.0", "react-sortable-hoc": "^2.0.0",
"shortid": "^2.2.16", "shortid": "^2.2.16",
"superagent": "^6.1.0", "superagent": "^6.1.0",
"uuid": "^8.3.1", "uuid": "^8.3.1",
"webpack-dev-server": "^3.11.2", "webpack-dev-server": "^3.11.2",
"xlsx": "^0.16.9" "xlsx": "^0.16.9"
} }
} }

441
web/routes/attachment/index.js

@ -7,245 +7,246 @@ const OSS = require('ali-oss');
const uuid = require('uuid'); const uuid = require('uuid');
const UploadPath = { const UploadPath = {
project: ['.txt', '.dwg', '.doc', '.docx', '.xls', '.xlsx', ".csv", '.pdf', '.pptx', '.png', '.jpg', '.svg', '.rar', '.zip', '.jpeg', '.mp4'], project: ['.txt', '.dwg', '.doc', '.docx', '.xls', '.xlsx', ".csv", '.pdf', '.pptx', '.png', '.jpg', '.svg', '.rar', '.zip', '.jpeg', '.mp4'],
report: ['.doc', '.docx', '.xls', '.xlsx', ".csv", '.pdf'], report: ['.doc', '.docx', '.xls', '.xlsx', ".csv", '.pdf'],
data: ['.txt', '.xls', '.xlsx', ".csv"], data: ['.txt', '.xls', '.xlsx', ".csv"],
image: ['.png', '.jpg', '.svg'], image: ['.png', '.jpg', '.svg'],
three: ['.js'], three: ['.js'],
video: ['.mp4'] video: ['.mp4']
}; };
const ext = { const ext = {
project: ['.txt', '.dwg', '.doc', '.docx', '.xls', '.xlsx', ".csv", '.pdf', '.pptx', '.png', '.jpg', '.svg', '.rar', '.zip', '.jpeg', '.mp4'], project: ['.txt', '.dwg', '.doc', '.docx', '.xls', '.xlsx', ".csv", '.pdf', '.pptx', '.png', '.jpg', '.svg', '.rar', '.zip', '.jpeg', '.mp4'],
report: [".doc", ".docx", ".xls", ".xlsx", ".pdf"], report: [".doc", ".docx", ".xls", ".xlsx", ".pdf"],
data: [".txt", ".xls", ".xlsx"], data: [".txt", ".xls", ".xlsx"],
image: [".png", ".jpg", ".svg"], image: [".png", ".jpg", ".svg"],
three: [".js"], three: [".js"],
video: [".mp4"], video: [".mp4"],
bpmn: [".bpmn", ".bpmn20.xml", ".zip", ".bar"], bpmn: [".bpmn", ".bpmn20.xml", ".zip", ".bar"],
app: [".apk"] app: [".apk"]
} }
module.exports = { module.exports = {
entry: function (app, router, opts) { entry: function (app, router, opts) {
let download_ = async function (ctx, next) { let download_ = async function (ctx, next) {
const { fetchUrl } = opts.qiniu; const { fetchUrl } = opts.qiniu;
const { fetchUrl: aliFetchUrl, bucket, region } = opts.aliOss const { fetchUrl: aliFetchUrl, bucket, region } = opts.aliOss
if (ctx.path && ctx.path.includes(fetchUrl)) { if (ctx.path && ctx.path.includes(fetchUrl)) {
try { try {
const { filename } = ctx.request.query; const { filename } = ctx.request.query;
const fkey = decodeURI(ctx.path.slice(fetchUrl.length + 1)).replace(/\.json$/, '.js'); const fkey = decodeURI(ctx.path.slice(fetchUrl.length + 1)).replace(/\.json$/, '.js');
if (ctx.path) { if (ctx.path) {
const extNames = ctx.path.split('.'); const extNames = ctx.path.split('.');
app.fs.logger.log('info', 'extNames', extNames); app.fs.logger.log('info', 'extNames', extNames);
if (extNames.length > 0) { if (extNames.length > 0) {
let fileType = extNames[extNames.length - 1].toLowerCase(); let fileType = extNames[extNames.length - 1].toLowerCase();
if (fileType === 'pdf') { if (fileType === 'pdf') {
ctx.type = 'application/pdf'; ctx.type = 'application/pdf';
app.fs.logger.log('info', 'application/pdf', fileType); app.fs.logger.log('info', 'application/pdf', fileType);
} }
} }
} }
const publicDownloadUrl = await app.fs.attachment.download(fkey); const publicDownloadUrl = await app.fs.attachment.download(fkey);
ctx.status = 200; ctx.status = 200;
if (filename) ctx.attachment(filename); if (filename) ctx.attachment(filename);
ctx.body = request.get(publicDownloadUrl); ctx.body = request.get(publicDownloadUrl);
} catch (err) { } catch (err) {
ctx.fs.logger.error(err); ctx.fs.logger.error(err);
ctx.status = 404; ctx.status = 404;
ctx.body = { error: 'file not found.' }; ctx.body = { error: 'file not found.' };
}
} else if (ctx.path && ctx.path.includes(aliFetchUrl)) {
const { filename } = ctx.request.query;
const fkey = decodeURI(ctx.path.slice(aliFetchUrl.length + 1)).replace(/\.json$/, '.js');
if (ctx.path) {
const extNames = ctx.path.split('.');
app.fs.logger.log('info', 'extNames', extNames);
if (extNames.length > 0) {
let fileType = extNames[extNames.length - 1].toLowerCase();
if (fileType === 'pdf') {
ctx.type = 'application/pdf';
app.fs.logger.log('info', 'application/pdf', fileType);
}
}
}
const publicDownloadUrl = `http://${bucket}.${region}.aliyuncs.com/${encodeURIComponent(fkey)}`
ctx.status = 200;
ctx.body = request.get(publicDownloadUrl);
} else {
await next();
} }
}; } else if (ctx.path && ctx.path.includes(aliFetchUrl)) {
const getApiRoot = async function (ctx) { const { filename } = ctx.request.query;
const { apiUrl, qiniu } = opts; const fkey = decodeURI(ctx.path.slice(aliFetchUrl.length + 1)).replace(/\.json$/, '.js');
const { bucket, region } = opts.aliOss if (ctx.path) {
const extNames = ctx.path.split('.');
app.fs.logger.log('info', 'extNames', extNames);
if (extNames.length > 0) {
let fileType = extNames[extNames.length - 1].toLowerCase();
if (fileType === 'pdf') {
ctx.type = 'application/pdf';
app.fs.logger.log('info', 'application/pdf', fileType);
}
}
}
const publicDownloadUrl = `http://${bucket}.${region}.aliyuncs.com/${encodeURIComponent(fkey)}`
ctx.status = 200; ctx.status = 200;
ctx.body = { ctx.body = request.get(publicDownloadUrl);
root: apiUrl, } else {
qiniu: qiniu.domain, await next();
aliAdmin: `http://${bucket}.${region}.aliyuncs.com` }
}; };
}; const getApiRoot = async function (ctx) {
const { apiUrl, qiniu, webScreen } = opts;
const { bucket, region } = opts.aliOss
let upload = async function (ctx, next) { ctx.status = 200;
try { ctx.body = {
const { files } = await parse(ctx.req); root: apiUrl,
const file = files[0]; qiniu: qiniu.domain,
const extname = path.extname(file.filename).toLowerCase(); aliAdmin: `http://${bucket}.${region}.aliyuncs.com`,
const fileType = ctx.query.type || "image"; webScreen,
const fileFolder = ctx.query.fileFolder || 'common'; };
if (ext[fileType].indexOf(extname) < 0) { };
ctx.status = 400;
ctx.body = JSON.stringify({ name: 'UploadFailed', message: '文件格式无效' });
return;
}
const date = new Date().toLocaleDateString();
const time = new Date().getTime();
let fileName = time + '_' + file.filename;
let saveFile = path.join(__dirname, '../../', `/client/assets/files/${fileFolder}`, fileName);
const pathUrl = `./client/assets/files/${fileFolder}`;
const res1 = fs.existsSync(`./client/assets/files/${fileFolder}`); let upload = async function (ctx, next) {
!res1 && fs.mkdirSync(`./client/assets/files/${fileFolder}`); try {
const res = fs.existsSync(pathUrl); const { files } = await parse(ctx.req);
!res && fs.mkdirSync(pathUrl); const file = files[0];
let stream = fs.createWriteStream(saveFile); const extname = path.extname(file.filename).toLowerCase();
fs.createReadStream(file.path).pipe(stream); const fileType = ctx.query.type || "image";
stream.on('error', function (err) { const fileFolder = ctx.query.fileFolder || 'common';
app.fs.logger.log('error', '[Upload Heatmap]', err); if (ext[fileType].indexOf(extname) < 0) {
}); ctx.status = 400;
ctx.status = 200; ctx.body = JSON.stringify({ name: 'UploadFailed', message: '文件格式无效' });
ctx.body = { filename: path.join(`/assets/files/${fileFolder}`, fileName), name: 'UploadSuccess', message: '上传成功' }; return;
} catch (err) {
ctx.status = 500;
ctx.fs.logger.error(err);
ctx.body = { err: 'upload error.' };
} }
} const date = new Date().toLocaleDateString();
const time = new Date().getTime();
let fileName = time + '_' + file.filename;
let saveFile = path.join(__dirname, '../../', `/client/assets/files/${fileFolder}`, fileName);
const pathUrl = `./client/assets/files/${fileFolder}`;
let remove = async function (ctx, next) { const res1 = fs.existsSync(`./client/assets/files/${fileFolder}`);
try { !res1 && fs.mkdirSync(`./client/assets/files/${fileFolder}`);
const fkeys = ctx.request.body; const res = fs.existsSync(pathUrl);
let removeUrl = path.join(__dirname, '../../', './client', fkeys.url); !res && fs.mkdirSync(pathUrl);
const res = fs.existsSync(removeUrl); let stream = fs.createWriteStream(saveFile);
if (!res) { fs.createReadStream(file.path).pipe(stream);
ctx.status = 400; stream.on('error', function (err) {
ctx.body = JSON.stringify({ name: 'DeleteFailed', message: '文件地址不存在' }); app.fs.logger.log('error', '[Upload Heatmap]', err);
return; });
} ctx.status = 200;
fs.unlink(removeUrl, function (error) { ctx.body = { filename: path.join(`/assets/files/${fileFolder}`, fileName), name: 'UploadSuccess', message: '上传成功' };
if (error) { } catch (err) {
console.log(error); ctx.status = 500;
} ctx.fs.logger.error(err);
}) ctx.body = { err: 'upload error.' };
ctx.status = 200; }
ctx.body = { name: 'DeleteSuccess.', message: '删除成功' }; }
} catch (err) {
ctx.status = 500; let remove = async function (ctx, next) {
ctx.fs.logger.error(err); try {
ctx.body = { err: 'upload cleanup error.' }; const fkeys = ctx.request.body;
let removeUrl = path.join(__dirname, '../../', './client', fkeys.url);
const res = fs.existsSync(removeUrl);
if (!res) {
ctx.status = 400;
ctx.body = JSON.stringify({ name: 'DeleteFailed', message: '文件地址不存在' });
return;
} }
} fs.unlink(removeUrl, function (error) {
let upload_ = async function (ctx, next) { if (error) {
let fkey = null; console.log(error);
try { }
const { p } = ctx.params; })
const { files } = await parse(ctx.req); ctx.status = 200;
const file = files[0]; ctx.body = { name: 'DeleteSuccess.', message: '删除成功' };
const extname = path.extname(file.filename).toLowerCase(); } catch (err) {
if (!UploadPath[p]) { ctx.status = 500;
ctx.status = 400; ctx.fs.logger.error(err);
ctx.body = JSON.stringify({ error: '附件存放的文件夹名称无效' }); ctx.body = { err: 'upload cleanup error.' };
return; }
} else if (UploadPath[p].indexOf(extname) < 0) { }
ctx.status = 400; let upload_ = async function (ctx, next) {
ctx.body = JSON.stringify({ error: '文件格式无效' }); let fkey = null;
return; try {
} else { const { p } = ctx.params;
const fileInfo = await ctx.app.fs.attachment.upload(file, { uploadPath: p }); const { files } = await parse(ctx.req);
fkey = fileInfo.key; const file = files[0];
ctx.body = { uploaded: fkey }; const extname = path.extname(file.filename).toLowerCase();
} if (!UploadPath[p]) {
} catch (err) { ctx.status = 400;
ctx.status = 500; ctx.body = JSON.stringify({ error: '附件存放的文件夹名称无效' });
ctx.fs.logger.error(err); return;
ctx.body = { err: 'upload error.' }; } else if (UploadPath[p].indexOf(extname) < 0) {
ctx.status = 400;
ctx.body = JSON.stringify({ error: '文件格式无效' });
return;
} else {
const fileInfo = await ctx.app.fs.attachment.upload(file, { uploadPath: p });
fkey = fileInfo.key;
ctx.body = { uploaded: fkey };
} }
} } catch (err) {
ctx.status = 500;
ctx.fs.logger.error(err);
ctx.body = { err: 'upload error.' };
}
}
const uploadAliOSS = async (ctx,) => { const uploadAliOSS = async (ctx,) => {
// 这个是上传到阿里 // 这个是上传到阿里
try { try {
const { aliOss } = opts const { aliOss } = opts
const { p = 'default' } = ctx.params; const { p = 'default' } = ctx.params;
const { files } = await parse(ctx.req); const { files } = await parse(ctx.req);
const file = files[0]; const file = files[0];
const filename = file.filename || path.basename(file); const filename = file.filename || path.basename(file);
const client = new OSS({ const client = new OSS({
// yourRegion填写Bucket所在地域。以华东1(杭州)为例,Region填写为oss-cn-hangzhou。 // yourRegion填写Bucket所在地域。以华东1(杭州)为例,Region填写为oss-cn-hangzhou。
region: aliOss.region, region: aliOss.region,
// 阿里云账号AccessKey拥有所有API的访问权限,风险很高。强烈建议您创建并使用RAM用户进行API访问或日常运维,请登录RAM控制台创建RAM用户。 // 阿里云账号AccessKey拥有所有API的访问权限,风险很高。强烈建议您创建并使用RAM用户进行API访问或日常运维,请登录RAM控制台创建RAM用户。
accessKeyId: aliOss.accessKey, accessKeyId: aliOss.accessKey,
accessKeySecret: aliOss.secretKey, accessKeySecret: aliOss.secretKey,
// 填写Bucket名称,例如examplebucket。 // 填写Bucket名称,例如examplebucket。
bucket: aliOss.bucket, bucket: aliOss.bucket,
}); });
let uploadPath = path.posix.join(p, uuid.v4(), filename); let uploadPath = path.posix.join(p, uuid.v4(), filename);
let result = await client.putStream( let result = await client.putStream(
uploadPath, uploadPath,
file, file,
// { contentLength: size } // { contentLength: size }
); );
ctx.status = 200; ctx.status = 200;
ctx.body = { ctx.body = {
key: result.name, key: result.name,
uploaded: result.name, uploaded: result.name,
url: result.url, url: result.url,
}; };
} catch (error) { } catch (error) {
ctx.status = 400; ctx.status = 400;
ctx.fs.logger.error(error); ctx.fs.logger.error(error);
ctx.body = { err: 'upload error.' }; ctx.body = { err: 'upload error.' };
} }
} }
const downloadFromAli = async (ctx) => { const downloadFromAli = async (ctx) => {
try { try {
const { aliOss } = opts const { aliOss } = opts
const { path, filename } = ctx.query const { path, filename } = ctx.query
const client = new OSS({ const client = new OSS({
// yourRegion填写Bucket所在地域。以华东1(杭州)为例,Region填写为oss-cn-hangzhou。 // yourRegion填写Bucket所在地域。以华东1(杭州)为例,Region填写为oss-cn-hangzhou。
region: aliOss.region, region: aliOss.region,
// 阿里云账号AccessKey拥有所有API的访问权限,风险很高。强烈建议您创建并使用RAM用户进行API访问或日常运维,请登录RAM控制台创建RAM用户。 // 阿里云账号AccessKey拥有所有API的访问权限,风险很高。强烈建议您创建并使用RAM用户进行API访问或日常运维,请登录RAM控制台创建RAM用户。
accessKeyId: aliOss.accessKey, accessKeyId: aliOss.accessKey,
accessKeySecret: aliOss.secretKey, accessKeySecret: aliOss.secretKey,
// 填写Bucket名称,例如examplebucket。 // 填写Bucket名称,例如examplebucket。
bucket: aliOss.bucket, bucket: aliOss.bucket,
}); });
const filename_ = filename || path.split('/').pop() const filename_ = filename || path.split('/').pop()
const result = await client.get(path); const result = await client.get(path);
ctx.status = 200; ctx.status = 200;
ctx.set('Content-Type', 'application/x-xls'); ctx.set('Content-Type', 'application/x-xls');
ctx.set('Content-disposition', 'attachment; filename=' + filename_); ctx.set('Content-disposition', 'attachment; filename=' + filename_);
ctx.body = result.content; ctx.body = result.content;
} catch (error) { } catch (error) {
ctx.status = 400; ctx.status = 400;
ctx.fs.logger.error(error); ctx.fs.logger.error(error);
ctx.body = { err: 'download error.' }; ctx.body = { err: 'download error.' };
} }
} }
router.use(download_); router.use(download_);
router.get('/api/root', getApiRoot); router.get('/api/root', getApiRoot);
router.post('/_upload/new', upload); router.post('/_upload/new', upload);
router.delete('/_upload/cleanup', remove); router.delete('/_upload/cleanup', remove);
router.post('/_upload/attachments/ali/:p', uploadAliOSS); router.post('/_upload/attachments/ali/:p', uploadAliOSS);
router.get('/_download/attachments/ali', downloadFromAli); router.get('/_download/attachments/ali', downloadFromAli);
router.post('/_upload/attachments/:p', upload_); router.post('/_upload/attachments/:p', upload_);
} }
}; };

Loading…
Cancel
Save