Browse Source

(*)资源检索下载功能开发

master
peng.peng 2 years ago
parent
commit
8e85daf28a
  1. 7
      api/app/lib/controllers/latestMetadata/index.js
  2. 10
      api/app/lib/controllers/resourceConsumption/index.js
  3. 9
      api/app/lib/models/resource_consumption.js
  4. 4
      web/client/src/sections/metadataManagement/containers/databasesTable.js
  5. 4
      web/client/src/sections/metadataManagement/containers/filesTable.js
  6. 4
      web/client/src/sections/metadataManagement/containers/restapisTable.js
  7. 44
      web/client/src/sections/resourceRetrieval/components/keyModal.js
  8. 65
      web/client/src/sections/resourceRetrieval/containers/retrieval.js
  9. 30
      web/client/src/sections/resourceRetrieval/utils/index.js

7
api/app/lib/controllers/latestMetadata/index.js

@ -366,6 +366,7 @@ async function delMetadataDatabases(ctx) {
} else { } else {
let resourceConsumptionInfo = await models.ResourceConsumption.findOne({ let resourceConsumptionInfo = await models.ResourceConsumption.findOne({
where: { where: {
resourceId: id,
resourceName: metadataDatabaseInfo.name, resourceName: metadataDatabaseInfo.name,
resourceType: '库表' resourceType: '库表'
} }
@ -516,14 +517,14 @@ async function getTagMetadata(ctx) {
//申请资源 //申请资源
async function postMetadataResourceApplications(ctx) { async function postMetadataResourceApplications(ctx) {
try { try {
const { resourceName, applyBy, resourceType } = ctx.request.body; const { resourceName, applyBy, resourceType, resourceId } = ctx.request.body;
if (!resourceName || !applyBy || !resourceType) { if (!resourceName || !applyBy || !resourceType || !resourceId) {
ctx.status = 400; ctx.status = 400;
ctx.body = { message: '参数不全,请重新申请资源' } ctx.body = { message: '参数不全,请重新申请资源' }
} else { } else {
const models = ctx.fs.dc.models; const models = ctx.fs.dc.models;
const postOne = await models.ResourceConsumption.findOne({ const postOne = await models.ResourceConsumption.findOne({
where: { applyBy: applyBy, resourceName: resourceName } where: { applyBy: applyBy, resourceName: resourceName, resourceId, resourceType }
}); });
if (postOne) { if (postOne) {
ctx.status = 400; ctx.status = 400;

10
api/app/lib/controllers/resourceConsumption/index.js

@ -1,11 +1,11 @@
'use strict'; 'use strict';
const moment = require('moment') const moment = require('moment')
function getApproveList (opts) { function getApproveList(opts) {
return async function (ctx, next) { return async function (ctx, next) {
const models = ctx.fs.dc.models; const models = ctx.fs.dc.models;
const { page, limit, applyAt, approveState, resourceName, applyBy, applyById, state } = ctx.query; const { page, limit, applyAt, approveState, resourceName, applyBy, applyById, state ,} = ctx.query;
let errMsg = { message: '获取消费审批列表失败' } let errMsg = { message: '获取消费审批列表失败' }
try { try {
@ -81,7 +81,7 @@ function getApproveList (opts) {
} }
// 新增模型 // 新增模型
function addModelManagement (opts) { function addModelManagement(opts) {
return async function (ctx, next) { return async function (ctx, next) {
const models = ctx.fs.dc.models; const models = ctx.fs.dc.models;
@ -108,7 +108,7 @@ function addModelManagement (opts) {
} }
// 修改模型 // 修改模型
function postApprove (opts) { function postApprove(opts) {
return async function (ctx, next) { return async function (ctx, next) {
try { try {
@ -132,7 +132,7 @@ function postApprove (opts) {
} }
// 删除模型 // 删除模型
function deleteModelManagement (opts) { function deleteModelManagement(opts) {
return async function (ctx, next) { return async function (ctx, next) {
try { try {

9
api/app/lib/models/resource_consumption.js

@ -16,6 +16,15 @@ module.exports = dc => {
autoIncrement: true, autoIncrement: true,
unique: "t_resource_consumption_id_uindex" unique: "t_resource_consumption_id_uindex"
}, },
resourceId: {
type: DataTypes.INTEGER,
allowNull: false,
defaultValue: null,
comment: "资源id",
primaryKey: false,
field: "resource_id",
autoIncrement: false
},
resourceName: { resourceName: {
type: DataTypes.STRING, type: DataTypes.STRING,
allowNull: false, allowNull: false,

4
web/client/src/sections/metadataManagement/containers/databasesTable.js

@ -92,7 +92,7 @@ const DatabaseTable = (props) => {
}); });
} }
const applyResources = (record) => { const applyResources = (record) => {
setEditResourceData({ record: { resourceName: record.name, applyBy: user.id, applyByName: user.name, resourceType: '库表' } }); setEditResourceData({ record: { resourceId: record.id, resourceName: record.name, applyBy: user.id, applyByName: user.name, resourceType: '库表' } });
setResourceModalVisible(true); setResourceModalVisible(true);
} }
@ -170,7 +170,7 @@ const DatabaseTable = (props) => {
width: '8%', width: '8%',
render: (text, record) => { render: (text, record) => {
let resourceApplicationsRecords = metadataResourceApplications.filter(ra => let resourceApplicationsRecords = metadataResourceApplications.filter(ra =>
ra.applyBy == user.id && ra.resourceName === record.name); ra.applyBy == user.id && ra.resourceName === record.name && ra.resourceId == record.id);
return <ButtonGroup> return <ButtonGroup>
<a onClick={() => onView(record)}>查看</a> <a onClick={() => onView(record)}>查看</a>
{user.role == '数据消费者' ? null : {user.role == '数据消费者' ? null :

4
web/client/src/sections/metadataManagement/containers/filesTable.js

@ -102,7 +102,7 @@ const FilesTable = (props) => {
}); });
} }
const applyResources = (record) => { const applyResources = (record) => {
setEditResourceData({ record: { resourceName: record.name, applyBy: user.id, applyByName: user.name, resourceType: '文件' } }); setEditResourceData({ record: { resourceId: record.id, resourceName: record.name, applyBy: user.id, applyByName: user.name, resourceType: '文件' } });
setResourceModalVisible(true); setResourceModalVisible(true);
} }
@ -205,7 +205,7 @@ const FilesTable = (props) => {
width: '8%', width: '8%',
render: (text, record) => { render: (text, record) => {
let resourceApplicationsRecords = metadataResourceApplications.filter(ra => let resourceApplicationsRecords = metadataResourceApplications.filter(ra =>
ra.applyBy == user.id && ra.resourceName === record.name); ra.applyBy == user.id && ra.resourceName === record.name && ra.resourceId == record.id);
return <ButtonGroup> return <ButtonGroup>
{user.role == '数据消费者' ? null : {user.role == '数据消费者' ? null :
<> <>

4
web/client/src/sections/metadataManagement/containers/restapisTable.js

@ -79,7 +79,7 @@ const RestapisTable = (props) => {
}); });
} }
const applyResources = (record) => { const applyResources = (record) => {
setEditResourceData({ record: { resourceName: record.name, applyBy: user.id, applyByName: user.name, resourceType: '接口' } }); setEditResourceData({ record: { resourceId: record.id, resourceName: record.name, applyBy: user.id, applyByName: user.name, resourceType: '接口' } });
setResourceModalVisible(true); setResourceModalVisible(true);
} }
@ -141,7 +141,7 @@ const RestapisTable = (props) => {
width: '8%', width: '8%',
render: (text, record) => { render: (text, record) => {
let resourceApplicationsRecords = metadataResourceApplications.filter(ra => let resourceApplicationsRecords = metadataResourceApplications.filter(ra =>
ra.applyBy == user.id && ra.resourceName === record.name); ra.applyBy == user.id && ra.resourceName === record.name && ra.resourceId == record.id);
return <ButtonGroup> return <ButtonGroup>
{user.role == '数据消费者' ? null : {user.role == '数据消费者' ? null :
<> <>

44
web/client/src/sections/resourceRetrieval/components/keyModal.js

@ -0,0 +1,44 @@
import React from 'react'
import {
ModalForm,
ProFormText,
} from '@ant-design/pro-form';
import { Form, message } from 'antd';
export default (props) => {
const { resourceId, onFinish, approveList } = props;
const [form] = Form.useForm();
return (
<ModalForm
title="输入令牌"
trigger={
<a>下载</a>
}
form={form}
layout='horizontal'
autoFocusFirstInput
modalProps={{
destroyOnClose: true,
}}
onFinish={async (values) => {
console.log(values.name);
const token = approveList?.rows?.find(s => s.resourceId == resourceId)?.token
if (token == values.name) {
onFinish()
return true;
} else {
message.error('令牌错误')
}
}}
width={500}
>
<ProFormText
name="name"
label="访问令牌"
placeholder="请输入访问令牌"
rules={[{ required: true, message: '访问令牌不可空' }]}
/>
</ModalForm>
);
};

65
web/client/src/sections/resourceRetrieval/containers/retrieval.js

@ -1,12 +1,17 @@
import React, { useEffect, useState } from 'react' import React, { useEffect, useState } from 'react'
import { Input, Tooltip, Empty } from 'antd' import { Input, Tooltip, Empty, Pagination, Modal, Form } from 'antd'
import { InsertRowBelowOutlined, DatabaseOutlined, FileOutlined, PullRequestOutlined } from '@ant-design/icons'; import { InsertRowBelowOutlined, DatabaseOutlined, FileOutlined, PullRequestOutlined, KeyOutlined } from '@ant-design/icons';
import { useFsRequest, ApiTable } from '$utils'; import { useFsRequest, ApiTable } from '$utils';
import { connect } from 'react-redux';
import { downloadImg } from '../utils/index'
import KeyModal from '../components/keyModal';
import './style.less'; import './style.less';
function Retrieval(props) { function Retrieval(props) {
const { user } = props;
const [keywords, setKeywords] = useState() const [keywords, setKeywords] = useState()
const [firstInput, setFirstInput] = useState() const [firstInput, setFirstInput] = useState()
const [page, setPage] = useState(1)
const formRef = React.createRef();
const { data: catalogs = [] } = useFsRequest({ const { data: catalogs = [] } = useFsRequest({
url: ApiTable.getResourceCatalog, url: ApiTable.getResourceCatalog,
}); });
@ -20,7 +25,14 @@ function Retrieval(props) {
ready: !!keywords ready: !!keywords
}); });
console.log(result) const { data: approveList = {} } = useFsRequest({
url: ApiTable.approveList,
query: {
applyById: user?.id
},
refreshDeps: [user?.id],
ready: !!(user?.id)
});
const renderIcon = (type) => { const renderIcon = (type) => {
switch (type) { switch (type) {
@ -54,6 +66,19 @@ function Retrieval(props) {
</Tooltip> : text </Tooltip> : text
} }
const downloadData = (s) => {
if (s?.type == '文件') {
const suffix = s?.fileName?.substring(s?.fileName?.length - 3, s?.fileName?.length)
if (suffix == 'png' || suffix == 'jpg') {
downloadImg(s.fileName)
} else {
window.open('/assets/files/common/' + s.fileName)
}
} else {
alert('库表下载待开发')
}
}
return !result?.rows ? <div className='search-container'> return !result?.rows ? <div className='search-container'>
<div className='title'>数据资源检索</div> <div className='title'>数据资源检索</div>
<Input addonAfter={<div onClick={() => { setKeywords(firstInput) }} style={{ color: '#fff' }}>搜索一下</div>} <Input addonAfter={<div onClick={() => { setKeywords(firstInput) }} style={{ color: '#fff' }}>搜索一下</div>}
@ -66,7 +91,7 @@ function Retrieval(props) {
<Input.Search defaultValue={keywords} style={{ width: '30%', marginLeft: 10, marginBottom: 30 }} <Input.Search defaultValue={keywords} style={{ width: '30%', marginLeft: 10, marginBottom: 30 }}
onSearch={value => { setKeywords(value) }} onSearch={value => { setKeywords(value) }}
/> />
{result?.rows?.map(s => { {result?.rows?.slice((page - 1) * 10, (page - 1) * 10 + 10).map(s => {
const catalogText = renderCatalog(s?.catalog).split('/').reverse().toString().replaceAll(',', '/') const catalogText = renderCatalog(s?.catalog).split('/').reverse().toString().replaceAll(',', '/')
const tagText = s?.tagDatabases?.map(x => x.tag.name).toString() || '-' const tagText = s?.tagDatabases?.map(x => x.tag.name).toString() || '-'
return <div className='result-row'> return <div className='result-row'>
@ -78,13 +103,37 @@ function Retrieval(props) {
<span> 路径{renderText(catalogText)}</span> <span> 路径{renderText(catalogText)}</span>
<span> 标签{renderText(tagText)}</span> <span> 标签{renderText(tagText)}</span>
</div> </div>
<div className='column2'>相关操作<a>定位</a> <div className='column2'>相关操作<a onClick={() => { window.open('/metadataManagement/latestMetadata') }}>定位</a>
{s?.type == '表' || s?.type == '文件' ? <a>下载</a> : ''} {s?.type == '表' || s?.type == '文件' ?
user?.role == '数据消费者' ?
<KeyModal
resourceId={s.id}
approveList={approveList}
onFinish={() => {
downloadData(s)
}}
/> :
<a onClick={() => { downloadData(s) }}>下载</a> : ''}
</div> </div>
</div> </div>
})} })}
{result?.rows?.length > 0 && <Pagination
defaultCurrent={1} total={result?.rows?.length}
style={{ float: 'right', paddingRight: '5%' }}
showTotal={total => `${total} 条数据`}
onChange={(page, pageSize) => {
setPage(page)
}}
/>}
{!result?.rows?.length > 0 && <Empty />} {!result?.rows?.length > 0 && <Empty />}
</> </>
} }
export default Retrieval function mapStateToProps(state) {
const { auth, } = state;
return {
user: auth.user,
};
}
export default connect(mapStateToProps)(Retrieval)

30
web/client/src/sections/resourceRetrieval/utils/index.js

@ -0,0 +1,30 @@
const imageToBase64 = (img) => {
var canvas = document.createElement("canvas");
canvas.width = img.width;
canvas.height = img.height;
var ctx = canvas.getContext("2d");
console.log(img, canvas)
ctx.drawImage(img, 0, 0, img.width, img.height);
var ext = img.src.substring(img.src.lastIndexOf(".") + 1).toLowerCase();
var dataURL = canvas.toDataURL("image/" + ext);
return dataURL;
}
export const downloadImg = (fileName) => {
const url = '/assets/files/common/' + fileName
var image = new Image();
image.crossOrigin = '';
image.src = url;
image.onload = function () {
let base64 = imageToBase64(image); //图片转base64
const link = document.createElement('a')
link.style.display = 'none'
//设置下载的图片名称
link.download = fileName
link.href = base64
document.body.appendChild(link)
link.click()
document.body.removeChild(link)
}
}
Loading…
Cancel
Save