diff --git a/api/app/lib/controllers/dataQuality/index.js b/api/app/lib/controllers/dataQuality/index.js new file mode 100644 index 0000000..4a628b0 --- /dev/null +++ b/api/app/lib/controllers/dataQuality/index.js @@ -0,0 +1,398 @@ +'use strict'; +const moment = require('moment') + +function getStandardDocFolders (opts) { + return async function (ctx, next) { + + const models = ctx.fs.dc.models; + const { keyword, parent } = ctx.query; + + let errMsg = { message: '获取标准文档目录列表失败' } + try { + + let option = { + where: { parent: parent || null }, + order: [["id", "desc"]] + } + + let folderData = await models.StandardDocFolder.findAll(option) || [] + + + let fileAll = await models.StandardDoc.findAll({}) + let folderAll = await models.StandardDocFolder.findAll({}) + + + const recursive = (id) => { + let show = false + let fileOne = fileAll.filter(f => f.folder == id && (f.docName.indexOf(keyword) != -1 || f.standardType.indexOf(keyword) != -1)) + if (fileOne.length > 0) { + return true + } + let folderList = folderAll.filter(f => f.parent == id) + if (folderList.length > 0) { + let data = [] + folderList.map(d => { + let datum = recursive(d.id) + if (datum) { + data.push(d) + } + }) + if (data.length > 0) { + show = true + } + } else { + return false + } + return show + } + let res = [] + + if (folderData.length > 0 && keyword) { + + folderData.map(d => { + let findOne = recursive(d.id) + if (findOne) { + res.push(d) + } + }) + + } else { + res = folderData + } + + ctx.status = 200; + ctx.body = res; + } catch (error) { + ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`); + ctx.status = 400; + ctx.body = errMsg + } + } +} + + + + +// 标准文档目录新增失败 +function postStandardDocFolders (opts) { + return async function (ctx, next) { + + try { + const models = ctx.fs.dc.models; + + const { name, parent } = ctx.request.body; + + + await models.StandardDocFolder.create({ + name, parent, createAt: moment().format('YYYY-MM-DD HH:mm:ss') + }) + ctx.status = 204; + + } catch (error) { + ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`); + ctx.status = 400; + ctx.body = { message: '标准文档目录新增失败' } + } + } +} + + +// 新增标准文档 +function postStandardDocs (opts) { + return async function (ctx, next) { + + try { + const models = ctx.fs.dc.models; + + const { docName, standardType, tags, folder, path } = ctx.request.body; + + + await models.StandardDoc.create({ + docName, standardType, tags, folder, path, createAt: moment().format('YYYY-MM-DD HH:mm:ss') + }) + ctx.status = 204; + + } catch (error) { + ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`); + ctx.status = 400; + ctx.body = { message: '新增标准文档失败' } + } + } +} + +function getStandardDocs (opts) { + return async function (ctx, next) { + + const models = ctx.fs.dc.models; + const { keyword, folder } = ctx.query; + + let errMsg = { message: '获取标准文档列表失败' } + try { + + let option = { + where: { folder: folder || null }, + order: [["id", "desc"]], + + } + let type = ['国家标准', '行业标准', '地方标准'] + if (keyword) { + option.where['$or'] = [{ docName: { $iLike: `%${keyword}%` } }, { standardType: { $in: type.filter(v => v.indexOf(keyword) != -1) } }] + } + const res = await models.StandardDoc.findAll(option); + ctx.status = 200; + ctx.body = res; + } catch (error) { + ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`); + ctx.status = 400; + ctx.body = errMsg + } + } +} + +function postBusinessRules (opts) { + return async function (ctx, next) { + let message = (ctx.request.body.id ? '编辑' : '新增') + '业务规则失败' + try { + const models = ctx.fs.dc.models; + + const { id, name, description, problemType, problemLevel, ruleBasis } = ctx.request.body; + + if (id) { + await models.BusinessRule.update({ + name, description, problemType, problemLevel, ruleBasis + }, { where: { id: id } }) + } else { + await models.BusinessRule.create({ + name, description, problemType, problemLevel, ruleBasis, createAt: moment().format('YYYY-MM-DD HH:mm:ss') + }) + } + ctx.status = 204; + + } catch (error) { + ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`); + ctx.status = 400; + ctx.body = { message: message } + } + } +} + +function getBusinessRules (opts) { + return async function (ctx, next) { + + const models = ctx.fs.dc.models; + const { page, limit, keyword, } = ctx.query; + + let errMsg = { message: '查询业务规则列表失败' } + try { + + let option = { + where: {}, + order: [["id", "desc"]], + distinct: true, + include: [{ + model: models.StandardDoc, + attributes: ['id', 'docName', 'path'] + }] + } + if (keyword) { + option.where.name = { $iLike: `%${keyword}%` } + } + + if (limit) { + option.limit = Number(limit) + } + if (page && limit) { + option.offset = Number(page) * Number(limit) + } + + + const res = await models.BusinessRule.findAndCount(option); + ctx.status = 200; + ctx.body = res; + } catch (error) { + ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`); + ctx.status = 400; + ctx.body = errMsg + } + } +} + + +function delBusinessRules (opts) { + return async function (ctx, next) { + + try { + const models = ctx.fs.dc.models; + const { id } = ctx.params; + await models.BusinessRule.destroy({ + where: { + id: id + } + }) + ctx.status = 204; + ctx.body = { message: '删除业务规则成功' } + } catch (error) { + ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`); + ctx.status = 400; + ctx.body = { message: '删除业务规则失败' } + } + } +} + +function getRegularBasis (opts) { + return async function (ctx, next) { + + const models = ctx.fs.dc.models; + const { } = ctx.query; + try { + + let folders = await models.StandardDocFolder.findAll({ attributes: ['id', 'name', 'parent'] }) || [] + let files = await models.StandardDoc.findAll({ attributes: ['id', 'docName', 'folder'] }) || [] + + let res = [] + let carousel = (id) => { + let list = [] + let data = folders.filter(f => f.parent == id) + if (data.length > 0) { + data.map(c => { + list.push({ + value: c.id, + title: c.name, + disabled: true, + children: carousel(c.id) + }) + + }) + } + let filedata = files.filter(f => f.folder == id) + if (filedata.length > 0) { + filedata.map(f => { + list.push({ + value: f.id, + title: f.docName + }) + }) + } + + return list + } + if (folders.length > 0) { + folders.map(v => { + if (v.dataValues.parent == null) { + res.push({ + value: v.id, + title: v.name, + disabled: true, + children: carousel(v.id) + }) + } + }) + } + if (files.length > 0) { + files.map(v => { + if (v.dataValues.folder == null) { + res.push({ + value: v.id, + title: v.docName + }) + } + }) + } + + + + + ctx.status = 200; + ctx.body = res || []; + } catch (error) { + ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`); + ctx.status = 400; + ctx.body = { message: '查询规则依据列表失败' } + } + } +} + + +function postFolderFile (opts) { + return async function (ctx, next) { + let body = { message: '删除业务规则失败' } + try { + const models = ctx.fs.dc.models; + const { folderId, fileId } = ctx.request.body; + + let folderIds = folderId + let fileIds = fileId + + let folderLists = await models.StandardDocFolder.findAll() || [] + + let carousel = (id) => { + let folderListId = [] + folderLists.filter(d => { + if (id.includes(d.parent)) { + folderIds.push(d.id) + folderListId.push(d.id) + return true + } else { + return false + } + }) + + if (folderListId.length > 0) { + carousel(folderListId) + } + } + + carousel(folderIds) + + folderIds = [...new Set(folderIds)] + let fileList = await models.StandardDoc.findAll({ + where: { $or: [{ folder: { $in: folderIds } }, { id: { $in: fileIds } }] }, + distinct: true, + include: [{ + model: models.BusinessRule + }] + }) + let url = [] + fileList.map(v => { + if (v.businessRules.length > 0) { + body.data = v.businessRules + body.message = '当前创建的业务规则与标准文档关联' + throw '前创建的业务规则与标准文档关联' + } + fileIds.push(v.id) + url.push(v.path) + }) + fileIds = [...new Set(fileIds)] + + await models.StandardDocFolder.destroy({ + where: { + id: { $in: folderIds } + } + }) + await models.StandardDoc.destroy({ + where: { + id: { $in: fileIds } + } + }) + + ctx.status = 200; + ctx.body = url + } catch (error) { + ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`); + ctx.status = 400; + ctx.body = body + } + } +} + +module.exports = { + getStandardDocFolders, + postStandardDocFolders, + postStandardDocs, + getStandardDocs, + postBusinessRules, + getBusinessRules, + delBusinessRules, + getRegularBasis, + postFolderFile +} \ No newline at end of file diff --git a/api/app/lib/controllers/safetySpecification/index.js b/api/app/lib/controllers/safetySpecification/index.js new file mode 100644 index 0000000..ecc626f --- /dev/null +++ b/api/app/lib/controllers/safetySpecification/index.js @@ -0,0 +1,93 @@ +'use strict'; +const moment = require('moment') + +function getSpecifications (opts) { + return async function (ctx, next) { + + const models = ctx.fs.dc.models; + const { page, limit, keyword, } = ctx.query; + + let errMsg = { message: '查询数据安全规范列表失败' } + try { + + let option = { + where: {}, + order: [["id", "desc"]], + } + if (keyword) { + option.where.fileName = { $iLike: `%${keyword}%` } + } + + if (limit) { + option.limit = Number(limit) + } + if (page && limit) { + option.offset = Number(page) * Number(limit) + } + + + const res = await models.DataSecuritySpecification.findAndCount(option); + ctx.status = 200; + ctx.body = res; + } catch (error) { + ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`); + ctx.status = 400; + ctx.body = errMsg + } + } +} + + + +function delSpecifications (opts) { + return async function (ctx, next) { + + try { + const models = ctx.fs.dc.models; + const { fileIds } = ctx.params; + await models.DataSecuritySpecification.destroy({ + where: { + id: { $in: fileIds.split(',') } + } + }) + ctx.status = 204; + ctx.body = { message: '删除数据安全规范文件成功' } + } catch (error) { + ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`); + ctx.status = 400; + ctx.body = { message: '删除数据安全规范文件失败' } + } + } +} + + +// 新增标准文档 +function postSpecifications (opts) { + return async function (ctx, next) { + + try { + const models = ctx.fs.dc.models; + + const { fileName, tags, path } = ctx.request.body; + + + await models.DataSecuritySpecification.create({ + fileName, tags, path, createAt: moment().format('YYYY-MM-DD HH:mm:ss') + }) + ctx.status = 204; + + } catch (error) { + ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`); + ctx.status = 400; + ctx.body = { message: '新增数据安全规范失败' } + } + } +} + + + +module.exports = { + getSpecifications, + postSpecifications, + delSpecifications +} \ No newline at end of file diff --git a/api/app/lib/index.js b/api/app/lib/index.js index 08387ac..eb4331c 100644 --- a/api/app/lib/index.js +++ b/api/app/lib/index.js @@ -56,7 +56,7 @@ module.exports.models = function (dc) { const { DataSource, AcquisitionTask, Adapter, User, MetadataDatabase, MetadataFile, MetadataRestapi, AcquisitionLog, ResourceCatalog, - BusinessMetadataDatabase, BusinessMetadataFile, BusinessMetadataRestapi,ResourceConsumption + BusinessMetadataDatabase, BusinessMetadataFile, BusinessMetadataRestapi,ResourceConsumption,BusinessRule,StandardDoc } = dc.models; AcquisitionTask.belongsTo(DataSource, { foreignKey: 'dataSourceId', targetKey: 'id' }); @@ -88,4 +88,8 @@ module.exports.models = function (dc) { ResourceConsumption.belongsTo(User, { foreignKey: 'applyBy', targetKey: 'id' ,as:"applyUser"}); ResourceConsumption.belongsTo(User, { foreignKey: 'approveBy', targetKey: 'id',as:'approveUser' }); + + BusinessRule.belongsTo(StandardDoc, { foreignKey: 'ruleBasis', targetKey: 'id' }); + StandardDoc.hasMany(BusinessRule, { foreignKey: 'ruleBasis', targetKey: 'id' }); + }; diff --git a/api/app/lib/models/business_rule.js b/api/app/lib/models/business_rule.js new file mode 100644 index 0000000..d74489f --- /dev/null +++ b/api/app/lib/models/business_rule.js @@ -0,0 +1,89 @@ +/* eslint-disable*/ + +'use strict'; + +module.exports = dc => { + const DataTypes = dc.ORM; + const sequelize = dc.orm; + const BusinessRule = sequelize.define("businessRule", { + id: { + type: DataTypes.INTEGER, + allowNull: false, + defaultValue: null, + comment: "唯一标识", + primaryKey: true, + field: "id", + autoIncrement: true, + unique: "t_business_rule_id_uindex" + }, + name: { + type: DataTypes.STRING, + allowNull: false, + defaultValue: null, + comment: "业务规则名称", + primaryKey: false, + field: "name", + autoIncrement: false, + }, + description: { + type: DataTypes.STRING, + allowNull: false, + defaultValue: null, + comment: "业务规则描述", + primaryKey: false, + field: "description", + autoIncrement: false, + }, + problemType: { + type: DataTypes.STRING, + allowNull: false, + defaultValue: null, + comment: "标签", + primaryKey: false, + field: "problem_type", + autoIncrement: false, + }, + ruleBasis: { + type: DataTypes.INTEGER, + allowNull: false, + defaultValue: null, + comment: "制定依据", + primaryKey: false, + field: "rule_basis", + autoIncrement: false, + references: { + key: "id", + model: "tStandardDoc" + } + }, + problemLevel: { + type: DataTypes.STRING, + allowNull: false, + defaultValue: null, + comment: "问题级别", + primaryKey: false, + field: "problem_level", + autoIncrement: false, + }, + createAt: { + type: DataTypes.DATE, + allowNull: false, + defaultValue: null, + comment: "创建时间", + primaryKey: false, + field: "create_at", + autoIncrement: false, + }, + }, { + tableName: "t_business_rule", + comment: "", + indexes: [] + }); + dc.models.BusinessRule = BusinessRule; + + // const { StandardDoc } = dc.models; + // BusinessRule.belongsTo(StandardDoc, { foreignKey: 'ruleBasis', targetKey: 'id' }); + // MetadataDatabase.hasMany(TagDatabase, { foreignKey: 'database', sourceKey: 'id' }); + + return BusinessRule; +}; \ No newline at end of file diff --git a/api/app/lib/models/data_security_specification.js b/api/app/lib/models/data_security_specification.js new file mode 100644 index 0000000..6f65d69 --- /dev/null +++ b/api/app/lib/models/data_security_specification.js @@ -0,0 +1,67 @@ +/* eslint-disable*/ + +'use strict'; + +module.exports = dc => { + const DataTypes = dc.ORM; + const sequelize = dc.orm; + const DataSecuritySpecification = sequelize.define("dataSecuritySpecification", { + id: { + type: DataTypes.INTEGER, + allowNull: false, + defaultValue: null, + comment: "唯一标识", + primaryKey: true, + field: "id", + autoIncrement: true, + unique: "t_data_security_specification_id_uindex" + }, + fileName: { + type: DataTypes.STRING, + allowNull: false, + defaultValue: null, + comment: "文件名", + primaryKey: false, + field: "file_name", + autoIncrement: false, + }, + tags: { + type: DataTypes.STRING, + allowNull: true, + defaultValue: null, + comment: "标签", + primaryKey: false, + field: "tags", + autoIncrement: false, + }, + createAt: { + type: DataTypes.DATE, + allowNull: false, + defaultValue: null, + comment: "文件创建时间", + primaryKey: false, + field: "create_at", + autoIncrement: false, + }, + path: { + type: DataTypes.STRING, + allowNull: false, + defaultValue: null, + comment: "文件路径", + primaryKey: false, + field: "path", + autoIncrement: false, + }, + }, { + tableName: "t_data_security_specification", + comment: "", + indexes: [] + }); + dc.models.DataSecuritySpecification = DataSecuritySpecification; + + // const { StandardDoc } = dc.models; + // BusinessRule.belongsTo(StandardDoc, { foreignKey: 'ruleBasis', targetKey: 'id' }); + // MetadataDatabase.hasMany(TagDatabase, { foreignKey: 'database', sourceKey: 'id' }); + + return DataSecuritySpecification; +}; \ No newline at end of file diff --git a/api/app/lib/models/standard_doc.js b/api/app/lib/models/standard_doc.js new file mode 100644 index 0000000..52d8207 --- /dev/null +++ b/api/app/lib/models/standard_doc.js @@ -0,0 +1,89 @@ +/* eslint-disable*/ + +'use strict'; + +module.exports = dc => { + const DataTypes = dc.ORM; + const sequelize = dc.orm; + const StandardDoc = sequelize.define("standardDoc", { + id: { + type: DataTypes.INTEGER, + allowNull: false, + defaultValue: null, + comment: "唯一标识", + primaryKey: true, + field: "id", + autoIncrement: true, + unique: "t_standard_doc__id_uindex" + }, + docName: { + type: DataTypes.STRING, + allowNull: false, + defaultValue: null, + comment: "文档名称", + primaryKey: false, + field: "doc_name", + autoIncrement: false, + }, + standardType: { + type: DataTypes.STRING, + allowNull: false, + defaultValue: null, + comment: "标准类型", + primaryKey: false, + field: "standard_type", + autoIncrement: false, + }, + tags: { + type: DataTypes.STRING, + allowNull: true, + defaultValue: null, + comment: "标签", + primaryKey: false, + field: "tags", + autoIncrement: false, + }, + folder: { + type: DataTypes.INTEGER, + allowNull: true, + defaultValue: null, + comment: "归属的文件夹", + primaryKey: false, + field: "folder", + autoIncrement: false, + references: { + key: "id", + model: "tStandardDocFolder" + } + }, + path: { + type: DataTypes.STRING, + allowNull: false, + defaultValue: null, + comment: "文档存储路径", + primaryKey: false, + field: "path", + autoIncrement: false, + }, + createAt: { + type: DataTypes.DATE, + allowNull: false, + defaultValue: null, + comment: "文件夹创建时间", + primaryKey: false, + field: "create_at", + autoIncrement: false, + }, + }, { + tableName: "t_standard_doc", + comment: "", + indexes: [] + }); + dc.models.StandardDoc = StandardDoc; + + // const { StandardDocFolder } = dc.models; + // StandardDoc.belongsTo(StandardDocFolder, { foreignKey: 'folder', targetKey: 'id' }); + // MetadataDatabase.hasMany(TagDatabase, { foreignKey: 'database', sourceKey: 'id' }); + + return StandardDoc; +}; \ No newline at end of file diff --git a/api/app/lib/models/standard_doc_folder.js b/api/app/lib/models/standard_doc_folder.js new file mode 100644 index 0000000..7b3cedf --- /dev/null +++ b/api/app/lib/models/standard_doc_folder.js @@ -0,0 +1,62 @@ +/* eslint-disable*/ + +'use strict'; + +module.exports = dc => { + const DataTypes = dc.ORM; + const sequelize = dc.orm; + const StandardDocFolder = sequelize.define("standardDocFolder", { + id: { + type: DataTypes.INTEGER, + allowNull: false, + defaultValue: null, + comment: "唯一标识", + primaryKey: true, + field: "id", + autoIncrement: true, + unique: "t_standard_doc_folder_id_uindex" + }, + name: { + type: DataTypes.STRING, + allowNull: false, + defaultValue: null, + comment: "文件夹名称", + primaryKey: false, + field: "name", + autoIncrement: false, + }, + createAt: { + type: DataTypes.DATE, + allowNull: false, + defaultValue: null, + comment: "文件夹创建时间", + primaryKey: false, + field: "create_at", + autoIncrement: false, + }, + parent: { + type: DataTypes.INTEGER, + allowNull: true, + defaultValue: null, + comment: "父级文件夹", + primaryKey: false, + field: "parent", + autoIncrement: false, + references: { + key: "id", + model: "tStandardDocFolder" + } + } + }, { + tableName: "t_standard_doc_folder", + comment: "", + indexes: [] + }); + dc.models.StandardDocFolder = StandardDocFolder; + + // const { MetadataDatabase } = dc.models; + // StandardDocFolder.belongsTo(StandardDocFolder, { foreignKey: 'parent', targetKey: 'id' }); + // MetadataDatabase.hasMany(TagDatabase, { foreignKey: 'database', sourceKey: 'id' }); + + return StandardDocFolder; +}; \ No newline at end of file diff --git a/api/app/lib/routes/dataQuality/index.js b/api/app/lib/routes/dataQuality/index.js new file mode 100644 index 0000000..e308158 --- /dev/null +++ b/api/app/lib/routes/dataQuality/index.js @@ -0,0 +1,34 @@ +'use strict'; + +const model = require('../../controllers/dataQuality/index'); + +module.exports = function (app, router, opts, AuthCode) { + + app.fs.api.logAttr['POST/standard-doc-folders'] = { content: '标准文档目录新增', visible: true }; + router.post('/standard-doc-folders', model.postStandardDocFolders(opts)) + + app.fs.api.logAttr['GET/standard-doc-folders'] = { content: '标准文档目录列表', visible: true }; + router.get('/standard-doc-folders', model.getStandardDocFolders(opts)); + + + app.fs.api.logAttr['POST/standard-docs'] = { content: '新增标准文档', visible: true }; + router.post('/standard-docs', model.postStandardDocs(opts)) + + app.fs.api.logAttr['GET/standard-docs'] = { content: '标准文档列表', visible: true }; + router.get('/standard-docs', model.getStandardDocs(opts)); + + app.fs.api.logAttr['POST/postFolderFile'] = { content: '删除文件夹或文件', visible: true }; + router.post('/postFolderFile', model.postFolderFile(opts)) + + app.fs.api.logAttr['POST/business-rules'] = { content: '新增/修改业务规则', visible: true }; + router.post('/business-rules', model.postBusinessRules(opts)) + + app.fs.api.logAttr['GET/business-rules'] = { content: '查询业务规则列表', visible: true }; + router.get('/business-rules', model.getBusinessRules(opts)); + + app.fs.api.logAttr['DEL/business-rules/:id'] = { content: '删除业务规则', visible: true }; + router.del('/business-rules/:id', model.delBusinessRules(opts)) + + app.fs.api.logAttr['GET/regular-basis'] = { content: '查询规则依据列表', visible: true }; + router.get('/regular-basis', model.getRegularBasis(opts)); +}; diff --git a/api/app/lib/routes/safetySpecification/index.js b/api/app/lib/routes/safetySpecification/index.js new file mode 100644 index 0000000..8b4c0ba --- /dev/null +++ b/api/app/lib/routes/safetySpecification/index.js @@ -0,0 +1,22 @@ +'use strict'; + +const model = require('../../controllers/safetySpecification/index'); + +module.exports = function (app, router, opts, AuthCode) { + + // app.fs.api.logAttr['POST/meta/model'] = { content: '增加模型信息', visible: true }; + // router.post('/meta/model', model.addModelManagement(opts)) + + + + + app.fs.api.logAttr['POST/data-security/specifications'] = { content: '新增数据安全规范', visible: true }; + router.post('/data-security/specifications', model.postSpecifications(opts)) + + app.fs.api.logAttr['GET/data-security/specifications'] = { content: '查询数据安全规范列表', visible: true }; + router.get('/data-security/specifications', model.getSpecifications(opts)); + + app.fs.api.logAttr['del/data-security/specifications/:fileIds'] = { content: '查询数据安全规范列表', visible: true }; + router.del('/data-security/specifications/:fileIds', model.delSpecifications(opts)); + +}; diff --git a/scripts/0.0.8/01_alter_t_standard_doc_folder.sql b/scripts/0.0.8/01_alter_t_standard_doc_folder.sql new file mode 100644 index 0000000..11199e6 --- /dev/null +++ b/scripts/0.0.8/01_alter_t_standard_doc_folder.sql @@ -0,0 +1,25 @@ +create table t_standard_doc_folder +( + id serial not null, + name varchar(255) not null, + create_at timestamp with time zone not null, + parent integer +); + +comment on table t_standard_doc_folder is '标准文档文件夹'; + +comment on column t_standard_doc_folder.id is 'ID唯一标识'; + +comment on column t_standard_doc_folder.name is '文件夹名称'; + +comment on column t_standard_doc_folder.create_at is '文件夹创建时间'; + +comment on column t_standard_doc_folder.parent is '父级文件夹'; + +create unique index t_standard_doc_folder_id_uindex + on t_standard_doc_folder (id); + +alter table t_standard_doc_folder + add constraint t_standard_doc_folder_pk + primary key (id); + diff --git a/scripts/0.0.8/02_alter_t_standard_doc.sql b/scripts/0.0.8/02_alter_t_standard_doc.sql new file mode 100644 index 0000000..2e88909 --- /dev/null +++ b/scripts/0.0.8/02_alter_t_standard_doc.sql @@ -0,0 +1,41 @@ + +CREATE TYPE public."enum_standard_type" AS ENUM ( +'国家标准', +'行业标准', +'地方标准' +); + +create table t_standard_doc +( + id serial not null, + doc_name varchar(255) not null, + standard_type enum_standard_type not null, + tags varchar(255), + folder integer, + path varchar(255) not null, + create_at timestamp with time zone not null +); + +comment on table t_standard_doc is '文档管理文件'; + +comment on column t_standard_doc.id is 'ID唯一标识'; + +comment on column t_standard_doc.doc_name is '文档名称'; + +comment on column t_standard_doc.standard_type is '标准类型'; + +comment on column t_standard_doc.tags is '标签'; + +comment on column t_standard_doc.folder is '归属的文件夹'; + +comment on column t_standard_doc.path is '文档存储路径'; + +comment on column t_standard_doc.create_at is '文档创建时间'; + +create unique index t_standard_doc_id_uindex + on t_standard_doc (id); + +alter table t_standard_doc + add constraint t_standard_doc_pk + primary key (id); + diff --git a/scripts/0.0.8/03_alter_ t_business_rule.sql b/scripts/0.0.8/03_alter_ t_business_rule.sql new file mode 100644 index 0000000..6137e00 --- /dev/null +++ b/scripts/0.0.8/03_alter_ t_business_rule.sql @@ -0,0 +1,51 @@ +CREATE TYPE public."enum_problem_type" AS ENUM ( +'一致性', +'准确性', +'完整性', +'有效性', +'及时性', +'规范性' +); + +CREATE TYPE public."enum_problem_level" AS ENUM ( +'一般', +'重要', +'严重' +); + + + +create table t_business_rule +( + id serial not null, + name varchar(255) not null, + description varchar(255) not null, + problem_type enum_problem_type not null, + problem_level enum_problem_level not null, + rule_basis integer not null, + create_at timestamp with time zone not null +); + +comment on table t_business_rule is '业务规则表'; + +comment on column t_business_rule.id is 'ID唯一标识'; + +comment on column t_business_rule.name is '业务规则名称'; + +comment on column t_business_rule.description is '业务规则描述'; + +comment on column t_business_rule.problem_type is '问题类型'; + +comment on column t_business_rule.problem_level is '问题级别'; + +comment on column t_business_rule.rule_basis is '制定依据'; + +comment on column t_business_rule.create_at is '创建时间'; + +create unique index t_business_rule_id_uindex + on t_business_rule (id); + +alter table t_business_rule + add constraint t_business_rule_pk + primary key (id); + diff --git a/scripts/0.0.8/04_alter_t_data_security_specification .sql b/scripts/0.0.8/04_alter_t_data_security_specification .sql new file mode 100644 index 0000000..a39ab3c --- /dev/null +++ b/scripts/0.0.8/04_alter_t_data_security_specification .sql @@ -0,0 +1,28 @@ +create table t_data_security_specification +( + id serial not null, + file_name varchar(255) not null, + tags varchar(255), + create_at timestamp with time zone not null, + path varchar(255) not null +); + +comment on table t_data_security_specification is '数据安全规范'; + +comment on column t_data_security_specification.id is 'ID唯一标识'; + +comment on column t_data_security_specification.file_name is '文件名'; + +comment on column t_data_security_specification.tags is '标签'; + +comment on column t_data_security_specification.create_at is '文件创建时间'; + +comment on column t_data_security_specification.path is '文件路径'; + +create unique index t_data_security_specification_id_uindex + on t_data_security_specification (id); + +alter table t_data_security_specification + add constraint t_data_security_specification_pk + primary key (id); + diff --git a/web/client/assets/files/common/1687322895851_3.jpg b/web/client/assets/files/common/1687322895851_3.jpg new file mode 100644 index 0000000..8fe90ea Binary files /dev/null and b/web/client/assets/files/common/1687322895851_3.jpg differ diff --git a/web/client/assets/files/common/1687322905542_2.jpg b/web/client/assets/files/common/1687322905542_2.jpg new file mode 100644 index 0000000..3f96826 Binary files /dev/null and b/web/client/assets/files/common/1687322905542_2.jpg differ diff --git a/web/client/assets/files/common/1687654158463_1.jpg b/web/client/assets/files/common/1687654158463_1.jpg new file mode 100644 index 0000000..e2c29e8 Binary files /dev/null and b/web/client/assets/files/common/1687654158463_1.jpg differ diff --git a/web/client/assets/files/common/readme.txt b/web/client/assets/files/common/readme.txt deleted file mode 100644 index a685d95..0000000 --- a/web/client/assets/files/common/readme.txt +++ /dev/null @@ -1 +0,0 @@ -03专项三期文件本地上传默认路径 \ No newline at end of file diff --git a/web/client/src/layout/containers/layout/index.less b/web/client/src/layout/containers/layout/index.less index d55219a..ce3bc72 100644 --- a/web/client/src/layout/containers/layout/index.less +++ b/web/client/src/layout/containers/layout/index.less @@ -1,2 +1,3 @@ @import '~perfect-scrollbar/css/perfect-scrollbar.css'; -@import '~nprogress/nprogress.css'; \ No newline at end of file +@import '~nprogress/nprogress.css'; +@import '~simplebar-react/dist/simplebar.min.css'; \ No newline at end of file diff --git a/web/client/src/sections/dataQuality/actions/approve.js b/web/client/src/sections/dataQuality/actions/approve.js deleted file mode 100644 index 9f21dbd..0000000 --- a/web/client/src/sections/dataQuality/actions/approve.js +++ /dev/null @@ -1,29 +0,0 @@ -'use strict'; - -import { basicAction } from '@peace/utils' -import { ApiTable } from '$utils' - -export function getApproveList (query = {}) { - return dispatch => basicAction({ - type: 'get', - query, - dispatch: dispatch, - actionType: 'GET_APPROVE_LIST', - url: `${ApiTable.approveList}`, - msg: { error: '获取资源消费列表失败' }, - reducer: { name: '' } - }); -} - - -export function postApprove (data = {}) { - return dispatch => basicAction({ - type: 'post', - data, - dispatch: dispatch, - actionType: 'POST_APPROVE', - url: `${ApiTable.approveList}`, - msg: { option: '资源审批' }, - reducer: { name: '' } - }); -} diff --git a/web/client/src/sections/dataQuality/actions/documentLibrary.js b/web/client/src/sections/dataQuality/actions/documentLibrary.js new file mode 100644 index 0000000..1d4eed1 --- /dev/null +++ b/web/client/src/sections/dataQuality/actions/documentLibrary.js @@ -0,0 +1,66 @@ +'use strict'; + +import { basicAction } from '@peace/utils' +import { ApiTable } from '$utils' + +export function getStandardDocFolders (query = {}) { + return dispatch => basicAction({ + type: 'get', + query, + dispatch: dispatch, + actionType: 'GET_STANDARD_DOC_FOLDERS', + url: `${ApiTable.standardDocFolders}`, + msg: { error: '获取标准文档目录列表失败' }, + reducer: { name: '' } + }); +} + + +export function postStandardDocFolders (data = {}) { + return dispatch => basicAction({ + type: 'post', + data, + dispatch: dispatch, + actionType: 'POST_STANDARD_DOC_FOLDERS', + url: `${ApiTable.standardDocFolders}`, + msg: { option: '标准文档目录新增' }, + reducer: { name: '' } + }); +} + +export function postStandardDocs (data = {}) { + return dispatch => basicAction({ + type: 'post', + data, + dispatch: dispatch, + actionType: 'POST_STANDARD_DOCS', + url: `${ApiTable.standardDocs}`, + msg: { option: '新增标准文档' }, + reducer: { name: '' } + }); +} + +export function getStandardDocs (query = {}) { + return dispatch => basicAction({ + type: 'get', + query, + dispatch: dispatch, + actionType: 'GET_STANDARD_DOCS', + url: `${ApiTable.standardDocs}`, + msg: { error: '获取标准文档列表失败' }, + reducer: { name: '' } + }); +} + +export function postFolderFile (data) { + return dispatch => basicAction({ + type: 'post', + data, + dispatch: dispatch, + actionType: 'POST_FOLDER_FILE', + url: ApiTable.postFolderFile, + msg: { option: '删除文件夹或文件' }, + reducer: { name: '' } + }); +} + diff --git a/web/client/src/sections/dataQuality/actions/index.js b/web/client/src/sections/dataQuality/actions/index.js index f233405..bb9a933 100644 --- a/web/client/src/sections/dataQuality/actions/index.js +++ b/web/client/src/sections/dataQuality/actions/index.js @@ -1,9 +1,11 @@ 'use strict'; import * as example from './example' -import * as approve from './approve' +import * as documentLibrary from './documentLibrary' +import * as ruleLibrary from './ruleLibrary' export default { ...example, - ...approve, + ...documentLibrary, + ...ruleLibrary, } \ No newline at end of file diff --git a/web/client/src/sections/dataQuality/actions/ruleLibrary.js b/web/client/src/sections/dataQuality/actions/ruleLibrary.js new file mode 100644 index 0000000..b3182d5 --- /dev/null +++ b/web/client/src/sections/dataQuality/actions/ruleLibrary.js @@ -0,0 +1,52 @@ +'use strict'; + +import { basicAction } from '@peace/utils' +import { ApiTable } from '$utils' + +export function postBusinessRules (data = {}) { + let reminder = data?.id ? '修改业务规则' : '新增业务规则' + return dispatch => basicAction({ + type: 'post', + data, + dispatch: dispatch, + actionType: 'POST_BUSINESS_RULES', + url: `${ApiTable.businessRules}`, + msg: { option: reminder }, + reducer: { name: '' } + }); +} + +export function getBusinessRules (query = {}) { + return dispatch => basicAction({ + type: 'get', + query, + dispatch: dispatch, + actionType: 'GET_BUSINESS_RULES', + url: `${ApiTable.businessRules}`, + msg: { error: '查询业务规则列表失败' }, + reducer: { name: '' } + }); +} + +export function delBusinessRules (id) { + return dispatch => basicAction({ + type: 'del', + dispatch: dispatch, + actionType: 'del_BUSINESS_RULES', + url: `${ApiTable.delBusinessRules.replace('{id}', id)}`, + msg: { option: '删除业务规则' }, + reducer: { name: '' } + }); +} + +export function getRegularBasis (query = {}) { + return dispatch => basicAction({ + type: 'get', + query, + dispatch: dispatch, + actionType: 'GET_REGULAR_BASIS', + url: `${ApiTable.regularBasis}`, + msg: { error: '查询规则依据列表失败' }, + reducer: { name: '' } + }); +} diff --git a/web/client/src/sections/dataQuality/components/approveModal.js b/web/client/src/sections/dataQuality/components/approveModal.js deleted file mode 100644 index 4d01719..0000000 --- a/web/client/src/sections/dataQuality/components/approveModal.js +++ /dev/null @@ -1,94 +0,0 @@ -import React, { useEffect, useState } from 'react' -import { connect } from 'react-redux'; -import moment from 'moment'; -import { v4 as uuidv4 } from 'uuid' - -import { Tabs, Form, Input, DatePicker, Button, Modal, Radio } from 'antd'; - - -function ApproveModal ({ loading, clientHeight, user, actions, dispatch, close, success, editData, }) { - - const { resourceConsumption } = actions - const [tabsKey, setTabsKey] = useState("stay") - const [query, setQuery] = useState({ page: 0, limit: 10 }); - const [proTableList, setProTableList] = useState({ rows: [], count: 0 }); - const [approve, setApprove] = useState() - - const [form] = Form.useForm(); - useEffect(() => { - - }, []) - - - - - - - return <> - { - form.validateFields().then(v => { - console.log(v); - dispatch(resourceConsumption.postApprove({ - id: editData?.id, ...v, - approveAt: moment().format('YYYY-MM-DD HH:mm:ss'), - approveBy: user?.id, - approveState: '已审批' - })).then(res => { - if (res.success) { - close() - success() - } - }) - }) - }} - onCancel={() => { - close() - }} - > -
{ - console.log(v); - if (v.approve) { - setApprove(v.approve) - } - // setFormData(v) - }} - autoComplete="off" - > - - - 同意 - 不同意 - - - {!approve || approve == 'false' ? - - - : ""} - {!approve || approve == 'true' ?
- - - - -
: ""} -
-
- - -} -function mapStateToProps (state) { - const { global, auth, resourceCatalog } = state; - return { - user: auth.user, - actions: global.actions, - clientHeight: global.clientHeight, - // resourceCatalog: resourceCatalog?.data || [], - // isRequesting: resourceCatalog.isRequesting - }; -} -export default connect(mapStateToProps)(ApproveModal) \ No newline at end of file diff --git a/web/client/src/sections/dataQuality/components/fileModal.js b/web/client/src/sections/dataQuality/components/fileModal.js new file mode 100644 index 0000000..760a750 --- /dev/null +++ b/web/client/src/sections/dataQuality/components/fileModal.js @@ -0,0 +1,118 @@ +import React, { useEffect, useState } from 'react' +import { connect } from 'react-redux'; +import moment from 'moment'; +import { UploadLocal } from '$components'; + + +import { Tabs, Form, Input, DatePicker, Button, Modal, Select, Tag } from 'antd'; + + +function FileModal ({ loading, parent, user, actions, editData = {}, dispatch, close, success,remove }) { + + const { dataQuality } = actions + const [tabsKey, setTabsKey] = useState("stay") + const [query, setQuery] = useState({ page: 0, limit: 10 }); + const [proTableList, setProTableList] = useState({ rows: [], count: 0 }); + const [approve, setApprove] = useState() + + const [form] = Form.useForm(); + const [editUrl, setEditUrl] = useState([]); + useEffect(() => { + + }, []) + + + + const vsjunct = (params) => { + if (params.length) { + let appendix = [] + for (let p of params) { + appendix.push({ + fName: p.name, + size: p.size, + fileSize: p.size, + storageUrl: p.storageUrl,//必须有storageUrl + }) + } + setEditUrl(appendix) + } else { + setEditUrl([]) + } + } + + return <> + { + form.validateFields().then(v => { + dispatch(dataQuality.postStandardDocs({ + ...v, + path: v?.files[0]?.url, docName: v?.files[0]?.name, + folder: parent || null, + })).then(res => { + if (res.success) { + close() + success() + } + }) + }) + }} + onCancel={() => { + if (form.getFieldValue('files') && form.getFieldValue('files').length) { + remove(form.getFieldValue('files')[0]?.url) + } + close() + }} + > +
{ + + }} + autoComplete="off" + labelCol={{ span: 4 }} wrapperCol={{ span: 20 }} + > + + + + + + + + 文件大小不超过40MB,开放资源包含多个文件,建议将文件进行压缩,形成压缩包再上传 + 支持的文件格式:jpg,png,gif,txt,doc,docx,pdf,xsl,xlsx,zip,rar + +
+
+ + +} +function mapStateToProps (state) { + const { global, auth, resourceCatalog } = state; + return { + user: auth.user, + actions: global.actions, + clientHeight: global.clientHeight, + // resourceCatalog: resourceCatalog?.data || [], + // isRequesting: resourceCatalog.isRequesting + }; +} +export default connect(mapStateToProps)(FileModal) \ No newline at end of file diff --git a/web/client/src/sections/dataQuality/components/groupModal.js b/web/client/src/sections/dataQuality/components/groupModal.js new file mode 100644 index 0000000..f4d2f4a --- /dev/null +++ b/web/client/src/sections/dataQuality/components/groupModal.js @@ -0,0 +1,66 @@ +import React, { useEffect, useState } from 'react' +import { connect } from 'react-redux'; +import moment from 'moment'; +import { v4 as uuidv4 } from 'uuid' + +import { Tabs, Form, Input, DatePicker, Button, Modal, Radio } from 'antd'; + + +function GroupModal ({ loading, parent, user, actions, dispatch, close, success, }) { + + const { dataQuality } = actions + + const [form] = Form.useForm(); + useEffect(() => { + + }, []) + + + + + return <> + { + form.validateFields().then(v => { + dispatch(dataQuality.postStandardDocFolders({ + ...v, + parent: parent || null, + })).then(res => { + if (res.success) { + close() + success() + } + }) + }) + }} + onCancel={() => { + close() + }} + > +
{ + + }} + autoComplete="off" + > + + + +
+
+ + +} +function mapStateToProps (state) { + const { global, auth, resourceCatalog } = state; + return { + user: auth.user, + actions: global.actions, + clientHeight: global.clientHeight, + // resourceCatalog: resourceCatalog?.data || [], + // isRequesting: resourceCatalog.isRequesting + }; +} +export default connect(mapStateToProps)(GroupModal) \ No newline at end of file diff --git a/web/client/src/sections/dataQuality/components/ruleModal.js b/web/client/src/sections/dataQuality/components/ruleModal.js new file mode 100644 index 0000000..7b26e17 --- /dev/null +++ b/web/client/src/sections/dataQuality/components/ruleModal.js @@ -0,0 +1,104 @@ +import React, { useEffect, useState } from 'react' +import { connect } from 'react-redux'; +import moment from 'moment'; +import { v4 as uuidv4 } from 'uuid' + +import { Tabs, Form, Input, DatePicker, Button, Modal, Radio, Select, TreeSelect } from 'antd'; +const { TextArea } = Input; +const { Option, OptGroup } = Select; +function RuleModal ({ loading, parent, user, actions, dispatch, close, success, treeList, editData }) { + + const { dataQuality } = actions + const [tabsKey, setTabsKey] = useState("stay") + const [query, setQuery] = useState({ page: 0, limit: 10 }); + const [proTableList, setProTableList] = useState({ rows: [], count: 0 }); + const [approve, setApprove] = useState() + + const [form] = Form.useForm(); + useEffect(() => { + + }, []) + + + + + + + return <> + { + form.validateFields().then(v => { + // console.log(v); + dispatch(dataQuality.postBusinessRules({ + ...v, id: editData?.id + })).then(res => { + if (res.success) { + close() + success() + } + }) + }) + }} + onCancel={() => { + close() + }} + > +
{ + + }} + autoComplete="off" + labelCol={{ span: 4 }} wrapperCol={{ span: 20 }} + > + + + + +