ww664853070 2 years ago
parent
commit
3793387efd
  1. 40
      .vscode/launch.json
  2. 2
      api/app/lib/controllers/auth/index.js
  3. 12
      api/app/lib/controllers/report/index.js
  4. 4
      api/app/lib/routes/report/index.js
  5. 5
      web/.vscode/extensions.json
  6. 4
      web/.vscode/settings.json
  7. 6
      web/client/src/layout/actions/webSocket.js
  8. 10
      web/client/src/sections/auth/actions/auth.js
  9. 2
      web/client/src/sections/auth/containers/login.jsx
  10. 3
      web/client/src/sections/business/actions/index.js
  11. 13
      web/client/src/sections/business/actions/reserve-item.js
  12. 14
      web/client/src/sections/business/actions/service.js
  13. 5
      web/client/src/sections/business/constants/index.js
  14. 2
      web/client/src/sections/business/containers/pmLog.jsx
  15. 58
      web/client/src/sections/business/containers/reserveItemsDepSummary.jsx
  16. 57
      web/client/src/sections/business/containers/reserveItemsLostStatistics.jsx
  17. 59
      web/client/src/sections/business/containers/reserveItemsPeriodicStatistics.jsx
  18. 2
      web/client/src/utils/func.js
  19. 8
      web/client/src/utils/webapi.js
  20. 2
      web/package.json
  21. 22
      web/routes/attachment/index.js

40
.vscode/launch.json

