Browse Source

fix: 工作台页面

master
常旭 11 months ago
commit
8bc20069d2
374 changed files with 25289 additions and 0 deletions
  1. 16
      .editorconfig
  2. 8
      .eslintignore
  3. 8
      .eslintrc.js
  4. 40
      .gitignore
  5. 23
      .prettierignore
  6. 5
      .prettierrc.js
  7. 5
      .stylelintrc.js
  8. 57
      README.md
  9. 18
      config/config.dev.js
  10. 49
      config/config.js
  11. 16
      config/defaultSettings.js
  12. 36
      config/proxy.js
  13. 147
      config/routes.js
  14. BIN
      distribute.tar
  15. 9
      jest.config.js
  16. 10
      jsconfig.json
  17. 178
      mock/listTableList.js
  18. 103
      mock/notices.js
  19. 92
      mock/problem.js
  20. 7
      mock/route.js
  21. 166
      mock/user.js
  22. 106
      package.json
  23. 1
      public/CNAME
  24. 7
      public/config.json
  25. BIN
      public/favicon.ico
  26. BIN
      public/home_bg.png
  27. BIN
      public/icons/icon-128x128.png
  28. BIN
      public/icons/icon-192x192.png
  29. BIN
      public/icons/icon-512x512.png
  30. 5
      public/pro_icon.svg
  31. 58
      public/routes.json
  32. 7
      public/servers.json
  33. 1
      src/assets/logo.svg
  34. 1
      src/components/AJCZ/README.md
  35. 320
      src/components/AJCZ/index.jsx
  36. 16
      src/components/AJCZ/index.less
  37. 21
      src/components/Authorized/Authorized.jsx
  38. 25
      src/components/Authorized/AuthorizedRoute.jsx
  39. 72
      src/components/Authorized/CheckPermissions.jsx
  40. 78
      src/components/Authorized/PromiseRender.jsx
  41. 61
      src/components/Authorized/Secured.jsx
  42. 9
      src/components/Authorized/index.jsx
  43. 31
      src/components/Authorized/renderAuthorize.js
  44. 152
      src/components/BJSP-Batch/Agree.jsx
  45. 64
      src/components/BJSP-Batch/Info.jsx
  46. 1
      src/components/BJSP-Batch/README.md
  47. 64
      src/components/BJSP-Batch/Reject.jsx
  48. 166
      src/components/BJSP-Batch/index.jsx
  49. 16
      src/components/BJSP-Batch/index.less
  50. 152
      src/components/BJSP/Agree.jsx
  51. 64
      src/components/BJSP/Info.jsx
  52. 1
      src/components/BJSP/README.md
  53. 64
      src/components/BJSP/Reject.jsx
  54. 166
      src/components/BJSP/index.jsx
  55. 16
      src/components/BJSP/index.less
  56. 1
      src/components/CC/README.md
  57. 109
      src/components/CC/index.jsx
  58. 1
      src/components/CCJG/README.md
  59. 73
      src/components/CCJG/index.jsx
  60. 1
      src/components/CXPF/REASME.md
  61. 437
      src/components/CXPF/index.jsx
  62. 0
      src/components/CXPF/index.less
  63. 73
      src/components/CZMX/FormModal/TableSelect.jsx
  64. 332
      src/components/CZMX/FormModal/index.jsx
  65. 1
      src/components/CZMX/README.md
  66. 226
      src/components/CZMX/index.jsx
  67. 16
      src/components/CZMX/index.less
  68. 109
      src/components/CardList/index.jsx
  69. 5
      src/components/CardList/index.less
  70. 146
      src/components/FormModal/index.jsx
  71. 1
      src/components/GXBG/README.md
  72. 86
      src/components/GXBG/index.jsx
  73. 1
      src/components/GXBG/index.less
  74. 80
      src/components/GlobalHeader/AvatarDropdown.jsx
  75. 156
      src/components/GlobalHeader/NoticeIconView.jsx
  76. 42
      src/components/GlobalHeader/RightContent.jsx
  77. 86
      src/components/GlobalHeader/index.less
  78. 1
      src/components/HCBG/README.md
  79. 151
      src/components/HCBG/index.jsx
  80. 1
      src/components/HCZJ/README.md
  81. 92
      src/components/HCZJ/index.jsx
  82. 10
      src/components/HeaderDropdown/index.jsx
  83. 16
      src/components/HeaderDropdown/index.less
  84. 1
      src/components/HeaderMsg/README.md
  85. 387
      src/components/HeaderMsg/index.jsx
  86. 38
      src/components/HeaderMsg/index.less
  87. 86
      src/components/HeaderSearch/index.jsx
  88. 30
      src/components/HeaderSearch/index.less
  89. 1
      src/components/HeaderToDo/README.md
  90. 216
      src/components/HeaderToDo/index.jsx
  91. 1
      src/components/JDGZ/README.md
  92. 347
      src/components/JDGZ/index.jsx
  93. 1
      src/components/MyIcons/README.md
  94. 32
      src/components/MyIcons/index.jsx
  95. 1
      src/components/NextOrg/README.md
  96. 207
      src/components/NextOrg/index.js
  97. 97
      src/components/NoticeIcon/NoticeList.jsx
  98. 103
      src/components/NoticeIcon/NoticeList.less
  99. 119
      src/components/NoticeIcon/index.jsx
  100. 35
      src/components/NoticeIcon/index.less

16
.editorconfig

@ -0,0 +1,16 @@
# http://editorconfig.org
root = true
[*]
indent_style = space
indent_size = 2
end_of_line = lf
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true
[*.md]
trim_trailing_whitespace = false
[Makefile]
indent_style = tab

8
.eslintignore

@ -0,0 +1,8 @@
/lambda/
/scripts
/config
.history
public
dist
.umi
mock

8
.eslintrc.js

@ -0,0 +1,8 @@
module.exports = {
extends: [require.resolve('@umijs/fabric/dist/eslint')],
globals: {
ANT_DESIGN_PRO_ONLY_DO_NOT_USE_IN_YOUR_PRODUCTION: true,
page: true,
REACT_APP_ENV: true,
},
};

40
.gitignore

@ -0,0 +1,40 @@
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
# dependencies
**/node_modules
# roadhog-api-doc ignore
/src/utils/request-temp.js
_roadhog-api-doc
# production
/dist
/.vscode
# misc
.DS_Store
npm-debug.log*
yarn-error.log
/coverage
.idea
yarn.lock
package-lock.json
*bak
.vscode
# visual studio code
.history
*.log
functions/*
.temp/**
# umi
.umi
.umi-production
# screenshot
screenshot
.firebase
.eslintcache
build

23
.prettierignore

@ -0,0 +1,23 @@
**/*.svg
package.json
.umi
.umi-production
/dist
.dockerignore
.DS_Store
.eslintignore
*.png
*.toml
docker
.editorconfig
Dockerfile*
.gitignore
.prettierignore
LICENSE
.eslintcache
*.lock
yarn-error.log
.history
CNAME
/build
/public

5
.prettierrc.js

@ -0,0 +1,5 @@
const fabric = require('@umijs/fabric');
module.exports = {
...fabric.prettier,
};

5
.stylelintrc.js

@ -0,0 +1,5 @@
const fabric = require('@umijs/fabric');
module.exports = {
...fabric.stylelint,
};

57
README.md