@ -4,6 +4,26 @@
// 访: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"type": "node",
"request": "launch",
"name": "启动 web",
"program": "${workspaceRoot}/web/server.js",
"env": {
"NODE_ENV": "development"
},
"args": [
"-p", "5700",
"-u","http://localhost:4700",
"--apiHrUrl", "http://localhost:4700",
//
"--qnak", "5XrM4wEB9YU6RQwT64sPzzE6cYFKZgssdP5Kj3uu",
"--qnsk", "w6j2ixR_i-aelc6I7S3HotKIX-ukMzcKmDfH6-M5",
"--qnbkt", "pep-process-report",
"--qndmn", "https://pepsource.anxinyun.cn",
"--wkys", "http://10.8.30.109:14000"
]
},
{
"type": "node",
"request": "launch",
@ -15,31 +35,33 @@
"args": [
"-p 4700",
// "-f http://localhost:4700",
//
"-g postgres://postgres:123456@10.8.16.184:5432/ReportCenter",
//
// "-g postgres://postgres:123456@10.8.16.184:5432/ReportCenter",
// "--redisHost localhost",
// "--redisPort 6378",
// "--apiEmisUrl http://localhost:4000",
//
//
"-g postgres://FashionAdmin:123456@10.8.30.36:5432/data_center",
"--redisHost localhost",
"--redisPort 6378",
// "--apiEmisUrl http://10.8.30.112:14000",
"--redisPort 6379",
"--apiEmisUrl http://localhost:14000",
//
//
"--apiEmisUrl http://localhost:4000",
"--qnak XuDgkao6cL0HidoMAPnA5OB10Mc_Ew08mpIfRJK5",
"--qnsk yewcieZLzKZuDfig0wLZ9if9jKp2P_1jd3CMJPSa",
"--qnbkt dev-hr",
// "--qndmn http://resources.anxinyun.cn",
"--qndmn http://rjkwed13l.hn-bkt.clouddn.com",
// * 2
// "--clickHouseUser ",
// "--clickHousePassword ",
"--clickHousePort 30123",
//
// "--clickHouseUrl http://10.8.30.71",
// "--clickHousePepEmis pepca_dev",
// "--clickHouseCamworkflow camworkflow",
// "--clickHouseHr hr_dev",
//
"--clickHouseUrl http://10.8.16.221",
"--clickHousePepEmis pg_pepca",

2
api/app/lib/controllers/auth/index.js

@ -19,7 +19,7 @@ async function login (ctx, next) {
emisLoginRes.authorized = true
emisLoginRes.expired = moment().add(1, 'day')
emisLoginRes.hrUserInfo = undefined
emisLoginRes.dcUserInfo = undefined
await ctx.redis.hmset(emisLoginRes.token, {
expired: moment().add(1, 'day'),

12
api/app/lib/controllers/report/index.js

@ -2,15 +2,23 @@
// 查询储备项目统计表
async function getReserveItemReport(ctx, next) {
const { type } = ctx.request.query;
const { type } = ctx.params;
let rslt = null;
try {
rslt = await ctx.fs.dc.models.ReserveItemReport.findAll({
order: [['year', 'DESC'], ['month', 'DESC']],
where: { type: type }
})
let newReportData = rslt.map(e => {
return {
id: e.id,
date: e.year + '-' + e.month,
path: e.path,
type: e.type
}
})
ctx.status = 200
ctx.body = rslt
ctx.body = newReportData
} catch (error) {
ctx.fs.logger.error(`path:${ctx.path},error:${error}`)
ctx.status = 400;

4
api/app/lib/routes/report/index.js

@ -3,6 +3,6 @@
const report = require('../../controllers/report');
module.exports = function (app, router, opts) {
app.fs.api.logAttr['GET/getReserveItemReport'] = { content: '查询储备项目统计表', visible: false };
router.get('/getReserveItemReport', report.getReserveItemReport);
app.fs.api.logAttr['GET/reserveItem/report/:type'] = { content: '查询储备项目统计表', visible: false };
router.get('/reserveItem/report/:type', report.getReserveItemReport);
};

5
web/.vscode/extensions.json

@ -1,5 +0,0 @@
{
"recommendations": [
"formulahendry.code-runner"
]
}

4
web/.vscode/settings.json

@ -1,4 +0,0 @@
//
{
"editor.fontSize": 16,
}

6
web/client/src/layout/actions/webSocket.js

@ -2,19 +2,19 @@
import io from 'socket.io-client';
export const INIT_WEB_SOCKET = 'INIT_WEB_SOCKET'
export function initWebSocket ({ ioUrl, token, hrUserId }) {
export function initWebSocket ({ ioUrl, token, dcUserId }) {
if (!ioUrl) {
ioUrl = localStorage.getItem('apiRoot')
ioUrl = JSON.parse(ioUrl).root
}
if (!token) {
let user = sessionStorage.getItem('hrUser')
let user = sessionStorage.getItem('dcUser')
if (user) {
user = JSON.parse(user)
token = user.token
}
}
if (!ioUrl || !token || !hrUserId) {
if (!ioUrl || !token || !dcUserId) {
return {
type: '',
}

10
web/client/src/sections/auth/actions/auth.js

@ -5,10 +5,10 @@ import { Request } from '@peace/utils';
export const INIT_AUTH = 'INIT_AUTH';
export function initAuth(userData) {
const sessionUser = JSON.parse(sessionStorage.getItem('hrUser'))
const sessionUser = JSON.parse(sessionStorage.getItem('dcUser'))
const user = userData || sessionUser || {};
if (user.authorized && !sessionUser) {
sessionStorage.setItem('hrUser', JSON.stringify(user))
sessionStorage.setItem('dcUser', JSON.stringify(user))
}
return {
type: INIT_AUTH,
@ -45,7 +45,7 @@ export function login(username, password) {
return Request.post(ApiTable.login, { username, password, code: 'HR' })
.then(user => {
sessionStorage.setItem('hrUser', JSON.stringify(user));
sessionStorage.setItem('dcUser', JSON.stringify(user));
return dispatch({
type: LOGIN_SUCCESS,
payload: { user: user },
@ -64,13 +64,13 @@ export function login(username, password) {
export const LOGOUT = 'LOGOUT';
export function logout() {
const user = JSON.parse(sessionStorage.getItem('hrUser'))
const user = JSON.parse(sessionStorage.getItem('dcUser'))
user && user.token ?
Request.put(ApiTable.logout, {
token: user.token,
code: 'POMS'
}) : null;
sessionStorage.removeItem('hrUser');
sessionStorage.removeItem('dcUser');
localStorage.removeItem('poms_selected_sider');
localStorage.removeItem('poms_open_sider');

2
web/client/src/sections/auth/containers/login.jsx

@ -67,7 +67,7 @@ const Login = props => {
dispatch(login(values.username, values.password)).then(res => {
const data = res.payload.user
localStorage.setItem('word', JSON.stringify(values.password))
dispatch(actions.layout.initWebSocket({ ioUrl: apiRoot, token: data.token, hrUserId: data.hrUserInfo && hrUserInfo.id }))
dispatch(actions.layout.initWebSocket({ ioUrl: apiRoot, token: data.token, dcUserId: data.dcUserInfo && dcUserInfo.id }))
})
}}
getFormApi={formApi => form.current = formApi}

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

@ -1,5 +1,6 @@
'use strict';
import * as reserveItem from './reserve-item';
export default {
...reserveItem
}

13
web/client/src/sections/business/actions/reserve-item.js

@ -0,0 +1,13 @@
'use strict';
import { RouteTable, RouteRequest, ApiTable, basicAction } from '$utils';
export function getReserveItemReport(type) {
return dispatch => basicAction({
type: 'get',
dispatch: dispatch,
actionType: 'GET_RESERVEITEM_REPORT',
url: `${ApiTable.getReserveItemReport.replace('{type}', type)}`,
msg: { error: '获取储备项目统计信息失败' },
reducer: { name: 'reserveItemReport' }
});
}

14
web/client/src/sections/business/actions/service.js

@ -1,14 +0,0 @@
'use strict';
import { RouteTable, RouteRequest } from '$utils'
export function getServiceUrl() {
return dispatch => {
return RouteRequest.get(RouteTable.getWeeklyService)
.then(res => {
return dispatch({
type: "SERVER_WEEKLY_URL",
payload: res
})
});
}
}

5
web/client/src/sections/business/constants/index.js

@ -0,0 +1,5 @@
export const RESERVEITEM_TYPE = {
periodicStatistics: 1, //周期统计
depSummary: 2,
lostStatistic: 3
}

2
web/client/src/sections/business/containers/pmLog.jsx

@ -6,7 +6,7 @@ import { SkeletonScreen } from "$components";
import '../style.less'
import { Setup } from "$components";
import moment from 'moment'
import { getServiceUrl } from '../actions/service';
import { getServiceUrl } from '../actions/reserve-item';
const PMLog = (props) => {
const { dispatch, actions, history, user, loading, socket } = props;

58
web/client/src/sections/business/containers/reserveItemsDepSummary.jsx

@ -1,11 +1,42 @@
import React, { useEffect, useState } from 'react';
import { connect } from 'react-redux';
import { Select, Input, Button, RadioGroup, Radio, Tooltip } from '@douyinfe/semi-ui';
import { IconSearch } from '@douyinfe/semi-icons';
import { Select, Input, Table, Spin, Button } from '@douyinfe/semi-ui';
import { RESERVEITEM_TYPE } from '../constants';
import '../style.less'
import moment from 'moment'
const ReserveItemsDepSummary = (props) => {
const { dispatch, actions, isRequesting, reserveItemReport } = props;
const [downloadUrl, setDownloadUrl] = useState(null);
const [downloadKey, setDownloadKey] = useState(null);
useEffect(() => {
dispatch(actions.businessManagement.getReserveItemReport(RESERVEITEM_TYPE.depSummary));
}, []);
const exportReport = (url) => {
setDownloadUrl(`/_file-server${url}`);
setDownloadKey(Math.random());
}
const columns = [
{
title: '序号',
dataIndex: 'name',
render: (text, record, index) => index + 1
},
{
title: '时间',
dataIndex: 'date',
},
{
title: '名称',
dataIndex: 'path',
},
{
title: '操作',
dataIndex: 'action',
render: (text, record, indexe) => (<Button theme='solid' type='secondary' onClick={() => exportReport(record.path)} > 导出</Button >)
},
];
return (
<>
@ -26,12 +57,17 @@ const ReserveItemsDepSummary = (props) => {
</div>
</div>
<div style={{ borderBottom: '1px solid #F2F3F5', marginLeft: '-20px', marginBottom: 16 }}></div>
<div style={{ display: 'flex', justifyContent: 'space-between', marginBottom: 22 }}>
<div style={{ display: 'flex', }}>
<div style={{ color: '#646566', fontSize: 14 }}>
当前显示
</div>
</div>
{
downloadUrl ? <iframe key={downloadKey} src={downloadUrl} style={{ display: 'none' }} /> : ''
}
<div style={{ marginBottom: 22 }}>
<Spin spinning={isRequesting}>
<Table
rowKey={"id"}
columns={columns}
dataSource={reserveItemReport}
/>
</Spin>
</div>
</div>
</div>
@ -41,10 +77,12 @@ const ReserveItemsDepSummary = (props) => {
function mapStateToProps(state) {
const { auth, global } = state;
const { auth, global, reserveItemReport } = state;
return {
user: auth.user,
actions: global.actions,
reserveItemReport: reserveItemReport.data || [],
isRequesting: reserveItemReport.isRequesting
};
}

57
web/client/src/sections/business/containers/reserveItemsLostStatistics.jsx

@ -1,11 +1,41 @@
import React, { useEffect, useState } from 'react';
import { connect } from 'react-redux';
import { Select, Input, Button, RadioGroup, Radio, Tooltip } from '@douyinfe/semi-ui';
import { IconSearch } from '@douyinfe/semi-icons';
import { Select, Input, Spin, Table, Button } from '@douyinfe/semi-ui';
import { RESERVEITEM_TYPE } from '../constants';
import '../style.less'
import moment from 'moment'
const ReserveItemsLostStatistics = (props) => {
const { dispatch, actions, isRequesting, reserveItemReport } = props;
const [downloadUrl, setDownloadUrl] = useState(null);
const [downloadKey, setDownloadKey] = useState(null);
useEffect(() => {
dispatch(actions.businessManagement.getReserveItemReport(RESERVEITEM_TYPE.lostStatistic));
}, []);
const exportReport = (url) => {
setDownloadUrl(`/_file-server${url}`);
setDownloadKey(Math.random());
}
const columns = [
{
title: '序号',
dataIndex: 'name',
render: (text, record, index) => index + 1
},
{
title: '时间',
dataIndex: 'date',
},
{
title: '名称',
dataIndex: 'path',
},
{
title: '操作',
dataIndex: 'action',
render: (text, record, indexe) => (<Button theme='solid' type='secondary' onClick={() => exportReport(record.path)} > 导出</Button >)
},
];
return (
<>
@ -26,12 +56,17 @@ const ReserveItemsLostStatistics = (props) => {
</div>
</div>
<div style={{ borderBottom: '1px solid #F2F3F5', marginLeft: '-20px', marginBottom: 16 }}></div>
<div style={{ display: 'flex', justifyContent: 'space-between', marginBottom: 22 }}>
<div style={{ display: 'flex', }}>
<div style={{ color: '#646566', fontSize: 14 }}>
当前显示
</div>
</div>
{
downloadUrl ? <iframe key={downloadKey} src={downloadUrl} style={{ display: 'none' }} /> : ''
}
<div style={{ marginBottom: 22 }}>
<Spin spinning={isRequesting}>
<Table
rowKey={"id"}
columns={columns}
dataSource={reserveItemReport}
/>
</Spin>
</div>
</div>
</div>
@ -41,10 +76,12 @@ const ReserveItemsLostStatistics = (props) => {
function mapStateToProps(state) {
const { auth, global } = state;
const { auth, global, reserveItemReport } = state;
return {
user: auth.user,
actions: global.actions,
reserveItemReport: reserveItemReport.data || [],
isRequesting: reserveItemReport.isRequesting
};
}

59
web/client/src/sections/business/containers/reserveItemsPeriodicStatistics.jsx

@ -1,11 +1,22 @@
import React, { useEffect, useState } from 'react';
import { connect } from 'react-redux';
import { Select, Input, Button, RadioGroup, Radio, Table } from '@douyinfe/semi-ui';
import { IconSearch } from '@douyinfe/semi-icons';
import { Select, Input, Spin, Button, Table } from '@douyinfe/semi-ui';
import { RESERVEITEM_TYPE } from '../constants';
import '../style.less'
import moment from 'moment'
const ReserveItemsPeriodicStatistics = (props) => {
const { dispatch, actions, isRequesting, reserveItemReport } = props;
const [downloadUrl, setDownloadUrl] = useState(null);
const [downloadKey, setDownloadKey] = useState(null);
useEffect(() => {
dispatch(actions.businessManagement.getReserveItemReport(RESERVEITEM_TYPE.periodicStatistics));
}, []);
const exportReport = (url) => {
setDownloadUrl(`/_file-server${url}`);
setDownloadKey(Math.random());
}
const columns = [
{
title: '序号',
@ -14,34 +25,16 @@ const ReserveItemsPeriodicStatistics = (props) => {
},
{
title: '时间',
dataIndex: 'updateTime',
dataIndex: 'date',
},
{
title: '名称',
dataIndex: 'name',
dataIndex: 'path',
},
{
title: '操作',
dataIndex: 'action',
render: (text, record, indexe) => (<Button theme='solid' type='secondary'>导出</Button>)
},
];
const data = [
{
key: '1',
name: 'Semi Design 设计稿.fig',
updateTime: '2020-02-02 05:13',
avatarBg: 'grey',
},
{
key: '2',
name: 'Semi Design 分享演示文稿',
updateTime: '2020-01-17 05:31',
},
{
key: '3',
name: '设计文档',
updateTime: '2020-01-26 11:01',
render: (text, record, indexe) => (<Button theme='solid' type='secondary' onClick={() => exportReport(record.path)} > 导出</Button >)
},
];
@ -64,9 +57,17 @@ const ReserveItemsPeriodicStatistics = (props) => {
</div>
</div>
<div style={{ borderBottom: '1px solid #F2F3F5', marginLeft: '-20px', marginBottom: 16 }}></div>
<div style={{ display: 'flex', justifyContent: 'space-between', marginBottom: 22 }}>
<Table columns={columns} dataSource={data} pagination={false} />
{
downloadUrl ? <iframe key={downloadKey} src={downloadUrl} style={{ display: 'none' }} /> : ''
}
<div style={{ marginBottom: 22 }}>
<Spin spinning={isRequesting}>
<Table
rowKey={"id"}
columns={columns}
dataSource={reserveItemReport}
/>
</Spin>
</div>
</div>
</div>
@ -76,10 +77,12 @@ const ReserveItemsPeriodicStatistics = (props) => {
function mapStateToProps(state) {
const { auth, global } = state;
const { auth, global, reserveItemReport } = state;
return {
user: auth.user,
actions: global.actions,
reserveItemReport: reserveItemReport.data || [],
isRequesting: reserveItemReport.isRequesting
};
}

2
web/client/src/utils/func.js

@ -2,7 +2,7 @@
export const isAuthorized = (authcode) => {
if (JSON.parse(sessionStorage.getItem('user'))) {
const { resources } = JSON.parse(sessionStorage.getItem('hrUser'));
const { resources } = JSON.parse(sessionStorage.getItem('dcUser'));
return resources.includes(authcode);
} else {
return false;

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

@ -5,7 +5,7 @@ export const AxyRequest = new ProxyRequest("_axy");
export const EmisRequest = new ProxyRequest("_emis")
export const webUtils = new customWebUtils({
userKey: 'hrUser'
userKey: 'dcUser'
});
const { basicAction, RouteRequest } = webUtils
export {
@ -17,11 +17,13 @@ export const ApiTable = {
logout: "logout",
//项目报表
getReserveItemReport: "reserveItem/report/{type}"
};
export const RouteTable = {
apiRoot: "/api/root",
fileUpload: "/_upload/new",
cleanUpUploadTrash: "/_upload/cleanup",
getWeeklyService: '/_service/weekly'
getWeeklyService: '/_service/weekly',
qnDownload:'/file/qiniu/download'
};

2
web/package.json

@ -7,7 +7,7 @@
"test": "mocha",
"start-vite": "cross-env NODE_ENV=developmentVite npm run start-params",
"start": "cross-env NODE_ENV=development npm run start-params",
"start-params": "node server -p 5700 -u http://localhost:4700 --apiHrUrl http://localhost:4700 --qnak XuDgkao6cL0HidoMAPnA5OB10Mc_Ew08mpIfRJK5 --qnsk yewcieZLzKZuDfig0wLZ9if9jKp2P_1jd3CMJPSa --qnbkt dev-hr --qndmn http://rjkwed13l.hn-bkt.clouddn.com --wkys http://10.8.30.109:14000",
"start-params": "node server -p 5700 -u http://localhost:4700 --apiHrUrl http://localhost:4700 --qnak 5XrM4wEB9YU6RQwT64sPzzE6cYFKZgssdP5Kj3uu --qnsk w6j2ixR_i-aelc6I7S3HotKIX-ukMzcKmDfH6-M5 --qnbkt pep-process-report --qndmn https://pepsource.anxinyun.cn --wkys http://10.8.30.109:14000",
"deploy": "export NODE_ENV=production&& npm run build && node server",
"build-dev": "cross-env NODE_ENV=development&&webpack --config webpack.config.js",
"build": "cross-env NODE_ENV=production&&webpack --config webpack.config.prod.js"

22
web/routes/attachment/index.js

@ -82,6 +82,27 @@ module.exports = {
}
}
}
let qnDownload = async function (ctx, next) {
try {
const { src, filename } = ctx.query;
const fkey = src.replace(/\.json$/, '.js');
console.log("qnDownload->fkey: ", fkey);
const publicDownloadUrl = await ctx.app.fs.attachment.download(fkey);
if (filename) {
// download
ctx.attachment(filename);
} else {
// display
if (/\.(png)|(jpg)|(jpeg)|(gif)$/g.test(src.toLowerCase())) ctx.type = 'image/png';
}
ctx.status = 200;
ctx.body = request.get(publicDownloadUrl);
} catch (err) {
ctx.fs.logger.error(`path: ${ctx.path}, error: ${err}`);
ctx.status = 400;
ctx.body = { name: 'FindError', message: '附件下载失败' };
}
}
let remove = async function (ctx, next) {
try {
@ -109,6 +130,7 @@ module.exports = {
router.use(download);
router.get('/api/root', getApiRoot);
router.post('/file/qiniu/upload', upload);
router.get('/file/qiniu/download', qnDownload);
router.post('/file/qiniu/remove', remove);
}
};

Loading…
Cancel
Save