@ -0,0 +1,57 @@
# Ant Design Pro
This project is initialized with [Ant Design Pro](https://pro.ant.design). Follow is the quick guide for how to use.
## Environment Prepare
Install `node_modules`:
```bash
npm install
```
or
```bash
yarn
```
## Provided Scripts
Ant Design Pro provides some useful script to help you quick start and build with web project, code style check and test.
Scripts provided in `package.json`. It's safe to modify or add additional script:
### Start project
```bash
npm start
```
### Build project
```bash
npm run build
```
### Check code style
```bash
npm run lint
```
You can also use script to auto fix some lint error:
```bash
npm run lint:fix
```
### Test code
```bash
npm test
```
## More
You can view full document on our [official website](https://pro.ant.design). And welcome any feedback in our [github](https://github.com/ant-design/ant-design-pro).

18
config/config.dev.js

@ -0,0 +1,18 @@
// https://umijs.org/config/
import { defineConfig } from 'umi';
export default defineConfig({
plugins: [
// https://github.com/zthxxx/react-dev-inspector
'react-dev-inspector/plugins/umi/react-inspector',
],
// https://github.com/zthxxx/react-dev-inspector#inspector-loader-props
inspectorConfig: {
exclude: [],
babelPlugins: [],
babelOptions: {},
},
});

49
config/config.js

@ -0,0 +1,49 @@
// https://umijs.org/config/
import { defineConfig } from 'umi';
import defaultSettings from './defaultSettings';
import proxy from './proxy';
import routes from './routes';
const { REACT_APP_ENV } = process.env;
export default defineConfig({
hash: true,
antd: {},
dva: {
hmr: true,
},
history: {
type: 'browser',
},
locale: {
// default zh-CN
default: 'zh-CN',
antd: true,
// default true, when it is true, will use `navigator.language` overwrite default
baseNavigator: true,
},
dynamicImport: {
loading: '@/components/PageLoading/index',
},
targets: {
ie: 11,
},
// umi routes: https://umijs.org/docs/routing
routes,
// Theme for antd: https://ant.design/docs/react/customize-theme-cn
theme: {
'primary-color': defaultSettings.primaryColor,
},
base: '/superintend/',
publicPath: '/superintend/',
title: false,
ignoreMomentLocale: true,
proxy: proxy[REACT_APP_ENV || 'dev'],
manifest: {
basePath: '/',
},
esbuild: {},
define: {
}
});

16
config/defaultSettings.js

@ -0,0 +1,16 @@
const proSettings = {
"navTheme": "light",
"primaryColor": "#1890ff",
"layout": "side",
// "contentWidth": "Fluid",
"fixedHeader": false,
"fixSiderbar": false,
"pwa": false,
"iconfontUrl": "",
"menu": {
"locale": false
},
"footerRender": false,
"menuHeaderRender": false
};
export default proSettings;

36
config/proxy.js

@ -0,0 +1,36 @@
/**
* 在生产环境 代理是无法生效的所以这里没有生产环境的配置
* The agent cannot take effect in the production environment
* so there is no configuration of the production environment
* For details, please see
* https://pro.ant.design/docs/deploy
*/
export default {
dev: {
'/api/': {
target: 'https://preview.pro.ant.design',
changeOrigin: true,
pathRewrite: {
'^': '',
},
},
},
test: {
'/api/': {
target: 'https://preview.pro.ant.design',
changeOrigin: true,
pathRewrite: {
'^': '',
},
},
},
pre: {
'/api/': {
target: 'your pre url',
changeOrigin: true,
pathRewrite: {
'^': '',
},
},
},
};

147
config/routes.js

@ -0,0 +1,147 @@
// 注释:hideInMenu参数控制菜单隐藏
export default [
{
path: '/',
component: '../layouts/BlankLayout',
routes: [
// {
// path: '/user',
// component: '../layouts/UserLayout',
// routes: [
// {
// name: 'login',
// path: '/user/login',
// component: './User/login',
// },
// ],
// },
{
path: '/',
component: '../layouts/SecurityLayout',
routes: [
{
path: '/resultdata',
component: './ResultData',
},
{
path:"/GZT",
component:"./GZT"
},
{
path: '/',
component: '../layouts/BasicLayout',
// authority: ['admin', 'user'],
routes: [
{
path: '/',
redirect: '/doingcases',
},
{
name: '在办事项',
path: '/doingcases',
icon: 'BarsOutlined',
component: './DoingCases',
},
{
name: '已办事项',
path: '/donecases',
icon: 'AuditOutlined',
component: './DoneCases',
},
{
name: '进度查询',
path: '/progresssearch',
icon: 'ProfileOutlined',
component: './ProgressSearch',
},
{
name: '问题处理单查询',
path: '/problemhandlingsearch',
icon: 'ScheduleOutlined',
hideInMenu: false, // 控制菜单隐藏
component: './ProblemHandlingSearch',
},
// {
// name: '督察专项',
// path: '/superviseitem',
// icon: 'ProjectOutlined',
// component: './SuperviseItem',
// },
{
name: '督察专项',
path: '/superviseitem',
icon: 'ProjectOutlined',
routes: [
{
name: '专项审批',
path: '/superviseitem/approve',
icon: 'AuditOutlined',
authority: ['bu'],
component: './SuperviseItem/ApproveItem',
},
{
name: '专项签收',
path: '/superviseitem/check',
icon: 'AuditOutlined',
component: './SuperviseItem/CheckItem',
},
],
},
{
name: '模型审批',
path: '/modelapprove',
icon: 'SnippetsOutlined',
routes: [
{
name: '模型分享',
path: '/modelapprove/share',
icon: 'AuditOutlined',
component: './ModelApprove/Share',
},
{
name: '省级上报',
path: '/modelapprove/report',
icon: 'AuditOutlined',
component: './ModelApprove/Report',
authority: ['bu', 'sheng'],
},
{
name: '市级上报',
path: '/modelapprove/reportshi',
icon: 'AuditOutlined',
component: './ModelApprove/Report',
authority: ['sheng', 'shi'],
},
],
},
{
name: '系统配置',
path: '/systemmanage',
icon: 'SettingOutlined',
authority: ['gly'],
routes: [
{
name: '层级联动',
path: '/systemmanage/levelmanage',
icon: 'AuditOutlined',
component: './SystemManage/LevelManage',
},
],
},
{
component: './404',
},
],
},
{
component: './404',
},
],
},
],
},
{
component: './404',
},
];

BIN
distribute.tar

9
jest.config.js

@ -0,0 +1,9 @@
module.exports = {
testURL: 'http://localhost:8000',
testEnvironment: './tests/PuppeteerEnvironment',
verbose: false,
globals: {
ANT_DESIGN_PRO_ONLY_DO_NOT_USE_IN_YOUR_PRODUCTION: false,
localStorage: null,
},
};

10
jsconfig.json

@ -0,0 +1,10 @@
{
"compilerOptions": {
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"baseUrl": ".",
"paths": {
"@/*": ["./src/*"]
}
}
}

178
mock/listTableList.js

@ -0,0 +1,178 @@
// eslint-disable-next-line import/no-extraneous-dependencies
import { parse } from 'url';
// mock tableListDataSource
const genList = (current, pageSize) => {
const tableListDataSource = [];
for (let i = 0; i < pageSize; i += 1) {
const index = (current - 1) * 10 + i;
tableListDataSource.push({
key: index,
disabled: i % 6 === 0,
href: 'https://ant.design',
avatar: [
'https://gw.alipayobjects.com/zos/rmsportal/eeHMaZBwmTvLdIwMfBpg.png',
'https://gw.alipayobjects.com/zos/rmsportal/udxAbMEhpwthVVcjLXik.png',
][i % 2],
name: `TradeCode ${index}`,
owner: '曲丽丽',
desc: '这是一段描述',
callNo: Math.floor(Math.random() * 1000),
status: Math.floor(Math.random() * 10) % 4,
updatedAt: new Date(),
createdAt: new Date(),
progress: Math.ceil(Math.random() * 100),
});
}
tableListDataSource.reverse();
return tableListDataSource;
};
let tableListDataSource = genList(1, 100);
function getRule(req, res, u) {
let realUrl = u;
if (!realUrl || Object.prototype.toString.call(realUrl) !== '[object String]') {
realUrl = req.url;
}
const { current = 1, pageSize = 10 } = req.query;
const params = parse(realUrl, true).query;
let dataSource = [...tableListDataSource].slice((current - 1) * pageSize, current * pageSize);
const sorter = JSON.parse(params.sorter);
if (sorter) {
dataSource = dataSource.sort((prev, next) => {
let sortNumber = 0;
Object.keys(sorter).forEach(key => {
if (sorter[key] === 'descend') {
if (prev[key] - next[key] > 0) {
sortNumber += -1;
} else {
sortNumber += 1;
}
return;
}
if (prev[key] - next[key] > 0) {
sortNumber += 1;
} else {
sortNumber += -1;
}
});
return sortNumber;
});
}
if (params.filter) {
const filter = JSON.parse(params.filter);
if (Object.keys(filter).length > 0) {
dataSource = dataSource.filter(item =>
Object.keys(filter).some(key => {
if (!filter[key]) {
return true;
}
if (filter[key].includes(`${item[key]}`)) {
return true;
}
return false;
}),
);
}
}
if (params.name) {
dataSource = dataSource.filter(data => data.name.includes(params.name || ''));
}
const result = {
data: dataSource,
total: tableListDataSource.length,
success: true,
pageSize,
current: parseInt(`${params.currentPage}`, 10) || 1,
};
return res.json(result);
}
function postRule(req, res, u, b) {
let realUrl = u;
if (!realUrl || Object.prototype.toString.call(realUrl) !== '[object String]') {
realUrl = req.url;
}
const body = (b && b.body) || req.body;
const { method, name, desc, key } = body;
switch (method) {
/* eslint no-case-declarations:0 */
case 'delete':
tableListDataSource = tableListDataSource.filter(item => key.indexOf(item.key) === -1);
break;
case 'post':
(() => {
const i = Math.ceil(Math.random() * 10000);
const newRule = {
key: tableListDataSource.length,
href: 'https://ant.design',
avatar: [
'https://gw.alipayobjects.com/zos/rmsportal/eeHMaZBwmTvLdIwMfBpg.png',
'https://gw.alipayobjects.com/zos/rmsportal/udxAbMEhpwthVVcjLXik.png',
][i % 2],
name,
owner: '曲丽丽',
desc,
callNo: Math.floor(Math.random() * 1000),
status: Math.floor(Math.random() * 10) % 2,
updatedAt: new Date(),
createdAt: new Date(),
progress: Math.ceil(Math.random() * 100),
};
tableListDataSource.unshift(newRule);
return res.json(newRule);
})();
return;
case 'update':
(() => {
let newRule = {};
tableListDataSource = tableListDataSource.map(item => {
if (item.key === key) {
newRule = { ...item, desc, name };
return { ...item, desc, name };
}
return item;
});
return res.json(newRule);
})();
return;
default:
break;
}
const result = {
list: tableListDataSource,
pagination: {
total: tableListDataSource.length,
},
};
res.json(result);
}
export default {
'GET /api/rule': getRule,
'POST /api/rule': postRule,
};

103
mock/notices.js

@ -0,0 +1,103 @@
const getNotices = (req, res) => {
res.json([
{
id: '000000001',
avatar: 'https://gw.alipayobjects.com/zos/rmsportal/ThXAXghbEsBCCSDihZxY.png',
title: '你收到了 14 份新周报',
datetime: '2017-08-09',
type: 'notification',
},
{
id: '000000002',
avatar: 'https://gw.alipayobjects.com/zos/rmsportal/OKJXDXrmkNshAMvwtvhu.png',
title: '你推荐的 曲妮妮 已通过第三轮面试',
datetime: '2017-08-08',
type: 'notification',
},
{
id: '000000003',
avatar: 'https://gw.alipayobjects.com/zos/rmsportal/kISTdvpyTAhtGxpovNWd.png',
title: '这种模板可以区分多种通知类型',
datetime: '2017-08-07',
read: true,
type: 'notification',
},
{
id: '000000004',
avatar: 'https://gw.alipayobjects.com/zos/rmsportal/GvqBnKhFgObvnSGkDsje.png',
title: '左侧图标用于区分不同的类型',
datetime: '2017-08-07',
type: 'notification',
},
{
id: '000000005',
avatar: 'https://gw.alipayobjects.com/zos/rmsportal/ThXAXghbEsBCCSDihZxY.png',
title: '内容不要超过两行字,超出时自动截断',
datetime: '2017-08-07',
type: 'notification',
},
{
id: '000000006',
avatar: 'https://gw.alipayobjects.com/zos/rmsportal/fcHMVNCjPOsbUGdEduuv.jpeg',
title: '曲丽丽 评论了你',
description: '描述信息描述信息描述信息',
datetime: '2017-08-07',
type: 'message',
clickClose: true,
},
{
id: '000000007',
avatar: 'https://gw.alipayobjects.com/zos/rmsportal/fcHMVNCjPOsbUGdEduuv.jpeg',
title: '朱偏右 回复了你',
description: '这种模板用于提醒谁与你发生了互动,左侧放『谁』的头像',
datetime: '2017-08-07',
type: 'message',
clickClose: true,
},
{
id: '000000008',
avatar: 'https://gw.alipayobjects.com/zos/rmsportal/fcHMVNCjPOsbUGdEduuv.jpeg',
title: '标题',
description: '这种模板用于提醒谁与你发生了互动,左侧放『谁』的头像',
datetime: '2017-08-07',
type: 'message',
clickClose: true,
},
{
id: '000000009',
title: '任务名称',
description: '任务需要在 2017-01-12 20:00 前启动',
extra: '未开始',
status: 'todo',
type: 'event',
},
{
id: '000000010',
title: '第三方紧急代码变更',
description: '冠霖提交于 2017-01-06,需在 2017-01-07 前完成代码变更任务',
extra: '马上到期',
status: 'urgent',
type: 'event',
},
{
id: '000000011',
title: '信息安全考试',
description: '指派竹尔于 2017-01-09 前完成更新并发布',
extra: '已耗时 8 天',
status: 'doing',
type: 'event',
},
{
id: '000000012',
title: 'ABCD 版本发布',
description: '冠霖提交于 2017-01-06,需在 2017-01-07 前完成代码变更任务',
extra: '进行中',
status: 'processing',
type: 'event',
},
]);
};
export default {
'GET /api/notices': getNotices,
};

92
mock/problem.js

@ -0,0 +1,92 @@
const getProblemList = (req, res) => {
res.json({
total: 1,
resCode: 0,
data: [
{
DCWTLXDM: "01010100",
DCWTMC_BT: "督办单测试",
JWDCFSDM: "101",
OPEN_DATE: "2018/9/28 15:31:32",
OrgNo: "650000000000",
TIMEOUT_DATE: "2018/9/28 15:31:54",
WTSJASJ_ASJFSKSSJ: "2018-09-28 15:31:28",
WTSJDW_GAJGJGDM: "650000000000",
WTSJDW_GAJGMC: "新疆维吾尔自治区公安厅",
XXDJDW_GAJGJGDM: "650000000000",
XXDJDW_GAJGMC: "新疆维吾尔自治区公安厅",
XXDJRY_GMSFHM: "430124198602200038",
XXDJRY_XM: "管理",
ZYCD_PDBZ: 0,
JJCD_PDBZ_NAME: "否",
WTSJASJ_ASJFSKSSJ_VIEW: "2018-09-28 15:31:28",
ZYCD_PDBZ_NAME: "否",
ZJMC: "测试一下督察问题证据信息证据名称",
JYQK: "没有什么可以写的",
GMSFHM: "430124198602200038",
UName: "管理",
OrgNo: "650000000000",
GAJGMC: "新疆维吾尔自治区公安厅",
wtsjrItem: [{
WTSJR_GMSFHM: " 4310************11",
WTSJR_XM: "张三",
WTSJR_XBDM: "1",
WTSJR_CSRQ: " 19870101",
WTSJR_JH: " 10019",
WTSJR_JXYWZJBDM: "",
WTSJR_ZZMMDM: "",
WTSJR_GBZWDM: " 430000000000",
WTSJR_GAJGJGDM: " 430000000000",
WTSJR_LXDH: ""
}, {
WTSJR_GMSFHM: " 4310************25",
WTSJR_XM: "张红强",
WTSJR_XBDM: "1",
WTSJR_CSRQ: " 19000101",
WTSJR_JH: " 10008",
WTSJR_JXYWZJBDM: "",
WTSJR_ZZMMDM: "",
WTSJR_GBZWDM: " 431000000000",
WTSJR_GAJGJGDM: " 431000000000",
WTSJR_LXDH: ""
}],
evidenceItem: {
head: [{
fieldName: "KeyWord",
fieldAlias: "关键字"
}, {
fieldName: "StartTime",
fieldAlias: "开始时间"
}, {
fieldName: "EndTime",
fieldAlias: "结束时间"
}, {
fieldName: "FileName",
fieldAlias: "文件名称"
}, {
fieldName: "FilePosition",
fieldAlias: "文件路径"
}
],
data: [{
KeyWord: "关键字1",
StartTime: "2018-10-2 17:28:36",
EndTime: "2018-10-2 17:28:42",
FileName: "文件名1",
FilePosition: "http://www.baidu.com"
}, {
KeyWord: "关键字2",
StartTime: "2018-10-2 17:28:46",
EndTime: "2018-10-2 17:28:50",
FileName: "文件名2",
FilePosition: "http://www.baidu.com"
}]
}
}
]
});
};
export default {
'POST /Api/Dispose/BTDisposeList': getProblemList,
};

7
mock/route.js

@ -0,0 +1,7 @@
export default {
'/api/auth_routes': {
'/form/advanced-form': {
authority: ['admin', 'user'],
},
},
};

166
mock/user.js

@ -0,0 +1,166 @@
const waitTime = (time = 100) =>
new Promise(resolve => {
setTimeout(() => {
resolve(true);
}, time);
});
async function getFakeCaptcha(req, res) {
await waitTime(2000);
return res.json('captcha-xxx');
} // 代码中会兼容本地 service mock 以及部署站点的静态数据
export default {
// 支持值为 Object 和 Array
'GET /api/currentUser': {
name: 'Serati Ma',
avatar: 'https://gw.alipayobjects.com/zos/antfincdn/XAosXuNZyF/BiazfanxmamNRoxxVxka.png',
userid: '00000001',
email: 'antdesign@alipay.com',
signature: '海纳百川,有容乃大',
title: '交互专家',
group: '蚂蚁集团-某某某事业群-某某平台部-某某技术部-UED',
tags: [
{
key: '0',
label: '很有想法的',
},
{
key: '1',
label: '专注设计',
},
{
key: '2',
label: '辣~',
},
{
key: '3',
label: '大长腿',
},
{
key: '4',
label: '川妹子',
},
{
key: '5',
label: '海纳百川',
},
],
notifyCount: 12,
unreadCount: 11,
country: 'China',
geographic: {
province: {
label: '浙江省',
key: '330000',
},
city: {
label: '杭州市',
key: '330100',
},
},
address: '西湖区工专路 77 号',
phone: '0752-268888888',
},
// GET POST 可省略
'GET /api/users': [
{
key: '1',
name: 'John Brown',
age: 32,
address: 'New York No. 1 Lake Park',
},
{
key: '2',
name: 'Jim Green',
age: 42,
address: 'London No. 1 Lake Park',
},
{
key: '3',
name: 'Joe Black',
age: 32,
address: 'Sidney No. 1 Lake Park',
},
],
'POST /api/login/account': async (req, res) => {
const { password, userName, type } = req.body;
await waitTime(2000);
if (password === 'ant.design' && userName === 'admin') {
res.send({
status: 'ok',
type,
currentAuthority: 'admin',
});
return;
}
if (password === 'ant.design' && userName === 'user') {
res.send({
status: 'ok',
type,
currentAuthority: 'user',
});
return;
}
if (type === 'mobile') {
res.send({
status: 'ok',
type,
currentAuthority: 'admin',
});
return;
}
res.send({
status: 'error',
type,
currentAuthority: 'guest',
});
},
'POST /api/register': (req, res) => {
res.send({
status: 'ok',
currentAuthority: 'user',
});
},
'GET /api/500': (req, res) => {
res.status(500).send({
timestamp: 1513932555104,
status: 500,
error: 'error',
message: 'error',
path: '/base/category/list',
});
},
'GET /api/404': (req, res) => {
res.status(404).send({
timestamp: 1513932643431,
status: 404,
error: 'Not Found',
message: 'No message available',
path: '/base/category/list/2121212',
});
},
'GET /api/403': (req, res) => {
res.status(403).send({
timestamp: 1513932555104,
status: 403,
error: 'Unauthorized',
message: 'Unauthorized',
path: '/base/category/list',
});
},
'GET /api/401': (req, res) => {
res.status(401).send({
timestamp: 1513932555104,
status: 401,
error: 'Unauthorized',
message: 'Unauthorized',
path: '/base/category/list',
});
},
'GET /api/login/captcha': getFakeCaptcha,
};

106
package.json

@ -0,0 +1,106 @@
{
"name": "ant-design-pro",
"version": "4.5.0",
"private": true,
"description": "An out-of-box UI solution for enterprise applications",
"scripts": {
"analyze": "cross-env ANALYZE=1 umi build",
"build": "umi build",
"build:sheng": "cross-env PRO=sheng umi build",
"deploy": "npm run site && npm run gh-pages",
"dev": "npm run start:dev",
"fetch:blocks": "pro fetch-blocks && npm run prettier",
"gh-pages": "gh-pages -d dist",
"i18n-remove": "pro i18n-remove --locale=zh-CN --write",
"postinstall": "umi g tmp",
"lint": "umi g tmp && npm run lint:js && npm run lint:style && npm run lint:prettier",
"lint-staged:js": "eslint --ext .js,.jsx,.ts,.tsx ",
"lint:fix": "eslint --fix --cache --ext .js,.jsx,.ts,.tsx --format=pretty ./src && npm run lint:style",
"lint:js": "eslint --cache --ext .js,.jsx,.ts,.tsx --format=pretty ./src",
"lint:prettier": "prettier --check \"src/**/*\" --end-of-line auto",
"lint:style": "stylelint --fix \"src/**/*.less\" --syntax less",
"prettier": "prettier -c --write \"src/**/*\"",
"start": "cross-env UMI_ENV=dev a=1 umi dev",
"start:dev": "cross-env REACT_APP_ENV=dev MOCK=none UMI_ENV=dev umi dev",
"start:no-mock": "cross-env MOCK=none UMI_ENV=dev umi dev",
"start:no-ui": "cross-env UMI_UI=none UMI_ENV=dev umi dev",
"start:pre": "cross-env REACT_APP_ENV=pre UMI_ENV=dev umi dev",
"start:test": "cross-env REACT_APP_ENV=test MOCK=none UMI_ENV=dev umi dev",
"pretest": "node ./tests/beforeTest",
"test": "umi test",
"test:all": "node ./tests/run-tests.js",
"test:component": "umi test ./src/components",
"tsc": "tsc --noEmit"
},
"browserslist": [
"> 1%",
"last 2 versions",
"not ie <= 10"
],
"dependencies": {
"@ant-design/icons": "^4.0.0",
"@ant-design/pro-descriptions": "^1.2.0",
"@ant-design/pro-form": "^1.3.0",
"@ant-design/pro-layout": "^6.9.0",
"@ant-design/pro-table": "^2.17.0",
"@umijs/route-utils": "^1.0.33",
"antd": "^4.10.0",
"classnames": "^2.2.6",
"lodash": "^4.17.11",
"moment": "^2.25.3",
"omit.js": "^2.0.2",
"qs": "^6.9.0",
"react": "^17.0.0",
"react-dev-inspector": "^1.1.1",
"react-dom": "^17.0.0",
"react-helmet-async": "^1.0.4",
"umi": "^3.2.14",
"umi-request": "^1.0.8"
},
"devDependencies": {
"@ant-design/pro-cli": "^1.0.28",
"@types/classnames": "^2.2.7",
"@types/express": "^4.17.0",
"@types/history": "^4.7.2",
"@types/jest": "^26.0.0",
"@types/lodash": "^4.14.144",
"@types/qs": "^6.5.3",
"@types/react": "^17.0.0",
"@types/react-dom": "^17.0.0",
"@types/react-helmet": "^6.1.0",
"@umijs/fabric": "^2.5.1",
"@umijs/plugin-blocks": "^2.0.5",
"@umijs/plugin-esbuild": "^1.0.1",
"@umijs/preset-ant-design-pro": "^1.2.0",
"@umijs/preset-react": "^1.4.8",
"@umijs/yorkie": "^2.0.3",
"carlo": "^0.9.46",
"chalk": "^4.0.0",
"cross-env": "^7.0.0",
"cross-port-killer": "^1.1.1",
"detect-installer": "^1.0.1",
"enzyme": "^3.11.0",
"eslint": "^7.1.0",
"express": "^4.17.1",
"gh-pages": "^3.0.0",
"jsdom-global": "^3.0.2",
"lint-staged": "^10.0.0",
"mockjs": "^1.0.1-beta3",
"prettier": "^2.0.1",
"puppeteer-core": "^5.0.0",
"stylelint": "^13.0.0",
"typescript": "^4.0.3",
"uuid": "^8.3.2",
"uuidv4": "^6.2.13"
},
"engines": {
"node": ">=10.0.0"
},
"checkFiles": [
"src/**/*.js*",
"src/**/*.ts*",
"src/**/*.less",
"config/**/*.js*",
"scripts/**/*.js"
]
}

1
public/CNAME

@ -0,0 +1 @@
preview.pro.ant.design

7
public/config.json

@ -0,0 +1,7 @@
{
"resCode": 0,
"msg": "成功",
"data": {
"moduleResultCycleCount": 10
}
}

BIN
public/favicon.ico

Before After

BIN
public/home_bg.png

Before After
Width: 750  |  Height: 1024  |  Size: 199 KiB

BIN
public/icons/icon-128x128.png

Before After
Width: 128  |  Height: 128  |  Size: 1.3 KiB

BIN
public/icons/icon-192x192.png

Before After
Width: 192  |  Height: 192  |  Size: 1.8 KiB

BIN
public/icons/icon-512x512.png

Before After
Width: 512  |  Height: 512  |  Size: 5.0 KiB

5
public/pro_icon.svg

@ -0,0 +1,5 @@
<svg width="42" height="42" xmlns="http://www.w3.org/2000/svg">
<g>
<path fill="#070707" d="m6.717392,13.773912l5.6,0c2.8,0 4.7,1.9 4.7,4.7c0,2.8 -2,4.7 -4.9,4.7l-2.5,0l0,4.3l-2.9,0l0,-13.7zm2.9,2.2l0,4.9l1.9,0c1.6,0 2.6,-0.9 2.6,-2.4c0,-1.6 -0.9,-2.4 -2.6,-2.4l-1.9,0l0,-0.1zm8.9,11.5l2.7,0l0,-5.7c0,-1.4 0.8,-2.3 2.2,-2.3c0.4,0 0.8,0.1 1,0.2l0,-2.4c-0.2,-0.1 -0.5,-0.1 -0.8,-0.1c-1.2,0 -2.1,0.7 -2.4,2l-0.1,0l0,-1.9l-2.7,0l0,10.2l0.1,0zm11.7,0.1c-3.1,0 -5,-2 -5,-5.3c0,-3.3 2,-5.3 5,-5.3s5,2 5,5.3c0,3.4 -1.9,5.3 -5,5.3zm0,-2.1c1.4,0 2.2,-1.1 2.2,-3.2c0,-2 -0.8,-3.2 -2.2,-3.2c-1.4,0 -2.2,1.2 -2.2,3.2c0,2.1 0.8,3.2 2.2,3.2z" class="st0" id="Ant-Design-Pro"/>
</g>
</svg>

58
public/routes.json

@ -0,0 +1,58 @@
{
"resCode": 0,
"msg": "成功",
"data": {
"/doingcases": {
"name": "在办事项",
"show": true
},
"/donecases": {
"name": "已办事项",
"show": true
},
"/progresssearch": {
"name": "进度查询",
"show": true
},
"/problemhandlingsearch": {
"name": "问题处理单查询",
"show": false
},
"/superviseitem": {
"name": "督察专项",
"show": true
},
"/superviseitem/approve": {
"name": "专项审批",
"show": true
},
"/superviseitem/check": {
"name": "专项签收",
"show": true
},
"/modelapprove": {
"name": "模型审批",
"show": true
},
"/modelapprove/share": {
"name": "模型分享",
"show": true
},
"/modelapprove/report": {
"name": "省级上报",
"show": true
},
"/modelapprove/reportshi": {
"name": "市级上报",
"show": true
},
"/systemmanage": {
"name": "系统配置",
"show": true
},
"/systemmanage/levelmanage": {
"name": "层级联动",
"show": true
}
}
}

7
public/servers.json

@ -0,0 +1,7 @@
{
"API_URL": "http://localhost:8080/api/v4",
"SYS_MAN_URL": "http://localhost:8080/api",
"LOGIN_URL": "http://localhost:8080",
"PARENT_URL": "http://localhost:8080",
"moduleFactory": "http://localhost:8080/api/v4/sys/self"
}

1
src/assets/logo.svg

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200" version="1.1" viewBox="0 0 200 200"><title>Group 28 Copy 5</title><desc>Created with Sketch.</desc><defs><linearGradient id="linearGradient-1" x1="62.102%" x2="108.197%" y1="0%" y2="37.864%"><stop offset="0%" stop-color="#4285EB"/><stop offset="100%" stop-color="#2EC7FF"/></linearGradient><linearGradient id="linearGradient-2" x1="69.644%" x2="54.043%" y1="0%" y2="108.457%"><stop offset="0%" stop-color="#29CDFF"/><stop offset="37.86%" stop-color="#148EFF"/><stop offset="100%" stop-color="#0A60FF"/></linearGradient><linearGradient id="linearGradient-3" x1="69.691%" x2="16.723%" y1="-12.974%" y2="117.391%"><stop offset="0%" stop-color="#FA816E"/><stop offset="41.473%" stop-color="#F74A5C"/><stop offset="100%" stop-color="#F51D2C"/></linearGradient><linearGradient id="linearGradient-4" x1="68.128%" x2="30.44%" y1="-35.691%" y2="114.943%"><stop offset="0%" stop-color="#FA8E7D"/><stop offset="51.264%" stop-color="#F74A5C"/><stop offset="100%" stop-color="#F51D2C"/></linearGradient></defs><g id="Page-1" fill="none" fill-rule="evenodd" stroke="none" stroke-width="1"><g id="logo" transform="translate(-20.000000, -20.000000)"><g id="Group-28-Copy-5" transform="translate(20.000000, 20.000000)"><g id="Group-27-Copy-3"><g id="Group-25" fill-rule="nonzero"><g id="2"><path id="Shape" fill="url(#linearGradient-1)" d="M91.5880863,4.17652823 L4.17996544,91.5127728 C-0.519240605,96.2081146 -0.519240605,103.791885 4.17996544,108.487227 L91.5880863,195.823472 C96.2872923,200.518814 103.877304,200.518814 108.57651,195.823472 L145.225487,159.204632 C149.433969,154.999611 149.433969,148.181924 145.225487,143.976903 C141.017005,139.771881 134.193707,139.771881 129.985225,143.976903 L102.20193,171.737352 C101.032305,172.906015 99.2571609,172.906015 98.0875359,171.737352 L28.285908,101.993122 C27.1162831,100.824459 27.1162831,99.050775 28.285908,97.8821118 L98.0875359,28.1378823 C99.2571609,26.9692191 101.032305,26.9692191 102.20193,28.1378823 L129.985225,55.8983314 C134.193707,60.1033528 141.017005,60.1033528 145.225487,55.8983314 C149.433969,51.69331 149.433969,44.8756232 145.225487,40.6706018 L108.58055,4.05574592 C103.862049,-0.537986846 96.2692618,-0.500797906 91.5880863,4.17652823 Z"/><path id="Shape" fill="url(#linearGradient-2)" d="M91.5880863,4.17652823 L4.17996544,91.5127728 C-0.519240605,96.2081146 -0.519240605,103.791885 4.17996544,108.487227 L91.5880863,195.823472 C96.2872923,200.518814 103.877304,200.518814 108.57651,195.823472 L145.225487,159.204632 C149.433969,154.999611 149.433969,148.181924 145.225487,143.976903 C141.017005,139.771881 134.193707,139.771881 129.985225,143.976903 L102.20193,171.737352 C101.032305,172.906015 99.2571609,172.906015 98.0875359,171.737352 L28.285908,101.993122 C27.1162831,100.824459 27.1162831,99.050775 28.285908,97.8821118 L98.0875359,28.1378823 C100.999864,25.6271836 105.751642,20.541824 112.729652,19.3524487 C117.915585,18.4685261 123.585219,20.4140239 129.738554,25.1889424 C125.624663,21.0784292 118.571995,14.0340304 108.58055,4.05574592 C103.862049,-0.537986846 96.2692618,-0.500797906 91.5880863,4.17652823 Z"/></g><path id="Shape" fill="url(#linearGradient-3)" d="M153.685633,135.854579 C157.894115,140.0596 164.717412,140.0596 168.925894,135.854579 L195.959977,108.842726 C200.659183,104.147384 200.659183,96.5636133 195.960527,91.8688194 L168.690777,64.7181159 C164.472332,60.5180858 157.646868,60.5241425 153.435895,64.7316526 C149.227413,68.936674 149.227413,75.7543607 153.435895,79.9593821 L171.854035,98.3623765 C173.02366,99.5310396 173.02366,101.304724 171.854035,102.473387 L153.685633,120.626849 C149.47715,124.83187 149.47715,131.649557 153.685633,135.854579 Z"/></g><ellipse id="Combined-Shape" cx="100.519" cy="100.437" fill="url(#linearGradient-4)" rx="23.6" ry="23.581"/></g></g></g></g></svg>

1
src/components/AJCZ/README.md

@ -0,0 +1 @@
案件处置 (办结申请)

320
src/components/AJCZ/index.jsx

@ -0,0 +1,320 @@
import React, { useEffect, useState } from 'react';
import { Card, Input, Select, Form, Button, Radio, Spin, message } from 'antd';
import { connect } from 'umi';
import UploadBtn from '../UploadBtn';
import SPLS from '../SPLS';
import CZMX from '../CZMX';
import { ALLSPFS, CSQK, UserLevel } from '@/utils/constants';
import { getDicsName } from '@/utils/utils';
import styles from './index.less';
/**
* 请求数据为空显示保存按钮可输入
* 请求数据不为空为编辑按钮点击后可编辑可发布
* 少一个添加处置信息弹窗
*
*
*/
const layout = {
labelCol: { span: 4 },
wrapperCol: { span: 18 },
};
const tailLayout = {
wrapperCol: { offset: 10, span: 10 },
};
const { Option } = Select;
const { TextArea } = Input;
const AJBJ = (props) => {
const { id, sysToken, loading, hideModal, fetchDictCZLX, onlyRead, global, user } = props;
const [form] = Form.useForm();
const [czInfo, setCzInfo] = useState(null);
const [CZLX, setCZLX] = useState([]);
const [btns, setBtns] = useState(null); //
const [sjldspr, setSjldspr] = useState([]); //
const getBjldSpr = () => {
props.fetchSprList();
}
const getSjldspr = () => {
// tab gatway gatway
if (sysToken === 'bu' ) {
// && (user.departmentOrgLevel === UserLevel.City.value || user.departmentOrgLevel === UserLevel.Town.value)
props.fetchUperSprList({ params: user?.departmentCode ?? '', sysToken: user.departmentOrgLevel === UserLevel.Province.value ? 'bu' :'sheng' }).then(data => {
setSjldspr(data);
})
} else {
props.fetchUperSprList({ params: user?.departmentCode ?? '', sysToken }).then(data => {
setSjldspr(data);
});
}
}
const getBtns = () => {
props.fetchBjBtns({ params: id, sysToken }).then(data => {
setBtns(data);
if (data?.bjldsp) getBjldSpr();
if (data?.sjldsp) getSjldspr();
});
}
useEffect(() => {
getBtns();
fetchDictCZLX(sysToken).then((res) => {
if (res && res.resCode === 0) {
setCZLX(res.data);
}
});
if (onlyRead) props.fetchCzInfo({ params: id, sysToken }).then((data) => setCzInfo(data));
return () => {
// cleanup
};
}, []);
const saveBj = (params) => {
props.fetchSaveBJSQ({ params, sysToken }).then(data => {
if (data.resCode === 0) {
message.success('操作成功');
props.hideModal(true);
} else {
message.error(data.resMsg);
}
});
}
const onFinish = (values) => { // tab
const czParmas = {
pfId: id,
cljg: values.cljg,
ssqk: values.ssqk,
ssqkMc: values.ssqkMc,
};
const bjParmas = {
pfId: id,
bjyj: values.bjyj,
wj: values.wj,
xjSpr: values.xjSpr,
xjSprMc: values.xjSprMc,
spFs: values.spFs,
};
if (values.spFs === ALLSPFS.sjldsp.value) { //
bjParmas.sjDw = values.sjDw;
bjParmas.sjDwMc = values.sjDwMc;
}
props.fetchSaveCz({ params: czParmas, sysToken }).then((data) => {
if (data.resCode === 0) {
saveBj(bjParmas);
} else {
message.error(data.resMsg);
}
});
};
const renderBtns = (ops) => {
return Object.keys(ALLSPFS).map(key => {
if (ops?.[key] === true) {
return <Radio key={key} value={ALLSPFS[key].value}>{ALLSPFS[key].name}</Radio>
}
})
}
return (
<Card title="">
<Spin spinning={loading}>
{
onlyRead ?
<Card>
<Form.Item label="属实情况">
{getDicsName(CSQK,czInfo?.ssqk)}
</Form.Item>
<Form.Item label="处理意见">
{czInfo?.cljg}
</Form.Item>
</Card>
:
<Form
{...layout}
name="ajcz"
form={form}
// initialValues={initFormData}
onFinish={onFinish}
>
<Form.Item
label="属实情况"
name="ssqk"
rules={[{ required: true, message: '请选择属实情况!' }]}
>
<Select
// disabled={!editing}
onSelect={(value, item) => {
form.setFieldsValue({ ssqkMc: item.mc });
}}
>
{Object.keys(CSQK).map((key) => {
return (
<Option key={key} mc={CSQK[key].name} value={CSQK[key].value}>
{CSQK[key].name}
</Option>
);
})}
</Select>
</Form.Item>
<Form.Item hidden label="属实情况名称" name="ssqkMc">
<Input />
</Form.Item>
<Form.Item
label="处理意见"
name="cljg"
rules={[{ required: true, message: '请填写处理意见!' }]}
>
<TextArea rows={3} />
</Form.Item>
<Form.Item label="办结意见" name='bjyj' rules={[{ required: true, message: '请填写办结意见!' }]}>
<TextArea rows={3} />
</Form.Item>
<Form.Item
label="附件"
name="wj"
>
<UploadBtn sysToken={sysToken} onChange={newValues => {
form.setFieldsValue({ wj: newValues })
}} />
</Form.Item>
<Form.Item label="办结方式" onChange={() => form.setFieldsValue({ xjSpr: '', xjSprMc: '' })} name='spFs' rules={[{ required: true, message: '请选择办结方式!' }]}>
<Radio.Group>
{renderBtns(btns)}
</Radio.Group>
</Form.Item>
<Form.Item
noStyle
shouldUpdate={(prevValues, currentValues) => prevValues.spFs !== currentValues.spFs}
>
{({ getFieldValue }) => {
return getFieldValue('spFs') === ALLSPFS.bjldsp.value ? (
<>
<Form.Item
label="审批人"
name="xjSpr"
rules={[{ required: true, message: '请选择审批人!' }]}
>
<Select style={{ width: 150 }} onSelect={(value, item) => { form.setFieldsValue({ xjSprMc: item.children }) }}>
{
global?.sprList.map(item => <Option key={item.id} value={item.logingId}>{`${item.surname}${item.commonName}`}</Option>)
}
</Select>
</Form.Item>
<Form.Item
hidden
label="审批人名称"
name="xjSprMc"
>
<Input />
</Form.Item>
</>
) : null;
}}
</Form.Item>
<Form.Item
noStyle
shouldUpdate={(prevValues, currentValues) => prevValues.spFs !== currentValues.spFs}
>
{({ getFieldValue }) => {
return getFieldValue('spFs') === ALLSPFS.sjldsp.value ? ( //
<>
<Form.Item
label="审批人"
name="xjSpr"
rules={[{ required: true, message: '请选择审批人!' }]}
>
<Select style={{ width: 150 }} onSelect={(value, item) => { form.setFieldsValue({ ...item.others }) }}>
{
sjldspr.map(item => <Option key={item.id} value={item.jsr} others={{ xjSprMc: item.jsrMc, sjDw: item.jsdw, sjDwMc: item.jsdwMc }} >{item.jsrMc}</Option>)
}
</Select>
</Form.Item>
<Form.Item
hidden
label="审批人名称"
name="xjSprMc"
>
<Input />
</Form.Item>
<Form.Item
hidden
label="接受单位"
name="sjDw"
>
<Input />
</Form.Item>
<Form.Item
hidden
label="接受单位名称"
name="sjDwMc"
>
<Input />
</Form.Item>
</>
) : null;
}}
</Form.Item>
<Form.Item {...tailLayout}>
<Button onClick={() => props.hideModal(false)} style={{ marginRight: 20 }}>取消</Button>
<Button type="primary" htmlType="submit">保存</Button>
</Form.Item>
</Form>
}
<CZMX id={id} sysToken={sysToken} CZLX={CZLX} onlyRead={onlyRead} />
{ onlyRead && <SPLS id={id} sysToken={sysToken} type='bjsp'/>}
</Spin>
</Card>
);
};
const mapStateToProps = ({ user, doing, global, loading }) => ({
user: user.currentUser,
doing,
global,
loading:
loading.effects['doing/fetchSaveBJSQ'] ||
loading.effects['doing/fetchSaveCz'] ||
false,
});
const mapDispatchToProps = (dispatch) => ({
fetchCzInfo(params) {
return dispatch({ type: 'doing/fetchCzInfo', payload: params });
},
fetchSaveCz(params) {
return dispatch({ type: 'doing/fetchSaveCz', payload: params });
},
fetchDictCZLX(params) {
return dispatch({ type: 'global/fetchDictCZLX', payload: params });
},
fetchBjBtns(params) {
return dispatch({ type: 'doing/fetchBjBtns', payload: params });
},
fetchSprList(params) {
return dispatch({ type: 'global/fetchSprList', payload: params });
},
fetchUperSprList(params) {
return dispatch({ type: 'doing/fetchUperSprList', payload: params });
},
fetchSaveBJSQ(params) {
return dispatch({ type: 'doing/fetchSaveBJSQ', payload: params });
},
});
export default connect(mapStateToProps, mapDispatchToProps)(AJBJ);

16
src/components/AJCZ/index.less

@ -0,0 +1,16 @@
.titleAndButton {
display: flex;
justify-content: space-between;
height: 50px;
line-height: 50px;
.title {
color: cornflowerblue;
font-weight: 600;
}
.button {
color: white;
}
}
.submit {
text-align: right;
}

21
src/components/Authorized/Authorized.jsx

@ -0,0 +1,21 @@
import React from 'react';
import { Result } from 'antd';
import check from './CheckPermissions';
const Authorized = ({
children,
authority,
noMatch = (
<Result
status="403"
title="403"
subTitle="Sorry, you are not authorized to access this page."
/>
),
}) => {
const childrenRender = typeof children === 'undefined' ? null : children;
const dom = check(authority, childrenRender, noMatch);
return <>{dom}</>;
};
export default Authorized;

25
src/components/Authorized/AuthorizedRoute.jsx

@ -0,0 +1,25 @@
import { Redirect, Route } from 'umi';
import React from 'react';
import Authorized from './Authorized';
const AuthorizedRoute = ({ component: Component, render, authority, redirectPath, ...rest }) => (
<Authorized
authority={authority}
noMatch={
<Route
{...rest}
render={() => (
<Redirect
to={{
pathname: redirectPath,
}}
/>
)}
/>
}
>
<Route {...rest} render={props => (Component ? <Component {...props} /> : render(props))} />
</Authorized>
);
export default AuthorizedRoute;

72
src/components/Authorized/CheckPermissions.jsx

@ -0,0 +1,72 @@
import React from 'react';
import { CURRENT } from './renderAuthorize'; // eslint-disable-next-line import/no-cycle
import PromiseRender from './PromiseRender';
/**
* 通用权限检查方法 Common check permissions method
*
* @param { 权限判定 | Permission judgment } authority
* @param { 你的权限 | Your permission description } currentAuthority
* @param { 通过的组件 | Passing components } target
* @param { 未通过的组件 | no pass components } Exception
*/
const checkPermissions = (authority, currentAuthority, target, Exception) => {
// .
// Retirement authority, return target;
if (!authority) {
return target;
} //
if (Array.isArray(authority)) {
if (Array.isArray(currentAuthority)) {
if (currentAuthority.some(item => authority.includes(item))) {
return target;
}
} else if (authority.includes(currentAuthority)) {
return target;
}
return Exception;
} // string
if (typeof authority === 'string') {
if (Array.isArray(currentAuthority)) {
if (currentAuthority.some(item => authority === item)) {
return target;
}
} else if (authority === currentAuthority) {
return target;
}
return Exception;
} // Promise
if (authority instanceof Promise) {
return <PromiseRender ok={target} error={Exception} promise={authority} />;
} // Function
if (typeof authority === 'function') {
const bool = authority(currentAuthority); // Promise
if (bool instanceof Promise) {
return <PromiseRender ok={target} error={Exception} promise={bool} />;
}
if (bool) {
return target;
}
return Exception;
}
throw new Error('unsupported parameters');
};
export { checkPermissions };
function check(authority, target, Exception) {
return checkPermissions(authority, CURRENT, target, Exception);
}
export default check;

78
src/components/Authorized/PromiseRender.jsx

@ -0,0 +1,78 @@
import React from 'react';
import { Spin } from 'antd';
import isEqual from 'lodash/isEqual';
import { isComponentClass } from './Secured'; // eslint-disable-next-line import/no-cycle
export default class PromiseRender extends React.Component {
state = {
component: () => null,
};
componentDidMount() {
this.setRenderComponent(this.props);
}
shouldComponentUpdate = (nextProps, nextState) => {
const { component } = this.state;
if (!isEqual(nextProps, this.props)) {
this.setRenderComponent(nextProps);
}
if (nextState.component !== component) return true;
return false;
}; // set render Component : ok or error
setRenderComponent(props) {
const ok = this.checkIsInstantiation(props.ok);
const error = this.checkIsInstantiation(props.error);
props.promise
.then(() => {
this.setState({
component: ok,
});
return true;
})
.catch(() => {
this.setState({
component: error,
});
});
} // Determine whether the incoming component has been instantiated
// AuthorizedRoute is already instantiated
// Authorized render is already instantiated, children is no instantiated
// Secured is not instantiated
checkIsInstantiation = target => {
if (isComponentClass(target)) {
const Target = target;
return props => <Target {...props} />;
}
if (React.isValidElement(target)) {
return props => React.cloneElement(target, props);
}
return () => target;
};
render() {
const { component: Component } = this.state;
const { ok, error, promise, ...rest } = this.props;
return Component ? (
<Component {...rest} />
) : (
<div
style={{
width: '100%',
height: '100%',
margin: 'auto',
paddingTop: 50,
textAlign: 'center',
}}
>
<Spin size="large" />
</div>
);
}
}

61
src/components/Authorized/Secured.jsx

@ -0,0 +1,61 @@
import React from 'react';
import CheckPermissions from './CheckPermissions';
/** 默认不能访问任何页面 default is "NULL" */
const Exception403 = () => 403;
export const isComponentClass = component => {
if (!component) return false;
const proto = Object.getPrototypeOf(component);
if (proto === React.Component || proto === Function.prototype) return true;
return isComponentClass(proto);
}; // Determine whether the incoming component has been instantiated
// AuthorizedRoute is already instantiated
// Authorized render is already instantiated, children is no instantiated
// Secured is not instantiated
const checkIsInstantiation = target => {
if (isComponentClass(target)) {
const Target = target;
return props => <Target {...props} />;
}
if (React.isValidElement(target)) {
return props => React.cloneElement(target, props);
}
return () => target;
};
/**
* 用于判断是否拥有权限访问此 view 权限 authority 支持传入 string, () => boolean | Promise e.g. 'user' 只有 user 用户能访问
* e.g. 'user,admin' user admin 都能访问 e.g. ()=>boolean 返回true能访问,返回false不能访问 e.g. Promise then 能访问
* catch不能访问 e.g. authority support incoming string, () => boolean | Promise e.g. 'user' only user
* user can access e.g. 'user, admin' user and admin can access e.g. () => boolean true to be able
* to visit, return false can not be accessed e.g. Promise then can not access the visit to catch
*
* @param {string | function | Promise} authority
* @param {ReactNode} error 非必需参数
*/
const authorize = (authority, error) => {
/**
* Conversion into a class 防止传入字符串时找不到staticContext造成报错 String parameters can cause staticContext
* not found error
*/
let classError = false;
if (error) {
classError = () => error;
}
if (!authority) {
throw new Error('authority is required');
}
return function decideAuthority(target) {
const component = CheckPermissions(authority, target, classError || Exception403);
return checkIsInstantiation(component);
};
};
export default authorize;

9
src/components/Authorized/index.jsx

@ -0,0 +1,9 @@
import Authorized from './Authorized';
import Secured from './Secured';
import check from './CheckPermissions';
import renderAuthorize from './renderAuthorize';
Authorized.Secured = Secured;
Authorized.check = check;
const RenderAuthorize = renderAuthorize(Authorized);
export default RenderAuthorize;

31
src/components/Authorized/renderAuthorize.js

@ -0,0 +1,31 @@
/* eslint-disable eslint-comments/disable-enable-pair */
/* eslint-disable import/no-mutable-exports */
let CURRENT = 'NULL';
/**
* Use authority or getAuthority
*
* @param {string|()=>String} currentAuthority
*/
const renderAuthorize = Authorized => currentAuthority => {
if (currentAuthority) {
if (typeof currentAuthority === 'function') {
CURRENT = currentAuthority();
}
if (
Object.prototype.toString.call(currentAuthority) === '[object String]' ||
Array.isArray(currentAuthority)
) {
CURRENT = currentAuthority;
}
} else {
CURRENT = 'NULL';
}
return Authorized;
};
export { CURRENT };
export default Authorized => renderAuthorize(Authorized);

152
src/components/BJSP-Batch/Agree.jsx

@ -0,0 +1,152 @@
import React from 'react';
import { Form, Input, Select, Button, Space, Radio } from 'antd';
import UploadBtn from '../UploadBtn';
import { ALLSPFS } from '@/utils/constants';
const { Option } = Select;
const layout = {
labelCol: { span: 4 },
wrapperCol: { span: 18 },
};
const tailLayout = {
wrapperCol: { offset: 10, span: 10 },
};
const Agree = (props) => {
const [form] = Form.useForm();
const { btns, sysToken, sprList, sjldspr } = props;
const onFinish = (values) => {
props.handleSp(values);
}
const renderBtns = (ops) => {
const all = Object.keys(ALLSPFS).map(key => {
if (ops?.[key] === true) {
return <Radio key={key} value={ALLSPFS[key].value}>{ALLSPFS[key].name}</Radio>
}
})
return all;
}
return (
<div>
<Form
{...layout}
name="bjsp"
form={form}
// initialValues={{ }}
onFinish={onFinish}
>
<Form.Item
label="领导批示"
name="spyj"
rules={[{ max: 200, message: '最多能输入200字!' }]}
>
<Input.TextArea />
</Form.Item>
<Form.Item label="办结方式" onChange={() => form.setFieldsValue({ xjSpr: '', xjSprMc: '' })} name='spFs' rules={[{ required: true, message: '请选择办结方式!' }]}>
<Radio.Group>
{renderBtns(btns)}
</Radio.Group>
</Form.Item>
<Form.Item
noStyle
shouldUpdate={(prevValues, currentValues) => prevValues.spFs !== currentValues.spFs}
>
{({ getFieldValue }) => {
return getFieldValue('spFs') === ALLSPFS.bjldsp.value ? (
<>
<Form.Item
label="审批人"
name="xjSpr"
rules={[{ required: true, message: '请选择审批人!' }]}
>
<Select style={{ width: 150 }} onSelect={(value, item) => { form.setFieldsValue({ xjSprMc: item.children }) }}>
{
sprList.map(item => <Option key={item.id} value={item.logingId}>{`${item.surname}${item.commonName}`}</Option>)
}
</Select>
</Form.Item>
<Form.Item
hidden
label="审批人名称"
name="xjSprMc"
>
<Input />
</Form.Item>
</>
) : null;
}}
</Form.Item>
<Form.Item
noStyle
shouldUpdate={(prevValues, currentValues) => prevValues.spFs !== currentValues.spFs}
>
{({ getFieldValue }) => {
return getFieldValue('spFs') === ALLSPFS.sjldsp.value ? (
<>
<Form.Item
label="审批人"
name="xjSpr"
rules={[{ required: true, message: '请选择审批人!' }]}
>
<Select style={{ width: 150 }} onSelect={(value, item) => { form.setFieldsValue({ ...item.others }) }}>
{
sjldspr.map(item => <Option key={item.id} value={item.jsr} others={{xjSprMc: item.jsrMc, sjDw: item.jsdw, sjDwMc: item.jsdwMc }} >{item.jsrMc}</Option>)
}
</Select>
</Form.Item>
<Form.Item
hidden
label="审批人名称"
name="xjSprMc"
>
<Input />
</Form.Item>
<Form.Item
hidden
label="接受单位"
name="sjDw"
>
<Input />
</Form.Item>
<Form.Item
hidden
label="接受单位名称"
name="sjDwMc"
>
<Input />
</Form.Item>
</>
) : null;
}}
</Form.Item>
<Form.Item
label="办结报告"
name="wj"
>
<UploadBtn sysToken={sysToken} onChange={newValues => {
form.setFieldsValue({ wj: newValues })
}} />
</Form.Item>
<Form.Item {...tailLayout}>
<Space>
<Button type="default" onClick={() => props.hideModal(false)}>
取消
</Button>
<Button type="primary" htmlType="submit">
确认
</Button>
</Space>
</Form.Item>
</Form>
</div>
)
}
export default Agree;

64
src/components/BJSP-Batch/Info.jsx

@ -0,0 +1,64 @@
import React from 'react';
import { Form, Card, Button } from 'antd';
import commonDownLoad from '@/utils/downloadFile';
import { CSQK } from '@/utils/constants';
import { getDicsName } from '@/utils/utils';
const layout = {
labelCol: { span: 3 },
wrapperCol: { span: 18 },
};
const { Item } = Form;
const Info = (props) => {
const { czInfo, spInfo, sysToken } = props;
if (!spInfo?.ywSj) return '';
const { ywSj } = spInfo;
const ywSjIson = JSON.parse(ywSj);
return (
<Card title=''>
<div className='itemInfo'>
<Form {...layout}>
<Item label="属实情况">
{getDicsName(CSQK, czInfo?.ssqk)}
</Item>
<Item label="处理意见">
{czInfo?.cljg}
</Item>
{
spInfo?.sfSq === 1 ? //
<Item label="办结意见">
{ywSjIson?.bjyj}
</Item>
:
<Item label="审批意见">
{ywSjIson?.spyj}
</Item>
}
<Item label="附件">
{ywSjIson?.wj?.map(item => { return (<Button key={item.id} onClick={() => commonDownLoad(item, sysToken)} type='link'>{item.wjMc}</Button>) })}
</Item>
<Item label="申请人">
{spInfo?.clrMc}
</Item>
<Item label="申请时间">
{spInfo?.clSj}
</Item>
<Item label="申请单位">
{spInfo?.cldwMc}
</Item>
<Item label="审批人" style={{ borderTop: '1px solid #d9d9d9' }}>
{ywSjIson?.xjSprMc}
</Item>
</Form>
</div>
</Card>
)
}
export default Info;

1
src/components/BJSP-Batch/README.md

@ -0,0 +1 @@
办结审批,添加领导办结审批

64
src/components/BJSP-Batch/Reject.jsx

@ -0,0 +1,64 @@
import React from 'react';
import { Form, Input, Button, Space } from 'antd';
import UploadBtn from '../UploadBtn';
const layout = {
labelCol: { span: 4 },
wrapperCol: { span: 18 },
};
const tailLayout = {
wrapperCol: { offset: 10, span: 10 },
};
const Reject = (props) => {
const [form] = Form.useForm();
const { sysToken } = props;
const onFinish = (values) => {
props.handleSp({ ...values, spFs: 3 });
}
return (
<div>
<Form
{...layout}
name="bjbh"
form={form}
// initialValues={{ }}
onFinish={onFinish}
>
<Form.Item
label="驳回原因"
name="slyj"
rules={[{ max: 200, message: '最多能输入200字!' }]}
>
<Input.TextArea />
</Form.Item>
<Form.Item
label="附件"
name="wj"
>
<UploadBtn sysToken={sysToken} onChange={newValues => {
form.setFieldsValue({ wj: newValues })
}} />
</Form.Item>
<Form.Item {...tailLayout}>
<Space>
<Button type="default" onClick={() => props.hideModal(false)}>
取消
</Button>
<Button type="primary" htmlType="submit">
确认
</Button>
</Space>
</Form.Item>
</Form>
</div>
)
}
export default Reject;

166
src/components/BJSP-Batch/index.jsx

@ -0,0 +1,166 @@
import React, { useEffect, useState } from 'react';
import { Card, Spin, Radio, Button } from 'antd';
import { connect } from 'umi';
import Info from './Info';
import CZMX from '../CZMX';
import Agree from './Agree';
import Reject from './Reject';
import { UserLevel } from '@/utils/constants';
import styles from './index.less';
const BJSP = (props) => {
const { id, sysToken, loading, global, user, track } = props;
const [agree, setAgree] = useState(true);
const [btns, setBtns] = useState(null);
const [sjldspr, setSjldspr] = useState([]);
const [czInfo, setCzInfo] = useState(null);
const [spInfo, setSpInfo] = useState(null);
const [showCHBtn, setShowCHBtn] = useState(false);
const [CZLX, setCZLX] = useState([]);
const [showSP, setShowSP] = useState(!track);
const getBjldSpr = () => { //
props.fetchSprList();
}
const getSjldspr = () => { //
// tab gatway gatway
if (sysToken === 'bu' ) {
// && (user.departmentOrgLevel === UserLevel.City.value || user.departmentOrgLevel === UserLevel.Town.value)
props.fetchUperSprList({ params: user?.departmentCode ?? '', sysToken: user.departmentOrgLevel === UserLevel.Province.value ? 'bu' :'sheng' }).then(data => {
setSjldspr(data);
})
} else {
props.fetchUperSprList({ params: user?.departmentCode ?? '', sysToken }).then(data => {
setSjldspr(data);
});
}
}
const getBtns = () => { //
props.fetchBjBtns({ params: id, sysToken }).then(data => {
setBtns(data);
if (data?.bjldsp) getBjldSpr();
if (data?.sjldsp) getSjldspr();
}
);
}
useEffect(() => {
getBtns();
props.fetchCzInfo({ params: id, sysToken }).then(data => setCzInfo(data)); //
props.fetchBJSPInfo({ params: id, sysToken }).then(data => setSpInfo(data)); // , id pfId
props.fetchDictCZLX(sysToken).then((res) => {
if (res && res.resCode === 0) {
setCZLX(res.data);
}
});
return () => {
// cleanup
}
}, []);
useEffect(() => {
if (track && spInfo) {
props.fetchCheckCH({ params: { pfId: id, spId: spInfo.id }, sysToken }).then(res => {
if (res?.data) {
setShowCHBtn(true);
}
});
}
}, [spInfo]);
const handleSp = (values) => { //
const params = {
...values,
pfId: id,
spId: spInfo.id,
};
props.fetchSaveBJSP({ params, sysToken }).then(data => {
props.hideModal(true);
});
}
const onClickCH = () => { //
props.fetchSaveBJCH({ params: { pfId: id, spId: spInfo.id }, sysToken }).then(data => {
props.hideModal(true);
});
}
return (
<div>
<Info sysToken={sysToken} czInfo={czInfo} spInfo={spInfo} />
<Spin spinning={loading}>
{track &&
<div className={styles.btnCon}>
{showCHBtn && <Button onClick={onClickCH} type='primary'>撤回</Button>}
{/* <Button type='primary'>添加领导意见</Button> */}
</div>
}
{showSP &&
<Card title='领导审批'>
<div className={styles.agreeCon}>
<Radio.Group onChange={(e) => setAgree(e.target.value)} value={agree}>
<Radio value={true}>同意</Radio>
<Radio value={false}>驳回</Radio>
</Radio.Group>
</div>
{
agree ?
<Agree handleSp={handleSp} hideModal={props.hideModal} sysToken={sysToken} btns={btns} sjldspr={sjldspr} sprList={global.sprList} />
:
<Reject handleSp={handleSp} hideModal={props.hideModal} sysToken={sysToken} />
}
</Card>
}
<CZMX id={id} sysToken={sysToken} CZLX={CZLX} onlyRead />
</Spin>
</div>
);
};
const mapStateToProps = ({ user, doing, global, loading }) => ({
user: user.currentUser,
doing,
global,
loading:
loading.effects['doing/fetchBjBtns'] ||
loading.effects['doing/fetchSaveBJSP'] ||
loading.effects['doing/fetchSaveBJCH'] ||
false,
});
const mapDispatchToProps = dispatch => ({
fetchCzInfo(params) {
return dispatch({ type: 'doing/fetchCzInfo', payload: params });
},
fetchBjBtns(params) {
return dispatch({ type: 'doing/fetchBjBtns', payload: params });
},
fetchSprList(params) {
return dispatch({ type: 'global/fetchSprList', payload: params });
},
fetchUperSprList(params) {
return dispatch({ type: 'doing/fetchUperSprList', payload: params });
},
fetchSaveBJSP(params) {
return dispatch({ type: 'doing/fetchSaveBJSP', payload: params });
},
fetchBJSPInfo(params) {
return dispatch({ type: 'doing/fetchBJSPInfo', payload: params });
},
fetchCheckCH(params) {
return dispatch({ type: 'doing/fetchCheckCH', payload: params });
},
fetchSaveBJCH(params) {
return dispatch({ type: 'doing/fetchSaveBJCH', payload: params });
},
fetchDictCZLX(params) {
return dispatch({ type: 'global/fetchDictCZLX', payload: params });
},
});
export default connect(mapStateToProps, mapDispatchToProps)(BJSP);

16
src/components/BJSP-Batch/index.less

@ -0,0 +1,16 @@
.titleAndButton {
display: flex;
justify-content: space-between;
height: 50px;
line-height: 50px;
.title {
color: cornflowerblue;
font-weight: 600;
}
.button {
color: white;
}
}
.submit {
text-align: right;
}

152
src/components/BJSP/Agree.jsx

@ -0,0 +1,152 @@
import React from 'react';
import { Form, Input, Select, Button, Space, Radio } from 'antd';
import UploadBtn from '../UploadBtn';
import { ALLSPFS } from '@/utils/constants';
const { Option } = Select;
const layout = {
labelCol: { span: 4 },
wrapperCol: { span: 18 },
};
const tailLayout = {
wrapperCol: { offset: 10, span: 10 },
};
const Agree = (props) => {
const [form] = Form.useForm();
const { btns, sysToken, sprList, sjldspr } = props;
const onFinish = (values) => {
props.handleSp(values);
}
const renderBtns = (ops) => {
const all = Object.keys(ALLSPFS).map(key => {
if (ops?.[key] === true) {
return <Radio key={key} value={ALLSPFS[key].value}>{ALLSPFS[key].name}</Radio>
}
})
return all;
}
return (
<div>
<Form
{...layout}
name="bjsp"
form={form}
// initialValues={{ }}
onFinish={onFinish}
>
<Form.Item
label="领导批示"
name="spyj"
rules={[{ max: 200, message: '最多能输入200字!' }]}
>
<Input.TextArea />
</Form.Item>
<Form.Item label="办结方式" onChange={() => form.setFieldsValue({ xjSpr: '', xjSprMc: '' })} name='spFs' rules={[{ required: true, message: '请选择办结方式!' }]}>
<Radio.Group>
{renderBtns(btns)}
</Radio.Group>
</Form.Item>
<Form.Item
noStyle
shouldUpdate={(prevValues, currentValues) => prevValues.spFs !== currentValues.spFs}
>
{({ getFieldValue }) => {
return getFieldValue('spFs') === ALLSPFS.bjldsp.value ? (
<>
<Form.Item
label="审批人"
name="xjSpr"
rules={[{ required: true, message: '请选择审批人!' }]}
>
<Select style={{ width: 150 }} onSelect={(value, item) => { form.setFieldsValue({ xjSprMc: item.children }) }}>
{
sprList.map(item => <Option key={item.id} value={item.logingId}>{`${item.surname}${item.commonName}`}</Option>)
}
</Select>
</Form.Item>
<Form.Item
hidden
label="审批人名称"
name="xjSprMc"
>
<Input />
</Form.Item>
</>
) : null;
}}
</Form.Item>
<Form.Item
noStyle
shouldUpdate={(prevValues, currentValues) => prevValues.spFs !== currentValues.spFs}
>
{({ getFieldValue }) => {
return getFieldValue('spFs') === ALLSPFS.sjldsp.value ? (
<>
<Form.Item
label="审批人"
name="xjSpr"
rules={[{ required: true, message: '请选择审批人!' }]}
>
<Select style={{ width: 150 }} onSelect={(value, item) => { form.setFieldsValue({ ...item.others }) }}>
{
sjldspr.map(item => <Option key={item.id} value={item.jsr} others={{xjSprMc: item.jsrMc, sjDw: item.jsdw, sjDwMc: item.jsdwMc }} >{item.jsrMc}</Option>)
}
</Select>
</Form.Item>
<Form.Item
hidden
label="审批人名称"
name="xjSprMc"
>
<Input />
</Form.Item>
<Form.Item
hidden
label="接受单位"
name="sjDw"
>
<Input />
</Form.Item>
<Form.Item
hidden
label="接受单位名称"
name="sjDwMc"
>
<Input />
</Form.Item>
</>
) : null;
}}
</Form.Item>
<Form.Item
label="办结报告"
name="wj"
>
<UploadBtn sysToken={sysToken} onChange={newValues => {
form.setFieldsValue({ wj: newValues })
}} />
</Form.Item>
<Form.Item {...tailLayout}>
<Space>
<Button type="default" onClick={() => props.hideModal(false)}>
取消
</Button>
<Button type="primary" htmlType="submit">
确认
</Button>
</Space>
</Form.Item>
</Form>
</div>
)
}
export default Agree;

64
src/components/BJSP/Info.jsx

@ -0,0 +1,64 @@
import React from 'react';
import { Form, Card, Button } from 'antd';
import commonDownLoad from '@/utils/downloadFile';
import { CSQK } from '@/utils/constants';
import { getDicsName } from '@/utils/utils';
const layout = {
labelCol: { span: 3 },
wrapperCol: { span: 18 },
};
const { Item } = Form;
const Info = (props) => {
const { czInfo, spInfo, sysToken } = props;
if (!spInfo?.ywSj) return '';
const { ywSj } = spInfo;
const ywSjIson = JSON.parse(ywSj);
return (
<Card title=''>
<div className='itemInfo'>
<Form {...layout}>
<Item label="属实情况">
{getDicsName(CSQK, czInfo?.ssqk)}
</Item>
<Item label="处理意见">
{czInfo?.cljg}
</Item>
{
spInfo?.sfSq === 1 ? //
<Item label="办结意见">
{ywSjIson?.bjyj || czInfo?.bjyj}
</Item>
:
<Item label="审批意见">
{ywSjIson?.spyj}
</Item>
}
<Item label="附件">
{ywSjIson?.wj?.map(item => { return (<Button key={item.id} onClick={() => commonDownLoad(item, sysToken)} type='link'>{item.wjMc}</Button>) })}
</Item>
<Item label="申请人">
{spInfo?.clrMc}
</Item>
<Item label="申请时间">
{spInfo?.clSj}
</Item>
<Item label="申请单位">
{spInfo?.cldwMc}
</Item>
<Item label="审批人" style={{ borderTop: '1px solid #d9d9d9' }}>
{ywSjIson?.xjSprMc}
</Item>
</Form>
</div>
</Card>
)
}
export default Info;

1
src/components/BJSP/README.md

@ -0,0 +1 @@
办结审批,添加领导办结审批

64
src/components/BJSP/Reject.jsx

@ -0,0 +1,64 @@
import React from 'react';
import { Form, Input, Button, Space } from 'antd';
import UploadBtn from '../UploadBtn';
const layout = {
labelCol: { span: 4 },
wrapperCol: { span: 18 },
};
const tailLayout = {
wrapperCol: { offset: 10, span: 10 },
};
const Reject = (props) => {
const [form] = Form.useForm();
const { sysToken } = props;
const onFinish = (values) => {
props.handleSp({ ...values, spFs: 3 });
}
return (
<div>
<Form
{...layout}
name="bjbh"
form={form}
// initialValues={{ }}
onFinish={onFinish}
>
<Form.Item
label="驳回原因"
name="slyj"
rules={[{ max: 200, message: '最多能输入200字!' }]}
>
<Input.TextArea />
</Form.Item>
<Form.Item
label="附件"
name="wj"
>
<UploadBtn sysToken={sysToken} onChange={newValues => {
form.setFieldsValue({ wj: newValues })
}} />
</Form.Item>
<Form.Item {...tailLayout}>
<Space>
<Button type="default" onClick={() => props.hideModal(false)}>
取消
</Button>
<Button type="primary" htmlType="submit">
确认
</Button>
</Space>
</Form.Item>
</Form>
</div>
)
}
export default Reject;

166
src/components/BJSP/index.jsx

@ -0,0 +1,166 @@
import React, { useEffect, useState } from 'react';
import { Card, Spin, Radio, Button } from 'antd';
import { connect } from 'umi';
import Info from './Info';
import CZMX from '../CZMX';
import Agree from './Agree';
import Reject from './Reject';
import { UserLevel } from '@/utils/constants';
import styles from './index.less';
const BJSP = (props) => {
const { id, sysToken, loading, global, user, track } = props;
const [agree, setAgree] = useState(true);
const [btns, setBtns] = useState(null);
const [sjldspr, setSjldspr] = useState([]);
const [czInfo, setCzInfo] = useState(null);
const [spInfo, setSpInfo] = useState(null);
const [showCHBtn, setShowCHBtn] = useState(false);
const [CZLX, setCZLX] = useState([]);
const [showSP, setShowSP] = useState(!track);
const getBjldSpr = () => { //
props.fetchSprList();
}
const getSjldspr = () => { //
// tab gatway gatway
if (sysToken === 'bu') {
// && (user.departmentOrgLevel === UserLevel.City.value || user.departmentOrgLevel === UserLevel.Town.value)
props.fetchUperSprList({ params: user?.departmentCode ?? '', sysToken: user.departmentOrgLevel === UserLevel.Province.value ? 'bu' :'sheng' }).then(data => {
setSjldspr(data);
})
} else {
props.fetchUperSprList({ params: user?.departmentCode ?? '', sysToken }).then(data => {
setSjldspr(data);
});
}
}
const getBtns = () => { //
props.fetchBjBtns({ params: id, sysToken }).then(data => {
setBtns(data);
if (data?.bjldsp) getBjldSpr();
if (data?.sjldsp) getSjldspr();
}
);
}
useEffect(() => {
getBtns();
props.fetchCzInfo({ params: id, sysToken }).then(data => setCzInfo(data)); //
props.fetchBJSPInfo({ params: id, sysToken }).then(data => setSpInfo(data)); // , id pfId
props.fetchDictCZLX(sysToken).then((res) => {
if (res && res.resCode === 0) {
setCZLX(res.data);
}
});
return () => {
// cleanup
}
}, []);
useEffect(() => {
if (track && spInfo) {
props.fetchCheckCH({ params: { pfId: id, spId: spInfo.id }, sysToken }).then(res => {
if (res?.data) {
setShowCHBtn(true);
}
});
}
}, [spInfo]);
const handleSp = (values) => { //
const params = {
...values,
pfId: id,
spId: spInfo.id,
};
props.fetchSaveBJSP({ params, sysToken }).then(data => {
props.hideModal(true);
});
}
const onClickCH = () => { //
props.fetchSaveBJCH({ params: { pfId: id, spId: spInfo.id }, sysToken }).then(data => {
props.hideModal(true);
});
}
return (
<div>
<Info sysToken={sysToken} czInfo={czInfo} spInfo={spInfo} />
<Spin spinning={loading}>
{track &&
<div className={styles.btnCon}>
{showCHBtn && <Button onClick={onClickCH} type='primary'>撤回</Button>}
{/* <Button type='primary'>添加领导意见</Button> */}
</div>
}
{showSP &&
<Card title='领导审批'>
<div className={styles.agreeCon}>
<Radio.Group onChange={(e) => setAgree(e.target.value)} value={agree}>
<Radio value={true}>同意</Radio>
<Radio value={false}>驳回</Radio>
</Radio.Group>
</div>
{
agree ?
<Agree handleSp={handleSp} hideModal={props.hideModal} sysToken={sysToken} btns={btns} sjldspr={sjldspr} sprList={global.sprList} />
:
<Reject handleSp={handleSp} hideModal={props.hideModal} sysToken={sysToken} />
}
</Card>
}
<CZMX id={id} sysToken={sysToken} CZLX={CZLX} onlyRead />
</Spin>
</div>
);
};
const mapStateToProps = ({ user, doing, global, loading }) => ({
user: user.currentUser,
doing,
global,
loading:
loading.effects['doing/fetchBjBtns'] ||
loading.effects['doing/fetchSaveBJSP'] ||
loading.effects['doing/fetchSaveBJCH'] ||
false,
});
const mapDispatchToProps = dispatch => ({
fetchCzInfo(params) {
return dispatch({ type: 'doing/fetchCzInfo', payload: params });
},
fetchBjBtns(params) {
return dispatch({ type: 'doing/fetchBjBtns', payload: params });
},
fetchSprList(params) {
return dispatch({ type: 'global/fetchSprList', payload: params });
},
fetchUperSprList(params) {
return dispatch({ type: 'doing/fetchUperSprList', payload: params });
},
fetchSaveBJSP(params) {
return dispatch({ type: 'doing/fetchSaveBJSP', payload: params });
},
fetchBJSPInfo(params) {
return dispatch({ type: 'doing/fetchBJSPInfo', payload: params });
},
fetchCheckCH(params) {
return dispatch({ type: 'doing/fetchCheckCH', payload: params });
},
fetchSaveBJCH(params) {
return dispatch({ type: 'doing/fetchSaveBJCH', payload: params });
},
fetchDictCZLX(params) {
return dispatch({ type: 'global/fetchDictCZLX', payload: params });
},
});
export default connect(mapStateToProps, mapDispatchToProps)(BJSP);

16
src/components/BJSP/index.less

@ -0,0 +1,16 @@
.titleAndButton {
display: flex;
justify-content: space-between;
height: 50px;
line-height: 50px;
.title {
color: cornflowerblue;
font-weight: 600;
}
.button {
color: white;
}
}
.submit {
text-align: right;
}

1
src/components/CC/README.md

@ -0,0 +1 @@
抽查按钮

109
src/components/CC/index.jsx

@ -0,0 +1,109 @@
import React, { useEffect, useState } from 'react';
import { Input, Radio, Form, Button, Spin, Modal, Space } from 'antd';
import { connect } from 'umi';
import { CCQK } from '@/utils/constants';
/**
*
*
*
*/
const { Item } = Form;
const { TextArea } = Input;
const layout = {
labelCol: { span: 4 },
wrapperCol: { span: 18 },
};
const tailLayout = {
wrapperCol: { offset: 10, span: 10 },
};
const CC = (props) => {
const { id, sysToken, loading } = props;
const [form] = Form.useForm();
const [visible, setVisible] = useState(false);
useEffect(() => {
return () => {
// cleanup
};
}, []);
const onClose = () => {
form.resetFields();
setVisible(false);
}
const onFinish = (values) => {
const params = { ...values, pfId: id };
props.fetchSaveCC({ params, sysToken }).then((data) => {
if (data) {
onClose();
props.hideModal(true);
}
});
};
return (
<div title="">
<Spin spinning={loading}>
<div style={{textAlign: 'right', marginBottom: 20 }}><Button type='primary' onClick={() => setVisible(true)}>抽查</Button></div>
<Modal
title='抽查情况'
onCancel={onClose}
visible={visible}
footer={null}
width={640}
maskClosable={false}
>
<Form onFinish={onFinish} {...layout}>
{/* <Item label='' name='ccSj' rules={[{ required: true, message: '!' }]}>
<DatePicker format='YYYY-MM-DD HH:mm:ss' />
</Item> */}
<Item label='抽查结果' name='ccjg' rules={[{ required: true, message: '请选择抽查结果!' }]}>
<Radio.Group>
{Object.keys(CCQK).map(key => {
if (key !== 'WCC') { //
return <Radio key={key} value={CCQK[key].value}>{CCQK[key].name}</Radio>
}
})}
</Radio.Group>
</Item>
<Item label='备注' name='bzxx' rules={[{ max: 200, message: '最多能输入200字!' }]}>
<TextArea />
</Item>
<Form.Item {...tailLayout}>
<Space>
<Button type="default" onClick={onClose}>
取消
</Button>
<Button type="primary" htmlType="submit">
确认
</Button>
</Space>
</Form.Item>
</Form>
</Modal>
</Spin>
</div>
);
};
const mapStateToProps = ({ doing, global, loading }) => ({
doing,
global,
loading: loading.effects['doing/fetchSaveCC'] || false,
});
const mapDispatchToProps = (dispatch) => ({
fetchSaveCC(params) {
return dispatch({ type: 'doing/fetchSaveCC', payload: params });
},
});
export default connect(mapStateToProps, mapDispatchToProps)(CC);

1
src/components/CCJG/README.md

@ -0,0 +1 @@
抽查结果

73
src/components/CCJG/index.jsx

@ -0,0 +1,73 @@
import React, { useEffect, useState } from 'react';
import { Table, Card } from 'antd';
import { connect } from 'umi';
import { CCQK } from '@/utils/constants';
import { getDicsName } from '@/utils/utils';
/**
*
*
*
*/
const columns = [
{
title: '抽查时间',
dataIndex: 'ccSj',
},
{
title: '抽查人',
dataIndex: 'ccrMc',
},
{
title: '抽查结果',
dataIndex: 'ccjg',
key: 'id',
render: (text) => getDicsName(CCQK, text),
},
{
title: '备注信息',
dataIndex: 'bzxx',
},
]
const CCJG = (props) => {
const { id, sysToken } = props;
const [ccjg, setCcjg] = useState(null);
const getCcjg = () => {
props.fetchCcjg({ id, sysToken }).then((data) => {
if (data) {
setCcjg(data);
}
});
}
useEffect(() => {
getCcjg();
return () => {
// cleanup
};
}, []);
if (!ccjg) return '';
return (
<Card title="抽查">
<Table
columns={columns}
dataSource={ccjg}
/>
</Card>
);
};
const mapStateToProps = ({ doing, }) => ({
doing,
});
const mapDispatchToProps = (dispatch) => ({
fetchCcjg(params) {
return dispatch({ type: 'doing/fetchCcjg', payload: params });
},
});
export default connect(mapStateToProps, mapDispatchToProps)(CCJG);

1
src/components/CXPF/REASME.md

@ -0,0 +1 @@
被驳回重新派发 或者派发失败重新派发 或者是 受理派发

437
src/components/CXPF/index.jsx

@ -0,0 +1,437 @@
import React, { useEffect, useState } from 'react';
import moment from 'moment';
import { Form, Input, Button, Card, Select, Radio, DatePicker, Row, Col, Space, Spin, message } from 'antd';
import { connect } from 'umi';
import UploadBtn from '../UploadBtn';
import NextOrg from '../NextOrg';
import { YJLX, BLFS, SPFS, UserLevel } from '@/utils/constants';
import { getDicsName } from '@/utils/utils';
import { truncate } from 'lodash';
const { Option } = Select;
const layout1 = {
labelCol: { span: 12 },
wrapperCol: { span: 12 },
};
const layout2 = {
labelCol: { span: 5 },
wrapperCol: { span: 19 },
};
const layout = {
labelCol: { span: 3 },
wrapperCol: { span: 20 },
};
const layoutSPFS = { // layout
labelCol: { span: 6 },
wrapperCol: { span: 17 },
};
const tailLayout = {
wrapperCol: { offset: 10, span: 10 },
};
const initFormData = { blfs: YJLX.XJBL.value, nbfs: BLFS.DB.value, spFs: SPFS.LDSP.value, wj: [] };
// -
//
//
//
//
// bljb
// bljb
const PF = (props) => {
const { global, id, sysToken, loading, user } = props;
const [form] = Form.useForm();
const [newestInfo, setNewestInfo] = useState(null);
const [toDays, setToDays] = useState('');
const changeData = s => {
let days = '';
if (s) {
days = moment(moment(s).format('YYYY-MM-DD')).diff(moment().format('YYYY-MM-DD'), 'day');
}
setToDays(days);
}
const setDefaultForm = (data) => {
// sjPfdwzxSl null
// sfSsf 1
const defaultForm = {
blfs: data.blfs,
blfsMc: data.blfsMc,
nbfs: data.nbfs,
zcfkSj: moment(data.zcfkSj),
slyj: data.slyj,
wj: data.wj || [],
wtjs: data.wtjs,
}
changeData(data.zcfkSj)
// bljb
if (user.departmentOrgLevel === UserLevel.Town.value) {
defaultForm.blfs = YJLX.BJBL.value;
defaultForm.blfsMc = YJLX.BJBL.name;
defaultForm.slyj = YJLX.BJBL.name;
}
// defaultForm.slyj = `${defaultForm.blfsMc}-${getDicsName(BLFS, defaultForm.nbfs)}`;
form.setFieldsValue({ ...defaultForm });
}
useEffect(() => {
props.fetchSprList && props.fetchSprList();
props.fetchCbrList && props.fetchCbrList();
props.fetchNewest({ params: id, sysToken }).then(data => {
if (data.sfSsf === 1) form.setFieldsValue({ spFs: SPFS.ZJBL.value });
// debugger;
setNewestInfo(data);
if (data.sjPfdwzxSl) {
setDefaultForm(data.sjPfdwzxSl)
} else if (user.departmentOrgLevel === UserLevel.Town.value) { //
const defaultForm = {};
defaultForm.blfs = YJLX.BJBL.value;
defaultForm.blfsMc = YJLX.BJBL.name;
defaultForm.slyj = YJLX.BJBL.name;
form.setFieldsValue({ ...defaultForm });
}
}
);
return () => {
// cleanup
}
}, []);
const onFinish = (values) => {
const params = {
...values,
blfsMc: getDicsName(YJLX, values.blfs),
zcfkSj: `${moment(values.zcfkSj).format('YYYY-MM-DD')} 23:59:59`,
pfId: id,
};
props.fetchSavePF({ params, sysToken }).then((data) => {
if (data?.resCode === 0) {
message.success('操作成功');
props.hideModal(true);
}
})
};
const onFinishFailed = (errorInfo) => {
console.log('Failed:', errorInfo);
};
const onChangeBLFS = (e) => {
const text = `${YJLX.XJBL.name}-${getDicsName(BLFS, e.target.value)}`;
form.setFieldsValue({ slyj: text })
}
const changeYJLX = (v, item) => {
const text = v === YJLX.BJBL.value ? item.children : `${YJLX.XJBL.name}-${getDicsName(BLFS, form.getFieldValue('nbfs'))}`;
form.setFieldsValue({ slyj: text });
}
const onChangeOrg = params => {
const { bm, mc } = params;
form.setFieldsValue({ xjdwBm: bm, xjdwMc: mc });
}
const renderDw = () => {
return (
<Col span={9} key='dbcbr'>
<Form.Item label="接收单位" name='xjdwBm' rules={[{ required: true, message: '请选择下级单位!' }]} {...layout2}>
{/* 办理方式是督办 */}
<NextOrg noLoad onChange={onChangeOrg} />
</Form.Item>
<Form.Item
hidden
label="下级单位名称"
name="xjdwMc"
>
<Input />
</Form.Item>
</Col>
);
// if (blfs === BLFS.DB.value) {
// return (<Col span={9} key='dbcbr'>
// <Form.Item label="" name='xjdwBm' rules={[{ required: true, message: '' }]} {...layout2}>
// {/* */}
// <NextOrg noLoad onChange={onChangeOrg} />
// </Form.Item>
// <Form.Item
// hidden
// label=""
// name="xjdwMc"
// >
// <Input />
// </Form.Item>
// </Col>)
// }
// if (blfs === BLFS.ZB.value) {
// return (
// <Col span={9} key='zbcbr'>
// <Form.Item label="" name='xjdwBm' rules={[{ required: true, message: '' }]} {...layout2}>
// {/* */}
// <NextOrg onChange={onChangeOrg} />
// </Form.Item>
// <Form.Item
// hidden
// label=""
// name="xjdwMc"
// >
// <Input />
// </Form.Item>
// </Col>
// )
// }
}
const disabledDate = (current) => {
// console.log(newestInfo)
// console.log(current)
return current ? (current < moment(moment().add(-1, 'days')).endOf('days')) || current.isAfter(moment(Date.now()).add(29, 'days')) : false;
}
return (
<div>
<Spin spinning={loading}>
<Card title='派发'>
<Form
{...layout}
name="cxpf"
form={form}
initialValues={initFormData}
onFinish={onFinish}
onFinishFailed={onFinishFailed}
>
<Row>
<Col span={6}>
<Form.Item
label="预警流向"
{...layout1}
name="blfs"
rules={[{ required: true, message: '请选择预警流向!' }]}
>
<Select style={{ width: 120 }} onChange={changeYJLX} disabled={user.departmentOrgLevel === UserLevel.Town.value}>
{Object.keys(YJLX).map(key => {
return <Option key={key} value={YJLX[key].value}>{YJLX[key].name}</Option>
})}
</Select>
</Form.Item>
</Col>
<Form.Item
noStyle
shouldUpdate={(prevValues, currentValues) => prevValues.blfs !== currentValues.blfs}
>
{({ getFieldValue }) => {
return getFieldValue('blfs') === YJLX.XJBL.value ? (
<>
<Col span={8}>
<Form.Item
label="办理方式"
{...layout2}
name="nbfs"
>
<Radio.Group onChange={onChangeBLFS} disabled={newestInfo?.sjPfdwzxSl?.nbfs === BLFS.DB.value}>
{Object.keys(BLFS).map(key => {
return <Radio key={key} value={BLFS[key].value}>{BLFS[key].name}</Radio>
})}
</Radio.Group>
</Form.Item>
</Col>
<Form.Item
noStyle
shouldUpdate={(prevValues, currentValues) => (prevValues.nbfs !== currentValues.nbfs) || (prevValues.blfs !== currentValues.blfs) || (prevValues.xjdwBm !== currentValues.xjdwBm)}
>
{() => {
// return renderDw(getFieldValue('nbfs'))
return renderDw();
}}
</Form.Item>
</>
) : '';
}}
</Form.Item>
<Form.Item
noStyle
shouldUpdate={(prevValues, currentValues) => (prevValues.blfs !== currentValues.blfs) || (prevValues.spFs !== currentValues.spFs)}
>
{({ getFieldValue }) => {
return getFieldValue('blfs') === YJLX.BJBL.value && getFieldValue('spFs') === SPFS.ZJBL.value ?
<Col span={8}>
<Form.Item
{...layout2}
label="承办人"
name="cbr"
rules={[{ required: true, message: '请选择承办人' }]}
>
<Select onSelect={(value, item) => { form.setFieldsValue({ cbrMc: item.children }) }}>
{
global?.cbrList.map(item => <Option key={item.id} value={item.logingId}>{`${item.surname}${item.commonName}`}</Option>)
}
</Select>
</Form.Item>
<Form.Item
hidden
label="承办人名称"
name="cbrMc"
>
<Input />
</Form.Item>
</Col>
:
''
}}
</Form.Item>
</Row>
<Form.Item
label="受理意见"
name="slyj"
rules={[{ max: 200, message: '最多能输入200字!' }]}
>
<Input.TextArea />
</Form.Item>
<Row>
<Col span={6}>
<Form.Item
{...layout1}
label="反馈期限"
name="zcfkSj"
rules={[{ required: true, message: '请选择反馈期限!' }]}
>
<DatePicker disabledDate={disabledDate} onChange={(m, s) => changeData(s)} />
</Form.Item>
</Col>
{toDays !== '' ? <span style={{ marginLeft: 20, marginTop: 4 }}>距今<span style={{ margin: 6 }}>{toDays}</span></span> : ''}
</Row>
<Form.Item
label="附件"
name="wj"
>
<UploadBtn defList={newestInfo?.sjPfdwzxSl?.wj} sysToken={sysToken} onChange={newValues => {
form.setFieldsValue({ wj: newValues })
}} />
</Form.Item>
<Form.Item
label="问题简述"
name="wtjs"
rules={[{ max: 200, message: '最多能输入200字!' }]}
>
<Input.TextArea />
</Form.Item>
<Row style={{ borderTop: '1px solid #d9d9d9', paddingTop: 6 }}>
{/* <Col span={2}> <span >下一步</span></Col> */}
<Col span={12}>
<Form.Item
{...layoutSPFS}
label='审批方式'
// colon={false}
name="spFs"
rules={[{ required: true, message: '请选择审批方式!' }]}
>
<Radio.Group disabled={newestInfo?.sfSsf === 0}>
{Object.keys(SPFS).map(key => {
return <Radio key={key} value={SPFS[key].value}>{SPFS[key].name}</Radio>
})}
</Radio.Group>
</Form.Item>
</Col>
<Col span={12}>
<Form.Item
noStyle
shouldUpdate={(prevValues, currentValues) => prevValues.spFs !== currentValues.spFs}
>
{({ getFieldValue }) => {
return getFieldValue('spFs') === SPFS.LDSP.value ? (
<div>
<Form.Item
{...layoutSPFS}
label="审批人"
name="xjSpr"
rules={[{ required: true, message: '请选择审批人!' }]}
>
<Select onSelect={(value, item) => { form.setFieldsValue({ xjSprMc: item.children }) }}>
{
global?.sprList.map(item => <Option key={item.id} value={item.logingId}>{`${item.surname}${item.commonName}`}</Option>)
}
</Select>
</Form.Item>
<Form.Item
hidden
label="审批人名称"
name="xjSprMc"
>
<Input />
</Form.Item>
</div>
) : null;
}}
</Form.Item>
</Col>
</Row>
<Form.Item {...tailLayout}>
<Space>
<Button type="default" onClick={() => props.hideModal(null)}>
取消
</Button>
<Button type="primary" htmlType="submit">
确认
</Button>
</Space>
</Form.Item>
</Form>
</Card>
</Spin>
</div>
)
}
const mapStateToProps = ({ user, doing, global, loading }) => ({
user: user.currentUser,
doing,
global,
loading:
loading.effects['doing/fetchNewest'] ||
loading.effects['doing/fetchSpInfo'] ||
loading.effects['doing/fetchSavePF'] ||
false,
});
const mapDispatchToProps = dispatch => ({
//
fetchSprList(params) {
return dispatch({ type: 'global/fetchSprList', payload: { ...params } });
},
fetchCbrList(params) {
return dispatch({ type: 'global/fetchCbrList', payload: { ...params } });
},
fetchSavePF(params) {
return dispatch({ type: 'doing/fetchSavePF', payload: { ...params } });
},
//
fetchNewest(params) {
return dispatch({ type: 'doing/fetchNewest', payload: params });
},
fetchSpInfo(params) {
return dispatch({ type: 'doing/fetchSpInfo', payload: params });
},
});
export default connect(mapStateToProps, mapDispatchToProps)(PF);

0
src/components/CXPF/index.less

73
src/components/CZMX/FormModal/TableSelect.jsx

@ -0,0 +1,73 @@
import React, { useEffect, useState } from 'react';
import { Modal, Table, Input, Button, Pagination } from 'antd';
const { Search } = Input;
const TableSelect = (props) => {
const { getList, visible, handleClose, handleSetOrg } = props;
const [searchParams, setSearchParams] = useState({ page: 1, limit: 10, name: '' });
const [tableData, setTableData] = useState();
const columns = [
{
dataIndex: 'name',
key: 'name',
title: '单位名称',
width: '80%',
},
{
key: 'action',
title: '操作',
render: (text) => {
return (
<Button type="link" onClick={() => handleSelect(text)}>
选择
</Button>
);
},
},
];
const handleGetList = (params) => {
getList(params).then((res) => {
setTableData(res);
});
};
const onSearch = (value) => {
setSearchParams({ page: 1, limit: 10, name: value });
};
const onChange = (page, limit) => {
setSearchParams({ ...searchParams, page, limit });
};
const handleSelect = (org) => {
handleSetOrg(org.name);
};
useEffect(() => {
handleGetList(searchParams);
}, [searchParams]);
return (
<Modal width={620} visible={visible} onCancel={handleClose} title="选择单位" footer={false}>
<Search
placeholder="请输入单位名称关键词"
allowClear
enterButton
onSearch={onSearch}
style={{ marginBottom: 10 }}
/>
<Table
columns={columns}
dataSource={tableData?.records || []}
rowKey={(record) => record.id}
size="small"
pagination={false}
/>
<Pagination
size="small"
current={tableData?.current || 1}
pageSize={tableData?.size || 0}
total={tableData?.total || 0}
showQuickJumper
showLessItems
onChange={onChange}
/>
</Modal>
);
};
export default TableSelect;

332
src/components/CZMX/FormModal/index.jsx

@ -0,0 +1,332 @@
import React, { useEffect, useState } from 'react';
import { Modal, Button, Input, Form, Select, message, Radio, TreeSelect } from 'antd';
import UploadBtn from '@/components/UploadBtn';
import { CzqkList, IdCardReg } from '@/utils/constants';
import TableSelect from './TableSelect';
/**
* visible:弹窗状态
* handleClose:弹窗开关
*/
const layout = {
labelCol: { span: 5 },
wrapperCol: { span: 17 },
};
const { TextArea } = Input;
const FormModal = (props) => {
const {
id,
sysToken,
visible,
handleClose,
getTable,
fetchAddAJCZ,
fetchOrgTreeData,
fetchOrgDataByName,
CZLXList,
loading,
} = props;
const [form] = Form.useForm();
const [nowRadio, setNowRadio] = useState();
const [treeData, setTreeData] = useState();
const [value, setValue] = useState(undefined);
const [tableVisible, setTableVisible] = useState(false);
//
const handleCloseModal = () => {
handleClose();
form.resetFields();
};
//
const onFinish = (values) => {
const params = {
...values,
pfId: id,
};
console.log('params', params);
fetchAddAJCZ({ params, sysToken }).then((res) => {
if (res && res.resCode === 0) {
// message.success(res.resMsg);
getTable();
handleCloseModal();
} else {
message.error(res.resMsg);
}
});
};
//
const handleMakePoint = (list) => {
const arr = list?.map((item) => {
return {
...item,
pId: item?.upGovId,
title: item.name,
key: item.name,
value: item.name,
isLeaf: false,
};
});
return arr;
};
//
const handleToIsLeaf = (id, tree) => {
if (id) {
return tree?.map((i) => {
const item = {
...i,
};
if (i.id === id) {
item.isLeaf = true;
item.children = [];
} else if (i.children) {
item.children = handleMakeTree(id, i.children);
}
return item;
});
} else {
return tree;
}
};
//
const handleGetTree = (id = undefined) => {
fetchOrgTreeData({ id }).then((res) => {
if (res) setTreeData(handleMakePoint(res));
});
};
//
const handleMakeTree = (list, tree) => {
if (list && list.length) {
return tree?.map((i) => {
const item = {
...i,
};
if (i.id === list[0].pId) {
item.children = list;
} else if (i.children) {
item.children = handleMakeTree(list, i.children);
}
return item;
});
} else {
return tree;
}
};
//
const onLoadData = (treeNode) => {
return new Promise((resolve) => {
const { id } = treeNode.props;
fetchOrgTreeData({ id }).then((res) => {
if (res && res.length) {
// children
const newRes = handleMakePoint(res);
setTreeData(handleMakeTree(newRes, treeData));
resolve();
} else {
//
setTreeData(handleToIsLeaf(id, treeData));
resolve();
}
});
});
};
const onChange = (value) => {
setValue(value);
};
const handleSetOrg = (value) => {
form.setFieldsValue({
czDw: value,
});
setTableVisible(false);
};
const handleSearchOrgListByName = (params) => {
fetchOrgDataByName(params).then((res) => {
setNameList(handleMakePoint(res?.records));
});
};
// radio
useEffect(() => {
form.setFieldsValue({
czqk: '0',
});
setNowRadio('0');
handleGetTree();
}, []);
return (
<div>
<Modal title="添加" visible={visible} width={600} closable={false} footer={false}>
<Form form={form} {...layout} name="form" onFinish={onFinish}>
<Form.Item
label="处置情况"
name="czqk"
rules={[{ required: true, message: '请选择处置情况' }]}
>
<Radio.Group
onChange={(e) => {
setNowRadio(e.target.value);
}}
>
{CzqkList.map((i) => (
<Radio value={i.value} key={i.value}>
{i.text}
</Radio>
))}
</Radio.Group>
</Form.Item>
{nowRadio !== '0' ? (
<Form.Item
label="情况说明"
name="qksm"
rules={[
{ required: true, message: '请输入情况说明' },
{ max: 1000, message: '请输入不超过1000个字符' },
]}
>
<TextArea rows={4} />
</Form.Item>
) : (
''
)}
{nowRadio === '0' ? (
<Form.Item
label="处置类型"
name="czlx"
rules={[{ required: true, message: '请选择处置类型' }]}
>
<Select>
{CZLXList?.map((item) => {
return (
<Select.Option value={item.id} key={item.id}>
{item.mc}
</Select.Option>
);
})}
</Select>
</Form.Item>
) : (
''
)}
{nowRadio === '0' ? (
<Form.Item
label="姓名"
name="czMc"
rules={[
{ required: true, message: '请输入姓名' },
{ max: 128, message: '请输入不超过128个字符' },
]}
>
<Input />
</Form.Item>
) : (
''
)}
{nowRadio === '0' ? (
<Form.Item
label="身份证号"
name="czSfz"
rules={[
{ required: true, message: '请输入身份证号' },
{ pattern: IdCardReg, message: '请输入身份证号'}
]}
>
<Input />
</Form.Item>
) : (
''
)}
{nowRadio === '0' ? (
<Form.Item
label="警号"
name="czJh"
rules={[
{ required: true, message: '请输入警号' },
{ max: 32, message: '请输入不超过32个字符' },
]}
>
<Input />
</Form.Item>
) : (
''
)}
{nowRadio === '0' ? (
<div id="czdw">
<Form.Item
label="单位"
name="czDw"
rules={[{ required: true, message: '请选择单位' }]}
extra={
<a
onClick={() => {
setTableVisible(true);
console.log('aaa');
}}
>
点击搜索单位
</a>
}
>
<TreeSelect
getPopupContainer={() => document.getElementById('czdw')}
treeDataSimpleMode
style={{ width: '100%' }}
value={value}
dropdownStyle={{ maxHeight: 400, overflow: 'auto' }}
onChange={(e) => onChange(e)}
loadData={onLoadData}
treeData={treeData}
/>
</Form.Item>
</div>
) : (
''
)}
<Form.Item
label="附件"
name="files"
rules={[{ required: nowRadio === '0', message: '请选择附件' }]}
>
<UploadBtn
sysToken={sysToken}
onChange={(newValues) => {
form.setFieldsValue({ files: newValues });
}}
/>
</Form.Item>
<Form.Item>
<div style={{ width: 520, textAlign: 'right', marginTop: 20 }}>
<Button type="primary" htmlType="submit" loading={loading}>
确认
</Button>
&nbsp;
<Button onClick={handleCloseModal}>取消</Button>
</div>
</Form.Item>
</Form>
</Modal>
{tableVisible && (
<TableSelect
visible={tableVisible}
getList={fetchOrgDataByName}
handleClose={() => setTableVisible(false)}
handleSetOrg={handleSetOrg}
/>
)}
</div>
);
};
export default FormModal;

1
src/components/CZMX/README.md

@ -0,0 +1 @@
案件处置--处置明细

226
src/components/CZMX/index.jsx

@ -0,0 +1,226 @@
import React, { useState, useEffect } from 'react';
import { connect } from 'umi';
import { Button, Table, Popconfirm, message } from 'antd';
import { CzqkList } from '@/utils/constants';
import FormModal from './FormModal';
import styles from './index.less';
const CZBtn = (props) => {
const {
id,
sysToken,
fetchAJCZtable,
fetchAddAJCZ,
fetchDeleteAJCZ,
fetchDownloadFile,
fetchOrgTreeData,
fetchOrgDataByName,
CZLX,
onlyRead,
loading,
} = props;
const [visible, setVisible] = useState(false);
const [tableData, setTableData] = useState([]);
// const [CZLX, setCZLX] = useState([]);
const handleOpenModal = () => {
// fetchDictCZLX(sysToken).then((res) => {
// if (res && res.resCode === 0) {
// setCZLX(res.data);
// setVisible(true);
// }
// });
setVisible(true);
};
const handleCloseModal = () => {
setVisible(false);
};
const handleGetTable = () => {
fetchAJCZtable({ id, sysToken }).then((res) => {
setTableData(res);
});
};
const handleDelete = (id) => {
fetchDeleteAJCZ({ id, sysToken }).then((res) => {
if (res && res.resCode === 0) {
message.success(res.resMsg);
handleGetTable();
} else {
message.error(res.resMsg);
}
});
};
useEffect(() => {
handleGetTable();
// fetchCzlx();
}, []);
//
const handleDownload = (file) => {
const params = {
mc: file.wjMc,
path: file.wjPath,
url: file.wjUrl,
};
fetchDownloadFile({ params, sysToken });
};
const getCZLXMc = (text) => {
const p = [];
CZLX?.forEach((item) => {
if (item.id === Number(text)) {
p.push(item.mc);
}
});
return p[0];
};
const columns = [
{
title: '处置类型',
dataIndex: 'czlx',
key: '',
render: (text) => {
return <span>{getCZLXMc(text)}</span>;
},
},
{
title: '处置情况',
dataIndex: 'czqk',
width: '10%',
render: (text) => CzqkList.filter((i) => i.value === String(text))[0]?.text,
},
{
title: '情况说明',
dataIndex: 'qksm',
width: '15%',
},
{
title: '姓名',
dataIndex: 'czMc',
key: 'czMc',
},
{
title: '身份证号',
dataIndex: 'czSfz',
key: 'czSfz',
},
{
title: '警号',
dataIndex: 'czJh',
key: 'czJh',
},
{
title: '单位',
dataIndex: 'czDw',
key: 'czDw',
},
{
title: '法律文书',
dataIndex: 'flwsMc',
key: 'flwsMc',
render: (text, record) => {
return record?.wjList?.map((file, index) => {
return (
<a key={file.id} onClick={() => handleDownload(file)}>
{file.wjMc}
{index === record?.wjList?.length - 1 ? '' : ';'}
</a>
);
});
},
},
{
title: '操作',
key: 'action',
render: (text, record) => {
if (onlyRead) {
return (
<a type="text" disabled={onlyRead}>
删除
</a>
);
} else {
return (
<Popconfirm
placement="left"
title="确定删除吗?"
onConfirm={() => handleDelete(record.id)}
okText="确定"
cancelText="取消"
>
<a type="text" disabled={onlyRead}>
删除
</a>
</Popconfirm>
);
}
},
},
];
return (
<div>
<div className={styles.titleAndButton}>
<div className={styles.title}>处置明细</div>
{!onlyRead && (
<div className={styles.button}>
<Button onClick={handleOpenModal} type="primary" disabled={onlyRead} loading={loading}>
添加处置信息
</Button>
</div>
)}
</div>
<div>
<Table
rowKey="id"
columns={columns}
dataSource={tableData || []}
pagination={false}
scroll={{ x: 1400 }}
/>
</div>
{visible && (
<FormModal
id={id}
sysToken={sysToken}
visible={visible}
CZLXList={CZLX}
handleClose={handleCloseModal}
getTable={handleGetTable}
fetchAddAJCZ={fetchAddAJCZ}
fetchOrgTreeData={fetchOrgTreeData}
fetchOrgDataByName={fetchOrgDataByName}
loading={loading}
/>
)}
</div>
);
};
const mapStateToProps = ({ doing, global, loading }) => ({
...doing,
...global,
loading: loading.effects['doing/fetchAddAJCZ'] || false,
});
const mapDispatchToProps = (dispatch) => ({
fetchAJCZtable(params) {
return dispatch({ type: 'doing/fetchAJCZtable', payload: { ...params } });
},
fetchAddAJCZ(params) {
return dispatch({ type: 'doing/fetchAddAJCZ', payload: { ...params } });
},
fetchDeleteAJCZ(params) {
return dispatch({ type: 'doing/fetchDeleteAJCZ', payload: { ...params } });
},
fetchDownloadFile(params) {
return dispatch({ type: 'doing/fetchDownloadFile', payload: { ...params } });
},
fetchOrgTreeData(params) {
return dispatch({ type: 'global/fetchOrgTreeData', payload: { ...params } });
},
fetchOrgDataByName(params) {
return dispatch({ type: 'global/fetchOrgDataByName', payload: { ...params } });
},
});
export default connect(mapStateToProps, mapDispatchToProps)(CZBtn);

16
src/components/CZMX/index.less

@ -0,0 +1,16 @@
.titleAndButton {
display: flex;
justify-content: space-between;
height: 50px;
line-height: 50px;
.title {
color: cornflowerblue;
font-weight: 600;
}
.button {
color: white;
}
}
.submit {
text-align: right;
}

109
src/components/CardList/index.jsx

@ -0,0 +1,109 @@
import React, { useState } from 'react';
import moment from 'moment';
import { connect } from 'umi';
import { Row, Col, Button, message } from 'antd';
import FormModal from '@/components/FormModal';
import styles from './index.less';
import commonDownLoad from '@/utils/downloadFile';
const CardList = (props) => {
const {
sysToken,
sourceType,
dataSource,
fetchDeleteHCZJ,
getTable,
fetchEditHCZJ,
onlyRead,
} = props;
const [visible, setVisible] = useState(false);
const [record, setRecord] = useState();
const handleDelete = (id) => {
fetchDeleteHCZJ({ id, sysToken }).then((res) => {
if (res && res.resCode === 0) {
message.success(res.resMsg);
getTable();
} else {
message.error(res.resMsg);
}
});
};
const handleOpenModal = (item) => {
setRecord(item);
setVisible(true);
};
const handleCloseModal = () => {
setVisible(false);
setRecord();
};
const renderList = (arr) => {
return arr?.map((item) => {
return (
<div className={styles.card} key={item.id}>
<Row gutter={[0, 16]}>
<Col span={3} align="right">
{sourceType === 'bg' ? '报告信息:' : '证据信息:'}
</Col>
<Col span={21}>{sourceType === 'bg' ? item.bgXx : item.zjXx}</Col>
<Col span={3} align="right">
文件
</Col>
<Col span={21}>
{item?.wjList?.map((i, index) => {
return (
<a key={index} onClick={() => commonDownLoad(i, sysToken)}>
{i.wjMc}
{index === item?.wjList?.length - 1 ? '' : ';'}
</a>
);
})}
</Col>
<Col span={3} align="right">
补充时间
</Col>
<Col span={5}>
<span>{moment(item.bcSj).format('YYYY-MM-DD HH:mm:ss')}</span>
</Col>
<Col span={3} align="right">
补充人
</Col>
<Col span={5}>{item.bcrMc}</Col>
<Col span={3} align="right">
补充单位
</Col>
<Col span={5}>{item.bcdwMc}</Col>
{
!onlyRead &&
<Col>
<Button size='small' type="primary" onClick={() => handleOpenModal(item)} disabled={onlyRead}>
编辑
</Button>
&nbsp;
<Button size='small' onClick={() => handleDelete(item.id)} disabled={onlyRead}>
{sourceType === 'bg' ? '报告撤回' : '证据撤回'}
</Button>
</Col>
}
</Row>
{visible && (
<FormModal
record={record}
visible={visible}
setVisible={setVisible}
getTable={getTable}
fetchEditHCZJ={fetchEditHCZJ}
handleClose={handleCloseModal}
sourceType={'zj'}
actionType={'edit'}
sysToken={sysToken}
/>
)}
</div>
);
});
};
return <div>{renderList(dataSource)}</div>;
};
export default connect()(CardList);

5
src/components/CardList/index.less

@ -0,0 +1,5 @@
.card {
padding: 10px 5px 0;
border-top: 1px solid #f1f1f1;
border-bottom: 1px solid #f1f1f1;
}

146
src/components/FormModal/index.jsx

@ -0,0 +1,146 @@
import React, { useState, useEffect } from 'react';
import { Modal, Button, Input, Form, message } from 'antd';
import UploadBtn from '@/components/UploadBtn';
/**
* visible:弹窗状态
* handleClose:弹窗开关
* sourceType:来源 bg-核查报告 zj-核查证据
*/
const layout = {
labelCol: { span: 3 },
wrapperCol: { span: 19 },
};
const FormModal = (props) => {
const {
id,
sysToken,
visible,
handleClose,
actionType,
sourceType,
fetchAddHCZJ,
fetchEditHCZJ,
fetchAddHCBG,
getTable,
record,
} = props;
const [file, setFile] = useState([]);
const { TextArea } = Input;
const [form] = Form.useForm();
const handleCloseModal = () => {
handleClose();
form.resetFields();
};
useEffect(() => {
if (record?.id) {
form.setFieldsValue({
files: record.wjList,
zjXx: record.zjXx,
});
setFile(record.wjList);
}
}, []);
const fileCheck = () => {
if (!file?.length) {
return Promise.reject(new Error('请选择文件'));
}
return Promise.resolve();
};
const onFinish = (values) => {
if (sourceType === 'zj' && actionType === 'add') {
const params = {
...values,
pfId: id,
};
fetchAddHCZJ({ params, sysToken }).then((data) => {
if (data && data.resCode === 0) {
message.success(data.resMsg);
handleCloseModal();
getTable();
} else {
message.error(data.resMsg);
}
});
}
if (sourceType === 'zj' && actionType === 'edit') {
const params = {
...values,
id: record.id,
};
fetchEditHCZJ({ params, sysToken }).then((data) => {
if (data && data.resCode === 0) {
message.success(data.resMsg);
handleCloseModal();
getTable();
} else {
message.error(data.resMsg);
}
});
}
if (sourceType === 'bg') {
const pf = [id];
const params = {
...values,
pfIds: pf,
};
fetchAddHCBG({ params, sysToken }).then((data) => {
if (data && data.resCode === 0) {
message.success(data.resMsg);
handleCloseModal();
getTable();
} else {
message.error(data.resMsg);
}
});
}
};
return (
<Modal
title={actionType === 'add' ? '添加' : '编辑'}
visible={visible}
width={750}
closable={false}
footer={false}
>
<Form form={form} {...layout} name="form" onFinish={onFinish}>
{sourceType === 'zj' && (
<Form.Item
label={sourceType === 'bg' ? '报告信息' : '证据信息'}
name="zjXx"
rules={[
{ required: true, message: '请输入信息' },
{ max: 512, message: '请输入不超过512个字符' },
]}
>
<TextArea rows={5} />
</Form.Item>
)}
<Form.Item label="附件" name="files" rules={[{ required: true }]}>
<UploadBtn
defList={record?.id ? record.wjList : null}
sysToken={sysToken}
config={{ multiple: true }}
disable={sourceType === 'bg' && file?.length > 1}
onChange={(newValues) => {
form.setFieldsValue({ files: newValues });
setFile(newValues);
}}
/>
</Form.Item>
<Form.Item>
<div style={{ width: 600, textAlign: 'right', marginTop: 20 }}>
<Button type="primary" htmlType="submit">
确认
</Button>
&nbsp;
<Button onClick={handleCloseModal}>取消</Button>
</div>
</Form.Item>
</Form>
</Modal>
);
};
export default FormModal;

1
src/components/GXBG/README.md

@ -0,0 +1 @@
管辖变更

86
src/components/GXBG/index.jsx

@ -0,0 +1,86 @@
import React, { useState, useEffect } from 'react';
import { connect } from 'umi';
import { Form, Button, Modal, Spin, Select, Input } from 'antd';
const { Option } = Select;
const { TextArea } = Input;
//
const HeaderToDo = (props) => {
const [form] = Form.useForm();
const [visible, setVisible] = useState(false);
useEffect(() => {
}, []);
const onFinish = values => {
console.log('vla', values);
}
return (
<div>
<Spin spinning={false}>
<Button onClick={() => setVisible(true)}>管辖变更</Button>
<Modal
visible={visible}
>
<Form
name="gxbg"
form={form}
// initialValues={initFormData}
onFinish={onFinish}
>
<Form.Item
label="变更原因"
name="bgyy"
rules={[{ required: true, message: '请选择变更原因!' }]}
>
{/* <Select onSelect={(value, item) => { form.setFieldsValue({ ssqkMc: item.mc }) }}>
{Object.keys(CSQK).map((key) => {
return (
<Option key={key} mc={CSQK[key].name} value={CSQK[key].value} >
{CSQK[key].name}
</Option>
);
})}
</Select> */}
</Form.Item>
<Form.Item
label="描述"
name="ms"
rules={[{ required: true, message: '请填写处理意见!' }]}
>
<TextArea rows={3} />
</Form.Item>
<Form.Item>
<Button >
保存
</Button>
<Button type="primary" htmlType="submit">
保存
</Button>
</Form.Item>
</Form>
</Modal>
</Spin>
</div>
)
}
const mapStateToProps = ({ doing }) => ({
...doing,
});
const mapDispatchToProps = (dispatch) => ({
fetchJDGZInfo(params) {
return dispatch({ type: 'doing/fetchJDGZInfo', payload: { ...params } });
},
});
export default connect(mapStateToProps, mapDispatchToProps)(HeaderToDo);

1
src/components/GXBG/index.less

@ -0,0 +1 @@

80
src/components/GlobalHeader/AvatarDropdown.jsx

@ -0,0 +1,80 @@
import { LogoutOutlined, SettingOutlined, UserOutlined } from '@ant-design/icons';
import { Avatar, Menu, Spin } from 'antd';
import React from 'react';
import { history, connect } from 'umi';
import HeaderDropdown from '../HeaderDropdown';
import styles from './index.less';
class AvatarDropdown extends React.Component {
onMenuClick = event => {
const { key } = event;
if (key === 'logout') {
const { dispatch } = this.props;
if (dispatch) {
dispatch({
type: 'user/getLogout',
});
}
return;
}
history.push(`/account/${key}`);
};
render() {
const {
currentUser = {
avatar: '',
name: '',
},
menu,
} = this.props;
const menuHeaderDropdown = (
<Menu className={styles.menu} selectedKeys={[]} onClick={this.onMenuClick}>
{menu && (
<Menu.Item key="center">
<UserOutlined />
个人中心
</Menu.Item>
)}
{menu && (
<Menu.Item key="settings">
<SettingOutlined />
个人设置
</Menu.Item>
)}
{menu && <Menu.Divider />}
<Menu.Item key="logout">
<LogoutOutlined />
退出登录
</Menu.Item>
</Menu>
);
return currentUser && currentUser.name ? (
<HeaderDropdown overlay={menuHeaderDropdown}>
<span className={`${styles.action} ${styles.account}`}>
<Avatar size="small" className={styles.avatar} src={currentUser.avatar} alt="avatar" />
<span className={`${styles.name} anticon`}>{currentUser.name}</span>
</span>
</HeaderDropdown>
) : (
<span className={`${styles.action} ${styles.account}`}>
<Spin
size="small"
style={{
marginLeft: 8,
marginRight: 8,
}}
/>
</span>
);
}
}
export default connect(({ user }) => ({
currentUser: user.currentUser,
}))(AvatarDropdown);

156
src/components/GlobalHeader/NoticeIconView.jsx

@ -0,0 +1,156 @@
import React, { Component } from 'react';
import { connect } from 'umi';
import { Tag, message } from 'antd';
import groupBy from 'lodash/groupBy';
import moment from 'moment';
import NoticeIcon from '../NoticeIcon';
import styles from './index.less';
class GlobalHeaderRight extends Component {
componentDidMount() {
const { dispatch } = this.props;
if (dispatch) {
dispatch({
type: 'global/fetchNotices',
});
}
}
changeReadState = clickedItem => {
const { id } = clickedItem;
const { dispatch } = this.props;
if (dispatch) {
dispatch({
type: 'global/changeNoticeReadState',
payload: id,
});
}
};
handleNoticeClear = (title, key) => {
const { dispatch } = this.props;
message.success(`${'清空了'} ${title}`);
if (dispatch) {
dispatch({
type: 'global/clearNotices',
payload: key,
});
}
};
getNoticeData = () => {
const { notices = [] } = this.props;
if (!notices || notices.length === 0 || !Array.isArray(notices)) {
return {};
}
const newNotices = notices.map(notice => {
const newNotice = { ...notice };
if (newNotice.datetime) {
newNotice.datetime = moment(notice.datetime).fromNow();
}
if (newNotice.id) {
newNotice.key = newNotice.id;
}
if (newNotice.extra && newNotice.status) {
const color = {
todo: '',
processing: 'blue',
urgent: 'red',
doing: 'gold',
}[newNotice.status];
newNotice.extra = (
<Tag
color={color}
style={{
marginRight: 0,
}}
>
{newNotice.extra}
</Tag>
);
}
return newNotice;
});
return groupBy(newNotices, 'type');
};
getUnreadData = noticeData => {
const unreadMsg = {};
Object.keys(noticeData).forEach(key => {
const value = noticeData[key];
if (!unreadMsg[key]) {
unreadMsg[key] = 0;
}
if (Array.isArray(value)) {
unreadMsg[key] = value.filter(item => !item.read).length;
}
});
return unreadMsg;
};
render() {
const { currentUser, fetchingNotices, onNoticeVisibleChange } = this.props;
const noticeData = this.getNoticeData();
const unreadMsg = this.getUnreadData(noticeData);
return (
<NoticeIcon
className={styles.action}
count={currentUser && currentUser.unreadCount}
onItemClick={item => {
this.changeReadState(item);
}}
loading={fetchingNotices}
clearText="清空"
viewMoreText="查看更多"
onClear={this.handleNoticeClear}
onPopupVisibleChange={onNoticeVisibleChange}
onViewMore={() => message.info('Click on view more')}
clearClose
>
<NoticeIcon.Tab
tabKey="notification"
count={unreadMsg.notification}
list={noticeData.notification}
title="通知"
emptyText="你已查看所有通知"
showViewMore
/>
<NoticeIcon.Tab
tabKey="message"
count={unreadMsg.message}
list={noticeData.message}
title="消息"
emptyText="您已读完所有消息"
showViewMore
/>
<NoticeIcon.Tab
tabKey="event"
title="待办"
emptyText="你已完成所有待办"
count={unreadMsg.event}
list={noticeData.event}
showViewMore
/>
</NoticeIcon>
);
}
}
export default connect(({ user, global, loading }) => ({
currentUser: user.currentUser,
collapsed: global.collapsed,
fetchingMoreNotices: loading.effects['global/fetchMoreNotices'],
fetchingNotices: loading.effects['global/fetchNotices'],
notices: global.notices,
}))(GlobalHeaderRight);

42
src/components/GlobalHeader/RightContent.jsx

@ -0,0 +1,42 @@
import { Tag } from 'antd';
import React from 'react';
import { connect } from 'umi';
import HeaderMsg from '../HeaderMsg';
import HeaderToDo from '../HeaderToDo';
import Avatar from './AvatarDropdown';
import styles from './index.less';
const ENVTagColor = {
dev: 'orange',
test: 'green',
pre: '#87d068',
};
const GlobalHeaderRight = props => {
const { theme, layout } = props;
let className = styles.right;
if (theme === 'dark' && layout === 'top') {
className = `${styles.right} ${styles.dark}`;
}
return (
<div className={className}>
<HeaderMsg />
<HeaderToDo />
{/* <Avatar /> */}
{/* {REACT_APP_ENV && (
<span>
<Tag color={ENVTagColor[REACT_APP_ENV]}>{REACT_APP_ENV}</Tag>
</span>
)} */}
</div>
);
};
export default connect(({ settings }) => ({
theme: settings.navTheme,
layout: settings.layout,
}))(GlobalHeaderRight);

86
src/components/GlobalHeader/index.less

@ -0,0 +1,86 @@
@import '~antd/es/style/themes/default.less';
@pro-header-hover-bg: rgba(0, 0, 0, 0.025);
.menu {
:global(.anticon) {
margin-right: 8px;
}
:global(.ant-dropdown-menu-item) {
min-width: 160px;
}
:global(.ant-pro-global-header) {
background: red;
}
}
.right {
display: flex;
float: right;
height: 20px;
margin-top: 15px;
margin-left: auto;
// overflow: hidden;
.action {
display: flex;
align-items: center;
height: 100%;
padding: 0 12px;
cursor: pointer;
transition: all 0.3s;
> span {
vertical-align: middle;
}
&:hover {
background: @pro-header-hover-bg;
}
&:global(.opened) {
background: @pro-header-hover-bg;
}
}
.search {
padding: 0 12px;
&:hover {
background: transparent;
}
}
.account {
.avatar {
margin: ~'calc((@{layout-header-height} - 24px) / 2)' 0;
margin-right: 8px;
color: @primary-color;
vertical-align: top;
background: rgba(255, 255, 255, 0.85);
}
}
}
.dark {
.action {
color: rgba(255, 255, 255, 0.85);
> span {
color: rgba(255, 255, 255, 0.85);
}
&:hover,
&:global(.opened) {
background: @primary-color;
}
}
}
:global(.ant-pro-global-header) {
.dark {
.action {
color: @text-color;
> span {
color: @text-color;
}
&:hover {
color: rgba(255, 255, 255, 0.85);
> span {
color: rgba(255, 255, 255, 0.85);
}
}
}
}
}

1
src/components/HCBG/README.md

@ -0,0 +1 @@
核查报告

151
src/components/HCBG/index.jsx

@ -0,0 +1,151 @@
import React, { useState, useEffect } from 'react';
import { connect } from 'umi';
import moment from 'moment';
import { Card, Button, Table, message } from 'antd';
import FormModal from '@/components/FormModal';
const HCBG = (props) => {
const {
id,
sysToken,
fetchHCBGtable,
fetchDeleteHCBG,
fetchAddHCBG,
fetchDownloadFile,
onlyRead,
} = props;
const [visible, setVisible] = useState(false);
const [dataSource, setDataSource] = useState([]);
const getTable = () => {
fetchHCBGtable({ pfId: id, sysToken }).then((res) => {
setDataSource(res);
});
};
useEffect(() => {
getTable();
}, []);
const handleOpenModal = () => {
setVisible(true);
};
const handleCloseModal = () => {
setVisible(false);
};
const handleDeleteBG = (id) => {
fetchDeleteHCBG({ id, sysToken }).then((res) => {
if (res && res.resCode === 0) {
message.success(res.resMsg);
getTable();
} else {
message.error(res.resMsg);
}
});
};
const handleDownload = (file) => {
const params = {
mc: file.wjMc,
path: file.wjPath,
url: file.wjUrl,
};
fetchDownloadFile({ params, sysToken });
};
const columns = [
{
key: 'id',
title: '序号',
dataIndex: 'id',
render: (t, r, i) => i + 1
},
{
key: 'wjMc',
title: '文件名称',
dataIndex: 'wjMc',
render: (text, record) => {
return record?.wjList?.map((file, index) => {
return (
<a key={file.id} onClick={() => handleDownload(file)}>
{file.wjMc}
{index === record?.wjList?.length - 1 ? '' : ';'}
</a>
);
});
},
},
{
key: 'bcrMc',
title: '补充人',
dataIndex: 'bcrMc',
},
{
key: 'bcrDwMc',
title: '补充单位',
dataIndex: 'bcrDwMc',
},
{
key: 'bcSj',
title: '补充时间',
dataIndex: 'bcSj',
render: (text) => {
return <span>{moment(text).format('YYYY-MM-DD HH:mm:ss')}</span>;
},
},
{
key: 'action',
render: (text, record) => {
return (
<a onClick={() => onlyRead ? null : handleDeleteBG(record.id)} disabled={onlyRead}>
删除
</a>
);
},
},
];
return (
<Card title="核查报告">
{!onlyRead && (
<div className="rightButton">
<Button type="primary" onClick={handleOpenModal}>
上传核查报告
</Button>
</div>
)}
<div>
<Table rowKey={(record) => record?.id || null} columns={columns} dataSource={dataSource || []} pagination={false} />
</div>
{visible && (
<FormModal
id={id}
visible={visible}
handleClose={handleCloseModal}
sourceType={'bg'}
actionType={'add'}
fetchAddHCBG={fetchAddHCBG}
sysToken={sysToken}
getTable={getTable}
/>
)}
</Card>
);
};
const mapStateToProps = ({ doing }) => ({
...doing,
});
const mapDispatchToProps = (dispatch) => ({
fetchHCBGtable(params) {
return dispatch({ type: 'doing/fetchHCBGtable', payload: { ...params } });
},
fetchAddHCBG(params) {
return dispatch({ type: 'doing/fetchAddHCBG', payload: { ...params } });
},
fetchDeleteHCBG(params) {
return dispatch({ type: 'doing/fetchDeleteHCBG', payload: { ...params } });
},
fetchDownloadFile(params) {
return dispatch({ type: 'doing/fetchDownloadFile', payload: { ...params } });
},
});
export default connect(mapStateToProps, mapDispatchToProps)(HCBG);

1
src/components/HCZJ/README.md

@ -0,0 +1 @@
核查证据

92
src/components/HCZJ/index.jsx

@ -0,0 +1,92 @@
import React, { useState, useEffect } from 'react';
import { connect } from 'umi';
import { Card, Button } from 'antd';
import FormModal from '@/components/FormModal';
import CardList from '@/components/CardList';
const HCZJ = (props) => {
const {
id,
sysToken,
fetchHCZJtable,
fetchAddHCZJ,
fetchEditHCZJ,
fetchDeleteHCZJ,
onlyRead,
} = props;
const [visible, setVisible] = useState(false);
const [dataList, setDataList] = useState([]);
const getTable = () => {
fetchHCZJtable({ pfId: id, sysToken }).then((res) => {
if (res) {
setDataList(res);
}
});
};
useEffect(() => {
getTable();
}, []);
const handleOpenModal = () => {
setVisible(true);
};
const handleCloseModal = () => {
setVisible(false);
};
return (
<Card title="核查证据">
{
!onlyRead &&
<div className="rightButton">
<Button type="primary" onClick={handleOpenModal} >
上传核查证据
</Button>
</div>
}
<div>
<CardList
onlyRead={onlyRead}
sourceType={'zj'}
dataSource={dataList}
fetchDeleteHCZJ={fetchDeleteHCZJ}
fetchEditHCZJ={fetchEditHCZJ}
getTable={getTable}
sysToken={sysToken}
/>
</div>
{visible && (
<FormModal
visible={visible}
id={id}
sysToken={sysToken}
handleClose={handleCloseModal}
sourceType={'zj'}
actionType={'add'}
fetchAddHCZJ={fetchAddHCZJ}
getTable={getTable}
/>
)}
</Card>
);
};
const mapStateToProps = ({ doing }) => ({
...doing,
});
const mapDispatchToProps = (dispatch) => ({
fetchHCZJtable(params) {
return dispatch({ type: 'doing/fetchHCZJtable', payload: { ...params } });
},
fetchAddHCZJ(params) {
return dispatch({ type: 'doing/fetchAddHCZJ', payload: { ...params } });
},
fetchEditHCZJ(params) {
return dispatch({ type: 'doing/fetchEditHCZJ', payload: { ...params } });
},
fetchDeleteHCZJ(params) {
return dispatch({ type: 'doing/fetchDeleteHCZJ', payload: { ...params } });
},
});
export default connect(mapStateToProps, mapDispatchToProps)(HCZJ);

10
src/components/HeaderDropdown/index.jsx

@ -0,0 +1,10 @@
import { Dropdown } from 'antd';
import React from 'react';
import classNames from 'classnames';
import styles from './index.less';
const HeaderDropdown = ({ overlayClassName: cls, ...restProps }) => (
<Dropdown overlayClassName={classNames(styles.container, cls)} {...restProps} />
);
export default HeaderDropdown;

16
src/components/HeaderDropdown/index.less

@ -0,0 +1,16 @@
@import '~antd/es/style/themes/default.less';
.container > * {
background-color: @popover-bg;
border-radius: 4px;
box-shadow: @shadow-1-down;
}
@media screen and (max-width: @screen-xs) {
.container {
width: 100% !important;
}
.container > * {
border-radius: 0 !important;
}
}

1
src/components/HeaderMsg/README.md

@ -0,0 +1 @@
头部-消息

387
src/components/HeaderMsg/index.jsx

@ -0,0 +1,387 @@
import React, { useState, useEffect } from 'react';
import { connect } from 'umi';
import { Popover, Badge, Table, Button, message, Tooltip, Modal, Tabs } from 'antd';
import { BellOutlined } from '@ant-design/icons';
import CK from '../Tabs-CK';
import styles from './index.less';
import { platformLevel } from '@/utils/constants';
//
const HeaderToDo = (props) => {
const { isLocationInBu, fetchMsgList, fetchSetIsReaded, fetchReadOnce, fetchGetDqXx, locationType } = props;
// debugger;
console.log(platformLevel['BU'])
const sysToken = isLocationInBu ? '' : 'bu'; // sysToken,
const { TabPane } = Tabs;
const [count, setCount] = useState(0);
const [visible, setVisible] = useState(false);
const [tabVisible, setTabVisible] = useState(false);
const [nowTab, setNowTab] = useState(0); // 0- 1-
const [buBtn, setBuBtn] = useState(0); // 1- 0-
const [shBtn, setShBtn] = useState(0); // 1- 0-
const [buSearchParams, setBuSearchParams] = useState({ page: 1, isRead: buBtn });
const [shSearchParams, setShSearchParams] = useState({ page: 1, isRead: shBtn });
const [shiSearchParams, setShiSearchParams] = useState({ page: 1, isRead: shBtn });
const [buTableData, setBuTableData] = useState([]);
const [shTableData, setShTableData] = useState([]);
const [shiTableData, setShiTableData] = useState([]);
const [showId, setShowId] = useState(); // id
const [showInfo, setShowInfo] = useState([]); // info
// /
const handleIsRead = (type) => {
if (type === 1) {
// sysToken
setShBtn(Number(!shBtn));
setShSearchParams({ page: 1, isRead: Number(!shBtn) });
}
if (type === 0) {
// &sysToken
setBuBtn(Number(!buBtn));
setBuSearchParams({ page: 1, isRead: Number(!buBtn) });
}
};
//
const changeBuPage = (pagination) => {
setBuSearchParams({ ...buSearchParams, page: pagination });
};
//
const changeShPage = (pagination) => {
setShSearchParams({ ...shSearchParams, page: pagination });
};
//
const changeShiPage = (pagination) => {
setShiSearchParams({ ...shiSearchParams, page: pagination });
};
//
const handleVisibleChange = () => {
setVisible(!visible);
};
//
const handleAllRead = () => {
if (nowTab === 1) {
fetchSetIsReaded('').then((res) => {
if (res && res.resCode === 0) {
getTable({ page: 1, isRead: buBtn }, { page: 1, isRead: shBtn });
}
});
}
if (nowTab === 0) {
fetchSetIsReaded(sysToken).then((res) => {
if (res && res.resCode === 0) {
getTable({ page: 1, isRead: buBtn }, { page: 1, isRead: shBtn });
}
});
}
};
// pageInfo
const getTable = (buSearch, shSearch, shiSearch) => {
if (sysToken === 'bu') {
//
let psh = new Promise(function (resolve, reject) {
const search = {
params: locationType === platformLevel['SHENG'] ? { ...shSearch } : {...shiSearch},
sysToken: '',
};
fetchMsgList(search).then((res) => {
if (res && res.resCode === 0) {
resolve(res.data);
}
});
});
let pbu = new Promise(function (resolve, reject) {
const search = {
params: { ...buSearch },
sysToken,
};
fetchMsgList(search).then((res) => {
if (res && res.resCode === 0) {
resolve(res.data);
}
});
});
let pshi = new Promise(function (resolve, reject) {
const search = {
params: { ...shSearch },
sysToken: 'sheng',
};
fetchMsgList(search).then((res) => {
if (res && res.resCode === 0) {
resolve(res.data);
}
});
});
if(locationType === platformLevel['SHENG']){
// (bu)()
Promise.all([psh, pbu]).then(function (results) {
const num = Number(results[0].unread) + Number(results[1].unread);
setCount(num);
setBuTableData(results[1].list);
setShTableData(results[0].list);
});
}
if(locationType === platformLevel['SHI']){
Promise.all([psh, pbu, pshi]).then(function (results) {
console.log("results",results);
const num = Number(results[0].unread) + Number(results[1].unread)+ Number(results[2].unread);
setCount(num);
setShiTableData(results[0].list);
setBuTableData(results[1].list);
setShTableData(results[2].list);
});
}
}
if (sysToken === '') {
// sysToken
const search = {
params: { ...buSearch },
sysToken,
};
fetchMsgList(search).then((res) => {
if (res && res.resCode === 0) {
setCount(res.data.unread);
setBuTableData(res.data.list);
}
});
}
};
//
const clickItem = (record) => {
const { pfId, id } = record;
setShowId(pfId);
if (nowTab === 1) {
// 穿sysToken
const p = {
id: pfId,
sysToken: '',
};
fetchGetDqXx(p).then((res) => {
if (res && res.resCode === 0) {
setShowInfo(res.data);
setVisible(false);
setTabVisible(true);
fetchReadOnce({ id, sysToken: '' }).then((response) => {
if (response && response.resCode === 0) {
getTable({ page: 1, isRead: buBtn }, { page: 1, isRead: shBtn });
}
});
}
});
}
if (nowTab === 0) {
// &sysToken
fetchGetDqXx({ id: pfId, sysToken }).then((res) => {
if (res && res.resCode === 0) {
setShowInfo(res.data);
setVisible(false);
setTabVisible(true);
fetchReadOnce({ id, sysToken }).then((response) => {
if (response && response.resCode === 0) {
getTable({ page: 1, isRead: buBtn }, { page: 1, isRead: shBtn });
}
});
}
});
}
};
//
const columns = [
{
title: '编号',
dataIndex: 'xxnr',
width: '40%',
render: (text, item) => {
return (
<Tooltip placement="topLeft" title={text}>
<Button type="link" onClick={() => clickItem(item)}>
<div className={styles.xxnr}>{text}</div>
</Button>
</Tooltip>
);
},
},
{
title: '消息类型',
dataIndex: 'xxLxMc',
width: '20%',
render: (text, item) => {
return (
<Tooltip placement="topLeft" title={text}>
{text}
</Tooltip>
);
},
},
{
title: '时间',
dataIndex: 'createTime',
width: '30%',
render: (text) => {
return (
<Tooltip placement="topLeft" title={text}>
{text}
</Tooltip>
);
},
},
{
title: '状态',
dataIndex: 'sfyd',
width: '10%',
render: (text) => {
return text == 1 ? '已读' : '未读';
},
},
];
//
const renderContent = () => {
console.log(sysToken === 'bu' && locationType === platformLevel['SHI']);
return (
<div style={{ width: 700 }}>
<Tabs
tabBarExtraContent={
nowTab === 0 ? (
<div style={{ textAlign: 'right' }}>
<Button onClick={handleAllRead}>全部标为已读</Button>
<Button type={buBtn === 0 ? 'primary' : ''} onClick={() => handleIsRead(0)}>
所有未读
</Button>
</div>
) : (
<div style={{ textAlign: 'right' }}>
<Button onClick={handleAllRead}>全部标为已读</Button>
<Button type={shBtn === 0 ? 'primary' : ''} onClick={() => handleIsRead(1)}>
所有未读
</Button>
</div>
)
}
onTabClick={(key) => {
setNowTab(Number(key));
}}
>
<TabPane tab="部级平台" key={0}>
<Table
columns={columns}
dataSource={buTableData?.records}
rowKey={(record) => record.id}
showHeader={false}
bordered={false}
pagination={{
current: buTableData?.current,
pageSize: buTableData?.size,
total: buTableData?.total,
onChange: (page) => changeBuPage(page),
}}
/>
</TabPane>
{
sysToken === 'bu' && locationType === platformLevel['SHI'] ?
<TabPane tab="省级平台" key={1}>
<Table
columns={columns}
dataSource={shTableData?.records}
rowKey={(record) => record.id}
showHeader={false}
bordered={false}
pagination={{
current: shTableData?.current,
pageSize: shTableData?.size,
total: shTableData?.total,
onChange: (page) => changeShPage(page),
}}
/>
</TabPane>
: ''
}
{sysToken === 'bu' && (
<TabPane tab="本级平台" key={2}>
<Table
columns={columns}
dataSource={locationType === platformLevel['SHENG'] ? shTableData?.records : shiTableData?.records }
rowKey={(record) => record.id}
showHeader={false}
bordered={false}
pagination={{
current: locationType === platformLevel['SHENG'] ? shTableData?.current : shiTableData?.current,
pageSize: locationType === platformLevel['SHENG'] ? shTableData?.size : shiTableData?.size,
total: locationType === platformLevel['SHENG'] ? shTableData?.total : shTableData?.total,
onChange: (page) => locationType === platformLevel['SHENG'] ? changeShPage(page) : changeShiPage(page),
}}
/>
</TabPane>
)}
</Tabs>
</div>
);
};
useEffect(() => {
if (sysToken === 'bu') {
if(locationType === platformLevel['SHENG']) {
getTable(buSearchParams, shSearchParams);
}
if(locationType === platformLevel['SHI'] ){
getTable(buSearchParams, shSearchParams, shiSearchParams);
}
//
}
if (sysToken !== 'bu') {
getTable(buSearchParams);
//
}
}, [buSearchParams, shSearchParams, shiSearchParams]);
return (
<>
<Popover
content={renderContent()}
title=""
trigger="click"
visible={visible}
onVisibleChange={handleVisibleChange}
placement="bottomRight"
>
<Badge count={count}>
<a href="#" style={{ marginLeft: 16, fontSize: 22 }}>
<BellOutlined />
</a>
</Badge>
</Popover>
{tabVisible && (
<Modal
width={1200}
visible={tabVisible}
footer={false}
onCancel={() => setTabVisible(false)}
>
<CK id={showId} sysToken={sysToken} info={showInfo} />
</Modal>
)}
</>
);
};
const mapStateToProps = ({ global, user }) => ({
...global,
isLocationInBu: user.isLocationInBu,
locationType: user.locationType
});
const mapDispatchToProps = (dispatch) => ({
fetchMsgList(params) {
return dispatch({ type: 'global/fetchMsgList', payload: { ...params } });
},
fetchSetIsReaded(params) {
return dispatch({ type: 'global/fetchSetIsReaded', payload: params });
},
fetchReadOnce(params) {
return dispatch({ type: 'global/fetchReadOnce', payload: { ...params } });
},
fetchGetDqXx(params) {
return dispatch({ type: 'global/fetchGetDqXx', payload: { ...params } });
},
});
export default connect(mapStateToProps, mapDispatchToProps)(HeaderToDo);

38
src/components/HeaderMsg/index.less

@ -0,0 +1,38 @@
.titles {
:global {
.ant-col-11 {
text-align: right;
a {
margin-left: 24px;
}
}
}
}
.xxnr {
width: 320px;
overflow: hidden;
white-space: nowrap;
text-align: left;
text-overflow: ellipsis;
}
.contents {
width: 800px;
.pagination {
margin-top: 16px;
text-align: right;
[class~='ant-pagination'] {
float: right;
}
.total {
float: right;
margin-left: 16px;
line-height: 32px;
.prompt {
margin: 0 4px;
color: #3488e9;
}
}
}
}

86
src/components/HeaderSearch/index.jsx

@ -0,0 +1,86 @@
import { SearchOutlined } from '@ant-design/icons';
import { AutoComplete, Input } from 'antd';
import useMergedState from 'rc-util/es/hooks/useMergedState';
import React, { useRef } from 'react';
import classNames from 'classnames';
import styles from './index.less';
const HeaderSearch = props => {
const {
className,
defaultValue,
onVisibleChange,
placeholder,
open,
defaultOpen,
...restProps
} = props;
const inputRef = useRef(null);
const [value, setValue] = useMergedState(defaultValue, {
value: props.value,
onChange: props.onChange,
});
const [searchMode, setSearchMode] = useMergedState(defaultOpen ?? false, {
value: props.open,
onChange: onVisibleChange,
});
const inputClass = classNames(styles.input, {
[styles.show]: searchMode,
});
return (
<div
className={classNames(className, styles.headerSearch)}
onClick={() => {
setSearchMode(true);
if (searchMode && inputRef.current) {
inputRef.current.focus();
}
}}
onTransitionEnd={({ propertyName }) => {
if (propertyName === 'width' && !searchMode) {
if (onVisibleChange) {
onVisibleChange(searchMode);
}
}
}}
>
<SearchOutlined
key="Icon"
style={{
cursor: 'pointer',
}}
/>
<AutoComplete
key="AutoComplete"
className={inputClass}
value={value}
style={{
height: 28,
marginTop: -6,
}}
options={restProps.options}
onChange={setValue}
>
<Input
ref={inputRef}
defaultValue={defaultValue}
aria-label={placeholder}
placeholder={placeholder}
onKeyDown={e => {
if (e.key === 'Enter') {
if (restProps.onSearch) {
restProps.onSearch(value);
}
}
}}
onBlur={() => {
setSearchMode(false);
}}
/>
</AutoComplete>
</div>
);
};
export default HeaderSearch;

30
src/components/HeaderSearch/index.less

@ -0,0 +1,30 @@
@import '~antd/es/style/themes/default.less';
.headerSearch {
.input {
width: 0;
min-width: 0;
overflow: hidden;
background: transparent;
border-radius: 0;
transition: width 0.3s, margin-left 0.3s;
:global(.ant-select-selection) {
background: transparent;
}
input {
padding-right: 0;
padding-left: 0;
border: 0;
box-shadow: none !important;
}
&,
&:hover,
&:focus {
border-bottom: 1px solid @border-color-base;
}
&.show {
width: 210px;
margin-left: 8px;
}
}
}

1
src/components/HeaderToDo/README.md

@ -0,0 +1 @@
头部-待办

216
src/components/HeaderToDo/index.jsx

@ -0,0 +1,216 @@
import React, { useState, useEffect } from 'react';
import { connect, history } from 'umi';
import { Popover, Tabs, Badge } from 'antd';
import { HourglassOutlined } from '@ant-design/icons';
import { AJZT, platformLevel } from '@/utils/constants';
//
const HeaderToDo = (props) => {
const { fetchZbYbList, isLocationInBu, refresh, currentUser, locationType} = props;
console.log(currentUser, 'currentUser')
// debugger;
const sysToken = isLocationInBu ? '' : 'bu';
const { TabPane } = Tabs;
const [nowTab, setNowTab] = useState(0);
const [count, setCount] = useState(0);
const [visible, setVisible] = useState(false);
const [buDataSource, setBuDataSource] = useState([]);
const [shDataSource, setShDataSource] = useState([]);
const [shiDataSource, setShiDataSource] = useState([]);
const [reload, setReload] = useState(0);
const clickItem = (item) => {
console.log(item)
const list = [];
list.push(item.ajzt);
// debugger;
const pathParams = {
type: Number(nowTab) === 0 ? 'department' : Number(nowTab) === 1 ? 'province' : 'city',
msg: { dqZt: list, page: 1, size: 10, isClr: [0] },
reload,
};
//
if (item.ajzt === AJZT.WSL.value) pathParams.msg.dqbldwBm = [currentUser?.departmentCode ?? ''];
history.push({
pathname: '/doingcases',
params: pathParams,
});
setReload(reload + 1);
setVisible(false);
};
const handleChangeTab = (e) => {
setNowTab(e);
};
const renderContent = () => {
console.log(shDataSource)
return (
<Tabs
onTabClick={(e) => {
handleChangeTab(e);
}}
>
<TabPane tab="部级平台" key={0}>
<div style={{ width: 150 }}>
<div style={{ fontWeight: 600, fontSize: 16, marginBottom: 5 }}>工作中心</div>
{buDataSource?.map((item) => {
return (
<div key={item} style={{ paddingLeft: 15 }} onClick={() => clickItem(item)}>
<a style={{ color: '#000' }}>
{item.ajztValue}({item.count})
</a>
</div>
);
})}
</div>
</TabPane>
{
sysToken === 'bu' && locationType === platformLevel['SHI'] ?
<TabPane tab="省级平台" key={1}>
<div style={{ width: 150 }}>
<div style={{ fontWeight: 600, fontSize: 16, marginBottom: 5 }}>工作中心</div>
{shDataSource?.map((item) => {
return (
<div key={item} style={{ paddingLeft: 15 }} onClick={() => clickItem(item)}>
<a style={{ color: '#000' }}>
{item.ajztValue}({item.count})
</a>
</div>
);
})}
</div>
</TabPane>
: ''
}
{sysToken === 'bu' && (
<TabPane tab="本级平台" key={locationType === platformLevel['SHI'] ? 2 : 1 }>
<div style={{ width: 150 }}>
<div style={{ fontWeight: 600, fontSize: 16, marginBottom: 5 }}>工作中心</div>
{
(locationType === platformLevel['SHENG'] ? shDataSource:shiDataSource)?.map((item) => {
return (
<div key={item} style={{ paddingLeft: 15 }} onClick={() => clickItem(item)}>
<a style={{ color: '#000' }}>
{item.ajztValue}({item.count})
</a>
</div>
);
})
}
</div>
</TabPane>
)}
</Tabs>
);
};
const handleVisibleChange = () => {
setVisible(!visible);
};
const getCount = (list) => {
let num = 0;
list?.forEach((item) => {
num += Number(item.count);
});
return num;
};
const getData = () => {
if (sysToken === 'bu') {
//
const psh = new Promise(function (resolve, reject) {
fetchZbYbList('').then((res) => {
if (res && res.resCode === 0) {
resolve(res.data);
}
});
});
const pbu = new Promise(function (resolve, reject) {
fetchZbYbList(sysToken).then((res) => {
if (res && res.resCode === 0) {
resolve(res.data);
}
});
});
const pshi = new Promise(function (resolve, reject) {
fetchZbYbList('sheng').then((res) => {
if (res && res.resCode === 0) {
resolve(res.data);
}
});
});
if(locationType === platformLevel['SHENG']) {
// (bu)()
Promise.all([psh, pbu]).then(function (results) {
console.log("results",results);
const num = getCount(results[0]) + getCount(results[1]);
setCount(num);
setBuDataSource(results[1]);
setShDataSource(results[0]);
});
}
if(locationType === platformLevel['SHI'] ) {
Promise.all([psh, pbu, pshi]).then(function (results) {
console.log("results",results);
const num = getCount(results[0]) + getCount(results[1]) + getCount(results[2]);
setCount(num);
setShiDataSource(results[0]);
setBuDataSource(results[1]);
setShDataSource(results[2]);
});
}
}
if (sysToken === '') {
fetchZbYbList(sysToken).then((res) => {
if (res && res.resCode === 0) {
setCount(getCount(res.data));
setBuDataSource(res.data);
}
});
}
};
useEffect(() => {
getData();
}, [refresh]);
return (
<Popover
content={renderContent}
title=""
trigger="click"
visible={visible}
onVisibleChange={handleVisibleChange}
placement="bottomRight"
>
<Badge count={count}>
<a href="#" style={{ marginLeft: 16, fontSize: 22 }}>
<HourglassOutlined />
</a>
</Badge>
</Popover>
);
};
const mapStateToProps = ({ global, user, doing }) => ({
...global,
...user,
isLocationInBu: user.isLocationInBu,
currentUser: user.currentUser,
refresh: doing.refresh,
locationType:user.locationType
});
const mapDispatchToProps = (dispatch) => ({
fetchZbYbList(params) {
return dispatch({ type: 'global/fetchZbYbList', payload: params });
},
});
export default connect(mapStateToProps, mapDispatchToProps)(HeaderToDo);

1
src/components/JDGZ/README.md

@ -0,0 +1 @@
进度跟踪

347
src/components/JDGZ/index.jsx

@ -0,0 +1,347 @@
import React, { useState, useEffect } from 'react';
import { connect } from 'umi';
import moment from 'moment';
import { Card, Row, Col, Timeline, Table } from 'antd';
import { JDLX, ALLSPFS, YJLX, BLFS } from '@/utils/constants';
const JDGZ = (props) => {
const {
id,
sysToken,
fetchJDGZInfo,
fetchJDGZtableSqSp,
fetchJDGZtableCh,
fetchDownloadFile,
fetchJDGZtableAjhcz,
} = props;
const [nowId, setNowId] = useState(); // ID
const [tWidth, setTWidth] = useState(); //
const [tColumns, setTColumns] = useState([]); //
const [timeLine, setTimeLine] = useState(); // 线
const [tableData, setTableData] = useState(); //
//
const getJDLX = (item) => {
const jdlx = Object.values(JDLX).find((e) => e.value === item) || {};
return jdlx;
};
//
const getSPFS = (item) => {
const spfs = Object.values(ALLSPFS).find((e) => Number(e.value) === Number(item)) || {};
return spfs;
};
//
const getYJLX = (item) => {
const yjlx = Object.values(YJLX).find((e) => Number(e.value) === Number(item)) || {};
return yjlx;
};
//
const getNBFS = (item) => {
const nbfs = Object.values(BLFS).find((e) => Number(e.value) === Number(item)) || {};
return nbfs;
};
//
const handleDownload = (file) => {
const params = {
mc: file.wjMc,
path: file.wjPath,
url: file.wjUrl,
};
fetchDownloadFile({ params, sysToken });
};
const getColumns = (lx) => {
const commonColumns = [
{
title: '处理时间',
dataIndex: 'clSj',
key: 'clSj',
},
{
title: '处理人',
dataIndex: 'clrMc',
key: 'clrMc',
},
{
title: '处理单位',
dataIndex: 'cldwMc',
key: 'cldwMc',
},
{
title: '审批方式',
dataIndex: 'sp',
key: 'sp',
render: (text, record) => {
return getSPFS(record?.spFs).name;
},
},
{
title: '下级审批人',
dataIndex: 'xjSprMc',
key: 'xjSprMc',
},
];
const SLSPColums = [
{
title: '预警流向',
dataIndex: 'yjlx',
key: 'yjlx',
render: (text, record) => {
return getYJLX(record?.blfs).name;
},
},
{
title: '拟办方式', //
dataIndex: 'nbfs',
key: 'nbfs',
render: (text, record) => {
return getNBFS(record?.nbfs).name;
},
},
{
title: '接收单位',
dataIndex: 'xjdwMc',
key: 'xjdwMc',
},
{
title: '受理意见',
dataIndex: 'slyj',
key: 'slyj',
},
{
title: '反馈期限',
dataIndex: 'fksj',
key: 'fksj',
render: (text, record) => {
return moment(record?.zcfkSj).format('YYYY-MM-DD HH:mm:ss');
},
},
{
title: '附件',
dataIndex: 'fj',
key: 'fj',
render: (text, record) => {
return record?.wj?.map((file, index) => {
return (
<a key={file.id} onClick={() => handleDownload(file)}>
{file.wjMc}
{index === record?.wj?.length - 1 ? '' : ';'}
</a>
);
});
},
},
// {
// title: '',
// dataIndex: 'wtms',
// key: 'wtms',
// },
];
const BJSPColumns = [
{
title: '附件',
dataIndex: 'fj',
key: 'fj',
render: (text, record) => {
return record?.wj?.map((file, index) => {
return (
<a key={file.id} onClick={() => handleDownload(file)}>
{file.wjMc}
{index === record?.wj?.length - 1 ? '' : ';'}
</a>
);
});
},
},
{
title: '办结意见',
dataIndex: 'bjyj',
key: 'bjyj',
},
{
title: '审批意见',
dataIndex: 'spyj',
key: 'spyj',
render: (text, record) => {
return text || JSON.parse(record?.ywSj)?.wtjs || JSON.parse(record?.ywSj)?.slyj || '';
},
},
];
const ANHCZColumns = [
{
title: '承办时间',
dataIndex: 'createTime',
key: 'cbsj',
},
{
title: '承办人',
dataIndex: 'cbrMc',
key: 'cbr',
},
];
const CHColumns = [
{
title: '撤回单位',
dataIndex: 'chdwMc',
key: 'chdwMc',
},
{
title: '处理人',
dataIndex: 'chrMc',
key: 'chrMc',
},
{
title: '撤回原因',
dataIndex: 'chyy',
key: 'chyy',
},
{
title: '撤回文书',
dataIndex: 'chwj',
key: 'chwj',
render: (text, record) => {
return record?.wj?.map((file, index) => {
return (
<a key={file.id} onClick={() => handleDownload(file)}>
{file.wjMc}
{index === record?.wj?.length - 1 ? '' : ';'}
</a>
);
});
},
},
];
const CCColumns = [
{
title: '抽查单位',
dataIndex: 'chdwMc',
key: 'chdwMc',
},
{
title: '处理人',
dataIndex: 'chrMc',
key: 'chrMc',
},
{
title: '备注',
dataIndex: 'chyy',
key: 'chyy',
},
];
//
if (lx === '1') return { tableWidth: 1800, tableColumns: [...commonColumns, ...SLSPColums] };
//
if (lx === '4') return { tableWidth: 1400, tableColumns: [...commonColumns, ...BJSPColumns] };
//
if (lx === '2' || lx === '3') return { tableWidth: 900, tableColumns: [...commonColumns] };
//
if (lx === '6') return { tableWidth: 400, tableColumns: [...ANHCZColumns] };
//
if (lx === '5') return { tableWidth: 800, tableColumns: [...CHColumns] };
if (lx === '7') return { tableWidth: 800, tableColumns: [...CCColumns] };
};
// 线
const handleClickTimeline = (record) => {
const { id, lx, ywId, open, pfId } = record;
if (open) {
const tableInfo = getColumns(lx);
const { tableWidth, tableColumns } = tableInfo;
setTableData([]);
setNowId(id);
setTWidth(tableWidth);
setTColumns(tableColumns);
if (lx === '5' || lx === '7') {
//
fetchJDGZtableCh({ id: ywId, sysToken }).then((res) => {
if (res) setTableData([res]);
});
} else if (lx === '6') {
//
const params = {
id,
pfId,
};
fetchJDGZtableAjhcz({ params, sysToken }).then((res) => {
if (res) setTableData([res]);
});
} else {
fetchJDGZtableSqSp({ jdgzId: id, sysToken }).then((res) => {
const source = [];
res?.forEach((item) => {
source.push({ ...item, ...JSON.parse(item?.ywSj) });
});
if (res) setTableData(source);
});
}
}
};
useEffect(() => {
fetchJDGZInfo({ pfId: id, sysToken }).then((res) => {
setTimeLine(res?.data);
handleClickTimeline(res?.data[0]);
});
}, []);
const renderTimeLineItem = (list) => {
return list?.map((item) => {
return (
<Timeline.Item key={item.id} onClick={() => handleClickTimeline(item)}>
<Row>
<Col span={6}>
<div>{item?.sj}</div>
<div>{item?.dwMc}</div>
<div>{getJDLX(item?.lx)?.name}</div>
</Col>
<Col span={18}>
{item.id === nowId ? (
<Table
scroll={{ x: tWidth }}
columns={tColumns}
rowKey={(record) => record.id}
dataSource={tableData}
pagination={false}
/>
) : null}
</Col>
</Row>
</Timeline.Item>
);
});
};
return (
<Card title="进度跟踪">
<Timeline>{timeLine?.length && renderTimeLineItem(timeLine)}</Timeline>
</Card>
);
};
const mapStateToProps = ({ doing }) => ({
...doing,
});
const mapDispatchToProps = (dispatch) => ({
fetchJDGZInfo(params) {
return dispatch({ type: 'doing/fetchJDGZInfo', payload: { ...params } });
},
fetchJDGZtableSqSp(params) {
return dispatch({ type: 'doing/fetchJDGZtableSqSp', payload: { ...params } });
},
fetchJDGZtableCh(params) {
return dispatch({ type: 'doing/fetchJDGZtableCh', payload: { ...params } });
},
fetchJDGZtableAjhcz(params) {
return dispatch({ type: 'doing/fetchJDGZtableAjhcz', payload: { ...params } });
},
fetchDownloadFile(params) {
return dispatch({ type: 'doing/fetchDownloadFile', payload: { ...params } });
},
});
export default connect(mapStateToProps, mapDispatchToProps)(JDGZ);

1
src/components/MyIcons/README.md

@ -0,0 +1 @@

32
src/components/MyIcons/index.jsx

@ -0,0 +1,32 @@
import React from 'react';
import { FileDoneOutlined, FileExcelOutlined, BulbFilled } from '@ant-design/icons';
import { YQQK } from '@/utils/constants';
export const HGIcon = <FileDoneOutlined style={{ marginRight: 10, color: '#1AB58F' }} />;
export const BHGIcon = <FileExcelOutlined style={{ marginRight: 10, color: '#FF704F' }} />
export const ExampleBar = () => {
return <div style={{ marginRight: 20, marginTop: 3}}>
{HGIcon}<span style={{ marginRight: 15}}>抽查合格</span>
{BHGIcon}<span style={{ marginRight: 15}}>抽查不合格</span>
</div>
}
export const getHGIcons = (type) => {
if (type === 1) return HGIcon;
if (type === 0) return BHGIcon;
return <span style={{display: 'inline-block', width: 24, height: 14 }}></span>
}
export const getTimeLine = (type) => {
if (type === YQQK.CQ.value) {
return <BulbFilled style={{ color: YQQK.CQ.color}} />
} if (type === YQQK.JCQ.value) {
return <BulbFilled style={{ color: YQQK.JCQ.color}} />
} if (type === YQQK.ZC.value) {
return <BulbFilled style={{ color: YQQK.ZC.color}} />
}
return ''
}

1
src/components/NextOrg/README.md

@ -0,0 +1 @@
自动派发

207
src/components/NextOrg/index.js

@ -0,0 +1,207 @@
import React, { useEffect, useState } from 'react';
import { TreeSelect, Form, } from 'antd';
// import _ from 'lodash';
import { connect } from 'umi';
const { TreeNode } = TreeSelect;
/*
*受理时的下级单位;列表上部搜索的涉案单位当前办理单位
*下级单位有可能需要回显也有可能跨级回显
*列表上部搜索中用到的需要用自己来当根节点在办列表中当前办理单位这个字段可能有回显来展示消息调整来的页面
*selfRoot布尔值 true 需要用自己的信息当作根节点当用在列表上部搜索时有这个需求否则就需要用当前登陆人code来查下级单位
*noLoad 布尔值 不允许下钻树节点 办理方式 督办不允许下钻转办可以下钻
*multiple 布尔值 可以多选 当用在列表上部搜索时有这个需求
*/
const NextOrg = (props) => {
const { user, selfRoot, noLoad, defaultVal, multiple, fetchOrgList, fetchOrgBranch } = props;
const selfTreeData = [
{
code: user?.departmentCode ?? '',
name: user?.departmentName ?? '',
orgLevel: user?.departmentOrgLevel ?? '',
isLeaf: user?.departmentOrgLevel ?? '' === 3,
},
];
const [treeList, setTreeList] = useState(selfRoot ? selfTreeData : []);
const [form] = Form.useForm();
const [loadMoreOrg, setLoadMoreOrg] = useState([]);
const [treeValue, setTreeValue] = useState(defaultVal);
const [hited, setHited] = useState(false); // 第一次查询默认值是否命中
const loopChildren = (key, list, appendList) => {
return list.map(item => {
const obj = { ...item };
if (item.code === key) {
if (appendList.length > 0) {
obj.children = appendList;
} else {
obj.isLeaf = true;
}
} else if (item.children) {
obj.children = loopChildren(key, item.children, appendList);
}
return obj;
})
}
const onLoadData = treeNode => {
/* eslint-disable */
return new Promise(resolve => {
if (treeNode?.props?.children) {
resolve();
return;
}
const { key } = treeNode;
fetchOrgList(key).then(res => {
const newObj = treeList.map(item => {
const obj = { ...item };
if (item.code === key) {
if (res.length > 0) {
obj.children = res;
} else {
obj.isLeaf = true;
}
} else if (item.children) {
obj.children = loopChildren(key, item.children, res);
}
return obj;
});
setTreeList(newObj);
resolve();
})
});
}
const getHit = (data) => {
if (defaultVal) { // 如果有默认值 要回显
if (!data.some((item) => item.code === defaultVal)) { // 回显的值和当前级别没有匹配的 需要向下查询 来正确回显
fetchOrgBranch(defaultVal).then(res => { // 获取到需要回显的层级路径
const nowIndex = res.findIndex((item) => item.code === user?.departmentCode ?? '');
const paths = res.slice(nowIndex + 1);
setLoadMoreOrg(paths);
});
} else {
setHited(true);
}
}
}
const getOrgList = () => {
if (treeList.length === 0) { // 初始没有, 需要查询
fetchOrgList(user?.departmentCode ?? '').then(data => { // 查询树的第一层
setTreeList(data);
getHit(data);
});
} else { // 已经查询过 但是defatVal当时没有更新
getHit(treeList);
}
}
useEffect(() => {
// 因为有时defaultVal 赋值迟缓导致实际有值却是传过来undefined,导致getOrgList方法运算中defaultVal 为undefined,这样就无法继续查询匹配
if (treeValue === undefined && defaultVal && typeof defaultVal === 'string' && !hited) {
getOrgList();
}
setTreeValue(defaultVal);
return () => {
// cleanup
}
}, [defaultVal]);
useEffect(() => {
if (!selfRoot) { // 自己不是根节点,需要查询第一层数据
getOrgList();
}
return () => {
// cleanup
}
}, []);
useEffect(() => { // 查询更深的回显路径
if (loadMoreOrg.length > 0) {
onLoadData({ key: loadMoreOrg[0].code, orgLevel: loadMoreOrg[0].orgLevel }).then(() => {
const paths = loadMoreOrg.slice(1);
setLoadMoreOrg(paths);
})
}
return () => {
// cleanup
}
}, [loadMoreOrg]);
const loop = data => {
if (!data) return;
const list = data.map(item => {
if (item.children) {
return (
<TreeNode
key={item.code}
value={item.code}
title={item.name}
orgLevel={item.orgLevel}
isLeaf={item.isLeaf || noLoad || item.orgLevel === 3}
>
{loop(item.children)}
</TreeNode>
);
}
return (
<TreeNode
key={item.code}
value={item.code}
orgLevel={item.orgLevel}
title={item.name}
isLeaf={item.isLeaf || noLoad || item.orgLevel === 3}
/>
);
})
return list;
};
const onChange = (value, lable) => {
setTreeValue(value);
if (multiple) {
props.onChange({ bm: value, mc: lable });
} else {
props.onChange({ bm: value, mc: lable[0] });
}
}
return (
<TreeSelect
multiple={multiple}
style={{ width: '100%' }}
dropdownStyle={{ overflow: 'auto' }}
allowClear
onChange={onChange}
loadData={noLoad ? null : onLoadData}
value={treeValue}
>
{loop(treeList)}
</TreeSelect>
)
}
const mapStateToProps = ({ user, global }) => ({
user: user.currentUser,
global,
});
const mapDispatchToProps = dispatch => ({
// 查询审批人列表
fetchOrgList(params) {
return dispatch({ type: 'global/fetchOrgList', payload: params });
},
fetchOrgBranch(params) {
return dispatch({ type: 'global/fetchOrgBranch', payload: params });
},
});
export default connect(mapStateToProps, mapDispatchToProps)(NextOrg);

97
src/components/NoticeIcon/NoticeList.jsx

@ -0,0 +1,97 @@
import { Avatar, List } from 'antd';
import React from 'react';
import classNames from 'classnames';
import styles from './NoticeList.less';
const NoticeList = ({
data = [],
onClick,
onClear,
title,
onViewMore,
emptyText,
showClear = true,
clearText,
viewMoreText,
showViewMore = false,
}) => {
if (!data || data.length === 0) {
return (
<div className={styles.notFound}>
<img
src="https://gw.alipayobjects.com/zos/rmsportal/sAuJeJzSKbUmHfBQRzmZ.svg"
alt="not found"
/>
<div>{emptyText}</div>
</div>
);
}
return (
<div>
<List
className={styles.list}
dataSource={data}
renderItem={(item, i) => {
const itemCls = classNames(styles.item, {
[styles.read]: item.read,
}); // eslint-disable-next-line no-nested-ternary
const leftIcon = item.avatar ? (
typeof item.avatar === 'string' ? (
<Avatar className={styles.avatar} src={item.avatar} />
) : (
<span className={styles.iconElement}>{item.avatar}</span>
)
) : null;
return (
<List.Item
className={itemCls}
key={item.key || i}
onClick={() => {
onClick?.(item);
}}
>
<List.Item.Meta
className={styles.meta}
avatar={leftIcon}
title={
<div className={styles.title}>
{item.title}
<div className={styles.extra}>{item.extra}</div>
</div>
}
description={
<div>
<div className={styles.description}>{item.description}</div>
<div className={styles.datetime}>{item.datetime}</div>
</div>
}
/>
</List.Item>
);
}}
/>
<div className={styles.bottomBar}>
{showClear ? (
<div onClick={onClear}>
{clearText} {title}
</div>
) : null}
{showViewMore ? (
<div
onClick={e => {
if (onViewMore) {
onViewMore(e);
}
}}
>
{viewMoreText}
</div>
) : null}
</div>
</div>
);
};
export default NoticeList;

103
src/components/NoticeIcon/NoticeList.less

@ -0,0 +1,103 @@
@import '~antd/es/style/themes/default.less';
.list {
max-height: 400px;
overflow: auto;
&::-webkit-scrollbar {
display: none;
}
.item {
padding-right: 24px;
padding-left: 24px;
overflow: hidden;
cursor: pointer;
transition: all 0.3s;
.meta {
width: 100%;
}
.avatar {
margin-top: 4px;
background: @component-background;
}
.iconElement {
font-size: 32px;
}
&.read {
opacity: 0.4;
}
&:last-child {
border-bottom: 0;
}
&:hover {
background: @primary-1;
}
.title {
margin-bottom: 8px;
font-weight: normal;
}
.description {
font-size: 12px;
line-height: @line-height-base;
}
.datetime {
margin-top: 4px;
font-size: 12px;
line-height: @line-height-base;
}
.extra {
float: right;
margin-top: -1.5px;
margin-right: 0;
color: @text-color-secondary;
font-weight: normal;
}
}
.loadMore {
padding: 8px 0;
color: @primary-6;
text-align: center;
cursor: pointer;
&.loadedAll {
color: rgba(0, 0, 0, 0.25);
cursor: unset;
}
}
}
.notFound {
padding: 73px 0 88px;
color: @text-color-secondary;
text-align: center;
img {
display: inline-block;
height: 76px;
margin-bottom: 16px;
}
}
.bottomBar {
height: 46px;
color: @text-color;
line-height: 46px;
text-align: center;
border-top: 1px solid @border-color-split;
border-radius: 0 0 @border-radius-base @border-radius-base;
transition: all 0.3s;
div {
display: inline-block;
width: 50%;
cursor: pointer;
transition: all 0.3s;
user-select: none;
&:only-child {
width: 100%;
}
&:not(:only-child):last-child {
border-left: 1px solid @border-color-split;
}
}
}

119
src/components/NoticeIcon/index.jsx

@ -0,0 +1,119 @@
import { BellOutlined } from '@ant-design/icons';
import { Badge, Spin, Tabs } from 'antd';
import useMergedState from 'rc-util/es/hooks/useMergedState';
import React from 'react';
import classNames from 'classnames';
import NoticeList from './NoticeList';
import HeaderDropdown from '../HeaderDropdown';
import styles from './index.less';
const { TabPane } = Tabs;
const NoticeIcon = props => {
const getNotificationBox = () => {
const {
children,
loading,
onClear,
onTabChange,
onItemClick,
onViewMore,
clearText,
viewMoreText,
} = props;
if (!children) {
return null;
}
const panes = [];
React.Children.forEach(children, child => {
if (!child) {
return;
}
const { list, title, count, tabKey, showClear, showViewMore } = child.props;
const len = list && list.length ? list.length : 0;
const msgCount = count || count === 0 ? count : len;
const tabTitle = msgCount > 0 ? `${title} (${msgCount})` : title;
panes.push(
<TabPane tab={tabTitle} key={tabKey}>
<NoticeList
{...child.props}
clearText={clearText}
viewMoreText={viewMoreText}
data={list}
onClear={() => {
onClear?.(title, tabKey);
}}
onClick={item => {
onItemClick?.(item, child.props);
}}
onViewMore={event => {
onViewMore?.(child.props, event);
}}
showClear={showClear}
showViewMore={showViewMore}
title={title}
/>
</TabPane>,
);
});
return (
<Spin spinning={loading} delay={300}>
<Tabs className={styles.tabs} onChange={onTabChange}>
{panes}
</Tabs>
</Spin>
);
};
const { className, count, bell } = props;
const [visible, setVisible] = useMergedState(false, {
value: props.popupVisible,
onChange: props.onPopupVisibleChange,
});
const noticeButtonClass = classNames(className, styles.noticeButton);
const notificationBox = getNotificationBox();
const NoticeBellIcon = bell || <BellOutlined className={styles.icon} />;
const trigger = (
<span
className={classNames(noticeButtonClass, {
opened: visible,
})}
>
<Badge
count={count}
style={{
boxShadow: 'none',
}}
className={styles.badge}
>
{NoticeBellIcon}
</Badge>
</span>
);
if (!notificationBox) {
return trigger;
}
return (
<HeaderDropdown
placement="bottomRight"
overlay={notificationBox}
overlayClassName={styles.popover}
trigger={['click']}
visible={visible}
onVisibleChange={setVisible}
>
{trigger}
</HeaderDropdown>
);
};
NoticeIcon.defaultProps = {
emptyImage: 'https://gw.alipayobjects.com/zos/rmsportal/wAhyIChODzsoKIOBHcBk.svg',
};
NoticeIcon.Tab = NoticeList;
export default NoticeIcon;

35
src/components/NoticeIcon/index.less

@ -0,0 +1,35 @@
@import '~antd/es/style/themes/default.less';
.popover {
position: relative;
width: 336px;
}
.noticeButton {
display: inline-block;
cursor: pointer;
transition: all 0.3s;
}
.icon {
padding: 4px;
vertical-align: middle;
}
.badge {
font-size: 16px;
}
.tabs {
:global {
.ant-tabs-nav-list {
margin: auto;
}
.ant-tabs-nav-scroll {
text-align: center;
}
.ant-tabs-bar {
margin-bottom: 0;
}
}
}

Some files were not shown because too many files changed in this diff

Loading…
Cancel
Save