forked from Gitlink/forgeplus-react
Merge pull request 'pre-release merge' (#77) from pre_dev_military into dev_military
This commit is contained in:
commit
16ca2a359e
|
@ -86,3 +86,6 @@ typings/
|
|||
|
||||
.DS_Store
|
||||
.idea/*
|
||||
|
||||
package.json
|
||||
package-lock.json
|
|
@ -101,9 +101,13 @@ module.exports = {
|
|||
extensions: [".web.js", ".mjs", ".js", ".json", ".web.jsx", ".jsx"],
|
||||
alias: {
|
||||
educoder: __dirname + "/../src/common/educoder.js",
|
||||
src: path.join(paths.appSrc), // 整个源代码目录
|
||||
forge: path.join(paths.appSrc, 'forge'),
|
||||
military: path.join(paths.appSrc, 'military'),
|
||||
// Support React Native Web
|
||||
// https://www.smashingmagazine.com/2016/08/a-glimpse-into-the-future-with-react-native-for-web/
|
||||
"react-native": "react-native-web",
|
||||
'react-dom': '@hot-loader/react-dom',
|
||||
},
|
||||
plugins: [
|
||||
// Prevents users from importing files from outside of src/ (or node_modules/).
|
||||
|
|
|
@ -87,6 +87,9 @@ module.exports = {
|
|||
extensions: [".web.js", ".mjs", ".js", ".json", ".web.jsx", ".jsx"],
|
||||
alias: {
|
||||
educoder: __dirname + "/../src/common/educoder.js",
|
||||
src: path.join(paths.appSrc),
|
||||
forge: path.join(paths.appSrc, 'forge'),
|
||||
military: path.join(paths.appSrc, 'military'),
|
||||
// Support React Native Web
|
||||
// https://www.smashingmagazine.com/2016/08/a-glimpse-into-the-future-with-react-native-for-web/
|
||||
"react-native": "react-native-web",
|
||||
|
|
|
@ -261,6 +261,25 @@
|
|||
"version": "0.13.9",
|
||||
"resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz",
|
||||
"integrity": "sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA=="
|
||||
<<<<<<< HEAD
|
||||
}
|
||||
}
|
||||
},
|
||||
"@babel/runtime-corejs3": {
|
||||
"version": "7.15.3",
|
||||
"resolved": "https://registry.npmjs.org/@babel/runtime-corejs3/-/runtime-corejs3-7.15.3.tgz",
|
||||
"integrity": "sha512-30A3lP+sRL6ml8uhoJSs+8jwpKzbw8CqBvDc1laeptxPm5FahumJxirigcbD2qTs71Sonvj1cyZB0OKGAmxQ+A==",
|
||||
"requires": {
|
||||
"core-js-pure": "^3.16.0",
|
||||
"regenerator-runtime": "^0.13.4"
|
||||
},
|
||||
"dependencies": {
|
||||
"regenerator-runtime": {
|
||||
"version": "0.13.9",
|
||||
"resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz",
|
||||
"integrity": "sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA=="
|
||||
=======
|
||||
>>>>>>> 01f71bca87fac88ba9ad56c16260521c47f4ca6c
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -362,6 +381,18 @@
|
|||
"resolved": "https://registry.npmjs.org/@emotion/unitless/-/unitless-0.7.5.tgz",
|
||||
"integrity": "sha512-OWORNpfjMsSSUBVrRBVGECkhWcULOAJz9ZW8uK9qgxD+87M7jHRcvh/A96XXNhXTLmKcoYSQtBEX7lHMO7YRwg=="
|
||||
},
|
||||
"@hot-loader/react-dom": {
|
||||
"version": "16.14.0",
|
||||
"resolved": "https://registry.npmjs.org/@hot-loader/react-dom/-/react-dom-16.14.0.tgz",
|
||||
"integrity": "sha512-EN9czvcLsMYmSDo5yRKZOAq3ZGRlDpad1gPtX0NdMMomJXcPE3yFSeFzE94X/NjOaiSVimB7LuqPYpkWVaIi4Q==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"loose-envify": "^1.1.0",
|
||||
"object-assign": "^4.1.1",
|
||||
"prop-types": "^15.6.2",
|
||||
"scheduler": "^0.19.1"
|
||||
}
|
||||
},
|
||||
"@hypnosphi/create-react-context": {
|
||||
"version": "0.3.1",
|
||||
"resolved": "https://registry.npmjs.org/@hypnosphi/create-react-context/-/create-react-context-0.3.1.tgz",
|
||||
|
@ -3908,6 +3939,14 @@
|
|||
"version": "2.6.12",
|
||||
"resolved": "https://registry.npmjs.org/core-js/-/core-js-2.6.12.tgz",
|
||||
"integrity": "sha512-Kb2wC0fvsWfQrgk8HU5lW6U/Lcs8+9aaYcy4ZFc6DDlo4nZ7n70dEgE5rtR0oG6ufKDUnrwfWL1mXR5ljDatrQ=="
|
||||
<<<<<<< HEAD
|
||||
},
|
||||
"core-js-pure": {
|
||||
"version": "3.16.4",
|
||||
"resolved": "https://registry.npmjs.org/core-js-pure/-/core-js-pure-3.16.4.tgz",
|
||||
"integrity": "sha512-bY1K3/1Jy9D8Jd12eoeVahNXHLfHFb4TXWI8SQ4y8bImR9qDPmGITBAfmcffTkgUvbJn87r8dILOTWW5kZzkgA=="
|
||||
=======
|
||||
>>>>>>> 01f71bca87fac88ba9ad56c16260521c47f4ca6c
|
||||
},
|
||||
"core-util-is": {
|
||||
"version": "1.0.2",
|
||||
|
@ -3990,6 +4029,61 @@
|
|||
"object-assign": "^4.1.1"
|
||||
}
|
||||
},
|
||||
<<<<<<< HEAD
|
||||
"cross-env": {
|
||||
"version": "7.0.3",
|
||||
"resolved": "https://registry.npmjs.org/cross-env/-/cross-env-7.0.3.tgz",
|
||||
"integrity": "sha512-+/HKd6EgcQCJGh2PSjZuUitQBQynKor4wrFbRg4DtAgS1aWO+gU52xpH7M9ScGgXSYmAVS9bIJ8EzuaGw0oNAw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"cross-spawn": "^7.0.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"cross-spawn": {
|
||||
"version": "7.0.3",
|
||||
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz",
|
||||
"integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"path-key": "^3.1.0",
|
||||
"shebang-command": "^2.0.0",
|
||||
"which": "^2.0.1"
|
||||
}
|
||||
},
|
||||
"path-key": {
|
||||
"version": "3.1.1",
|
||||
"resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz",
|
||||
"integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==",
|
||||
"dev": true
|
||||
},
|
||||
"shebang-command": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
|
||||
"integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"shebang-regex": "^3.0.0"
|
||||
}
|
||||
},
|
||||
"shebang-regex": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz",
|
||||
"integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==",
|
||||
"dev": true
|
||||
},
|
||||
"which": {
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
|
||||
"integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"isexe": "^2.0.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
=======
|
||||
>>>>>>> 01f71bca87fac88ba9ad56c16260521c47f4ca6c
|
||||
"cross-spawn": {
|
||||
"version": "5.1.0",
|
||||
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-5.1.0.tgz",
|
||||
|
@ -16217,6 +16311,7 @@
|
|||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz",
|
||||
"integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==",
|
||||
<<<<<<< HEAD
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"emoji-regex": "^7.0.1",
|
||||
|
@ -16245,6 +16340,36 @@
|
|||
"integrity": "sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
=======
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"emoji-regex": "^7.0.1",
|
||||
"is-fullwidth-code-point": "^2.0.0",
|
||||
"strip-ansi": "^5.1.0"
|
||||
}
|
||||
},
|
||||
"strip-ansi": {
|
||||
"version": "5.2.0",
|
||||
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz",
|
||||
"integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"ansi-regex": "^4.1.0"
|
||||
}
|
||||
},
|
||||
"which-module": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz",
|
||||
"integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=",
|
||||
"dev": true
|
||||
},
|
||||
"wrap-ansi": {
|
||||
"version": "5.1.0",
|
||||
"resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-5.1.0.tgz",
|
||||
"integrity": "sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
>>>>>>> 01f71bca87fac88ba9ad56c16260521c47f4ca6c
|
||||
"ansi-styles": "^3.2.0",
|
||||
"string-width": "^3.0.0",
|
||||
"strip-ansi": "^5.0.0"
|
||||
|
@ -18975,6 +19100,51 @@
|
|||
"makeerror": "1.0.x"
|
||||
}
|
||||
},
|
||||
"wangeditor": {
|
||||
"version": "4.7.7",
|
||||
"resolved": "https://registry.npmjs.org/wangeditor/-/wangeditor-4.7.7.tgz",
|
||||
"integrity": "sha512-eUpgP7i4pCYIjxjGMMcSUtkHUCkdX7BBwLZE6umseoK9hs3qIMu1tQ95FG48NJwL71JyAjt5c1gB56PzducL3Q==",
|
||||
"requires": {
|
||||
"@babel/runtime": "^7.11.2",
|
||||
"@babel/runtime-corejs3": "^7.11.2",
|
||||
"tslib": "^2.1.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"@babel/runtime": {
|
||||
"version": "7.15.3",
|
||||
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.15.3.tgz",
|
||||
"integrity": "sha512-OvwMLqNXkCXSz1kSm58sEsNuhqOx/fKpnUnKnFB5v8uDda5bLNEHNgKPvhDN6IU0LDcnHQ90LlJ0Q6jnyBSIBA==",
|
||||
"requires": {
|
||||
"regenerator-runtime": "^0.13.4"
|
||||
}
|
||||
},
|
||||
"regenerator-runtime": {
|
||||
"version": "0.13.9",
|
||||
"resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz",
|
||||
"integrity": "sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA=="
|
||||
}
|
||||
}
|
||||
},
|
||||
"wangeditor-for-react": {
|
||||
"version": "1.5.3",
|
||||
"resolved": "https://registry.npmjs.org/wangeditor-for-react/-/wangeditor-for-react-1.5.3.tgz",
|
||||
"integrity": "sha512-nnfZW6leWrVP5UFLEl93UmquSxgfkMpRM45nRusuA/QA+OPIKh0+JW4ZSmSjpmolhT8//iyQOry1I5EuVFwgog==",
|
||||
"requires": {
|
||||
"react": "^17.0.2",
|
||||
"wangeditor": "^4.7.5"
|
||||
},
|
||||
"dependencies": {
|
||||
"react": {
|
||||
"version": "17.0.2",
|
||||
"resolved": "https://registry.npmjs.org/react/-/react-17.0.2.tgz",
|
||||
"integrity": "sha512-gnhPt75i/dq/z3/6q/0asP78D0u592D5L1pd7M8P+dck6Fu/jJeL6iVVK23fptSUZj8Vjf++7wXA8UNclGQcbA==",
|
||||
"requires": {
|
||||
"loose-envify": "^1.1.0",
|
||||
"object-assign": "^4.1.1"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"warning": {
|
||||
"version": "4.0.3",
|
||||
"resolved": "https://registry.npmjs.org/warning/-/warning-4.0.3.tgz",
|
||||
|
@ -19075,13 +19245,22 @@
|
|||
"version": "2.1.1",
|
||||
"resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
|
||||
"integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=",
|
||||
<<<<<<< HEAD
|
||||
"dev": true,
|
||||
"optional": true
|
||||
=======
|
||||
"dev": true
|
||||
>>>>>>> 01f71bca87fac88ba9ad56c16260521c47f4ca6c
|
||||
},
|
||||
"is-glob": {
|
||||
"version": "4.0.1",
|
||||
"resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz",
|
||||
"integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==",
|
||||
"dev": true,
|
||||
<<<<<<< HEAD
|
||||
"optional": true,
|
||||
=======
|
||||
>>>>>>> 01f71bca87fac88ba9ad56c16260521c47f4ca6c
|
||||
"requires": {
|
||||
"is-extglob": "^2.1.1"
|
||||
}
|
||||
|
|
|
@ -107,6 +107,7 @@
|
|||
"styled-components": "^4.4.1",
|
||||
"sw-precache-webpack-plugin": "0.11.4",
|
||||
"url-loader": "0.6.2",
|
||||
"wangeditor-for-react": "^1.4.0",
|
||||
"webpack-cli": "^3.3.11",
|
||||
"webpack-dev-server": "^3.10.3",
|
||||
"webpack-manifest-plugin": "^2.2.0",
|
||||
|
@ -115,7 +116,7 @@
|
|||
},
|
||||
"scripts": {
|
||||
"start": "node --max_old_space_size=15360 scripts/start.js",
|
||||
"build": "NODE_ENV=production node --max_old_space_size=15360 scripts/build.js",
|
||||
"build": "cross-env NODE_ENV=production node --max_old_space_size=15360 scripts/build.js",
|
||||
"test-build": "NODE_ENV=testBuild node --max_old_space_size=15360 scripts/build.js",
|
||||
"pre-build": "NODE_ENV=preBuild node --max_old_space_size=15360 scripts/build.js",
|
||||
"gen_stats": "NODE_ENV=production webpack --profile --config=./config/webpack.config.prod.js --json > stats.json",
|
||||
|
@ -182,6 +183,7 @@
|
|||
"port": "3007",
|
||||
"devDependencies": {
|
||||
"@babel/runtime": "7.0.0-beta.51",
|
||||
"@hot-loader/react-dom": "^16.14.0",
|
||||
"babel-cli": "^6.26.0",
|
||||
"babel-core": "^6.26.0",
|
||||
"babel-plugin-import": "^1.13.0",
|
||||
|
@ -191,6 +193,7 @@
|
|||
"babel-preset-stage-2": "^6.24.1",
|
||||
"compression-webpack-plugin": "^1.1.12",
|
||||
"concat": "^1.0.3",
|
||||
"cross-env": "^7.0.3",
|
||||
"happypack": "^5.0.1",
|
||||
"mockjs": "^1.1.0",
|
||||
"node-sass": "^4.12.0",
|
||||
|
|
Binary file not shown.
After Width: | Height: | Size: 66 KiB |
Binary file not shown.
Before Width: | Height: | Size: 66 KiB After Width: | Height: | Size: 9.7 KiB |
|
@ -50,6 +50,11 @@ const Notice = Loadable({
|
|||
loader: () => import('./military/notice'),
|
||||
loading: Loading,
|
||||
})
|
||||
//任务/需求
|
||||
const Task = Loadable({
|
||||
loader: () => import('./military/task'),
|
||||
loading: Loading,
|
||||
})
|
||||
//403页面
|
||||
const Shixunauthority = Loadable({
|
||||
loader: () => import('./modules/403/Shixunauthority'),
|
||||
|
@ -254,6 +259,9 @@ class App extends Component {
|
|||
}
|
||||
}>
|
||||
</Route>
|
||||
{/*任务*/}
|
||||
<Route path="/task" component={Task} />
|
||||
|
||||
{/*403*/}
|
||||
<Route path="/403" component={Shixunauthority} />
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import moment from "moment";
|
||||
import moment from "moment";
|
||||
|
||||
// 处理整点 半点
|
||||
// 取传入时间往后的第一个半点
|
||||
|
@ -12,7 +12,7 @@ export function handleDateString(dateString) {
|
|||
if (miniute < 30 || miniute == 60) {
|
||||
return [ar[0], '30'].join(':')
|
||||
}
|
||||
if (miniute < 60) {
|
||||
if (miniute < 60) {
|
||||
// 加一个小时
|
||||
const tempStr = [ar[0], '00'].join(':');
|
||||
const format = "YYYY-MM-DD HH:mm";
|
||||
|
@ -20,7 +20,7 @@ export function handleDateString(dateString) {
|
|||
_moment.add(1, 'hours')
|
||||
return _moment.format(format)
|
||||
}
|
||||
|
||||
|
||||
return dateString
|
||||
}
|
||||
|
||||
|
@ -38,62 +38,91 @@ export function getNextHalfHourOfMoment(moment) {
|
|||
return moment
|
||||
}
|
||||
|
||||
export function formatSeconds(value) {
|
||||
export function formatSeconds(value) {
|
||||
|
||||
var theTime = parseInt(value);// 秒
|
||||
var middle= 0;// 分
|
||||
var hour= 0;// 小时
|
||||
|
||||
if(theTime > 60) {
|
||||
middle= parseInt(theTime/60);
|
||||
theTime = parseInt(theTime%60);
|
||||
if(middle> 60) {
|
||||
hour= parseInt(middle/60);
|
||||
middle= parseInt(middle%60);
|
||||
}
|
||||
}
|
||||
var result = ""+parseInt(theTime)+"秒";
|
||||
if(middle > 0) {
|
||||
if(hour>0){
|
||||
result = ""+parseInt(middle)+"分";
|
||||
}else{
|
||||
result = ""+parseInt(middle)+"分"+result;
|
||||
}
|
||||
|
||||
}
|
||||
if(hour> 0) {
|
||||
result = ""+parseInt(hour)+"小时"+result;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
var theTime = parseInt(value);// 秒
|
||||
var middle = 0;// 分
|
||||
var hour = 0;// 小时
|
||||
|
||||
export function formatDuring(mss){
|
||||
var days = parseInt(mss / (1000 * 60 * 60 * 24));
|
||||
var hours = parseInt((mss % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60));
|
||||
var minutes = parseInt((mss % (1000 * 60 * 60)) / (1000 * 60));
|
||||
// console.log("formatDuringformatDuring");
|
||||
// console.log(days);
|
||||
// console.log(hours);
|
||||
// console.log(minutes);
|
||||
// console.log(Math.abs(days));
|
||||
// console.log(Math.abs(hours));
|
||||
// console.log(Math.abs(minutes));
|
||||
if (theTime > 60) {
|
||||
middle = parseInt(theTime / 60);
|
||||
theTime = parseInt(theTime % 60);
|
||||
if (middle > 60) {
|
||||
hour = parseInt(middle / 60);
|
||||
middle = parseInt(middle % 60);
|
||||
}
|
||||
}
|
||||
var result = "" + parseInt(theTime) + "秒";
|
||||
if (middle > 0) {
|
||||
if (hour > 0) {
|
||||
result = "" + parseInt(middle) + "分";
|
||||
} else {
|
||||
result = "" + parseInt(middle) + "分" + result;
|
||||
}
|
||||
|
||||
try {
|
||||
days = Math.abs(days);
|
||||
} catch (e) {
|
||||
|
||||
}
|
||||
try {
|
||||
hours = Math.abs(hours);
|
||||
} catch (e) {
|
||||
|
||||
}
|
||||
try {
|
||||
minutes = Math.abs(minutes);
|
||||
} catch (e) {
|
||||
|
||||
}
|
||||
return days + "天" + hours + "小时" + minutes + "分";
|
||||
}
|
||||
if (hour > 0) {
|
||||
result = "" + parseInt(hour) + "小时" + result;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
export function formatDuring(s) {
|
||||
s = Math.abs(s);
|
||||
let days = Math.floor(s / (60 * 60 * 24));
|
||||
let hours = Math.floor((s % (60 * 60 * 24)) / (60 * 60));
|
||||
let minutes = Math.floor((s % (60 * 60)) / (60));
|
||||
let second = Math.floor(s % 60);
|
||||
|
||||
if (days) {
|
||||
if(hours){
|
||||
return days + "天" + hours + "小时";
|
||||
}
|
||||
return days + "天";
|
||||
}
|
||||
if (hours) {
|
||||
if(minutes){
|
||||
return hours + "小时" + minutes + "分";
|
||||
}
|
||||
return hours + "小时" ;
|
||||
}
|
||||
if (minutes) {
|
||||
return minutes + "分";
|
||||
}
|
||||
return second + "秒";
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
返回:多久以前
|
||||
backDate:以前的某个日期
|
||||
*/
|
||||
export function timeAgo(backDate) {
|
||||
try {
|
||||
moment(backDate);
|
||||
} catch (e) {
|
||||
return;
|
||||
}
|
||||
let time = new Date() - moment(backDate);
|
||||
var days = Math.floor(time / (1000 * 60 * 60 * 24));
|
||||
var hours = Math.floor((time % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60));
|
||||
var minutes = Math.floor((time % (1000 * 60 * 60)) / (1000 * 60));
|
||||
var seconds = Math.floor((time % (1000 * 60 * 60)) / 1000);
|
||||
if (time <= 0) {
|
||||
return "刚刚";
|
||||
}
|
||||
if (days) {
|
||||
return days + "天前";
|
||||
}
|
||||
if (hours) {
|
||||
return hours + "小时前";
|
||||
}
|
||||
if (minutes) {
|
||||
return minutes + "分前";
|
||||
}
|
||||
if (seconds) {
|
||||
return seconds + "秒前";
|
||||
}
|
||||
}
|
|
@ -12,6 +12,7 @@ export function getImageUrl(path) {
|
|||
// https://testbdweb.trustie.net
|
||||
// const local = 'http://localhost:3000'
|
||||
const local = 'http://39.105.176.215:49999';
|
||||
|
||||
if (isDev) {
|
||||
return `${local}/${path}`
|
||||
}
|
||||
|
|
|
@ -27,7 +27,7 @@ export {
|
|||
markdownToHTML, uploadNameSizeSeperator, appendFileSizeToUploadFile, appendFileSizeToUploadFileAll, isImageExtension,
|
||||
downloadFile, sortDirections, validateLength, mdJSONParse, exportMdtoHtml
|
||||
} from './TextUtil'
|
||||
export { handleDateString, getNextHalfHourOfMoment, formatDuring, formatSeconds } from './DateUtil'
|
||||
export { handleDateString, getNextHalfHourOfMoment, formatDuring, formatSeconds ,timeAgo} from './DateUtil'
|
||||
|
||||
export { configShareForIndex, configShareForPaths, configShareForShixuns, configShareForCourses, configShareForCustom } from './util/ShareUtil'
|
||||
|
||||
|
|
|
@ -0,0 +1,90 @@
|
|||
import React, { useEffect, useState } from "react";
|
||||
import { Upload, Button } from 'antd';
|
||||
import { appendFileSizeToUploadFileAll } from 'educoder';
|
||||
import { httpUrl } from '../fetch';
|
||||
|
||||
function Uploads({ className, size, actionUrl, fileList, showNotification, load }) {
|
||||
const [files, setFiles] = useState(undefined);
|
||||
|
||||
useEffect(() => {
|
||||
if (fileList) {
|
||||
init();
|
||||
}
|
||||
}, [fileList]);
|
||||
|
||||
function init() {
|
||||
let f = appendFileSizeToUploadFileAll(fileList);
|
||||
setFiles(f);
|
||||
}
|
||||
function onAttachmentRemove(file) {
|
||||
if (!file.percent || file.percent === 100) {
|
||||
deleteAttachment(file);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
function deleteAttachment(file) {
|
||||
let id = (file.response && file.response.data && file.response.data.id) || file.id;
|
||||
|
||||
// 暂时不直接删除上传的文件,只在最后保存的时候进行修改
|
||||
let nf = files.filter(item => {
|
||||
let itemId = (item.response && item.response.data && item.response.data.id) || item.id;
|
||||
return itemId !== id;
|
||||
});
|
||||
setFiles(nf);
|
||||
backFiles(nf);
|
||||
}
|
||||
|
||||
function backFiles(fileList) {
|
||||
let filesId = [];
|
||||
for (const item of fileList) {
|
||||
if (item) {
|
||||
let itemId = (item.response && item.response.data && item.response.data.id) || item.id;
|
||||
itemId && filesId.push(itemId);
|
||||
}
|
||||
}
|
||||
load && load(fileList, filesId.join());
|
||||
}
|
||||
|
||||
|
||||
function handleChange(info) {
|
||||
if (info.file.status === 'uploading' || info.file.status === 'done' || info.file.status === 'removed') {
|
||||
let fileList = info.fileList;
|
||||
setFiles(appendFileSizeToUploadFileAll(fileList));
|
||||
if (info.file.response) {
|
||||
for (let i = 0; i < fileList.length; i++) {
|
||||
if (fileList[i].response && !fileList[i].response.data) {
|
||||
fileList.splice(i, 1);
|
||||
}
|
||||
}
|
||||
backFiles(fileList);
|
||||
if (!info.file.response.data) {
|
||||
info.file.response && showNotification(info.file.response.message)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function beforeUpload(file) {
|
||||
const isLt100M = file.size / 1024 / 1024 < size;
|
||||
if (!isLt100M) {
|
||||
showNotification(`文件大小必须小于${size}MB!`);
|
||||
}
|
||||
return isLt100M;
|
||||
}
|
||||
|
||||
const upload = {
|
||||
name: 'file',
|
||||
fileList: files,
|
||||
action: (httpUrl || actionUrl) + `/busiAttachments/upload`,
|
||||
onChange: handleChange,
|
||||
onRemove: onAttachmentRemove,
|
||||
beforeUpload: beforeUpload,
|
||||
};
|
||||
return (
|
||||
<Upload {...upload} className={className}>
|
||||
<Button type="primary">点击上传</Button>
|
||||
<span className="ml10 color-grey-9">(你可以上传小于<span className="color-red">{size}MB</span>的文件)</span>
|
||||
</Upload>
|
||||
)
|
||||
}
|
||||
export default Uploads;
|
|
@ -0,0 +1,28 @@
|
|||
import React, { useEffect, useState,memo } from 'react';
|
||||
import classNames from 'classnames';
|
||||
import './index.scss';
|
||||
|
||||
export default memo((props) => {
|
||||
const { title, options, changeOptionId, type ,size} = props;
|
||||
const [option, setOption] = useState({ code: "", dicItemName: "" ,dicItemCode:""});
|
||||
|
||||
useEffect(() => {
|
||||
changeOptionId(option, type);
|
||||
}, [option])
|
||||
|
||||
return (
|
||||
|
||||
<div className={classNames({"choose-box":true,"choose-box-big":size})}>
|
||||
<div className="choose-title">{title}</div>
|
||||
<div className="choose-list">
|
||||
<div className={classNames({ "choose-item-checked": option.dicItemCode === "", "choose-item": true })} key={"all"} onClick={() => { setOption({ dicItemCode: "", dicItemName: "" }) }}>全部</div>
|
||||
{
|
||||
options.map((item) => {
|
||||
return <div className={classNames({ "choose-item-checked": option.dicItemCode === item.dicItemCode, "choose-item": true })} key={item.dicItemCode} onClick={() => { setOption(item) }} >{item.dicItemName}</div>
|
||||
})
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
)
|
||||
})
|
|
@ -0,0 +1,47 @@
|
|||
.nav-content {
|
||||
margin:20px 0;
|
||||
padding:1rem 0.2rem;
|
||||
background: #fff;
|
||||
box-shadow: 0px 0px 20px 0px rgba(0, 0, 0, 0.05);
|
||||
border-radius: 5px;
|
||||
}
|
||||
.choose-box {
|
||||
padding: .35em 0;
|
||||
display: flex;
|
||||
justify-content: start;
|
||||
font-size: .85rem;
|
||||
}
|
||||
.choose-title {
|
||||
width: 6.5em;
|
||||
text-align: center;
|
||||
color: #333;
|
||||
font-weight: 500;
|
||||
flex:none;
|
||||
}
|
||||
|
||||
.choose-box-big{
|
||||
font-size: 1rem;
|
||||
.choose-title{
|
||||
text-align: right;
|
||||
}
|
||||
}
|
||||
.choose-list {
|
||||
display: flex;
|
||||
justify-content: start;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
.choose-item {
|
||||
color:#666;
|
||||
text-align: center;
|
||||
padding: 0 15px ;
|
||||
cursor: pointer;
|
||||
&:hover{
|
||||
color: #1B8FFF;
|
||||
}
|
||||
}
|
||||
|
||||
.choose-item-checked {
|
||||
background: #f7f7f7;
|
||||
color: #1B8FFF;
|
||||
}
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
import { httpUrl } from '../fetch';
|
||||
|
||||
export const editorConfig = {
|
||||
placeholder: '请输入',
|
||||
uploadImgServer: httpUrl + '/busiAttachments/upload',
|
||||
uploadFileName: 'file',
|
||||
uploadImgHeaders: {
|
||||
'X-Requested-With': 'XMLHttpRequest'
|
||||
},
|
||||
excludeMenus: [
|
||||
'list',
|
||||
'todo',
|
||||
'emoticon',
|
||||
'video'
|
||||
],
|
||||
uploadImgHooks: {
|
||||
// 图片上传并返回了结果,想要自己把图片插入到编辑器中
|
||||
customInsert: function (insertImgFn, result) {
|
||||
// insertImgFn 可把图片插入到编辑器,传入图片 src ,执行函数即可
|
||||
if (result && result.data && result.data.id) {
|
||||
insertImgFn(`${httpUrl}/busiAttachments/view/${result.data.id}`);
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
|
@ -0,0 +1,54 @@
|
|||
import React, { useEffect, useState, memo } from 'react';
|
||||
import { Icon, } from 'antd';
|
||||
import classNames from 'classnames';
|
||||
import './index.scss';
|
||||
|
||||
export default memo((props) => {
|
||||
const { options, changeOptionId, type } = props;
|
||||
|
||||
const [myOptions, setMyOptions] = useState(()=>{
|
||||
return JSON.parse(JSON.stringify(options));
|
||||
});
|
||||
const [option, setOption] = useState({
|
||||
name: '综合',
|
||||
type: 'default',
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
changeOptionId(option, type);
|
||||
}, [option]);
|
||||
|
||||
function itemClick(activeItem) {
|
||||
const newOption = {
|
||||
...activeItem,
|
||||
desc: !activeItem.desc
|
||||
};
|
||||
for (const item of myOptions) {
|
||||
if (item.type === activeItem.type) {
|
||||
item.desc = newOption.desc;
|
||||
}
|
||||
}
|
||||
setOption(newOption);
|
||||
setMyOptions(myOptions);
|
||||
}
|
||||
|
||||
console.log('-----options----')
|
||||
return (
|
||||
|
||||
<div className="sort-box">
|
||||
{
|
||||
myOptions.map((item) => {
|
||||
return <div className={classNames({ "sort-item-checked": option.type === item.type, "sort-item": true })} key={item.type} onClick={() => { itemClick(item) }} >
|
||||
{item.name}
|
||||
{
|
||||
item.icon && <span className="caret-up-down">
|
||||
<Icon type="caret-up" className={classNames({ "caret-checked": !item.desc })} />
|
||||
<Icon type="caret-down" className={classNames({ "caret-checked": item.desc })} />
|
||||
</span>}
|
||||
</div>
|
||||
})
|
||||
}
|
||||
</div>
|
||||
|
||||
)
|
||||
})
|
|
@ -0,0 +1,40 @@
|
|||
.sort-box {
|
||||
display: flex;
|
||||
justify-content: start;
|
||||
align-items: center;
|
||||
margin-left: 10px;
|
||||
font-size: 1rem;
|
||||
.sort-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
color: #333;
|
||||
padding: 0 20px;
|
||||
background-color: #fff;
|
||||
&:hover {
|
||||
background-color: #fff;
|
||||
color: #409eff;
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
.sort-item-checked {
|
||||
// background-color: #409eff;
|
||||
// color: #fff;
|
||||
color: #409eff;
|
||||
}
|
||||
.caret-up-down {
|
||||
display: inline-flex;
|
||||
flex-flow: column nowrap;
|
||||
margin-left:.25em;
|
||||
font-size: .75em;
|
||||
color:#ccc;
|
||||
}
|
||||
.caret-checked{
|
||||
color: #409eff;
|
||||
}
|
||||
.anticon-caret-up{
|
||||
margin-bottom: -.15em;
|
||||
}
|
||||
.anticon-caret-down{
|
||||
margin-top: -.15em;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
import React, { useEffect, useState ,memo} from 'react';
|
||||
import classNames from 'classnames';
|
||||
import './index.scss';
|
||||
|
||||
export default memo((props) => {
|
||||
const { options, changeOptionId, type } = props;
|
||||
|
||||
const [option, setOption] = useState({ code: "", dicItemName: "" ,dicItemCode:""});
|
||||
|
||||
useEffect(() => {
|
||||
changeOptionId(option, type);
|
||||
}, [option])
|
||||
|
||||
return (
|
||||
|
||||
<div className="status-list">
|
||||
<div className={classNames({ "status-item-checked": option.dicItemCode === "", "status-item": true })} key={"all"} onClick={() => { setOption({ dicItemCode: "", dicItemName: "" }) }}>全部</div>
|
||||
{
|
||||
options.map((item) => {
|
||||
return <div className={classNames({ "status-item-checked": option.dicItemCode === item.dicItemCode, "status-item": true })} key={item.dicItemCode} onClick={() => { setOption(item) }} >{item.dicItemName}</div>
|
||||
})
|
||||
}
|
||||
</div>
|
||||
|
||||
)
|
||||
})
|
|
@ -0,0 +1,21 @@
|
|||
.status-list {
|
||||
padding: 1rem 0;
|
||||
display: flex;
|
||||
justify-content: start;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
.status-item {
|
||||
font-size: 14px;
|
||||
color: #666;
|
||||
text-align: center;
|
||||
padding: 3px 15px;
|
||||
cursor: pointer;
|
||||
&:hover {
|
||||
color: #4cacff;
|
||||
}
|
||||
}
|
||||
|
||||
.status-item-checked {
|
||||
background: #f7f7f7;
|
||||
color: #4cacff ;
|
||||
}
|
|
@ -1,40 +1,47 @@
|
|||
import { notification } from 'antd';
|
||||
import { notification,message } from 'antd';
|
||||
import axios from 'axios';
|
||||
import cookie from 'react-cookies';
|
||||
|
||||
|
||||
|
||||
let actionUrl = '';
|
||||
if (window.location.href.indexOf('localhost') > -1) {
|
||||
actionUrl='https://taskapi.osredm.com';
|
||||
// actionUrl='http://192.168.31.47:8081';
|
||||
}else if(window.location.href.indexOf('192.168.31.48') > -1){
|
||||
actionUrl='https://taskapi.osredm.com';
|
||||
axios.defaults.withCredentials = true;
|
||||
}else if(window.location.href.indexOf('noticeweb.osredm') > -1){
|
||||
actionUrl="https://taskapi.osredm.com";
|
||||
axios.defaults.withCredentials = true;
|
||||
}else if(window.location.href.indexOf('forge.osredm.com')>-1){
|
||||
actionUrl="https://info.osredm.com";
|
||||
actionUrl="https://task.osredm.com";
|
||||
axios.defaults.withCredentials = true;
|
||||
}
|
||||
export const httpUrl=actionUrl;
|
||||
// export const httpUrl = 'http://106.75.31.211:58088'; //可视化
|
||||
// export const httpUrl = 'http://117.50.100.12:8008'; //测试环境
|
||||
// export const httpUrl = 'https://info.osredm.com/'; //生产环境
|
||||
export const httpUrl = actionUrl;
|
||||
|
||||
const TokenKey = 'autologin_forge_military';
|
||||
axios.defaults.withCredentials = true;
|
||||
|
||||
// 创建axios实例
|
||||
const service = axios.create({
|
||||
baseURL: httpUrl,
|
||||
timeout: 5000 // 请求超时时间
|
||||
timeout: 10000, // 请求超时时间
|
||||
});
|
||||
|
||||
|
||||
// request拦截器
|
||||
service.interceptors.request.use(config => {
|
||||
if (cookie.load(TokenKey)) {
|
||||
console.log(cookie.load(TokenKey));
|
||||
config.headers['Authorization'] = cookie.load(TokenKey); // 让每个请求携带自定义token 请根据实际情况自行修改
|
||||
}
|
||||
if (window.location.port === "3007") {
|
||||
// 模拟token为登录用户
|
||||
const taskToken = sessionStorage.taskToken;
|
||||
if (config.url.indexOf('?') === -1) {
|
||||
config.url = `${config.url}?token=${taskToken}`;
|
||||
} else {
|
||||
config.url = `${config.url}&token=${taskToken}`;
|
||||
}
|
||||
}
|
||||
return config;
|
||||
}, error => {
|
||||
// Do something with request error
|
||||
|
@ -48,14 +55,21 @@ service.interceptors.response.use(
|
|||
if (res.status === 400) {
|
||||
notification.open({
|
||||
message: "提示",
|
||||
description: '请求错误',
|
||||
description: res.data.message || '验证失败',
|
||||
});
|
||||
return Promise.reject('error');
|
||||
}
|
||||
if (res.status === 401) {
|
||||
notification.open({
|
||||
message: "提示",
|
||||
description: '未授权,请登录!',
|
||||
description: res.data.message || '未授权,请登录!',
|
||||
});
|
||||
return Promise.reject('error');
|
||||
}
|
||||
if (res.status === 403) {
|
||||
notification.open({
|
||||
message: "提示",
|
||||
description: res.data.message || '无权限',
|
||||
});
|
||||
return Promise.reject('error');
|
||||
}
|
||||
|
@ -77,10 +91,30 @@ service.interceptors.response.use(
|
|||
},
|
||||
error => {
|
||||
console.log(error);
|
||||
notification.open({
|
||||
message: "提示",
|
||||
description: error.message,
|
||||
});
|
||||
let res = error.response||{};
|
||||
if (res.status === 400) {
|
||||
notification.open({
|
||||
message: "提示",
|
||||
description: res.data.message || '操作失败',
|
||||
});
|
||||
return Promise.reject('error');
|
||||
}
|
||||
if (res.status === 401) {
|
||||
notification.open({
|
||||
message: "提示",
|
||||
description: res.data.message || '登录信息已过期',
|
||||
});
|
||||
return Promise.reject('error');
|
||||
}
|
||||
if (res.status === 403) {
|
||||
notification.open({
|
||||
message: "提示",
|
||||
description: res.data.message || '无权限!',
|
||||
});
|
||||
window.location.href="/403";
|
||||
return Promise.reject('error');
|
||||
}
|
||||
|
||||
return Promise.reject(error);
|
||||
}
|
||||
);
|
||||
|
|
|
@ -1,17 +1,32 @@
|
|||
// 本模块公共样式
|
||||
|
||||
.color-grey3 {
|
||||
color: #333;
|
||||
}
|
||||
.color-grey9 {
|
||||
color: #999;
|
||||
}
|
||||
.color-orange {
|
||||
color: #ff6800;
|
||||
}
|
||||
.color-deep-blue {
|
||||
color: #1b8fff;
|
||||
}
|
||||
.centerbox {
|
||||
width: 1200px;
|
||||
margin: 40px auto;
|
||||
position: relative;
|
||||
}
|
||||
.head-navigation{
|
||||
position: absolute;
|
||||
top:-2.3em;
|
||||
span{
|
||||
.head-navigation {
|
||||
position: absolute;
|
||||
top: -2.3em;
|
||||
// width: 80vw;
|
||||
// max-width: 1280px;
|
||||
// margin: 40px auto;
|
||||
// position: relative;
|
||||
span {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
&:hover{
|
||||
&:hover {
|
||||
color: #409eff;
|
||||
}
|
||||
}
|
||||
|
@ -58,6 +73,17 @@
|
|||
color: #fff;
|
||||
}
|
||||
|
||||
|
||||
// 内容标题左侧样式
|
||||
.center-left-but {
|
||||
display: flex;
|
||||
justify-content: start;
|
||||
align-items: center;
|
||||
margin-left: 20px;
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
// 内容标题右侧样式
|
||||
.center-right-but {
|
||||
display: flex;
|
||||
|
@ -70,18 +96,6 @@
|
|||
cursor: pointer;
|
||||
}
|
||||
|
||||
// 通用标签样式
|
||||
.list-tag {
|
||||
display: inline-block;
|
||||
margin-right: 10px;
|
||||
background: #cfe9ff;
|
||||
color: #0089ff;
|
||||
font-size: 14px;
|
||||
border-radius: 3px;
|
||||
padding: 2px 5px;
|
||||
line-height: 25px;
|
||||
}
|
||||
|
||||
// 文件预览modal样式
|
||||
.file-modal {
|
||||
width: 800px !important;
|
||||
|
@ -109,24 +123,24 @@
|
|||
max-width: 500px;
|
||||
}
|
||||
|
||||
.link{
|
||||
.link {
|
||||
color: #0089ff;
|
||||
cursor: pointer;
|
||||
&:hover{
|
||||
color:#509eff;
|
||||
&:hover {
|
||||
color: #509eff;
|
||||
}
|
||||
}
|
||||
|
||||
.color-grey-a{
|
||||
.color-grey-a {
|
||||
color: #aaa;
|
||||
}
|
||||
|
||||
.greater{
|
||||
.greater {
|
||||
position: relative;
|
||||
top:-1px;
|
||||
top: -1px;
|
||||
}
|
||||
|
||||
.none_panels{
|
||||
.none_panels {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
|
@ -134,20 +148,48 @@
|
|||
height: 40vh;
|
||||
}
|
||||
|
||||
|
||||
.newFooter .footerInfos>ul {
|
||||
.newFooter .footerInfos > ul {
|
||||
padding: 0 40px;
|
||||
box-sizing: border-box;
|
||||
max-width: 25%;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.ant-modal-footer {
|
||||
text-align: center;
|
||||
border: 0;
|
||||
}
|
||||
|
||||
// 头像
|
||||
.head-log-big {
|
||||
width: 4rem;
|
||||
height: 4rem;
|
||||
margin-right: 0.5rem;
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
.head-log-middle {
|
||||
width: 3rem;
|
||||
height: 3rem;
|
||||
margin-right: 0.35rem;
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
.head-log-small {
|
||||
width: 1.25rem;
|
||||
height: 1.25rem;
|
||||
margin-right: 0.35rem;
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
// 富文本样式
|
||||
.w-e-text table td, .w-e-text table th{
|
||||
.w-e-text table td,
|
||||
.w-e-text table th {
|
||||
height: 30px;
|
||||
}
|
||||
.editor-w-text {
|
||||
table td, table th{
|
||||
table td,
|
||||
table th {
|
||||
border-bottom: 1px solid #ccc;
|
||||
border-right: 1px solid #ccc;
|
||||
padding: 3px 5px;
|
||||
|
@ -172,16 +214,18 @@
|
|||
font-size: 100%;
|
||||
background-color: #f1f1f1;
|
||||
}
|
||||
a{
|
||||
a {
|
||||
color: #409eff;
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
|
||||
.text-center{
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
|
||||
@media screen and (max-width: 1200px){
|
||||
@media screen and (max-width: 1200px) {
|
||||
.centerbox {
|
||||
width: 98%;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import fetch from '../fetch';
|
||||
import fetch from './fetch';
|
||||
import { notification } from 'antd';
|
||||
|
||||
|
||||
|
|
|
@ -0,0 +1,122 @@
|
|||
import { notification,message } from 'antd';
|
||||
import axios from 'axios';
|
||||
import cookie from 'react-cookies';
|
||||
|
||||
|
||||
let actionUrl = '';
|
||||
if (window.location.href.indexOf('localhost') > -1) {
|
||||
actionUrl='https://taskapi.osredm.com';
|
||||
// actionUrl='http://192.168.31.47:8081';
|
||||
}else if(window.location.href.indexOf('192.168.31.48') > -1){
|
||||
actionUrl='https://taskapi.osredm.com';
|
||||
axios.defaults.withCredentials = true;
|
||||
}else if(window.location.href.indexOf('noticeweb.osredm') > -1){
|
||||
actionUrl="https://taskapi.osredm.com";
|
||||
axios.defaults.withCredentials = true;
|
||||
}else if(window.location.href.indexOf('forge.osredm.com')>-1){
|
||||
actionUrl="https://info.osredm.com";
|
||||
axios.defaults.withCredentials = true;
|
||||
}
|
||||
export const httpUrl = actionUrl;
|
||||
|
||||
const TokenKey = 'autologin_forge_military';
|
||||
|
||||
// 创建axios实例
|
||||
const service = axios.create({
|
||||
baseURL: httpUrl,
|
||||
timeout: 10000, // 请求超时时间
|
||||
});
|
||||
|
||||
// request拦截器
|
||||
service.interceptors.request.use(config => {
|
||||
if (cookie.load(TokenKey)) {
|
||||
console.log(cookie.load(TokenKey));
|
||||
config.headers['Authorization'] = cookie.load(TokenKey); // 让每个请求携带自定义token 请根据实际情况自行修改
|
||||
}
|
||||
if (window.location.port === "3007") {
|
||||
// 模拟token为登录用户
|
||||
const taskToken = sessionStorage.taskToken;
|
||||
if (config.url.indexOf('?') === -1) {
|
||||
config.url = `${config.url}?token=${taskToken}`;
|
||||
} else {
|
||||
config.url = `${config.url}&token=${taskToken}`;
|
||||
}
|
||||
}
|
||||
return config;
|
||||
}, error => {
|
||||
// Do something with request error
|
||||
console.log(error); // for debug
|
||||
Promise.reject(error);
|
||||
});
|
||||
// respone拦截器
|
||||
service.interceptors.response.use(
|
||||
response => {
|
||||
const res = response;
|
||||
if (res.status === 400) {
|
||||
notification.open({
|
||||
message: "提示",
|
||||
description: res.data.message || '验证失败',
|
||||
});
|
||||
return Promise.reject('error');
|
||||
}
|
||||
if (res.status === 401) {
|
||||
notification.open({
|
||||
message: "提示",
|
||||
description: res.data.message || '未授权,请登录!',
|
||||
});
|
||||
return Promise.reject('error');
|
||||
}
|
||||
if (res.status === 403) {
|
||||
notification.open({
|
||||
message: "提示",
|
||||
description: res.data.message || '无权限',
|
||||
});
|
||||
return Promise.reject('error');
|
||||
}
|
||||
if (res.status === 40001) {
|
||||
notification.open({
|
||||
message: "提示",
|
||||
description: '账户或密码错误!',
|
||||
});
|
||||
return Promise.reject('error');
|
||||
}
|
||||
if (response.status !== 200 && res.status !== 200) {
|
||||
notification.open({
|
||||
message: "提示",
|
||||
description: res.message,
|
||||
});
|
||||
} else {
|
||||
return response.data;
|
||||
}
|
||||
},
|
||||
error => {
|
||||
console.log(error);
|
||||
let res = error.response||{};
|
||||
if (res.status === 400) {
|
||||
notification.open({
|
||||
message: "提示",
|
||||
description: res.data.message || '操作失败',
|
||||
});
|
||||
return Promise.reject('error');
|
||||
}
|
||||
if (res.status === 401) {
|
||||
notification.open({
|
||||
message: "提示",
|
||||
description: res.data.message || '登录信息已过期',
|
||||
});
|
||||
return Promise.reject('error');
|
||||
}
|
||||
if (res.status === 403) {
|
||||
notification.open({
|
||||
message: "提示",
|
||||
description: res.data.message || '无权限!',
|
||||
});
|
||||
window.location.href="/403";
|
||||
return Promise.reject('error');
|
||||
}
|
||||
|
||||
return Promise.reject(error);
|
||||
}
|
||||
);
|
||||
|
||||
export default service;
|
|
@ -148,7 +148,16 @@ export default Form.create()(({ match, history, showNotification, form }) => {
|
|||
{
|
||||
helper('联系方式',
|
||||
'contactInfo',
|
||||
[{ required: true, message: "请输入联系方式" }, { max: 100, message: '不能超过100字符' }],
|
||||
[{ required: true, message: "请输入联系方式" },
|
||||
{ max: 100, message: '不能超过100字符' },
|
||||
{ validator: (rule,val,callback) =>{
|
||||
var pattern = /^((\+)?86|((\+)?86)?)0?1[3458]\d{9}$/;
|
||||
if(pattern.test(val)){
|
||||
callback();
|
||||
}else {
|
||||
callback('请输入正确的联系方式!');
|
||||
}
|
||||
}}],
|
||||
<Input
|
||||
placeholder="请输入联系方式"
|
||||
/>
|
||||
|
|
|
@ -0,0 +1,118 @@
|
|||
import React, { Component, useEffect, useState } from "react";
|
||||
|
||||
import { Route, Switch } from "react-router-dom";
|
||||
import { withRouter } from "react-router";
|
||||
import { SnackbarHOC } from "educoder";
|
||||
import { CNotificationHOC } from "../modules/courses/common/CNotificationHOC";
|
||||
import { TPMIndexHOC } from "../modules/tpm/TPMIndexHOC";
|
||||
import Loadable from "react-loadable";
|
||||
import Loading from "../Loading";
|
||||
import { getUserInfo } from './task/api';
|
||||
import { ImageLayerOfCommentHOC } from "../modules/page/layers/ImageLayerOfCommentHOC";
|
||||
import './index.scss';
|
||||
|
||||
const TaskList = Loadable({
|
||||
loader: () => import("./task/taskList"),
|
||||
loading: Loading,
|
||||
});
|
||||
|
||||
const TaskDetail = Loadable({
|
||||
loader: () => import("./task/taskDetail"),
|
||||
loading: Loading,
|
||||
});
|
||||
|
||||
const TaskEdit = Loadable({
|
||||
loader: () => import("./task/taskEdit"),
|
||||
loading: Loading,
|
||||
});
|
||||
|
||||
const MyTask = Loadable({
|
||||
loader: () => import("./task/myTask"),
|
||||
loading: Loading,
|
||||
});
|
||||
|
||||
|
||||
const TaskAdminRouter = Loadable({
|
||||
loader: () => import("./task/taskAdminRouter"),
|
||||
loading: Loading,
|
||||
});
|
||||
|
||||
|
||||
|
||||
const Index = (propsTransmit) => {
|
||||
// 开发时,从代理的位置获取用户信息
|
||||
const [currentUser, setCurrentUser] = useState(propsTransmit.current_user);
|
||||
// const isDev = window.location.href.indexOf('3007') > -1 ? true : false;
|
||||
useEffect(() => {
|
||||
getUserInfo().then(res => {
|
||||
if (res && res.data) {
|
||||
setCurrentUser(res.data);
|
||||
}
|
||||
})
|
||||
}, [])
|
||||
let propsF = { ...propsTransmit };
|
||||
propsF.current_user = currentUser;
|
||||
|
||||
return (
|
||||
<div className="newMain clearfix">
|
||||
<Switch {...propsF}>
|
||||
|
||||
{/* 任务详情 */}
|
||||
<Route
|
||||
path="/task/taskDetail/:taskId"
|
||||
render={(props) => (
|
||||
<TaskDetail {...propsF} {...props} />
|
||||
)}
|
||||
></Route>
|
||||
|
||||
{/* 新增任务 */}
|
||||
<Route
|
||||
path="/task/taskAdd"
|
||||
render={(props) => (
|
||||
<TaskEdit {...propsF} {...props} />
|
||||
)}
|
||||
></Route>
|
||||
|
||||
{/* 编辑任务 */}
|
||||
<Route
|
||||
path="/task/taskEdit/:taskId"
|
||||
render={(props) => (
|
||||
<TaskEdit {...propsF} {...props} />
|
||||
)}
|
||||
></Route>
|
||||
|
||||
{/* 我的任务 */}
|
||||
<Route
|
||||
path="/task/myTask"
|
||||
render={(props) => (
|
||||
<MyTask {...propsF} {...props} />
|
||||
)}
|
||||
></Route>
|
||||
|
||||
{/* 管理员管理 */}
|
||||
<Route
|
||||
path="/task/:admin"
|
||||
render={(props) => (
|
||||
<TaskAdminRouter {...propsF} {...props} />
|
||||
)}
|
||||
></Route>
|
||||
|
||||
{/* 任务列表 */}
|
||||
<Route
|
||||
path="/task"
|
||||
render={(props) => (
|
||||
<TaskList {...propsF} {...props} />
|
||||
)}
|
||||
></Route>
|
||||
|
||||
</Switch>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
// }
|
||||
export default withRouter(
|
||||
ImageLayerOfCommentHOC({
|
||||
imgSelector: ".imageLayerParent img, .imageLayerParent .imageTarget",
|
||||
parentSelector: ".newMain",
|
||||
})(CNotificationHOC()(SnackbarHOC()(TPMIndexHOC(Index))))
|
||||
);
|
|
@ -0,0 +1,206 @@
|
|||
import React, { useCallback, useEffect, useState } from 'react';
|
||||
import { Input, Button, Form, Select } from 'antd';
|
||||
|
||||
import ItemAgreementManage from '../components/itemAgreementManage';
|
||||
import StatusNav from '../../components/statusNav';
|
||||
import { agreementArr } from '../static';
|
||||
import { agreementList } from '../api';
|
||||
import '../index.scss';
|
||||
const Option = Select.Option;
|
||||
|
||||
const agreementOptionArr = agreementArr.slice(0, 2);
|
||||
export default Form.create()(({ form, showNotification, match, history }) => {
|
||||
|
||||
|
||||
const { getFieldDecorator, validateFields, setFieldsValue, } = form;
|
||||
|
||||
const [approve, setApprove] = useState(1);
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [searchObj, setSearchObj] = useState({});
|
||||
const [status, setStatus] = useState('2');
|
||||
const [curPage, setCurPage] = useState(1);
|
||||
const [total, setTotal] = useState(0);
|
||||
const [taskList, setTaskList] = useState([]);
|
||||
const [type, setType] = useState('1');
|
||||
|
||||
const [reload, setReload] = useState(0);
|
||||
|
||||
const [loadPaper, setLoadPaper] = useState(0);
|
||||
|
||||
// 加载审核协议列表
|
||||
useEffect(() => {
|
||||
const params = {
|
||||
...searchObj,
|
||||
status,
|
||||
type,
|
||||
currentPage: curPage,
|
||||
pageSize: 10,
|
||||
};
|
||||
setLoading(true);
|
||||
agreementList(params).then(data => {
|
||||
if (data) {
|
||||
if (loadPaper === 0 && data.rows.length === 0) {
|
||||
setLoadPaper(1);
|
||||
} else {
|
||||
setLoadPaper(2);
|
||||
}
|
||||
setTaskList(data.rows);
|
||||
setTotal(data.total);
|
||||
}
|
||||
setLoading(false);
|
||||
});
|
||||
}, [reload, status, curPage, searchObj, type]);
|
||||
|
||||
// 如果第一次加载任务协议审核发现没有数据,那么切换成审核成果协议列表
|
||||
useEffect(() => {
|
||||
if (loadPaper === 1) {
|
||||
const params = {
|
||||
status: '2',
|
||||
type: '2',
|
||||
currentPage: 1,
|
||||
pageSize: 10,
|
||||
};
|
||||
setLoading(true);
|
||||
agreementList(params).then(data => {
|
||||
if (data && data.rows.length > 0) {
|
||||
setTaskList(data.rows);
|
||||
setTotal(data.total);
|
||||
setType('2');
|
||||
setLoadPaper(2);
|
||||
}
|
||||
setLoading(false);
|
||||
});
|
||||
}
|
||||
}, [loadPaper]);
|
||||
|
||||
// form表单公共处理函数
|
||||
const helper = useCallback(
|
||||
(name, rules, widget, initialValue) => (
|
||||
<Form.Item>
|
||||
{getFieldDecorator(name, { rules, initialValue, validateFirst: true, })(widget)}
|
||||
</Form.Item>
|
||||
), []);
|
||||
|
||||
|
||||
function onSearch() {
|
||||
validateFields((err, values) => {
|
||||
if (!err) {
|
||||
setSearchObj(values);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// 修改选项
|
||||
const changeOptionId = useCallback((option) => {
|
||||
setStatus(option.dicItemCode.toString() || '0,1');
|
||||
setCurPage(1);
|
||||
}, []);
|
||||
|
||||
// 修改状态
|
||||
function changeApprove(approve) {
|
||||
setApprove(approve);
|
||||
setCurPage(1);
|
||||
if (approve === 1) {
|
||||
setStatus('2');
|
||||
} else {
|
||||
setStatus('0,1');
|
||||
}
|
||||
}
|
||||
|
||||
// 清除查询内容
|
||||
function clearSearch() {
|
||||
setFieldsValue({
|
||||
taskNumber: '',
|
||||
taskName: '',
|
||||
userName: ''
|
||||
});
|
||||
setSearchObj({});
|
||||
}
|
||||
|
||||
// 刷新数据
|
||||
const reloadList = useCallback(() => {
|
||||
setReload(Math.random());
|
||||
}, []);
|
||||
|
||||
|
||||
return (
|
||||
<div className="centerbox task-manage">
|
||||
|
||||
<div className="center-screen" >
|
||||
<div className="center-left-but">
|
||||
{helper(
|
||||
"type",
|
||||
[],
|
||||
<Select
|
||||
showArrow
|
||||
placeholder="请选择协议"
|
||||
onChange={(type) => { setType(type) }}
|
||||
>
|
||||
<Option key={'1'}>委托协议</Option>
|
||||
<Option key={'2'}>成果协议</Option>
|
||||
</Select>,
|
||||
type
|
||||
)}
|
||||
<Button className="circle-button" type={approve === 1 ? 'primary' : ''} onClick={() => { changeApprove(1) }}>待审批</Button>
|
||||
<Button className="circle-button" type={approve === 2 ? 'primary' : ''} onClick={() => { changeApprove(2) }}>已审批</Button>
|
||||
</div>
|
||||
|
||||
<div className="center-right-but">
|
||||
{helper(
|
||||
"taskNumber",
|
||||
[{ max: 20, message: '长度不能超过20个字符' }],
|
||||
<Input
|
||||
placeholder="输入任务编号进行检索"
|
||||
/>
|
||||
)}
|
||||
|
||||
{helper(
|
||||
"taskName",
|
||||
[{ max: 20, message: '长度不能超过20个字符' }],
|
||||
<Input
|
||||
placeholder="输入任务名称进行检索"
|
||||
/>
|
||||
)}
|
||||
|
||||
{helper(
|
||||
"userName",
|
||||
[{ max: 20, message: '长度不能超过20个字符' }],
|
||||
<Input
|
||||
placeholder="输入发布人名称进行检索"
|
||||
/>
|
||||
)}
|
||||
|
||||
<Button className="mr10" type="primary" onClick={onSearch}>搜索</Button>
|
||||
<Button className="mr10" type="" onClick={clearSearch}>清除</Button>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div className="center-content">
|
||||
|
||||
{
|
||||
approve === 2 && <StatusNav
|
||||
key={'status'}
|
||||
type={'status'}
|
||||
options={agreementOptionArr}
|
||||
changeOptionId={changeOptionId}
|
||||
/>
|
||||
}
|
||||
<ItemAgreementManage
|
||||
list={taskList}
|
||||
curPage={curPage}
|
||||
total={total}
|
||||
changePage={(page) => { setCurPage(page) }}
|
||||
loading={loading}
|
||||
showNotification={showNotification}
|
||||
reloadList={reloadList}
|
||||
/>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
)
|
||||
}
|
||||
)
|
|
@ -0,0 +1,571 @@
|
|||
import fetch, { } from '../fetch';
|
||||
import { notification } from 'antd';
|
||||
import { func } from 'prop-types';
|
||||
|
||||
// 获取字典分类列表
|
||||
export function getDictionary(id) {
|
||||
return fetch({
|
||||
url: '/dicItem/getData?dicTypeCode=' + id,
|
||||
method: 'get'
|
||||
});
|
||||
}
|
||||
|
||||
// 获取用户信息
|
||||
export function getUserInfo() {
|
||||
return fetch({
|
||||
url: '/user/getUserInfo',
|
||||
method: 'get'
|
||||
});
|
||||
}
|
||||
|
||||
// 获取用户企业信息
|
||||
export function getCompanyInfo() {
|
||||
return fetch({
|
||||
url: '/api/tasks/getEnterpriseUserInfo',
|
||||
method: 'get'
|
||||
});
|
||||
}
|
||||
|
||||
// 获取任务领域
|
||||
export async function getTaskCategory() {
|
||||
let res = await fetch({
|
||||
url: '/api/taskCategory/getTaskCategory',
|
||||
method: 'get',
|
||||
});
|
||||
if (Array.isArray(res.data.rows)) {
|
||||
return res.data.rows;
|
||||
} else {
|
||||
notification.open({
|
||||
message: "提示",
|
||||
description: res.message || '请求错误',
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// 任务列表查询
|
||||
export async function getTaskList(params) {
|
||||
let res = await fetch({
|
||||
url: '/api/tasks/',
|
||||
method: 'get',
|
||||
params,
|
||||
});
|
||||
if (res.data) {
|
||||
return res.data;
|
||||
} else {
|
||||
notification.open({
|
||||
message: "提示",
|
||||
description: res.message || '请求错误',
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// 管理员任务列表查询
|
||||
export async function getTaskAdminList(params) {
|
||||
let res = await fetch({
|
||||
url: '/api/tasks/backend/list',
|
||||
method: 'get',
|
||||
params,
|
||||
});
|
||||
if (res.data) {
|
||||
return res.data;
|
||||
} else {
|
||||
notification.open({
|
||||
message: "提示",
|
||||
description: res.message || '请求错误',
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// 我的任务列表查询
|
||||
export async function getMyTaskList(params) {
|
||||
let res = await fetch({
|
||||
url: '/api/myTasks/',
|
||||
method: 'get',
|
||||
params,
|
||||
});
|
||||
if (res.data) {
|
||||
return res.data;
|
||||
} else {
|
||||
notification.open({
|
||||
message: "提示",
|
||||
description: res.message || '请求错误',
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// 我参与的任务列表查询
|
||||
export async function getJoinTaskList(params) {
|
||||
let res = await fetch({
|
||||
url: '/api/myTasks/myPapers',
|
||||
method: 'get',
|
||||
params,
|
||||
});
|
||||
if (res.data) {
|
||||
return res.data;
|
||||
} else {
|
||||
notification.open({
|
||||
message: "提示",
|
||||
description: res.message || '请求错误',
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
// 详情查询
|
||||
export async function getTaskDetail(id) {
|
||||
let res = await fetch({
|
||||
url: '/api/tasks/getTask/' + id,
|
||||
method: 'get',
|
||||
});
|
||||
if (res.data) {
|
||||
return res.data;
|
||||
} else {
|
||||
notification.open({
|
||||
message: "提示",
|
||||
description: res.message || '请求错误',
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
//新增任务
|
||||
export function addTask(data) {
|
||||
return fetch({
|
||||
url: '/api/tasks/add',
|
||||
method: 'post',
|
||||
data: data
|
||||
});
|
||||
}
|
||||
|
||||
//更新任务
|
||||
export function updateTask(data) {
|
||||
return fetch({
|
||||
url: '/api/tasks/',
|
||||
method: 'PUT',
|
||||
data: data
|
||||
});
|
||||
}
|
||||
|
||||
//删除
|
||||
export function deleteTask(id) {
|
||||
return fetch({
|
||||
url: '/api/tasks/' + id,
|
||||
method: 'DELETE',
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
//新增成果
|
||||
export function addPaper(data) {
|
||||
return fetch({
|
||||
url: '/api/paper/',
|
||||
method: 'post',
|
||||
data: data
|
||||
});
|
||||
}
|
||||
|
||||
// 任务成果
|
||||
export async function getTaskPaper(params) {
|
||||
let res = await fetch({
|
||||
url: '/api/paper/',
|
||||
method: 'get',
|
||||
params,
|
||||
});
|
||||
if (res.data) {
|
||||
return res.data;
|
||||
} else {
|
||||
notification.open({
|
||||
message: "提示",
|
||||
description: res.message || '请求错误',
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// 审核任务成果
|
||||
export async function readyCheckPapers(params) {
|
||||
let res = await fetch({
|
||||
url: '/api/paper/admin/readyCheckPapers',
|
||||
method: 'get',
|
||||
params,
|
||||
});
|
||||
if (res.data) {
|
||||
return res.data;
|
||||
} else {
|
||||
notification.open({
|
||||
message: "提示",
|
||||
description: res.message || '请求错误',
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// 我的成果
|
||||
export async function myPapers(params) {
|
||||
let res = await fetch({
|
||||
url: '/api/paper/my',
|
||||
method: 'get',
|
||||
params,
|
||||
});
|
||||
if (res.data) {
|
||||
return res.data;
|
||||
} else {
|
||||
notification.open({
|
||||
message: "提示",
|
||||
description: res.message || '请求错误',
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
//更新成果
|
||||
export function updatePaper(data) {
|
||||
return fetch({
|
||||
url: '/api/paper/',
|
||||
method: 'put',
|
||||
data: data
|
||||
});
|
||||
}
|
||||
|
||||
// 删除
|
||||
export function deletePaper(id) {
|
||||
return fetch({
|
||||
url: `api/paper/${id}`,
|
||||
method: 'delete',
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
//应征者名单公示
|
||||
export function makePublic(id) {
|
||||
return fetch({
|
||||
url: `/api/tasks/makeApplicantListPublic/${id}`,
|
||||
method: 'put',
|
||||
});
|
||||
}
|
||||
|
||||
//举报成果
|
||||
export function reportPaper(data) {
|
||||
return fetch({
|
||||
url: `/api/paper/${data.paperId}/paperReport`,
|
||||
method: 'post',
|
||||
data: data
|
||||
});
|
||||
}
|
||||
|
||||
//点赞成果
|
||||
export function thumbUpPaper(id) {
|
||||
return fetch({
|
||||
url: `/api/paper/${id}/thumbUp`,
|
||||
method: 'post',
|
||||
data: { paperId: id }
|
||||
});
|
||||
}
|
||||
|
||||
// 检查用户是否同意协议
|
||||
export function checkAgreement(taskId) {
|
||||
return fetch({
|
||||
url: `/api/paper/${taskId}/agreement`,
|
||||
method: 'get'
|
||||
});
|
||||
}
|
||||
|
||||
// 检查用户是否提交了成果
|
||||
export function checkHavePaper(taskId) {
|
||||
return fetch({
|
||||
url: `/api/paper/${taskId}/check`,
|
||||
method: 'get'
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
// 获取协议
|
||||
export function getAgreement() {
|
||||
return fetch({
|
||||
url: '/api/paper/agreementSettings/1',
|
||||
method: 'get'
|
||||
});
|
||||
}
|
||||
|
||||
// 同意协议
|
||||
export function agreement(taskId) {
|
||||
return fetch({
|
||||
url: `/api/paper/${taskId}/agreement`,
|
||||
method: 'post',
|
||||
data: { taskId }
|
||||
});
|
||||
}
|
||||
|
||||
// 新增评论
|
||||
export function commentAdd(data) {
|
||||
return fetch({
|
||||
url: `/api/paper/${data.paperId}/comment`,
|
||||
method: 'post',
|
||||
data,
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
//管理员审核任务
|
||||
export function checkTask(data) {
|
||||
return fetch({
|
||||
url: `/api/tasks/backend/adminCheck`,
|
||||
method: 'post',
|
||||
data: data
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
// 审核成果/评论
|
||||
export function checkPaper(data) {
|
||||
return fetch({
|
||||
url: `/api/paper/admin/complainPaper/${data.paperId}`,
|
||||
method: 'post',
|
||||
data: data.auditingVo
|
||||
});
|
||||
}
|
||||
|
||||
// 成果申诉
|
||||
export function complainPaper(data) {
|
||||
return fetch({
|
||||
url: `/api/paper/complainInfo/${data.paperId}`,
|
||||
method: 'post',
|
||||
data: data.params
|
||||
});
|
||||
}
|
||||
|
||||
// 审核申诉材料列表查询
|
||||
export async function complainPaperList(params) {
|
||||
let res = await fetch({
|
||||
url: '/api/paper/admin/readyComplaintPapers',
|
||||
method: 'get',
|
||||
params,
|
||||
});
|
||||
if (res.data) {
|
||||
return res.data;
|
||||
} else {
|
||||
notification.open({
|
||||
message: "提示",
|
||||
description: res.message || '请求错误',
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// 审核申诉材料
|
||||
export function checkComplain(data) {
|
||||
return fetch({
|
||||
url: `/api/paper/admin/complainMaterial/${data.paperId}`,
|
||||
method: 'post',
|
||||
data: data.auditingVo
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
// 佐证上传
|
||||
export function proofAdd(data) {
|
||||
return fetch({
|
||||
url: `/api/taskResultProof/addTaskResultProof`,
|
||||
method: 'post',
|
||||
data,
|
||||
});
|
||||
}
|
||||
|
||||
// 审核佐证材料列表查询
|
||||
export async function proofList(params) {
|
||||
let res = await fetch({
|
||||
url: '/api/tasks/backend/proofList',
|
||||
method: 'get',
|
||||
params,
|
||||
});
|
||||
if (res.data) {
|
||||
return res.data;
|
||||
} else {
|
||||
notification.open({
|
||||
message: "提示",
|
||||
description: res.message || '请求错误',
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// 审核佐证
|
||||
export function checkProof(data) {
|
||||
return fetch({
|
||||
url: `/api/taskResultProof/adminCheckResultAndProof`,
|
||||
method: 'post',
|
||||
data,
|
||||
});
|
||||
}
|
||||
|
||||
// 应征者公示期申诉
|
||||
export function publicityComplain(data) {
|
||||
return fetch({
|
||||
url: `/api/myTasks/applicantComplaintDuringPublicity`,
|
||||
method: 'post',
|
||||
data,
|
||||
});
|
||||
}
|
||||
|
||||
// 审核公示期申诉列表查询
|
||||
export async function publicityComplainList(params) {
|
||||
let res = await fetch({
|
||||
url: '/api/tasks/backend/complaintMaterialList',
|
||||
method: 'get',
|
||||
params,
|
||||
});
|
||||
if (res.data) {
|
||||
return res.data;
|
||||
} else {
|
||||
notification.open({
|
||||
message: "提示",
|
||||
description: res.message || '请求错误',
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// 审核公示期申诉
|
||||
export function checkPublicity(data) {
|
||||
return fetch({
|
||||
url: `/api/tasks/backend/adminCheck/complaintMaterialDuringPublicity`,
|
||||
method: 'post',
|
||||
data,
|
||||
});
|
||||
}
|
||||
|
||||
// 选择签订协议的方式
|
||||
export function signMethod(data) {
|
||||
return fetch({
|
||||
url: `/api/sign/method/${data.taskId}/${data.method}`,
|
||||
method: 'post',
|
||||
});
|
||||
}
|
||||
|
||||
// 上传委托协议
|
||||
export function uploadAgreeRequire(data) {
|
||||
return fetch({
|
||||
url: `/api/sign/task/contract/${data.taskId}`,
|
||||
method: 'post',
|
||||
data: data.params
|
||||
});
|
||||
}
|
||||
|
||||
// 审核委托协议列表
|
||||
export async function agreementList(params) {
|
||||
let res = await fetch({
|
||||
url: '/api/sign/task/contract',
|
||||
method: 'get',
|
||||
params,
|
||||
});
|
||||
if (res.data) {
|
||||
return res.data;
|
||||
} else {
|
||||
notification.open({
|
||||
message: "提示",
|
||||
description: res.message || '请求错误',
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// 审核协议
|
||||
export function adminCheckAgreement(data) {
|
||||
return fetch({
|
||||
url: `/api/sign/admin/${data.type === 1 ? 'task' : 'paper'}/contract/${data.agreementId}`,
|
||||
method: 'post',
|
||||
data: data.params
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
// 上传委托协议
|
||||
export function uploadAgreePaper(data) {
|
||||
return fetch({
|
||||
url: `/api/sign/paper/contract/${data.paperId}`,
|
||||
method: 'post',
|
||||
data: data.params
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
// 上传凭证列表查询
|
||||
export async function uploadPayProofList(params) {
|
||||
let res = await fetch({
|
||||
url: '/api/sign/admin/paper/payOrders',
|
||||
method: 'get',
|
||||
params,
|
||||
});
|
||||
if (res.data) {
|
||||
return res.data;
|
||||
} else {
|
||||
notification.open({
|
||||
message: "提示",
|
||||
description: res.message || '请求错误',
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// 管理员上传支付凭证
|
||||
export function uploadPayProof(data){
|
||||
return fetch({
|
||||
url: `/api/sign/admin/paper/payment/${data.paperId}`,
|
||||
method: 'post',
|
||||
data: data.params
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
// 胜出者确认收款
|
||||
export function confirmReceipt(paperId) {
|
||||
return fetch({
|
||||
url: `/api/sign/paper/money/${paperId}`,
|
||||
method: 'post',
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
// 下载协议签订凭证
|
||||
export function downAgreement(params) {
|
||||
return fetch({
|
||||
url: `/api/myTasks/getWinnersContractsByTaskId`,
|
||||
method: 'get',
|
||||
params,
|
||||
});
|
||||
}
|
||||
|
||||
// 管理员修改任务公示方式
|
||||
export function changeShowUserMode(data) {
|
||||
return fetch({
|
||||
url: `/api/tasks/backend/changeShowUserMode`,
|
||||
method: 'post',
|
||||
data,
|
||||
});
|
||||
}
|
||||
|
||||
// 延期列表查询
|
||||
export async function delayList(params) {
|
||||
let res = await fetch({
|
||||
url: '/api/tasks/backend/admin/delayList',
|
||||
method: 'get',
|
||||
params,
|
||||
});
|
||||
if (res.data) {
|
||||
return res.data;
|
||||
} else {
|
||||
notification.open({
|
||||
message: "提示",
|
||||
description: res.message || '请求错误',
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// 延期
|
||||
export function delayTask(data) {
|
||||
return fetch({
|
||||
url: `/api/tasks/backend/admin/task/delay/${data.taskId}`,
|
||||
method: 'post',
|
||||
data:data.params,
|
||||
});
|
||||
}
|
||||
|
||||
// 关闭
|
||||
export function closeTask(taskId) {
|
||||
return fetch({
|
||||
url: `/api/tasks/backend/admin/task/close/${taskId}`,
|
||||
method: 'post',
|
||||
});
|
||||
}
|
|
@ -0,0 +1,135 @@
|
|||
import React, { useMemo } from 'react';
|
||||
import { Menu, Dropdown, } from 'antd';
|
||||
import { current_main_site_url,main_web_site_url} from '../../static';
|
||||
|
||||
import './index.scss';
|
||||
|
||||
const { SubMenu } = Menu;
|
||||
|
||||
export default props => {
|
||||
|
||||
const projectMenu = useMemo(() => {
|
||||
return <Menu>
|
||||
<Menu.Item><a target="_blank" rel="noopener noreferrer" href={`${current_main_site_url}/admins`}>项目管理后台</a></Menu.Item>
|
||||
</Menu>
|
||||
});
|
||||
|
||||
const taskMenu = useMemo(() => {
|
||||
return <Menu>
|
||||
<SubMenu title="基础数据" >
|
||||
<Menu.Item><a href={`${main_web_site_url}/admin/categories/list`}>任务领域</a></Menu.Item>
|
||||
<Menu.Item><a href={`${main_web_site_url}/admin/industries/list`}>行业信息</a></Menu.Item>
|
||||
<Menu.Item><a href={`${main_web_site_url}/admin/placements/list`}>职位信息</a></Menu.Item>
|
||||
<Menu.Item><a href={`${main_web_site_url}/admin/task_templates/list`}>需求导入模板</a></Menu.Item>
|
||||
<Menu.Item><a href={`${main_web_site_url}/admin/agreement_setting`}>签订协议内容</a></Menu.Item>
|
||||
<Menu.Item><a href={`${main_web_site_url}/admin/sign_agreement_setting`}>应征投稿协议内容</a></Menu.Item>
|
||||
</SubMenu>
|
||||
<SubMenu title="代办事项" >
|
||||
<Menu.Item><a href={`/task/delayManage`}>延期任务处理</a></Menu.Item>
|
||||
<Menu.Item><a href={`${main_web_site_url}/admin/audit_files`}>协议签订凭证上传</a></Menu.Item>
|
||||
<Menu.Item><a href="/task/payProof">支付报酬凭证上传</a></Menu.Item>
|
||||
</SubMenu>
|
||||
|
||||
<Menu.Item><a href="/task/taskAdmin">创客列表</a></Menu.Item>
|
||||
<Menu.Item><a href="/task/paperManage">创意征集评论</a></Menu.Item>
|
||||
</Menu>
|
||||
});
|
||||
|
||||
const competitionMenu = useMemo(() => {
|
||||
return <Menu>
|
||||
<Menu.Item><a target="_blank" rel="noopener noreferrer" href={`${main_web_site_url}/admin/competitions/list`}>竞赛列表</a></Menu.Item>
|
||||
</Menu>
|
||||
});
|
||||
|
||||
const userMenu = useMemo(() => {
|
||||
return <Menu>
|
||||
<Menu.Item><a target="_blank" rel="noopener noreferrer" href={`${main_web_site_url}/managements/users`}>用户列表</a></Menu.Item>
|
||||
<Menu.Item><a target="_blank" rel="noopener noreferrer" href={`${main_web_site_url}/admin/entities`}>主体信息列表</a></Menu.Item>
|
||||
<Menu.Item><a target="_blank" rel="noopener noreferrer" href={`${main_web_site_url}/managements/users_trial`}>试用授权列表</a></Menu.Item>
|
||||
<Menu.Item><a target="_blank" rel="noopener noreferrer" href={`${main_web_site_url}/managements/auto_users_trial`}>自动授权列表</a></Menu.Item>
|
||||
</Menu>
|
||||
});
|
||||
|
||||
const forumMenu = useMemo(() => {
|
||||
return <Menu>
|
||||
<Menu.Item><a target="_blank" rel="noopener noreferrer" href={`${main_web_site_url}/managements/messages_list`}>帖子</a></Menu.Item>
|
||||
<Menu.Item><a target="_blank" rel="noopener noreferrer" href={`${main_web_site_url}/managements/apply_destroy_memos`}>申请删帖</a></Menu.Item>
|
||||
<Menu.Item><a target="_blank" rel="noopener noreferrer" href={`${main_web_site_url}/managements/memo_reply_list`}>回复</a></Menu.Item>
|
||||
<Menu.Item><a target="_blank" rel="noopener noreferrer" href={`${main_web_site_url}/admin/forum_sections`}>版块配置</a></Menu.Item>
|
||||
<Menu.Item><a target="_blank" rel="noopener noreferrer" href={`${main_web_site_url}/admin/banned_users`}>禁言列表</a></Menu.Item>
|
||||
<Menu.Item><a target="_blank" rel="noopener noreferrer" href={`${main_web_site_url}/admin/forum_applies`}>版主审批</a></Menu.Item>
|
||||
</Menu>
|
||||
});
|
||||
|
||||
|
||||
const checkMenu = useMemo(() => {
|
||||
return <Menu>
|
||||
<Menu.Item><a target="_blank" rel="noopener noreferrer" href={`${main_web_site_url}/managements/enterprise_authentication`}>企业认证</a></Menu.Item>
|
||||
<Menu.Item><a target="_blank" rel="noopener noreferrer" href={`${main_web_site_url}/admin/reviews/projects_list`}>开源项目</a></Menu.Item>
|
||||
<Menu.Item><a href="/task/taskManage">统筹任务发布审批</a></Menu.Item>
|
||||
<Menu.Item><a href="/task/paperComplain">成果上传申诉审批</a></Menu.Item>
|
||||
<Menu.Item><a href="/task/publicityComplain">公示期成果申诉审批</a></Menu.Item>
|
||||
<Menu.Item><a href="/task/agreementManage">协议审批</a></Menu.Item>
|
||||
<Menu.Item><a target="_blank" rel="noopener noreferrer" href={`${main_web_site_url}/admin/tasks/report_result_tasks`}>成果举报申诉</a></Menu.Item>
|
||||
<Menu.Item><a href="/task/proofManage">评选佐证材料</a></Menu.Item>
|
||||
</Menu>
|
||||
});
|
||||
|
||||
|
||||
const limitsMenu = useMemo(() => {
|
||||
return <Menu>
|
||||
<Menu.Item><a target="_blank" rel="noopener noreferrer" href={`${main_web_site_url}/managements/user_admin_roles`}>权限组配置</a></Menu.Item>
|
||||
<Menu.Item><a target="_blank" rel="noopener noreferrer" href={`${main_web_site_url}/managements/admin_role_permissions`}>权限操作配置</a></Menu.Item>
|
||||
</Menu>
|
||||
});
|
||||
|
||||
|
||||
const configMenu = useMemo(() => {
|
||||
return <Menu>
|
||||
<Menu.Item><a target="_blank" rel="noopener noreferrer" href={`${main_web_site_url}/admin/about_infos/new"`}>关于我们</a></Menu.Item>
|
||||
<Menu.Item><a target="_blank" rel="noopener noreferrer" href={`${main_web_site_url}/admin/home_sections"`}>首页版块</a></Menu.Item>
|
||||
<Menu.Item><a target="_blank" rel="noopener noreferrer" href={`${main_web_site_url}/admin/partners`}>合作伙伴</a></Menu.Item>
|
||||
</Menu>
|
||||
});
|
||||
|
||||
|
||||
return (
|
||||
<div className="centerbox managements_menus clearfix">
|
||||
<Dropdown key={'projectMenu'} overlay={projectMenu} placement="bottomLeft">
|
||||
<div className="drop-div">
|
||||
项目
|
||||
</div>
|
||||
</Dropdown>
|
||||
|
||||
<Dropdown key={'taskMenu'} overlay={taskMenu} placement="bottomLeft">
|
||||
<div className="drop-div">
|
||||
创客
|
||||
</div>
|
||||
</Dropdown>
|
||||
|
||||
<Dropdown key={'competitionMenu'} overlay={competitionMenu} placement="bottomLeft">
|
||||
<div className="drop-div">竞赛</div>
|
||||
</Dropdown>
|
||||
|
||||
<Dropdown key={'userMenu'} overlay={userMenu} placement="bottomLeft">
|
||||
<div className="drop-div">用户</div>
|
||||
</Dropdown>
|
||||
|
||||
<Dropdown key={'forumMenu'} overlay={forumMenu} placement="bottomLeft">
|
||||
<div className="drop-div">论坛交流</div>
|
||||
</Dropdown>
|
||||
|
||||
<Dropdown key={'checkMenu'} overlay={checkMenu} placement="bottomLeft">
|
||||
<div className="drop-div">审批</div>
|
||||
</Dropdown>
|
||||
|
||||
<Dropdown key={'limitsMenu'} overlay={limitsMenu} placement="bottomLeft">
|
||||
<div className="drop-div">权限管理</div>
|
||||
</Dropdown>
|
||||
|
||||
<Dropdown key={'configMenu'} overlay={configMenu} placement="bottomLeft">
|
||||
<div className="drop-div">网站配置</div>
|
||||
</Dropdown>
|
||||
</div>
|
||||
)
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
.managements_menus {
|
||||
background: #fff;
|
||||
border: 1px solid #eee;
|
||||
|
||||
.drop-div {
|
||||
position: relative;
|
||||
float: left;
|
||||
width: 108px;
|
||||
text-align: center;
|
||||
padding: 15px 0px;
|
||||
box-sizing: border-box;
|
||||
position: relative;
|
||||
cursor: pointer;
|
||||
&::after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
right: 1px;
|
||||
top: 20px;
|
||||
width: 1px;
|
||||
height: 20px;
|
||||
background-color: #ddd;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,75 @@
|
|||
import React, { useState, } from 'react';
|
||||
import { Modal, Form, Input, } from 'antd';
|
||||
import Upload from 'military/components/Upload';
|
||||
import { uploadAgreePaper } from "../../api";
|
||||
import '../../index.scss';
|
||||
|
||||
|
||||
export default Form.create()(props => {
|
||||
const { visible, setVisible, checkedItem, form, showNotification ,reloadList } = props;
|
||||
const { getFieldDecorator, validateFields, setFieldsValue, } = form;
|
||||
|
||||
const [fileList, setFileList] = useState([]);
|
||||
|
||||
|
||||
// 上传附件后得到的文件数组
|
||||
function uploadFunc(fileList, files) {
|
||||
setFileList(fileList);
|
||||
setFieldsValue({
|
||||
files,
|
||||
});
|
||||
}
|
||||
|
||||
function uploadAgree() {
|
||||
validateFields((err, values) => {
|
||||
if (!err) {
|
||||
uploadAgreePaper({
|
||||
paperId: checkedItem.id,
|
||||
params: {
|
||||
files: values.files,
|
||||
}
|
||||
}).then(res => {
|
||||
if (res.message === 'success') {
|
||||
setFieldsValue({
|
||||
files: '',
|
||||
});
|
||||
setVisible(false);
|
||||
showNotification("上传协议成功!");
|
||||
reloadList();
|
||||
} else {
|
||||
showNotification(res.message || "上传协议失败")
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
return (
|
||||
<Modal
|
||||
title="签订协议"
|
||||
visible={visible}
|
||||
onOk={uploadAgree}
|
||||
onCancel={() => { setVisible(false) }}
|
||||
className="form-edit-modal"
|
||||
>
|
||||
<div className="task-popup-content">
|
||||
{/* paperAuditing */}
|
||||
{checkedItem.paperAuditing && <p className=" mb10 color-orange task_tip">审核意见:{checkedItem.paperAuditing.message}</p>}
|
||||
<a href="http://117.50.100.12:8000/attachments/download/523/%E5%88%9B%E5%AE%A2%E4%BB%BB%E5%8A%A1%E5%88%97%E8%A1%A8_2019-07-26_20-53.xlsx" className="icon icon-attachment font-13 color-blue" length="32">协议样板.word</a>
|
||||
<Form.Item className="upload-form" label="附件上传" required={true}>
|
||||
<Upload
|
||||
load={uploadFunc}
|
||||
size={50}
|
||||
showNotification={showNotification}
|
||||
fileList={fileList}
|
||||
/>
|
||||
{getFieldDecorator('files', {
|
||||
rules: [{ required: visible, message: "请上传文件" }],
|
||||
validateFirst: true
|
||||
})(<Input style={{ display: 'none' }} />)}
|
||||
</Form.Item>
|
||||
</div>
|
||||
</Modal>
|
||||
)
|
||||
}
|
||||
)
|
|
@ -0,0 +1,109 @@
|
|||
import React, { useState, useCallback, useMemo} from 'react';
|
||||
import { Modal, Form, Input, } from 'antd';
|
||||
import Upload from 'military/components/Upload';
|
||||
import { complainPaper, publicityComplain, } from "../../api";
|
||||
import '../../index.scss';
|
||||
|
||||
const { TextArea } = Input;
|
||||
|
||||
export default Form.create()(props => {
|
||||
const { visible, setVisible, checkedItem, detailStatus, form, showNotification, reloadList } = props;
|
||||
const { getFieldDecorator, validateFields, setFieldsValue, } = form;
|
||||
|
||||
const [fileList, setFileList] = useState([]);
|
||||
|
||||
// 上传附件后得到的文件数组
|
||||
function uploadFunc(fileList, files) {
|
||||
setFileList(fileList);
|
||||
setFieldsValue({
|
||||
files,
|
||||
});
|
||||
}
|
||||
|
||||
const helper = useCallback(
|
||||
(name, rules, widget) => (
|
||||
<Form.Item>
|
||||
{getFieldDecorator(name, { rules, validateFirst: true })(widget)}
|
||||
</Form.Item>
|
||||
),
|
||||
[]
|
||||
);
|
||||
|
||||
function complain() {
|
||||
validateFields((error, values) => {
|
||||
if (!error) {
|
||||
if (detailStatus === 5) {
|
||||
publicityComplain({
|
||||
content: values.complainValue,
|
||||
files: values.files,
|
||||
paperId: checkedItem.id,
|
||||
}).then(res => {
|
||||
complainDeal(res);
|
||||
});
|
||||
} else {
|
||||
complainPaper({
|
||||
paperId: checkedItem.id,
|
||||
params: {
|
||||
content: values.complainValue,
|
||||
files: values.files,
|
||||
}
|
||||
}).then(res => {
|
||||
complainDeal(res);
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function complainDeal(res) {
|
||||
if (res && res.message === 'success') {
|
||||
showNotification('申诉提交成功');
|
||||
setVisible(false);
|
||||
setFileList(null);
|
||||
setFieldsValue({
|
||||
files: ''
|
||||
});
|
||||
reloadList();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return (
|
||||
<Modal
|
||||
title="申诉"
|
||||
visible={visible}
|
||||
onOk={complain}
|
||||
onCancel={() => { setVisible(false) }}
|
||||
className="form-edit-modal"
|
||||
>
|
||||
{checkedItem.checkStatus == 2 && detailStatus === 3 && <p className=" mb10 color-orange task_tip">审核意见:{checkedItem.auditing.message}</p>}
|
||||
<p className="edu-txt-center lineh-20 mb10">你的申诉信息将发送给平台管理员</p>
|
||||
<p className="edu-txt-center lineh-20">请如实填写有效的申诉原由,我们将尽快完成审核</p>
|
||||
{
|
||||
helper('complainValue', [{ required: visible, message: "(必填)请在此输入发起申诉的原因,最大限制100个字符" },
|
||||
{ max: 100, message: '长度不能超过100个字符' }],
|
||||
<TextArea
|
||||
placeholder="(必填)请在此输入发起申诉的原因,最大限制100个字符"
|
||||
autoSize={{ minRows: 6 }}
|
||||
className="applyText"
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
<Form.Item className="upload-form" label="附件上传" required={true}>
|
||||
<Upload
|
||||
className="commentStyle"
|
||||
load={uploadFunc}
|
||||
size={50}
|
||||
showNotification={showNotification}
|
||||
fileList={fileList}
|
||||
/>
|
||||
{getFieldDecorator('files', {
|
||||
rules: [{ required: visible, message: "请上传文件" }],
|
||||
validateFirst: true
|
||||
})(<Input style={{ display: 'none' }} />)}
|
||||
</Form.Item>
|
||||
</Modal>
|
||||
)
|
||||
}
|
||||
)
|
|
@ -0,0 +1,208 @@
|
|||
import React, { useEffect, useState, useCallback } from 'react';
|
||||
import { Pagination, Modal, Input, Form, } from 'antd';
|
||||
import { Link } from "react-router-dom";
|
||||
import Nodata from 'forge/Nodata';
|
||||
import Loading from "src/Loading";
|
||||
import { timeAgo, getImageUrl } from 'educoder';
|
||||
import { adminCheckAgreement } from '../../api';
|
||||
import { httpUrl } from 'military/fetch';
|
||||
import './index.scss';
|
||||
|
||||
const { TextArea } = Input;
|
||||
export default Form.create()((props) => {
|
||||
const { form, list, curPage, total, changePage, loading, showNotification, reloadList } = props;
|
||||
const { getFieldDecorator, validateFields, setFieldsValue } = form;
|
||||
const [checkedItem, setCheckedItem] = useState({});
|
||||
const [page, setPage] = useState(1);
|
||||
const [visible, setVisible] = useState(false);
|
||||
const pageSize = props.pageSize || 10;
|
||||
|
||||
useEffect(() => {
|
||||
changePage(page);
|
||||
}, [page]);
|
||||
|
||||
|
||||
function refuseClick(item) {
|
||||
setCheckedItem(item);
|
||||
setVisible(true);
|
||||
}
|
||||
|
||||
function dealAction() {
|
||||
validateFields((error, values) => {
|
||||
if (!error) {
|
||||
adminCheckAgreement({
|
||||
agreementId: checkedItem.id,
|
||||
type: checkedItem.type,
|
||||
params: {
|
||||
pass: 0,
|
||||
message: values.message
|
||||
}
|
||||
}).then(res => {
|
||||
if (res && res.message === 'success') {
|
||||
showNotification('操作成功');
|
||||
reloadList();
|
||||
setFieldsValue({
|
||||
message: '',
|
||||
});
|
||||
setVisible(false);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function agreeClick(item) {
|
||||
Modal.confirm({
|
||||
title: '确认审批通过?',
|
||||
onOk() {
|
||||
adminCheckAgreement({
|
||||
agreementId: item.id,
|
||||
type: item.type,
|
||||
params: {
|
||||
pass: 1,
|
||||
}
|
||||
}).then(res => {
|
||||
if (res && res.message === 'success') {
|
||||
showNotification('操作成功');
|
||||
reloadList();
|
||||
}
|
||||
})
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function goUser(login) {
|
||||
window.location.href = `/users/${login}`;
|
||||
}
|
||||
|
||||
function goUserMes(login) {
|
||||
window.location.href = `/users/${login}/message_detail`;
|
||||
}
|
||||
|
||||
function downFile(item) {
|
||||
let url = httpUrl + '/busiAttachments/download/' + item.id;
|
||||
window.open(url);
|
||||
}
|
||||
|
||||
const helper = useCallback(
|
||||
(label, name, rules, widget) => (
|
||||
<Form.Item label={label}>
|
||||
{getFieldDecorator(name, { rules, validateFirst: true })(widget)}
|
||||
</Form.Item>
|
||||
),
|
||||
[]
|
||||
);
|
||||
|
||||
return (
|
||||
loading ? <Loading /> :
|
||||
<React.Fragment>
|
||||
{
|
||||
list.map(item => {
|
||||
return (
|
||||
<div className="list-box" key={item.id}>
|
||||
|
||||
<img alt="" className="radius mr15" height="50px" src={item.user && getImageUrl(item.user.logo)} width="50px" />
|
||||
<div className="flex1">
|
||||
<li className="clearfix mb20">
|
||||
<a className="user-box fl mr15 color-grey-3 font-16" onClick={() => { goUser(item.user.login) }}>{item.user && (item.user.nickname || item.user.login)}</a>
|
||||
<span className="fl color-grey-9 mt3 mr15">{timeAgo(item.createdAt)}</span>
|
||||
<span className="fr">
|
||||
{item.status === 1 && <span className="spanTitle color-grey-6 fl ml20">已同意</span>}
|
||||
{item.status === 0 && <span className="spanTitle color-red fl ml20">已驳回</span>}
|
||||
|
||||
{
|
||||
item.status === 2 && <React.Fragment>
|
||||
<a className="edu-default-btn edu-orangeline-btn ml20 fl" onClick={() => { goUserMes(item.user.login) }}>私信</a>
|
||||
<a className="edu-default-btn edu-blueline-btn ml20 fl" onClick={() => { agreeClick(item) }}>同意</a>
|
||||
<a className="edu-default-btn edu-greyline-btn ml20 fl" onClick={() => { refuseClick(item) }}>驳回</a>
|
||||
</React.Fragment>
|
||||
}
|
||||
</span>
|
||||
</li>
|
||||
<div className="clearfix">
|
||||
<div className="width100 lineh-35">
|
||||
<span className="color-grey-9 fl">任务名称:</span>
|
||||
<span className="fl lineh-35 ml5">
|
||||
<Link className="primary-link" to={`/task/taskDetail/${item.taskId}`}>{item.taskName}</Link>
|
||||
</span>
|
||||
</div>
|
||||
<div className="clearfix"></div>
|
||||
<div className="width100 lineh-35">
|
||||
<span className="color-grey-9 fl">任务编号:</span>
|
||||
<span className="fl lineh-35 ml5">
|
||||
{item.taskNumber}
|
||||
</span>
|
||||
</div>
|
||||
<div className="clearfix"></div>
|
||||
|
||||
{
|
||||
item.paperNumber && <React.Fragment>
|
||||
<div className="width100 lineh-35">
|
||||
<span className="color-grey-9 fl">成果编号:</span>
|
||||
<span className="fl lineh-35 ml5">
|
||||
{item.paperNumber}
|
||||
</span>
|
||||
</div>
|
||||
<div className="clearfix"></div>
|
||||
</React.Fragment>
|
||||
}
|
||||
|
||||
<div className="width100 lineh-35 clearfix">
|
||||
<span className="color-grey-9 fl">协议文件:</span>
|
||||
{
|
||||
item.busiAttachments && item.busiAttachments.map(fileItem => {
|
||||
return <span className="file-list-prof " key={fileItem.id}>
|
||||
<a onClick={() => { downFile(fileItem) }}><i className="iconfont icon-fujian color-green font-14 mr3"></i>
|
||||
{fileItem.fileName} </a>
|
||||
<span className="ml10 color-grey-9">({fileItem.fileSizeString})</span>
|
||||
</span>
|
||||
})
|
||||
}
|
||||
</div>
|
||||
{/* <div className="width100 lineh-35">
|
||||
<span className="color-grey-9 fl">驳回原因:</span>
|
||||
<span className="infos_item">{item.content}</span>
|
||||
</div> */}
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
{list.length > 0 ?
|
||||
<div className="edu-txt-center mt20 mb20">
|
||||
{total > pageSize && <Pagination
|
||||
showQuickJumper
|
||||
onChange={(page) => { setPage(page) }}
|
||||
current={curPage}
|
||||
total={total}
|
||||
showTotal={total => `共 ${total} 条`}
|
||||
/>}
|
||||
</div> :
|
||||
<Nodata _html="暂无数据" />}
|
||||
|
||||
<Modal
|
||||
title="驳回协议"
|
||||
visible={visible}
|
||||
onOk={dealAction}
|
||||
onCancel={() => { setVisible(false) }}
|
||||
className="form-edit-modal"
|
||||
>
|
||||
{
|
||||
helper('驳回原因', 'message', [{ required: visible, message: "请输入驳回的原因" }, { max: 200, message: '不能超过200字符' }],
|
||||
<TextArea
|
||||
placeholder="(必填)我想说点什么呢,200字以内"
|
||||
autoSize={{ minRows: 6 }}
|
||||
className="applyText"
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
</Modal>
|
||||
</React.Fragment>
|
||||
|
||||
)
|
||||
}
|
||||
)
|
|
@ -0,0 +1,52 @@
|
|||
.list-box {
|
||||
position: relative;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
padding: 20px;
|
||||
margin: 0 1.5rem;
|
||||
background: #fff;
|
||||
border-bottom: 1px solid #dedede;
|
||||
a.edu-orangeline-btn {
|
||||
padding: 0px 10px;
|
||||
}
|
||||
}
|
||||
|
||||
a.primary-link {
|
||||
color: #1890ff;
|
||||
}
|
||||
|
||||
.infos_item {
|
||||
float: left;
|
||||
max-width: 273px;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
color: #343434;
|
||||
margin-right: 6px;
|
||||
line-height: 35px;
|
||||
margin-left: 5px;
|
||||
}
|
||||
|
||||
.file-list-prof{
|
||||
background: #fafafa;
|
||||
padding:.25rem .5rem;
|
||||
margin-right:.5rem;
|
||||
}
|
||||
|
||||
.form-edit-modal {
|
||||
.ant-form-item{
|
||||
display: flex;
|
||||
}
|
||||
.ant-form-item-label{
|
||||
min-width: 5rem;
|
||||
}
|
||||
.ant-form-item-control-wrapper{
|
||||
width: 75%;
|
||||
display: inline-block;
|
||||
}
|
||||
.ant-input-number{
|
||||
width: 50%;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,269 @@
|
|||
import React, { useEffect, useState, useCallback } from 'react';
|
||||
import { Pagination, Modal, Input, DatePicker, Form } from 'antd';
|
||||
import { Link } from "react-router-dom";
|
||||
import moment from 'moment';
|
||||
import Nodata from 'forge/Nodata';
|
||||
import Loading from "src/Loading";
|
||||
import { getImageUrl, formatDuring } from 'educoder';
|
||||
import { taskStatusAllArr } from '../../static';
|
||||
import { delayTask, closeTask } from '../../api';
|
||||
import './index.scss';
|
||||
|
||||
const format = "YYYY-MM-DD";
|
||||
|
||||
const statusArr = [];
|
||||
for (const item of taskStatusAllArr) {
|
||||
statusArr[item.dicItemCode] = item.dicItemName;
|
||||
}
|
||||
|
||||
const classArr = ['', 'list-done', 'list-error', 'list-red', 'list-yellow', 'list-pay', '', 'list-pay', 'list-gray',];
|
||||
|
||||
function getSomeDayAfter(time, nDay) {
|
||||
return moment(new Date(time).setDate(new Date(time).getDate() + nDay)).format('YYYY-MM-DD HH:mm');
|
||||
}
|
||||
|
||||
export default Form.create()((props) => {
|
||||
|
||||
const { list, curPage, total, changePage, loading, showNotification, reloadList, form } = props;
|
||||
const { getFieldDecorator, validateFields } = form;
|
||||
|
||||
const [checkedItem, setCheckedItem] = useState('');
|
||||
const [visible, setVisible] = useState(false);
|
||||
const pageSize = props.pageSize || 10;
|
||||
|
||||
function closeClick(item) {
|
||||
Modal.confirm({
|
||||
title: '是否关闭?',
|
||||
content: <p class="font-14 lineh-25 mb10 edu-txt-center">关闭后该任务立即结束,无法重新打开</p>,
|
||||
onOk() {
|
||||
closeTask(item.id).then(res => {
|
||||
if (res && res.message === 'success') {
|
||||
showNotification('操作成功');
|
||||
reloadList();
|
||||
}
|
||||
})
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function delayClick(item) {
|
||||
setCheckedItem(item);
|
||||
setVisible(true);
|
||||
}
|
||||
|
||||
function delayTime() {
|
||||
validateFields((err, values) => {
|
||||
if (!err) {
|
||||
delayTask({
|
||||
taskId: checkedItem.id,
|
||||
params: {
|
||||
delayedTo: moment(values.delayedTo).format(format)
|
||||
},
|
||||
}).then(res => {
|
||||
if (res && res.message === 'success') {
|
||||
showNotification('操作成功');
|
||||
reloadList();
|
||||
setVisible(false);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function goUser(login) {
|
||||
window.location.href = `/users/${login}`;
|
||||
}
|
||||
|
||||
function goUserMes(login) {
|
||||
window.location.href = `/users/${login}/message_detail`;
|
||||
}
|
||||
|
||||
const helper = useCallback(
|
||||
(label, name, rules, widget, initialValue) => (
|
||||
<Form.Item label={label}>
|
||||
{getFieldDecorator(name, { rules, initialValue, validateFirst: true, })(widget)}
|
||||
</Form.Item>
|
||||
), []);
|
||||
|
||||
const surplusTime = useCallback((item) => {
|
||||
let surplus;
|
||||
switch (item.currentStatus) {
|
||||
case 3:
|
||||
surplus = item.collectingDays * 24 * 3600 - (new Date() - new Date(item.publishedAt || item.createdAt)) / 1000;
|
||||
break;
|
||||
case 4:
|
||||
surplus = item.choosingDays * 24 * 3600 - (new Date() - new Date(item.collectingCompleteAt)) / 1000;
|
||||
break;
|
||||
case 5:
|
||||
surplus = item.makePublicDays * 24 * 3600 - (new Date() - new Date(item.makePublicAt)) / 1000;
|
||||
break;
|
||||
case 6:
|
||||
surplus = item.signingDays * 24 * 3600 - (new Date() - new Date(item.publicityCompleteAt)) / 1000;
|
||||
break;
|
||||
case 7:
|
||||
surplus = item.payingDays * 24 * 3600 - (new Date() - new Date(item.signingCompleteAt)) / 1000;
|
||||
break;
|
||||
default:
|
||||
surplus = 0;
|
||||
}
|
||||
let surplusTimetext = formatDuring(surplus);
|
||||
return surplus > 0 ? '剩余' + surplusTimetext : <span>延期 <span className="color-red">{surplusTimetext}</span></span>;
|
||||
}, []);
|
||||
|
||||
const stopTime = useCallback((item) => {
|
||||
switch (item.currentStatus) {
|
||||
case 3:
|
||||
return getSomeDayAfter(item.publishedAt, item.collectingDays);
|
||||
case 4:
|
||||
return getSomeDayAfter(item.collectingCompleteAt, item.choosingDays);
|
||||
case 5:
|
||||
return getSomeDayAfter(item.makePublicAt, item.makePublicDays);
|
||||
case 6:
|
||||
return getSomeDayAfter(item.publicityCompleteAt, item.signingDays);
|
||||
case 7:
|
||||
return getSomeDayAfter(item.signingCompleteAt, item.payingDays);
|
||||
case 8:
|
||||
return item.payingCompleteAt;
|
||||
default:
|
||||
return item.expiredAt;
|
||||
}
|
||||
})
|
||||
|
||||
function disabledDate(current) {
|
||||
return current && current < moment().endOf('day');
|
||||
}
|
||||
|
||||
return (
|
||||
loading ? <Loading /> :
|
||||
<React.Fragment>
|
||||
{
|
||||
list.map(item => {
|
||||
return (
|
||||
<div className="list-box" key={item.id}>
|
||||
|
||||
<img alt="" className="radius mr15" height="50px" src={item.user && getImageUrl(item.user.logo)} width="50px" onClick={() => { goUser(item.user.login) }} />
|
||||
<div className="flex1">
|
||||
|
||||
<div className="clearfix">
|
||||
<span className="lineh-35" style={{ display: "inline-flex" }}>
|
||||
<span className="color-grey-9 fl">任务编号:</span>
|
||||
<span className="infos_item mr15">{item.number}</span>
|
||||
<span className="fl lineh-35 ml5">
|
||||
<Link className="primary-link" to={`/task/taskDetail/${item.id}`}>{item.name}</Link>
|
||||
</span>
|
||||
<span>{item.currentStatus > 0 && <span className={classArr[item.currentStatus] + ' status-tag'}>{statusArr[item.currentStatus]}</span>}</span>
|
||||
</span>
|
||||
|
||||
<span className="fr">
|
||||
{item.cancelStatus === 1 && <span className="spanTitle color-red fl ml20">延期</span>}
|
||||
{item.cancelStatus === 2 && <span className="spanTitle color-grey-6 fl ml20">关闭</span>}
|
||||
|
||||
{
|
||||
item.cancelStatus === 0 && <React.Fragment>
|
||||
<a className="edu-default-btn edu-orangeline-btn ml20 fl" onClick={() => { goUserMes(item.user.login) }}>私信</a>
|
||||
<a className="edu-default-btn edu-blueline-btn ml20 fl" onClick={() => { delayClick(item) }}>延期</a>
|
||||
<a className="edu-default-btn edu-greyline-btn ml20 fl" onClick={() => { closeClick(item) }}>关闭</a>
|
||||
</React.Fragment>
|
||||
}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div className="clearfix">
|
||||
|
||||
<span className="with40 fl lineh-35">
|
||||
<span className="color-grey-9 fl">主体名称:</span>
|
||||
<span className="infos_item">{item.enterpriseName}</span>
|
||||
</span>
|
||||
|
||||
<span className="with30 fl lineh-35">
|
||||
<span className="color-grey-9 fl">发布方式:</span>
|
||||
<span className="infos_item mr15 fl">{item.publishMode === 1 ? '统筹任务' : '自主提交'}</span>
|
||||
</span>
|
||||
|
||||
</div>
|
||||
<div className="clearfix">
|
||||
<span className="with40 fl lineh-35">
|
||||
<span className="color-grey-9 fl">联系手机:</span>
|
||||
<span className="infos_item">{item.user.phone}(位置分析:{item.belongTo})</span>
|
||||
</span>
|
||||
|
||||
<span className="with40 fl lineh-35 color-orange">
|
||||
{
|
||||
item.status === 4 && item.papersCount > 0 && (!item.isProofBoolean) && '未上传佐证材料'
|
||||
}
|
||||
|
||||
{item.status === 6 && item.agreementSigning === 0 && '未选择协议签订方式'}
|
||||
|
||||
{
|
||||
item.status === 6 && item.agreementSigning === 2 && (item.contractStatus === null || item.contractStatus === 0) && '未上传委托协议'
|
||||
}
|
||||
|
||||
{
|
||||
item.status === 6 && item.agreementSigning === 2 && item.contractStatus === 2 && '已上传委托协议'
|
||||
}
|
||||
|
||||
{
|
||||
item.status === 7 && item.agreementSigning === 2 && '未上传支付报酬凭证'
|
||||
}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div className="clearfix">
|
||||
<span className="with40 fl lineh-35">
|
||||
<span className="color-grey-9 fl">截止时间:</span>
|
||||
<span className="infos_item">{stopTime(item)}</span>
|
||||
|
||||
{[3, 4, 5, 6, 7].includes(item.currentStatus) && <span className="ml10">{surplusTime(item)}</span>}
|
||||
</span>
|
||||
|
||||
{/* <span className="with40 lineh-35" style={{ display: "inline-flex" }}>
|
||||
<span className="color-grey-9 fl">任务编号:</span>
|
||||
<span className="infos_item mr15">{item.number}</span>
|
||||
<span className="fl lineh-35 ml5">
|
||||
<Link className="primary-link" to={`/task/taskDetail/${item.id}`}>{item.name}</Link>
|
||||
</span>
|
||||
</span> */}
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
{list.length > 0 ?
|
||||
<div className="edu-txt-center mt20 mb20">
|
||||
{total > pageSize && <Pagination
|
||||
showQuickJumper
|
||||
onChange={(page) => { changePage(page) }}
|
||||
current={curPage}
|
||||
total={total}
|
||||
showTotal={total => `共 ${total} 条`}
|
||||
/>}
|
||||
</div> :
|
||||
<Nodata _html="暂无数据" />}
|
||||
|
||||
<Modal
|
||||
title="请输入延期截止的具体时间"
|
||||
visible={visible}
|
||||
onOk={delayTime}
|
||||
onCancel={() => { setVisible(false) }}
|
||||
className="time-edit-modal"
|
||||
>
|
||||
{helper(
|
||||
"",
|
||||
"delayedTo",
|
||||
[{ required: true, message: "请选择日期" }],
|
||||
<DatePicker
|
||||
format={format}
|
||||
placeholder="请选择日期"
|
||||
disabledDate={disabledDate}
|
||||
/>,
|
||||
moment(new Date(), format)
|
||||
)}
|
||||
</Modal>
|
||||
</React.Fragment>
|
||||
|
||||
)
|
||||
}
|
||||
)
|
|
@ -0,0 +1,50 @@
|
|||
.list-box {
|
||||
position: relative;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
padding: 20px;
|
||||
margin: 0 1.5rem;
|
||||
background: #fff;
|
||||
border-bottom: 1px solid #dedede;
|
||||
a.edu-orangeline-btn {
|
||||
padding: 0px 10px;
|
||||
}
|
||||
}
|
||||
|
||||
a.primary-link {
|
||||
color: #1890ff;
|
||||
}
|
||||
|
||||
.infos_item {
|
||||
float: left;
|
||||
max-width: 273px;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
color: #343434;
|
||||
margin-right: 6px;
|
||||
line-height: 35px;
|
||||
margin-left: 5px;
|
||||
}
|
||||
|
||||
.file-list-prof{
|
||||
background: #fafafa;
|
||||
padding:.25rem .5rem;
|
||||
}
|
||||
|
||||
.status-tag {
|
||||
display: inline-block;
|
||||
padding: 0px 10px;
|
||||
margin-left: .625rem;
|
||||
background: #f8c753;
|
||||
font-size: 12px;
|
||||
color: #fff;
|
||||
border-radius: 14px;
|
||||
line-height: 22px;
|
||||
height: 22px;
|
||||
}
|
||||
|
||||
.time-edit-modal .ant-modal-body{
|
||||
width: 200px;
|
||||
margin:0 auto;
|
||||
}
|
|
@ -0,0 +1,351 @@
|
|||
import React, { useEffect, useState, useCallback, useMemo } from 'react';
|
||||
import { Form, Modal, Input, Pagination, Radio, Table } from 'antd';
|
||||
import { Link } from "react-router-dom";
|
||||
import Nodata from 'forge/Nodata';
|
||||
import Loading from "src/Loading";
|
||||
import Upload from 'military/components/Upload';
|
||||
import ProofModal from '../proofModal';
|
||||
import { publishModeArr, taskStatusAllArr, myPaperStatusArr } from '../../static';
|
||||
import { signMethod, uploadAgreeRequire, downAgreement } from "../../api";
|
||||
import { httpUrl } from 'military/fetch';
|
||||
import '../../index.scss';
|
||||
import './index.scss';
|
||||
|
||||
const statusArr = [];
|
||||
for (const item of taskStatusAllArr) {
|
||||
statusArr[item.dicItemCode] = item.dicItemName;
|
||||
}
|
||||
export default Form.create()((props) => {
|
||||
const { form, list, curPage, total, changePage, taskCategoryValueArr, loading, publish, showNotification, reloadList, joinTask } = props;
|
||||
const { getFieldDecorator, validateFields, setFieldsValue, } = form;
|
||||
|
||||
const [page, setPage] = useState(1);
|
||||
const [visibleProofs, setVisibleProofs] = useState(false);
|
||||
const [taskId, setTaskId] = useState();
|
||||
const [checkItem, setCheckItem] = useState({});
|
||||
const [taskModeId, setTaskModeId] = useState('');
|
||||
const pageSize = props.pageSize || 10;
|
||||
|
||||
const [visibleMethod, setVisibleMethod] = useState(false);
|
||||
const [visibleAgree, setVisibleAgree] = useState(false);
|
||||
const [fileList, setFileList] = useState(null);
|
||||
|
||||
const [dowloadTaskId, setDowloadTaskId] = useState('');
|
||||
const [visibleDownload, setVisibleDownload] = useState(false);
|
||||
const [uploadList, setUploadList] = useState([]);
|
||||
|
||||
|
||||
useEffect(() => {
|
||||
changePage(page);
|
||||
}, [page]);
|
||||
|
||||
useEffect(() => {
|
||||
visibleDownload && downAgreement({ taskId: dowloadTaskId }).then(res => {
|
||||
if (res && res.message === "success") {
|
||||
setUploadList(res.data);
|
||||
}
|
||||
})
|
||||
}, [visibleDownload])
|
||||
|
||||
function uploadProofs(item) {
|
||||
setVisibleProofs(true);
|
||||
setTaskId(item.id);
|
||||
setTaskModeId(item.taskModeId);
|
||||
}
|
||||
|
||||
function adviceModal(advice) {
|
||||
Modal.info({
|
||||
title: '审核意见',
|
||||
content: advice
|
||||
})
|
||||
}
|
||||
|
||||
function signMethodModal(item) {
|
||||
setVisibleMethod(true);
|
||||
setTaskId(item.id);
|
||||
}
|
||||
|
||||
function uploadAgree(item) {
|
||||
setVisibleAgree(true);
|
||||
setTaskId(item.id);
|
||||
setCheckItem(item);
|
||||
}
|
||||
|
||||
function chooseMethod() {
|
||||
validateFields((err, values) => {
|
||||
if (!err) {
|
||||
signMethod({
|
||||
taskId,
|
||||
method: values.method,
|
||||
}).then(res => {
|
||||
if (res && res.message === 'success') {
|
||||
showNotification('选择协议签订方式成功');
|
||||
setVisibleMethod(false);
|
||||
setFieldsValue({
|
||||
method: ''
|
||||
});
|
||||
reloadList();
|
||||
} else {
|
||||
showNotification((res && res.message) || '操作失败');
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
const helper = useCallback(
|
||||
(name, rules, widget) => (
|
||||
<Form.Item>
|
||||
{getFieldDecorator(name, { rules, validateFirst: true, })(widget)}
|
||||
</Form.Item>
|
||||
), []);
|
||||
|
||||
|
||||
function uploadAgreeList() {
|
||||
validateFields((err, values) => {
|
||||
if (!err) {
|
||||
uploadAgreeRequire({
|
||||
taskId,
|
||||
params: {
|
||||
files: values.files
|
||||
}
|
||||
}).then(res => {
|
||||
if (res && res.message === "success") {
|
||||
setFieldsValue({
|
||||
files: ''
|
||||
});
|
||||
reloadList();
|
||||
setVisibleAgree(false);
|
||||
showNotification('上传协议成功');
|
||||
} else {
|
||||
showNotification((res && res.message) || '上传协议失败');
|
||||
}
|
||||
})
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function uploadFunc(fileList, files) {
|
||||
setFileList(fileList);
|
||||
setFieldsValue({
|
||||
files,
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
const columns = useMemo(() => {
|
||||
return [
|
||||
{
|
||||
title: '成果物编号',
|
||||
dataIndex: 'paperNumber',
|
||||
},
|
||||
{
|
||||
title: '凭证文件',
|
||||
dataIndex: 'fileName',
|
||||
render: (text, record) => {
|
||||
return <a className="line_1 color-grey3" onClick={() => { download(record.winnerContracts[0].id) }}> {record.winnerContracts && record.winnerContracts[0].fileName}</a >
|
||||
}
|
||||
},
|
||||
{
|
||||
title: '操作',
|
||||
dataIndex: 'action',
|
||||
render: (text, record) => {
|
||||
return <a className="line_1 color-grey3" onClick={(e) => { download(record.winnerContracts[0].id) }}> 下载凭证</a >
|
||||
}
|
||||
}
|
||||
];
|
||||
}, []);
|
||||
|
||||
function download(id) {
|
||||
window.open(httpUrl + '/busiAttachments/download/' + id);
|
||||
}
|
||||
|
||||
return (
|
||||
<React.Fragment>
|
||||
<ul className="df mt10 needs_condition_content_nav">
|
||||
<li key={1} className="with35 edu-txt-left">任务</li>
|
||||
<li key={2} className="with15">类型</li>
|
||||
{publish && <li key={3} className="with10 draft_only">应征投稿</li>}
|
||||
<li key={4} className="with10">金额</li>
|
||||
<li key={5} className="flex1">任务状态</li>
|
||||
<li key={6} className="with15">操作</li>
|
||||
</ul>
|
||||
|
||||
{loading ? <Loading /> : <React.Fragment>
|
||||
{
|
||||
list.map(item => {
|
||||
return (
|
||||
<div key={item.id} className="needs_condition_content">
|
||||
<p className="needs_condition_content_t color-dark-grey">
|
||||
任务编号:{item.number}
|
||||
<i className="ml20 mr5 iconfont icon-shijian color-grey9 font-16"></i>
|
||||
{item.createdAt}
|
||||
</p>
|
||||
<ul className="df">
|
||||
<li key={1} className="mytask-title with35 edu-txt-left font-16 font-bd" >
|
||||
<Link className="color-grey3 font-16 font-bd" to={`/task/taskDetail/${item.id}`}>{item.name}</Link>
|
||||
{
|
||||
joinTask ? <React.Fragment>
|
||||
{item.myPaperStatus === 0 && <span className="list_status s_orange ml10">{myPaperStatusArr[item.myPaperStatus]}</span>}
|
||||
{item.myPaperStatus === 1 && <span className="list_status s_grey ml10">{myPaperStatusArr[item.myPaperStatus]}</span>}
|
||||
{item.myPaperStatus === 2 && <span className="list_status s_red ml10">{myPaperStatusArr[item.myPaperStatus]}</span>}
|
||||
|
||||
{item.status === 6 && (item.agreementSigning === 1 || (item.agreementSigning === 2 && item.contractStatus === 1)) && <span className="list_status s_orange ml10">待签订协议</span>}
|
||||
</React.Fragment> : <React.Fragment>
|
||||
{item.status === 6 && (item.agreementSigning === 1 || (item.agreementSigning === 2 && item.auditing && item.auditing.pass === 1)) && <span className="list_status s_orange ml10">待签订协议</span>}
|
||||
</React.Fragment>
|
||||
}
|
||||
</li>
|
||||
<li key={2} className="with15 flex-column">
|
||||
<span className="line_1">{taskCategoryValueArr[item.categoryId]}</span>
|
||||
<span className="line_1">{publishModeArr[item.publishMode]}</span>
|
||||
</li>
|
||||
|
||||
{publish && <li key={3} className="with10 draft_only">{item.papersCount || 0}</li>}
|
||||
|
||||
<li key={4} className="with10 color-orange">¥{item.bounty}</li>
|
||||
<li className="flex1">
|
||||
<span>
|
||||
<span className="line_1">{statusArr[item.status]}</span>
|
||||
</span>
|
||||
</li>
|
||||
<li key={5} className="with15 flex-column">
|
||||
{
|
||||
joinTask ? <Link className="line_1 color-grey3" to={`/task/taskDetail/${item.id}`}>查看详情</Link>
|
||||
:
|
||||
<React.Fragment>
|
||||
{
|
||||
item.status === 0 || item.status === 9 ?
|
||||
<Link className="line_1 color-grey3" to={`/task/taskEdit/${item.id}`}>编辑草稿</Link> :
|
||||
<Link className="line_1 color-grey3" to={`/task/taskDetail/${item.id}`}>查看详情</Link>
|
||||
}
|
||||
|
||||
{
|
||||
item.status === 4 && item.papersCount > 0 && (!item.isProofBoolean) && (!item.isProofBoolean)&&
|
||||
<a onClick={() => { uploadProofs(item) }} className="line_1 color-blue">上传佐证材料</a>
|
||||
}
|
||||
|
||||
{
|
||||
(!item.isProofBoolean) && (item.taskResultProof && item.taskResultProof.status === 0) &&
|
||||
<a onClick={() => { adviceModal(item.advice) }} className="line_1 color-blue">佐证被拒原因</a>
|
||||
}
|
||||
|
||||
{(item.status === 2 || item.status === 9) && <a onClick={() => { adviceModal(item.repairAdvice) }} className="line_1 color-blue">审核意见</a>}
|
||||
|
||||
{item.status === 6 && item.agreementSigning === 0 && <a className="line_1 color-blue" onClick={() => { signMethodModal(item) }}>选择协议签订方式</a>}
|
||||
|
||||
{item.status === 6 && item.agreementSigning === 2 && (item.contractStatus === null || item.contractStatus === 0) && <a className="line_1 color-blue" onClick={() => { uploadAgree(item) }}>上传委托协议</a>}
|
||||
|
||||
{item.status === 6 && item.agreementSigning === 2 && [1, 2].includes(item.contractStatus) && <a className="line_1 color-grey-9" >已上传委托协议</a>}
|
||||
|
||||
{item.status === 6 && item.agreementSigning === 1 && <span className="line_1 color-grey-9">已选择自主签订协议</span>}
|
||||
|
||||
{item.status === 7 && <span className="line_1 color-grey-9">{item.agreementSigning === 1 ? '待胜出者确认收款' : '待平台上传支付凭证'}</span>}
|
||||
|
||||
{item.status === 7 && <a className="line_1 color-blue" onClick={() => { setDowloadTaskId(item.id); setVisibleDownload(true); }}>下载协议签订凭证</a>}
|
||||
|
||||
</React.Fragment>
|
||||
}
|
||||
|
||||
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
{list.length > 0 ?
|
||||
<div className="edu-txt-center mt20 mb20">
|
||||
{total > pageSize && <Pagination
|
||||
showQuickJumper
|
||||
onChange={(page) => { setPage(page) }}
|
||||
current={curPage}
|
||||
total={total}
|
||||
showTotal={total => `共 ${total} 条`}
|
||||
/>}
|
||||
</div> :
|
||||
<Nodata _html="暂无数据" />}
|
||||
</React.Fragment>
|
||||
}
|
||||
|
||||
{visibleProofs && <ProofModal
|
||||
taskId={taskId}
|
||||
taskModeId={taskModeId}
|
||||
visible={visibleProofs}
|
||||
changeVisible={setVisibleProofs}
|
||||
showNotification={showNotification}
|
||||
reloadList={reloadList}
|
||||
/>}
|
||||
|
||||
|
||||
<Modal
|
||||
title="选择签订协议方式"
|
||||
visible={visibleMethod}
|
||||
onOk={chooseMethod}
|
||||
onCancel={() => { setVisibleMethod(false) }}
|
||||
className="form-edit-modal"
|
||||
>
|
||||
{
|
||||
helper('method', [{ required: visibleMethod, message: '请选择签订协议的方式' }],
|
||||
<Radio.Group className="vertical-radio">
|
||||
<Radio value={2}>
|
||||
<p>委托平台签订</p>
|
||||
<p className="color-grey-9">以平台名义与评选胜出者签订协议,需要经平台管理员审批需要发布方将奖励经费划归平台,在审核通过后平台自动发送电子协议</p>
|
||||
</Radio>
|
||||
<Radio value={1}>
|
||||
<p>自主签订</p>
|
||||
<p className="color-grey-9">通过线下的方式,以发布方名义与评选胜出者签订协议</p>
|
||||
</Radio>
|
||||
</Radio.Group>)
|
||||
}
|
||||
</Modal>
|
||||
|
||||
|
||||
<Modal
|
||||
title="上传委托协议"
|
||||
visible={visibleAgree}
|
||||
onOk={uploadAgreeList}
|
||||
onCancel={() => { setVisibleAgree(false) }}
|
||||
className="form-edit-modal"
|
||||
>
|
||||
{checkItem.auditing && <p className="color-orange mb10 task_tip">
|
||||
审核意见:{checkItem.auditing.message}
|
||||
</p>}
|
||||
<Form.Item className="upload-form" label="协议上传" required={true}>
|
||||
<Upload
|
||||
load={uploadFunc}
|
||||
size={50}
|
||||
showNotification={showNotification}
|
||||
fileList={fileList}
|
||||
/>
|
||||
{/* 用一个隐藏的input实现上传文件的必填校验 */}
|
||||
{getFieldDecorator('files', {
|
||||
rules: [{ required: visibleAgree, message: "请上传文件" }],
|
||||
validateFirst: true
|
||||
})(<Input style={{ display: 'none' }} />)}
|
||||
</Form.Item>
|
||||
</Modal>
|
||||
|
||||
<Modal
|
||||
title="下载协议签订凭证"
|
||||
visible={visibleDownload}
|
||||
onOk={() => { setVisibleDownload(false) }}
|
||||
onCancel={() => { setVisibleDownload(false) }}
|
||||
className="form-edit-modal"
|
||||
>
|
||||
<Table
|
||||
loading={loading}
|
||||
rowKey={(row) => row.id}
|
||||
dataSource={uploadList}
|
||||
columns={columns}
|
||||
pagination={false}
|
||||
/>
|
||||
|
||||
</Modal>
|
||||
|
||||
</React.Fragment>
|
||||
|
||||
)
|
||||
}
|
||||
)
|
|
@ -0,0 +1,106 @@
|
|||
.needs_condition_content_nav {
|
||||
padding: 0px 20px;
|
||||
background: #f7f7f7;
|
||||
height: 50px;
|
||||
line-height: 50px;
|
||||
color: #656565;
|
||||
text-align: center;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.needs_condition_content {
|
||||
border: 1px solid #eaeaea;
|
||||
border-radius: 4px;
|
||||
margin-bottom: 20px;
|
||||
|
||||
ul {
|
||||
margin: 0;
|
||||
padding: 20px;
|
||||
box-sizing: border-box;
|
||||
|
||||
li {
|
||||
text-align: center;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
display: -webkit-flex;
|
||||
}
|
||||
|
||||
.mytask-title {
|
||||
justify-content: left;
|
||||
a {
|
||||
word-break: break-all;
|
||||
}
|
||||
span {
|
||||
flex: 0 0 auto;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.list_status {
|
||||
border-radius: 10px;
|
||||
padding: 0px 10px;
|
||||
height: 22px;
|
||||
line-height: 22px;
|
||||
display: inline-block;
|
||||
color: #fff;
|
||||
background: #fa6400;
|
||||
margin-left: 0.625rem;
|
||||
font-size: 0.8rem;
|
||||
}
|
||||
|
||||
.s_orange {
|
||||
background: #ffb121;
|
||||
}
|
||||
|
||||
.s_red {
|
||||
background: #fe0e36;
|
||||
}
|
||||
|
||||
.s_blue {
|
||||
background: #4cacff;
|
||||
}
|
||||
|
||||
.s_grey {
|
||||
background: #bababa;
|
||||
}
|
||||
|
||||
.needs_condition_content_t {
|
||||
height: 40px;
|
||||
padding: 0px 20px;
|
||||
background: #f7f7f7;
|
||||
color: #333;
|
||||
border-bottom: 1px solid #eaeaea;
|
||||
line-height: 40px;
|
||||
}
|
||||
}
|
||||
|
||||
.tab-list-box {
|
||||
position: relative;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
padding: 20px;
|
||||
background: #fff;
|
||||
border-bottom: 1px solid #dedede;
|
||||
}
|
||||
|
||||
.flex-column {
|
||||
display: flex;
|
||||
flex-flow: column nowrap;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.vertical-radio {
|
||||
.ant-radio-wrapper {
|
||||
display: flex;
|
||||
line-height: 2rem;
|
||||
align-items: flex-start;
|
||||
.ant-radio {
|
||||
margin-top: 0.5rem;
|
||||
}
|
||||
p {
|
||||
white-space: normal;
|
||||
word-break: break-all;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,297 @@
|
|||
import React, { useEffect, useState, useCallback } from 'react';
|
||||
import { Pagination, Modal, Form, Input, Button } from 'antd';
|
||||
import ReactWEditor from 'wangeditor-for-react';
|
||||
import { timeAgo, getImageUrl } from 'educoder';
|
||||
import Nodata from 'forge/Nodata';
|
||||
import Loading from "src/Loading";
|
||||
import { editorConfig } from 'military/components/config';
|
||||
import AgreementModal from '../agreementModal';
|
||||
import ComplainModal from '../complainModal';
|
||||
import { reportPaper, thumbUpPaper, commentAdd, confirmReceipt } from '../../api';
|
||||
import { paperCheckStatusArr } from '../../static';
|
||||
import { httpUrl } from '../../../fetch';
|
||||
import winpng from '../../image/winner.png';
|
||||
import './index.scss';
|
||||
|
||||
const { TextArea } = Input;
|
||||
|
||||
const paperCheckStatus = [];
|
||||
for (const item of paperCheckStatusArr) {
|
||||
paperCheckStatus[item.dicItemCode] = item.dicItemName;
|
||||
}
|
||||
|
||||
export default Form.create()((props) => {
|
||||
const { list, curPage, total, changePage, loading, applyStatusAllNameArr, reloadList, showNotification, current_user, form, detailStatus } = props;
|
||||
const { getFieldDecorator, validateFields, setFieldsValue } = form;
|
||||
const [page, setPage] = useState(1);
|
||||
const pageSize = props.pageSize || 10;
|
||||
const [checkedItem, setCheckedItem] = useState({});
|
||||
const [reportVisible, setReportVisible] = useState(false);
|
||||
const [commentHtml, setCommentHtml] = useState('');
|
||||
|
||||
const [commentId, setCommentId] = useState(undefined);
|
||||
|
||||
const [complainVisible, setComplainVisible] = useState(false);
|
||||
const [agreeVisible, setAgreeVisible] = useState(false);
|
||||
|
||||
|
||||
const [loadingChild, setLoadingChild] = useState(false);
|
||||
|
||||
|
||||
useEffect(() => {
|
||||
changePage(page);
|
||||
}, [page]);
|
||||
|
||||
function downFile(item) {
|
||||
let url = httpUrl + '/busiAttachments/download/' + item.id;
|
||||
window.open(url);
|
||||
}
|
||||
|
||||
function report() {
|
||||
validateFields((error, values) => {
|
||||
if (!error) {
|
||||
setLoadingChild(true);
|
||||
reportPaper({
|
||||
paperId: checkedItem.id,
|
||||
content: values.reportValue
|
||||
}).then(res => {
|
||||
if (res && res.message === 'success') {
|
||||
showNotification('举报成功');
|
||||
setReportVisible(false);
|
||||
setFieldsValue({
|
||||
reportValue: '',
|
||||
complainValue: '',
|
||||
});
|
||||
}
|
||||
setLoadingChild(false);
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function thumbUp(id) {
|
||||
setLoadingChild(true);
|
||||
thumbUpPaper(id).then(res => {
|
||||
reloadList();
|
||||
setLoadingChild(false);
|
||||
});
|
||||
}
|
||||
|
||||
function commentPush(item) {
|
||||
if (!commentHtml) {
|
||||
showNotification("请输入评价");
|
||||
return;
|
||||
}
|
||||
if (commentHtml.length > 10000) {
|
||||
showNotification("评论过长,请减少评论内容或者简化评论格式");
|
||||
return;
|
||||
}
|
||||
commentAdd({
|
||||
content: commentHtml,
|
||||
paperId: item.id,
|
||||
taskId: item.taskId
|
||||
}).then(res => {
|
||||
if (res.message === 'success') {
|
||||
closeComment();
|
||||
reloadList();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function closeComment() {
|
||||
setCommentId(undefined);
|
||||
setCommentHtml('');
|
||||
}
|
||||
|
||||
function commentEdit(id) {
|
||||
setCommentId(id);
|
||||
setCommentHtml('');
|
||||
}
|
||||
|
||||
function goUser(login) {
|
||||
window.location.href = `/users/${login}`;
|
||||
}
|
||||
|
||||
|
||||
function confirmReceiptModal(paperId) {
|
||||
Modal.confirm({
|
||||
title: '确认收款',
|
||||
content: '确认已经收到任务报酬',
|
||||
onOk: () => {
|
||||
confirmReceipt(paperId).then(res => {
|
||||
if (res && res.message === "success") {
|
||||
showNotification("您已确认收款!");
|
||||
reloadList();
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
const helper = useCallback(
|
||||
(name, rules, widget) => (
|
||||
<Form.Item>
|
||||
{getFieldDecorator(name, { rules, validateFirst: true })(widget)}
|
||||
</Form.Item>
|
||||
),
|
||||
[]
|
||||
);
|
||||
|
||||
|
||||
return (
|
||||
<React.Fragment>
|
||||
{loading || loadingChild ? <Loading /> :
|
||||
<React.Fragment>
|
||||
{
|
||||
list.map(item => {
|
||||
return (
|
||||
|
||||
<div className="fileComments df" key={item.id}>
|
||||
<img alt="头像加载失败" src={item.user && getImageUrl(item.user.logo)} width="50" height="50" className="bor-radius-all mr20" />
|
||||
<div className="flex1">
|
||||
<ul>
|
||||
<li className="fl pr">
|
||||
<span className={item.user.nickname === "******" ? "font-16 mr20 color-grey3" : "user-box font-16 mr20 color-grey3 clickable"} onClick={() => { item.user.nickname === "******" ? "" : goUser(item.user.login) }}>
|
||||
{item.user.nickname || item.user.login}
|
||||
</span>
|
||||
<span className="color-grey9">{timeAgo(item.createdAt)}</span>
|
||||
{item.status === 2 ? <img alt="胜出" className="mr5" src={winpng} /> : <span className="color-blue ml10">{item.checkStatus !== 1 ? paperCheckStatus[item.checkStatus] : applyStatusAllNameArr[item.status]}</span>}
|
||||
</li>
|
||||
<li className="fr">
|
||||
{((item.needComplain && detailStatus === 3) || (detailStatus === 5 && item.publicTaskComplain && item.checkStatus === 1 && item.status !== 2)) && (current_user.login === item.user.login) &&
|
||||
<a className="base_smallBtn blue_line_btn fl" onClick={() => { setComplainVisible(true); setCheckedItem(item) }}>申诉</a>}
|
||||
|
||||
{item.status === 2 && detailStatus === 6 && (current_user.login === item.user.login) && (!item.sign) && (item.canApplicantSign || item.canApplicantSignByPlatform) &&
|
||||
<a className="base_smallBtn blue_line_btn fl" onClick={() => { setAgreeVisible(true); setCheckedItem(item) }}>签订协议</a>}
|
||||
|
||||
{item.status === 2 && detailStatus === 7 && (current_user.login === item.user.login) && (item.task && item.task.agreementSigning === 1) && (!item.isPay) &&
|
||||
<a className="base_smallBtn blue_line_btn fl" onClick={() => { confirmReceiptModal(item.id) }}>确认收款</a>}
|
||||
</li>
|
||||
</ul>
|
||||
<div className="paper-detail-content markdown-body editormd-html-preview editor-w-text" dangerouslySetInnerHTML={{ __html: item.paperDetail ? item.paperDetail.content : '' }}></div>
|
||||
|
||||
<div className="attachments" >
|
||||
{
|
||||
item.paperDetail && item.paperDetail.busiAttachments && item.paperDetail.busiAttachments.map(fileItem => {
|
||||
return <div className="file-list-box" key={fileItem.id}>
|
||||
<a onClick={() => { downFile(fileItem) }}><i className="iconfont icon-fujian color-green font-14 mr3"></i>
|
||||
{fileItem.fileName} </a>
|
||||
<span className="ml10 color-grey-9">({fileItem.fileSizeString})</span>
|
||||
</div>
|
||||
})
|
||||
}
|
||||
</div>
|
||||
|
||||
|
||||
{item.comments && item.comments.length > 0 && <div className="padding20 fileCommentsList">
|
||||
{item.comments.map(commentsItem => {
|
||||
return <div className="comments-item" key={commentsItem.id}>
|
||||
<div className="comments-author">
|
||||
<span className="color-grey3 font-bd mr20">{commentsItem.user.nickname || commentsItem.user.login}</span>
|
||||
<span className="color-grey9">{timeAgo(commentsItem.createdAt)}</span>
|
||||
</div>
|
||||
<div className="editor-w-text comments-content" dangerouslySetInnerHTML={{ __html: commentsItem.details && commentsItem.details.content }}>
|
||||
</div>
|
||||
</div>
|
||||
})
|
||||
}
|
||||
</div>}
|
||||
|
||||
|
||||
<li className="clearfix color-grey-6 mt10 mb20">
|
||||
<span className="mr50 fl"><span className="color-grey9">成果编号:</span>#{item.number}</span>
|
||||
<span className="mr50 fl"><span className="color-grey9">提交时间:</span>{item.createdAt}</span>
|
||||
<span className="fl"><span className="color-grey9">稿件状态:</span>{item.read ? '雇主已浏览' : '雇主未浏览'}</span>
|
||||
{
|
||||
item.user.nickname !== "******" && <span className="fr">
|
||||
{[4, 5].includes(detailStatus) && <a className="mr20" onClick={() => { setReportVisible(true); setCheckedItem(item) }}><i className="iconfont icon-jinggao font-15 mr3"></i>举报</a>}
|
||||
<a className="mr20" onClick={() => { commentEdit(item.id) }}><i className="iconfont icon-huifu1 font-15 mr3"></i>{item.comments ? item.comments.length : 0}</a>
|
||||
<a onClick={() => { thumbUp(item.id) }}><i className="iconfont icon-dianzan11 font-16 mr3"></i>{item.thumbsUp}</a>
|
||||
</span>
|
||||
}
|
||||
|
||||
</li>
|
||||
|
||||
{commentId === item.id && <React.Fragment>
|
||||
<ReactWEditor
|
||||
config={{
|
||||
...editorConfig,
|
||||
placeholder: "请输入评论",
|
||||
}}
|
||||
onChange={(html) => { setCommentHtml(html) }}
|
||||
/>
|
||||
<Button className="mt20 mr20 mb20 fr" type={"primary"} onClick={() => { commentPush(item) }}>发表</Button>
|
||||
<Button className="mt20 mr20 mb20 fr" onClick={closeComment}>取消</Button>
|
||||
</React.Fragment>}
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
{list.length > 0 ?
|
||||
<div className="edu-txt-center mt20 mb20">
|
||||
{total > pageSize && <Pagination
|
||||
showQuickJumper
|
||||
onChange={(page) => { setPage(page) }}
|
||||
current={curPage}
|
||||
total={total}
|
||||
showTotal={total => `共 ${total} 条`}
|
||||
/>}
|
||||
</div> :
|
||||
<Nodata _html="暂无数据" />}
|
||||
</React.Fragment>
|
||||
}
|
||||
|
||||
|
||||
<Modal
|
||||
title="举报"
|
||||
visible={reportVisible}
|
||||
onOk={report}
|
||||
onCancel={() => { setReportVisible(false) }}
|
||||
className="form-edit-modal"
|
||||
>
|
||||
<div className="task-popup-content">
|
||||
<p className="edu-txt-center lineh-20 mb10">你的举报信息将发送给平台管理员</p>
|
||||
<p className="edu-txt-center lineh-20">请如实填写有效的举报原由,我们将尽快完成审核</p>
|
||||
{
|
||||
helper('reportValue', [{ required: reportVisible, message: "(必填)请在此输入发起举报的原因,最大限制100个字符" },
|
||||
{ max: 100, message: '长度不能超过100个字符' }],
|
||||
<TextArea
|
||||
placeholder="(必填)请在此输入发起举报的原因,最大限制100个字符"
|
||||
autoSize={{ minRows: 6 }}
|
||||
className="applyText"
|
||||
/>
|
||||
)
|
||||
}
|
||||
</div>
|
||||
</Modal>
|
||||
|
||||
<ComplainModal
|
||||
visible={complainVisible}
|
||||
setVisible={setComplainVisible}
|
||||
checkedItem={checkedItem}
|
||||
detailStatus={detailStatus}
|
||||
showNotification={showNotification}
|
||||
reloadList={reloadList}
|
||||
/>
|
||||
|
||||
{agreeVisible && <AgreementModal
|
||||
paperId={checkedItem.id}
|
||||
checkedItem={checkedItem}
|
||||
visible={agreeVisible}
|
||||
setVisible={setAgreeVisible}
|
||||
showNotification={showNotification}
|
||||
reloadList={reloadList}
|
||||
/>}
|
||||
|
||||
</React.Fragment>
|
||||
|
||||
)
|
||||
}
|
||||
)
|
||||
|
|
@ -0,0 +1,46 @@
|
|||
.blue_line_btn {
|
||||
color: #4cacff !important;
|
||||
border: 1px solid #4cacff;
|
||||
background: #fff !important;
|
||||
}
|
||||
|
||||
.base_smallBtn {
|
||||
color: #ccc;
|
||||
font-size: 14px;
|
||||
background: #ccc;
|
||||
border-radius: 4px;
|
||||
height: 30px;
|
||||
line-height: 30px;
|
||||
display: block;
|
||||
width: 100px;
|
||||
box-sizing: border-box;
|
||||
text-align: center;
|
||||
margin-top: 1.25rem;
|
||||
}
|
||||
|
||||
.fileCommentsList {
|
||||
background: #fafafa;
|
||||
padding-top: .25rem;
|
||||
}
|
||||
|
||||
.comments-item{
|
||||
margin-top:1rem;
|
||||
}
|
||||
.comments-content {
|
||||
text-align: left;
|
||||
font-size: 16px;
|
||||
line-height: 1.6;
|
||||
padding: 20px;
|
||||
overflow: auto;
|
||||
width: 100%;
|
||||
background-color: #fff;
|
||||
}
|
||||
|
||||
.small-head{
|
||||
max-width: 2rem;
|
||||
}
|
||||
|
||||
.clickable:hover{
|
||||
color: #4cacff;
|
||||
cursor: pointer;
|
||||
}
|
|
@ -0,0 +1,76 @@
|
|||
import React, { useEffect, useState } from 'react';
|
||||
import { Icon, Pagination } from 'antd';
|
||||
import { getImageUrl } from 'educoder';
|
||||
import Nodata from 'forge/Nodata';
|
||||
import { taskStatusAllArr } from '../../static';
|
||||
import Loading from "src/Loading";
|
||||
import './index.scss';
|
||||
|
||||
const statusArr = [];
|
||||
for (const item of taskStatusAllArr) {
|
||||
statusArr[item.dicItemCode] = item.dicItemName;
|
||||
}
|
||||
|
||||
const classArr = ['', 'list-done', 'list-error', 'list-red', 'list-yellow', 'list-pay', '', 'list-pay', 'list-gray',];
|
||||
export default (props) => {
|
||||
const { list, itemClick, curPage, total, changePage, loading } = props;
|
||||
const [page, setPage] = useState(1);
|
||||
const pageSize = props.pageSize || 10;
|
||||
|
||||
useEffect(() => {
|
||||
changePage(page);
|
||||
}, [page]);
|
||||
|
||||
function goUser(login) {
|
||||
window.location.href = `/users/${login}`;
|
||||
}
|
||||
|
||||
|
||||
return (
|
||||
loading ? <Loading /> :
|
||||
<React.Fragment>
|
||||
{
|
||||
list.map(item => {
|
||||
return (
|
||||
<div className="list-box" key={item.id}>
|
||||
<div className="list-content">
|
||||
<div className="list-title mb10" onClick={() => { itemClick(item.id) }}>
|
||||
<div className="title-content text-ellipsis">{item.name}</div>
|
||||
{item.status && <span className={classArr[item.status]}>{item.exceptClosedBoolean?'已关闭':statusArr[item.status]}</span>}
|
||||
{(item.status !== 8) && item.delayTime.indexOf('延期') > -1 && <span className="list-yellow">延期中</span>}
|
||||
</div>
|
||||
<div className="list-other">
|
||||
<span className="user-box mr30" onClick={() => { goUser(item.user.login) }}>
|
||||
<img alt="" className="head-log-small" src={getImageUrl(item.user.logo)} />
|
||||
<span>{item.user.nickname || item.user.login}</span>
|
||||
</span>
|
||||
<span className="font-14 mr30"><i className="iconfont icon-dianjiliang mr3 font-12" />{item.visits || 0}</span>
|
||||
<span className="font-14 mr30"><Icon type="user" /><span className="color-orange">{item.papersCount || 0}</span>人参与</span>
|
||||
{(item.status !== 8) && <span className="color-orange mr30 font-14"><i className="mr5 iconfont icon-shijian color-grey9 font-14"></i>{item.delayTime}</span>}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<span className="price color-deep-blue ">
|
||||
<span className="font-16">¥</span>
|
||||
<span className="font-24">{item.bounty}</span>
|
||||
</span>
|
||||
</div>
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
{list.length > 0 ?
|
||||
<div className="edu-txt-center mt20 mb20">
|
||||
{total > pageSize && <Pagination
|
||||
showQuickJumper
|
||||
onChange={(page) => { setPage(page) }}
|
||||
current={curPage}
|
||||
total={total}
|
||||
showTotal={total => `共 ${total} 条`}
|
||||
/>}
|
||||
</div> :
|
||||
<Nodata _html="暂无数据" />}
|
||||
</React.Fragment>
|
||||
|
||||
)
|
||||
}
|
|
@ -0,0 +1,57 @@
|
|||
.list-box {
|
||||
position: relative;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
padding: 20px;
|
||||
margin: 0 1.5rem;
|
||||
background: #fff;
|
||||
border-bottom: 1px solid #dedede;
|
||||
}
|
||||
.user-box{
|
||||
cursor: pointer;
|
||||
&:hover{
|
||||
color: #409eff;
|
||||
}
|
||||
.head-log-small{
|
||||
position: relative;
|
||||
top:-2px;
|
||||
}
|
||||
}
|
||||
.price {
|
||||
font-weight: 500;
|
||||
padding-top: 10px;
|
||||
}
|
||||
.list-title {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
font-size: 1rem;
|
||||
color: #333;
|
||||
cursor: pointer;
|
||||
font-weight: 500;
|
||||
.title-content{
|
||||
display: inline-block;
|
||||
max-width: 80%;
|
||||
}
|
||||
}
|
||||
.list-title:hover {
|
||||
color: #409eff;
|
||||
}
|
||||
.list-title span {
|
||||
padding: 0px 10px;
|
||||
margin-left: .625rem;
|
||||
background: #f8c753;
|
||||
font-size: .8rem;
|
||||
line-height: 1.8;
|
||||
color: #fff;
|
||||
border-radius: 14px;
|
||||
}
|
||||
|
||||
|
||||
.list-other {
|
||||
font-size: 12px;
|
||||
color: #888;
|
||||
i {
|
||||
font-size: 14px;
|
||||
margin-right: 5px;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,157 @@
|
|||
import React, { useEffect, useState, useCallback } from 'react';
|
||||
import { Pagination, Modal, Input, Button, Form, InputNumber } from 'antd';
|
||||
import { Link } from "react-router-dom";
|
||||
import Nodata from 'forge/Nodata';
|
||||
import Loading from "src/Loading";
|
||||
import Upload from 'military/components/Upload';
|
||||
import { timeAgo, getImageUrl } from 'educoder';
|
||||
import { uploadPayProof } from '../../api';
|
||||
import './index.scss';
|
||||
|
||||
export default Form.create()((props) => {
|
||||
const { form, list, curPage, total, changePage, loading, showNotification, reloadList } = props;
|
||||
const { getFieldDecorator, validateFields, setFieldsValue } = form;
|
||||
const [checkedItem, setCheckedItem] = useState({});
|
||||
const [visible, setVisible] = useState(false);
|
||||
const [page, setPage] = useState(1);
|
||||
const [fileList, setFileList] = useState(null);
|
||||
const pageSize = props.pageSize || 10;
|
||||
|
||||
useEffect(() => {
|
||||
changePage(page);
|
||||
}, [page]);
|
||||
|
||||
|
||||
function goUser(login) {
|
||||
window.location.href = `/users/${login}`;
|
||||
}
|
||||
|
||||
function goUserMes(login) {
|
||||
window.location.href = `/users/${login}/message_detail`;
|
||||
}
|
||||
|
||||
|
||||
// 上传附件后得到的文件数组
|
||||
function uploadFunc(fileList, files) {
|
||||
setFileList(fileList);
|
||||
setFieldsValue({ files });
|
||||
}
|
||||
|
||||
function uploadPay() {
|
||||
validateFields((err, values) => {
|
||||
if (!err) {
|
||||
uploadPayProof({
|
||||
paperId: checkedItem.id,
|
||||
params: {
|
||||
files: values.files,
|
||||
}
|
||||
}).then(res => {
|
||||
if (res.message === 'success') {
|
||||
setFieldsValue({
|
||||
files: '',
|
||||
});
|
||||
setFileList([]);
|
||||
reloadList();
|
||||
setVisible(false);
|
||||
showNotification("上传支付凭证成功!");
|
||||
} else {
|
||||
showNotification(res.message || "上传支付凭证失败")
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
return (
|
||||
loading ? <Loading /> :
|
||||
<React.Fragment>
|
||||
{
|
||||
list.map(item => {
|
||||
return (
|
||||
<div className="list-box" key={item.id}>
|
||||
|
||||
<img alt="" className="radius mr15" height="50px" src={item.user && getImageUrl(item.user.logo)} width="50px" />
|
||||
<div className="flex1">
|
||||
<li className="clearfix mb20">
|
||||
<a className="user-box fl mr15 color-grey-3 font-16" onClick={() => { goUser(item.user.login) }}>{item.user && (item.user.nickname || item.user.login)}</a>
|
||||
<span className="fl color-grey-9 mt3 mr15">{timeAgo(item.createdAt)}</span>
|
||||
<span className="infos_item color-grey-9 fl">发布方式:</span>
|
||||
<span className="infos_item mr15 fl">{item.task && item.task.publishMode === 1 ? '统筹任务' : '自主提交'}</span>
|
||||
<span className="fr"><a className="edu-default-btn edu-orangeline-btn ml20 fl" onClick={() => { item.user && goUserMes(item.user.login) }}>私信</a></span>
|
||||
</li>
|
||||
<div className="clearfix">
|
||||
<div className="width100 lineh-35" >
|
||||
<span className="with40 fl lineh-35">
|
||||
<span className="color-grey-9 fl">任务编号:</span>
|
||||
<span className="fl lineh-35 ml5">
|
||||
<Link className="primary-link" to={`/task/taskDetail/${item.taskId}`}>{item.task.name}</Link>
|
||||
</span>
|
||||
</span>
|
||||
|
||||
<span className="with40 fl lineh-35">
|
||||
<span className="color-grey-9 fl">任务编号:</span>
|
||||
<span className="infos_item">{item.task.number}</span>
|
||||
</span>
|
||||
</div>
|
||||
<div className="clearfix">
|
||||
<span className="with40 fl lineh-35" style={{ display: "inline-flex" }}>
|
||||
<span className="color-grey-9 fl">联系手机:</span>
|
||||
<span className="infos_item">{item.user.phone}</span>
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div className="clearfix"></div>
|
||||
{!item.isPay && (item.status !== 8) && <div className="width100 lineh-35 clearfix">
|
||||
<Button type="primary" onClick={() => { setVisible(true); setCheckedItem(item) }}>上传支付报酬凭证</Button>
|
||||
</div>}
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
{list.length > 0 ?
|
||||
<div className="edu-txt-center mt20 mb20">
|
||||
{total > pageSize && <Pagination
|
||||
showQuickJumper
|
||||
onChange={(page) => { setPage(page) }}
|
||||
current={curPage}
|
||||
total={total}
|
||||
showTotal={total => `共 ${total} 条`}
|
||||
/>}
|
||||
</div> :
|
||||
<Nodata _html="暂无数据" />}
|
||||
|
||||
<Modal
|
||||
title="上传支付报酬凭证"
|
||||
visible={visible}
|
||||
onOk={uploadPay}
|
||||
onCancel={() => { setVisible(false) }}
|
||||
className="form-edit-modal"
|
||||
>
|
||||
<div className="task-popup-content">
|
||||
<Form.Item className="upload-form" label="附件上传" required={true}>
|
||||
<Upload
|
||||
className="commentStyle"
|
||||
load={uploadFunc}
|
||||
size={50}
|
||||
showNotification={showNotification}
|
||||
fileList={fileList}
|
||||
/>
|
||||
{getFieldDecorator('files', {
|
||||
rules: [{ required: visible, message: "请上传文件" }],
|
||||
validateFirst: true
|
||||
})(<Input style={{ display: 'none' }} />)}
|
||||
</Form.Item>
|
||||
</div>
|
||||
</Modal>
|
||||
|
||||
|
||||
</React.Fragment>
|
||||
|
||||
)
|
||||
}
|
||||
)
|
|
@ -0,0 +1,52 @@
|
|||
.list-box {
|
||||
position: relative;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
padding: 20px;
|
||||
margin: 0 1.5rem;
|
||||
background: #fff;
|
||||
border-bottom: 1px solid #dedede;
|
||||
a.edu-orangeline-btn {
|
||||
padding: 0px 10px;
|
||||
}
|
||||
}
|
||||
|
||||
a.primary-link {
|
||||
color: #1890ff;
|
||||
}
|
||||
|
||||
.infos_item {
|
||||
float: left;
|
||||
max-width: 273px;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
color: #343434;
|
||||
margin-right: 6px;
|
||||
line-height: 35px;
|
||||
margin-left: 5px;
|
||||
}
|
||||
|
||||
.file-list-prof{
|
||||
background: #fafafa;
|
||||
padding:.25rem .5rem;
|
||||
margin-right:.5rem;
|
||||
}
|
||||
|
||||
.form-edit-modal {
|
||||
.ant-form-item{
|
||||
display: flex;
|
||||
}
|
||||
.ant-form-item-label{
|
||||
min-width: 5rem;
|
||||
}
|
||||
.ant-form-item-control-wrapper{
|
||||
width: 75%;
|
||||
display: inline-block;
|
||||
}
|
||||
.ant-input-number{
|
||||
width: 50%;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,182 @@
|
|||
import React, { useEffect, useState, } from 'react';
|
||||
import { Pagination, Modal, Input } from 'antd';
|
||||
import { Link } from "react-router-dom";
|
||||
import Nodata from 'forge/Nodata';
|
||||
import Loading from "src/Loading";
|
||||
import { timeAgo, getImageUrl } from 'educoder';
|
||||
import { checkProof } from '../../api';
|
||||
import { httpUrl } from 'military/fetch';
|
||||
import './index.scss';
|
||||
|
||||
const { TextArea } = Input;
|
||||
export default (props) => {
|
||||
const { list, curPage, total, changePage, loading, showNotification, reloadList } = props;
|
||||
const [checkedItem, setCheckedItem] = useState('');
|
||||
const [page, setPage] = useState(1);
|
||||
const [visible, setVisible] = useState(false);
|
||||
const [advice, setRepairAdvice] = useState('');
|
||||
const pageSize = props.pageSize || 10;
|
||||
|
||||
useEffect(() => {
|
||||
changePage(page);
|
||||
}, [page]);
|
||||
|
||||
|
||||
function agreeClick(item) {
|
||||
Modal.confirm({
|
||||
title: '是否确认审批通过?',
|
||||
onOk() {
|
||||
checkProof({
|
||||
id: item.taskResultProof.id,
|
||||
isPassed: 1,
|
||||
taskId: item.id,
|
||||
advice: "",
|
||||
}).then(res => {
|
||||
if (res && res.message === 'success') {
|
||||
showNotification('操作成功');
|
||||
reloadList();
|
||||
}
|
||||
})
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function refuseClick(item) {
|
||||
setCheckedItem(item);
|
||||
setVisible(true);
|
||||
}
|
||||
|
||||
function refuse() {
|
||||
if (!advice) {
|
||||
showNotification('请输入拒绝的理由');
|
||||
return;
|
||||
}
|
||||
checkProof({
|
||||
id: checkedItem.taskResultProof.id,
|
||||
taskId: checkedItem.id,
|
||||
isPassed: 0,
|
||||
advice: advice
|
||||
}).then(res => {
|
||||
if (res && res.message === 'success') {
|
||||
showNotification('操作成功');
|
||||
reloadList();
|
||||
setRepairAdvice('');
|
||||
setVisible(false);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function goUser(login) {
|
||||
window.location.href = `/users/${login}`;
|
||||
}
|
||||
|
||||
function goUserMes(login) {
|
||||
window.location.href = `/users/${login}/message_detail`;
|
||||
}
|
||||
|
||||
function downFile(item) {
|
||||
let url = httpUrl + '/busiAttachments/download/' + item.id;
|
||||
window.open(url);
|
||||
}
|
||||
|
||||
|
||||
|
||||
return (
|
||||
loading ? <Loading /> :
|
||||
<React.Fragment>
|
||||
{
|
||||
list.map(item => {
|
||||
return (
|
||||
<div className="list-box" key={item.id}>
|
||||
|
||||
<img alt="" className="radius mr15" height="50px" src={item.user && getImageUrl(item.user.logo)} width="50px" />
|
||||
<div className="flex1">
|
||||
<li className="clearfix mb20">
|
||||
<a className="user-box fl mr15 color-grey-3 font-16" onClick={() => { goUser(item.user.login) }}>{item.user.nickname || item.user.login}</a>
|
||||
<span className="fl color-grey-9 mt3 mr15">{timeAgo(item.createdAt)}</span>
|
||||
<span className="with40 fl lineh-35">
|
||||
<span className="color-grey-9 fl">主体名称:</span>
|
||||
<span className="infos_item">{item.enterpriseName}</span>
|
||||
</span>
|
||||
<span className="fr">
|
||||
{item.taskResultProof.status === 1 && <span className="spanTitle color-grey-6 fl ml20">已同意</span>}
|
||||
{item.taskResultProof.status === 0 && <span className="spanTitle color-red fl ml20">已拒绝</span>}
|
||||
|
||||
{
|
||||
item.taskResultProof.status === 2 && <React.Fragment>
|
||||
<a className="edu-default-btn edu-orangeline-btn ml20 fl" onClick={() => { goUserMes(item.user.login) }}>私信</a>
|
||||
<a className="edu-default-btn edu-blueline-btn ml20 fl" onClick={() => { agreeClick(item) }}>同意</a>
|
||||
<a className="edu-default-btn edu-greyline-btn ml20 fl" onClick={() => { refuseClick(item) }}>拒绝</a>
|
||||
</React.Fragment>
|
||||
}
|
||||
</span>
|
||||
</li>
|
||||
<ul className="clearfix">
|
||||
<div className="width100 lineh-35" style={{ display: "inline-flex" }}>
|
||||
<span className="color-grey-9 fl">任务编号:</span>
|
||||
<span className="infos_item mr15">{item.number}</span>
|
||||
<span className="fl lineh-35 ml5">
|
||||
<Link className="primary-link" to={`/task/taskDetail/${item.id}`}>{item.name}</Link>
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div className="clearfix"></div>
|
||||
<div className="width100 lineh-35">
|
||||
<span className="color-grey-9 fl">评选胜出({item.taskResultProof.winnerName.split(',').length}):</span>
|
||||
<span className="infos_item">{item.taskResultProof.winnerName}</span>
|
||||
</div>
|
||||
<div className="clearfix"></div>
|
||||
<div className="width100 lineh-35 clearfix">
|
||||
<span className="color-grey-9 fl">佐证材料:</span>
|
||||
{
|
||||
item.taskProofAttachments && item.taskProofAttachments.map(fileItem => {
|
||||
return <span className="file-list-prof " key={fileItem.id}>
|
||||
<a onClick={() => { downFile(fileItem) }}><i className="iconfont icon-fujian color-green font-14 mr3"></i>
|
||||
{fileItem.fileName} </a>
|
||||
<span className="ml10 color-grey-9">({fileItem.fileSizeString})</span>
|
||||
</span>
|
||||
})
|
||||
}
|
||||
</div>
|
||||
|
||||
{item.taskResultProof.status === 0 && <p className="color-orange lineh-35 "><span className="fl color-orange mr5">拒绝原因:</span>{item.advice}</p>}
|
||||
</ul>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
{list.length > 0 ?
|
||||
<div className="edu-txt-center mt20 mb20">
|
||||
{total > pageSize && <Pagination
|
||||
showQuickJumper
|
||||
onChange={(page) => { setPage(page) }}
|
||||
current={curPage}
|
||||
total={total}
|
||||
showTotal={total => `共 ${total} 条`}
|
||||
/>}
|
||||
</div> :
|
||||
<Nodata _html="暂无数据" />}
|
||||
|
||||
<Modal
|
||||
title="拒绝原因"
|
||||
visible={visible}
|
||||
onOk={refuse}
|
||||
onCancel={() => { setVisible(false) }}
|
||||
className="form-edit-modal"
|
||||
>
|
||||
<TextArea
|
||||
value={advice}
|
||||
placeholder="(必填)我想说点什么呢,200字以内"
|
||||
autoSize={{ minRows: 6 }}
|
||||
className="applyText"
|
||||
onChange={(e) => { setRepairAdvice(e.target.value) }}
|
||||
maxLength={200}
|
||||
/>
|
||||
</Modal>
|
||||
</React.Fragment>
|
||||
|
||||
)
|
||||
}
|
|
@ -0,0 +1,33 @@
|
|||
.list-box {
|
||||
position: relative;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
padding: 20px;
|
||||
margin: 0 1.5rem;
|
||||
background: #fff;
|
||||
border-bottom: 1px solid #dedede;
|
||||
a.edu-orangeline-btn {
|
||||
padding: 0px 10px;
|
||||
}
|
||||
}
|
||||
|
||||
a.primary-link {
|
||||
color: #1890ff;
|
||||
}
|
||||
|
||||
.infos_item {
|
||||
float: left;
|
||||
max-width: 273px;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
color: #343434;
|
||||
margin-right: 6px;
|
||||
line-height: 35px;
|
||||
margin-left: 5px;
|
||||
}
|
||||
|
||||
.file-list-prof{
|
||||
background: #fafafa;
|
||||
padding:.25rem .5rem;
|
||||
}
|
|
@ -0,0 +1,228 @@
|
|||
import React, { useEffect, useState, useCallback } from 'react';
|
||||
import { Pagination, Modal, Input, Radio, Form, InputNumber } from 'antd';
|
||||
import { Link } from "react-router-dom";
|
||||
import Nodata from 'forge/Nodata';
|
||||
import Loading from "src/Loading";
|
||||
import { timeAgo, getImageUrl } from 'educoder';
|
||||
import { checkPublicity } from '../../api';
|
||||
import { httpUrl } from 'military/fetch';
|
||||
import './index.scss';
|
||||
|
||||
const { TextArea } = Input;
|
||||
export default Form.create()((props) => {
|
||||
const { form, list, curPage, total, changePage, loading, showNotification, reloadList } = props;
|
||||
const { getFieldDecorator, validateFields, setFieldsValue } = form;
|
||||
const [checkedItem, setCheckedItem] = useState('');
|
||||
const [page, setPage] = useState(1);
|
||||
const [visible, setVisible] = useState(false);
|
||||
const pageSize = props.pageSize || 10;
|
||||
|
||||
const [isAccepted, setIsAccepted] = useState('');
|
||||
const [isReconsidered, setIsReconsidered] = useState('');
|
||||
const [isChanged, setIsChanged] = useState('');
|
||||
|
||||
|
||||
useEffect(() => {
|
||||
changePage(page);
|
||||
}, [page]);
|
||||
|
||||
|
||||
function deal(item) {
|
||||
setCheckedItem(item);
|
||||
setVisible(true);
|
||||
}
|
||||
|
||||
function dealAction() {
|
||||
validateFields((error, values) => {
|
||||
if (!error) {
|
||||
checkPublicity({
|
||||
complaintMaterialId: checkedItem.id,
|
||||
...values,
|
||||
}).then(res => {
|
||||
if (res && res.message === 'success') {
|
||||
showNotification('操作成功');
|
||||
reloadList();
|
||||
setFieldsValue({
|
||||
isAccepted: '',
|
||||
reason: '',
|
||||
});
|
||||
setVisible(false);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
function goUser(login) {
|
||||
window.location.href = `/users/${login}`;
|
||||
}
|
||||
|
||||
function goUserMes(login) {
|
||||
window.location.href = `/users/${login}/message_detail`;
|
||||
}
|
||||
|
||||
function downFile(item) {
|
||||
let url = httpUrl + '/busiAttachments/download/' + item.id;
|
||||
window.open(url);
|
||||
}
|
||||
|
||||
const helper = useCallback(
|
||||
(label, name, rules, widget, rightDom) => (
|
||||
<Form.Item label={label}>
|
||||
{getFieldDecorator(name, { rules, validateFirst: true })(widget)}
|
||||
{rightDom}
|
||||
</Form.Item>
|
||||
),
|
||||
[]
|
||||
);
|
||||
|
||||
return (
|
||||
loading ? <Loading /> :
|
||||
<React.Fragment>
|
||||
{
|
||||
list.map(item => {
|
||||
return (
|
||||
<div className="list-box" key={item.id}>
|
||||
|
||||
<img alt="头像加载失败" className="radius mr15" height="50px" src={item.user && getImageUrl(item.user.logo)} width="50px" />
|
||||
<div className="flex1">
|
||||
<li className="clearfix mb20">
|
||||
<a className="user-box fl mr15 color-grey-3 font-16" onClick={() => { goUser(item.user.login) }}>{item.user && (item.user.nickname || item.user.login)}</a>
|
||||
<span className="fl color-grey-9 mt3 mr15">{timeAgo(item.createdAt)}</span>
|
||||
<span className="fr">
|
||||
<a className="edu-default-btn edu-orangeline-btn ml20 fl" onClick={() => { goUserMes(item.user.login) }}>私信</a>
|
||||
{item.status === 2 && <a className="edu-default-btn edu-blueline-btn ml20 fl" onClick={() => { deal(item) }}>处理</a>}
|
||||
</span>
|
||||
</li>
|
||||
<div className="clearfix">
|
||||
|
||||
{/* <div className="width100">
|
||||
<span className="with40 fl lineh-35">
|
||||
<span className="color-grey-9 fl">联系手机:</span>
|
||||
<span className="infos_item">{item.contactPhone}(位置分析:河北-唐山)</span>
|
||||
</span>
|
||||
<span className="inline-block lineh-35">
|
||||
<span className="color-grey-9 fl">IP地址:</span>
|
||||
<span className="infos_item">{item.ip}(位置分析:北京-北京)</span>
|
||||
</span>
|
||||
</div> */}
|
||||
|
||||
<div className="clearfix"></div>
|
||||
<div className="width100 lineh-35">
|
||||
<span className="color-grey-9 fl">成果编号:</span>
|
||||
<span className="fl lineh-35 ml5">
|
||||
<Link className="primary-link" to={`/task/taskDetail/${item.taskId}`}>{item.paperNumber}</Link>
|
||||
</span>
|
||||
</div>
|
||||
<div className="clearfix"></div>
|
||||
<div className="width100 lineh-35 clearfix">
|
||||
<span className="color-grey-9 fl">申诉材料:</span>
|
||||
{
|
||||
item.materials && item.materials.map(fileItem => {
|
||||
return <span className="file-list-prof " key={fileItem.id}>
|
||||
<a onClick={() => { downFile(fileItem) }}><i className="iconfont icon-fujian color-green font-14 mr3"></i>
|
||||
{fileItem.fileName} </a>
|
||||
<span className="ml10 color-grey-9">({fileItem.fileSizeString})</span>
|
||||
</span>
|
||||
})
|
||||
}
|
||||
</div>
|
||||
<div className="width100 lineh-35">
|
||||
<span className="color-grey-9 fl">申诉原因:</span>
|
||||
<span className="infos_item">{item.content}</span>
|
||||
</div>
|
||||
{/* {item.taskResultProof.status === 0 && <p className="color-orange lineh-35 "><span className="fl color-orange mr5">拒绝原因:</span>{item.advice}</p>} */}
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
{list.length > 0 ?
|
||||
<div className="edu-txt-center mt20 mb20">
|
||||
{total > pageSize && <Pagination
|
||||
showQuickJumper
|
||||
onChange={(page) => { setPage(page) }}
|
||||
current={curPage}
|
||||
total={total}
|
||||
showTotal={total => `共 ${total} 条`}
|
||||
/>}
|
||||
</div> :
|
||||
<Nodata _html="暂无数据" />}
|
||||
|
||||
<Modal
|
||||
title="处理申诉"
|
||||
visible={visible}
|
||||
onOk={dealAction}
|
||||
onCancel={() => { setVisible(false) }}
|
||||
className="form-edit-modal"
|
||||
>
|
||||
|
||||
{
|
||||
helper('是否受理', 'isAccepted', [{ required: true, message: "请选择是否受理" }],
|
||||
<Radio.Group
|
||||
className="mb10"
|
||||
onChange={(e) => { setIsAccepted(e.target.value); setIsReconsidered(''); setIsChanged(''); }}
|
||||
>
|
||||
<Radio value={'1'}>受理</Radio>
|
||||
<Radio value={'0'}>不受理</Radio>
|
||||
</Radio.Group>
|
||||
)
|
||||
}
|
||||
|
||||
{
|
||||
isAccepted === '1' && helper('复议评审', 'isReconsidered', [{ required: true, message: "请选择是否启动复议评审" }],
|
||||
<Radio.Group
|
||||
className="mb10"
|
||||
onChange={(e) => { setIsReconsidered(e.target.value); setIsChanged(''); }}
|
||||
>
|
||||
<Radio value={'1'}>启动</Radio>
|
||||
<Radio value={'0'}>不启动</Radio>
|
||||
</Radio.Group>
|
||||
)
|
||||
}
|
||||
|
||||
{
|
||||
isAccepted === '1' && isReconsidered === '0' && helper('公示结果', 'isChanged', [{ required: true, message: "请选择是否更改公示结果" }],
|
||||
<Radio.Group
|
||||
className="mb10"
|
||||
onChange={(e) => { setIsChanged(e.target.value) }}
|
||||
>
|
||||
<Radio value={'1'}>更改</Radio>
|
||||
<Radio value={'0'}>不更改</Radio>
|
||||
</Radio.Group>
|
||||
)
|
||||
}
|
||||
|
||||
{
|
||||
isAccepted === '1' && isReconsidered === '0' && isChanged === '1' && helper('延长公示', 'delayDuration',
|
||||
[{ required: true, message: "请输入延长天数" }],
|
||||
<InputNumber
|
||||
placeholder="您打算延长多少天呢"
|
||||
max={150}
|
||||
min={0}
|
||||
/>,
|
||||
' 天'
|
||||
)
|
||||
}
|
||||
|
||||
{
|
||||
helper('原因', 'reason', [{ required: true, message: "请输入原因" }, { max: 200, message: '不能超过200字符' }],
|
||||
<TextArea
|
||||
placeholder="(必填)我想说点什么呢,200字以内"
|
||||
autoSize={{ minRows: 6 }}
|
||||
className="applyText"
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
</Modal>
|
||||
</React.Fragment>
|
||||
|
||||
)
|
||||
}
|
||||
)
|
|
@ -0,0 +1,52 @@
|
|||
.list-box {
|
||||
position: relative;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
padding: 20px;
|
||||
margin: 0 1.5rem;
|
||||
background: #fff;
|
||||
border-bottom: 1px solid #dedede;
|
||||
a.edu-orangeline-btn {
|
||||
padding: 0px 10px;
|
||||
}
|
||||
}
|
||||
|
||||
a.primary-link {
|
||||
color: #1890ff;
|
||||
}
|
||||
|
||||
.infos_item {
|
||||
float: left;
|
||||
max-width: 90%;
|
||||
overflow: hidden;
|
||||
// white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
color: #343434;
|
||||
margin-right: 6px;
|
||||
line-height: 35px;
|
||||
margin-left: 5px;
|
||||
}
|
||||
|
||||
.file-list-prof{
|
||||
background: #fafafa;
|
||||
padding:.25rem .5rem;
|
||||
margin-right:.5rem;
|
||||
}
|
||||
|
||||
.form-edit-modal {
|
||||
.ant-form-item{
|
||||
display: flex;
|
||||
}
|
||||
.ant-form-item-label{
|
||||
min-width: 5rem;
|
||||
}
|
||||
.ant-form-item-control-wrapper{
|
||||
width: 75%;
|
||||
display: inline-block;
|
||||
}
|
||||
.ant-input-number{
|
||||
width: 50%;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,223 @@
|
|||
import React, { useEffect, useState } from 'react';
|
||||
import { Pagination, Modal, Input, Radio, Button } from 'antd';
|
||||
import { Link } from "react-router-dom";
|
||||
import Nodata from 'forge/Nodata';
|
||||
import Loading from "src/Loading";
|
||||
import { timeAgo, getImageUrl } from 'educoder';
|
||||
import { main_web_site_url } from '../../static';
|
||||
import { checkTask } from '../../api';
|
||||
import './index.scss';
|
||||
|
||||
const { TextArea } = Input;
|
||||
export default (props) => {
|
||||
const { list, categoryArr, curPage, total, changePage, loading, showNotification, reloadList } = props;
|
||||
const [checkedId, setCheckedId] = useState('');
|
||||
const [page, setPage] = useState(1);
|
||||
const [visible, setVisible] = useState(false);
|
||||
const [isRepairDocument, setIsRepairDocument] = useState('0');
|
||||
const [repairAdvice, setRepairAdvice] = useState('');
|
||||
const pageSize = props.pageSize || 10;
|
||||
|
||||
useEffect(() => {
|
||||
changePage(page);
|
||||
}, [page]);
|
||||
|
||||
|
||||
function agreeClick(id) {
|
||||
Modal.confirm({
|
||||
title: '是否确认审批通过?',
|
||||
onOk() {
|
||||
checkTask({
|
||||
id,
|
||||
isPassed: 1,
|
||||
}).then(res => {
|
||||
if (res && res.message === 'success') {
|
||||
showNotification('操作成功');
|
||||
reloadList();
|
||||
}
|
||||
})
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
function refuseClick(id) {
|
||||
setCheckedId(id);
|
||||
setVisible(true);
|
||||
}
|
||||
|
||||
function refuse() {
|
||||
if (!repairAdvice) {
|
||||
showNotification('请输入拒绝的理由');
|
||||
return;
|
||||
}
|
||||
checkTask({
|
||||
id: checkedId,
|
||||
isPassed: 0,
|
||||
isRepairDocument,
|
||||
repairAdvice: repairAdvice
|
||||
}).then(res => {
|
||||
if (res && res.message === 'success') {
|
||||
showNotification('操作成功');
|
||||
reloadList();
|
||||
setRepairAdvice('');
|
||||
setVisible(false);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function goUser(login) {
|
||||
window.location.href = `/users/${login}`;
|
||||
}
|
||||
|
||||
function goUserMes(login) {
|
||||
window.location.href = `/users/${login}/message_detail`;
|
||||
}
|
||||
|
||||
function scale(scale) {
|
||||
if (scale > 10000) {
|
||||
return '10000人以上';
|
||||
} else if (scale > 1000) {
|
||||
return '1001 - 10000人';
|
||||
} else if (scale > 100) {
|
||||
return '101 - 1000人';
|
||||
} else if (scale > 10) {
|
||||
return '11 - 99人';
|
||||
} else {
|
||||
return '0 - 10人';
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
loading ? <Loading /> :
|
||||
<React.Fragment>
|
||||
{
|
||||
list.map(item => {
|
||||
return (
|
||||
<div className="list-box" key={item.id}>
|
||||
|
||||
<img alt="头像加载失败" className="radius mr15" height="50px" src={item.user && getImageUrl(item.user.logo)} width="50px" />
|
||||
<div className="flex1">
|
||||
<li className="clearfix mb20">
|
||||
<a className="user-box fl mr15 color-grey-3 font-16" onClick={() => { goUser(item.user.login) }}>{item.user.nickname || item.user.login}</a>
|
||||
<span className="fl color-grey-9 mt3">{timeAgo(item.createdAt)}</span>
|
||||
<span className="fr">
|
||||
{item.status > 2 && item.status !== 9 && <span className="spanTitle color-grey-6 fl ml20">已同意</span>}
|
||||
{item.status === 9 && <span className="spanTitle color-yellow fl ml20">已处理</span>}
|
||||
{item.status === 2 && <span className="spanTitle color-red fl ml20">已拒绝</span>}
|
||||
|
||||
{
|
||||
item.status === 1 && <React.Fragment>
|
||||
<a className="edu-default-btn edu-orangeline-btn ml20 fl" onClick={() => { goUserMes(item.user.login) }}>私信</a>
|
||||
<a className="edu-default-btn edu-blueline-btn ml20 fl" onClick={() => { agreeClick(item.id) }}>同意</a>
|
||||
<a className="edu-default-btn edu-greyline-btn ml20 fl" onClick={() => { refuseClick(item.id) }}>拒绝</a>
|
||||
</React.Fragment>
|
||||
}
|
||||
</span>
|
||||
</li>
|
||||
<ul className="clearfix">
|
||||
<div className="width100">
|
||||
<span className="with40 fl inline-block lineh-35">
|
||||
<span className="color-grey-9 fl">任务名称:</span>
|
||||
<span className="fl lineh-35 ml5">
|
||||
<Link className="primary-link" to={`/task/taskDetail/${item.id}`}>{item.name}</Link>
|
||||
</span>
|
||||
</span>
|
||||
<span className=" lineh-35">
|
||||
<span className="color-grey-9 fl">任务编号:</span>
|
||||
<span className="infos_item">{item.number}</span>
|
||||
</span>
|
||||
|
||||
{item.status === 1 && <div className="fr text-center">
|
||||
<Button type="primary" onClick={() => { window.open(`${main_web_site_url}/admin/tasks/export_task_files.zip?task_id=${item.id}`) }} className="edu-default-btn edu-blueback-btn">导出任务需求材料</Button>
|
||||
</div>}
|
||||
</div>
|
||||
<div className="clearfix"></div>
|
||||
|
||||
<div className="width100">
|
||||
<div className="width100">
|
||||
<span className="with40 fl lineh-35">
|
||||
<span className="color-grey-9 fl">主体名称:</span>
|
||||
<span className="infos_item">{item.enterpriseName}</span>
|
||||
</span>
|
||||
<span className="inline-block lineh-35">
|
||||
<span className="color-grey-9 fl">信用代码:</span>
|
||||
<span className="infos_item">{item.enterpriseSimple ? item.enterpriseSimple.creditCode : ''}</span>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div className="clearfix"></div>
|
||||
<div className="width100">
|
||||
<span className="with40 fl lineh-35">
|
||||
<span className="color-grey-9 fl">联系手机:</span>
|
||||
<span className="infos_item">{item.contactPhone}{item.belongTo && `(位置分析:${item.belongTo})`}</span>
|
||||
</span>
|
||||
<span className="inline-block lineh-35">
|
||||
<span className="color-grey-9 fl">IP地址:</span>
|
||||
<span className="infos_item">{item.ip}{item.belongTo && `(位置分析:${item.belongTo})`}</span>
|
||||
</span>
|
||||
</div>
|
||||
<div className="clearfix"></div>
|
||||
<div className="width100">
|
||||
<span className="with40 fl lineh-35">
|
||||
<span className="color-grey-9 fl">所在行业:</span>
|
||||
<span className="infos_item" style={{ maxWidth: '100px' }}>{categoryArr[item.categoryId]}</span>
|
||||
</span>
|
||||
{
|
||||
item.enterpriseSimple && <span className="with25 fl lineh-35">
|
||||
<span className="color-grey-9 fl">企业规模:</span>
|
||||
<span className="infos_item" style={{ maxWidth: '100px' }}>{scale(item.enterpriseSimple.scale)}</span>
|
||||
</span>}
|
||||
{/* <span className="inline-block lineh-35">
|
||||
<span className="color-grey-9 fl">所在职位:</span>
|
||||
<span className="infos_item">普通员工</span>
|
||||
</span> */}
|
||||
</div>
|
||||
|
||||
</ul>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
{list.length > 0 ?
|
||||
<div className="edu-txt-center mt20 mb20">
|
||||
{total > pageSize && <Pagination
|
||||
showQuickJumper
|
||||
onChange={(page) => { setPage(page) }}
|
||||
current={curPage}
|
||||
total={total}
|
||||
showTotal={total => `共 ${total} 条`}
|
||||
/>}
|
||||
</div> :
|
||||
<Nodata _html="暂无数据" />}
|
||||
|
||||
<Modal
|
||||
title="拒绝原因"
|
||||
visible={visible}
|
||||
onOk={refuse}
|
||||
onCancel={() => { setVisible(false) }}
|
||||
className="form-edit-modal"
|
||||
>
|
||||
<Radio.Group
|
||||
className="mb10"
|
||||
value={isRepairDocument}
|
||||
onChange={(e) => { setIsRepairDocument(e.target.value) }}>
|
||||
<Radio value={'0'}>不允许重新发布</Radio>
|
||||
<Radio value={'1'}>允许修缮后重新发布</Radio>
|
||||
</Radio.Group>
|
||||
<TextArea
|
||||
value={repairAdvice}
|
||||
placeholder="(必填)我想说点什么呢,200字以内"
|
||||
autoSize={{ minRows: 6 }}
|
||||
className="applyText"
|
||||
onChange={(e) => { setRepairAdvice(e.target.value) }}
|
||||
maxLength={200}
|
||||
/>
|
||||
</Modal>
|
||||
</React.Fragment>
|
||||
|
||||
)
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
.list-box {
|
||||
position: relative;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
padding: 20px;
|
||||
margin: 0 1.5rem;
|
||||
background: #fff;
|
||||
border-bottom: 1px solid #dedede;
|
||||
a.edu-orangeline-btn {
|
||||
padding: 0px 10px;
|
||||
}
|
||||
}
|
||||
|
||||
a.primary-link {
|
||||
color: #1890ff;
|
||||
}
|
||||
|
||||
.infos_item {
|
||||
float: left;
|
||||
max-width: 273px;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
color: #343434;
|
||||
margin-right: 6px;
|
||||
line-height: 35px;
|
||||
margin-left: 5px;
|
||||
}
|
|
@ -0,0 +1,229 @@
|
|||
import React, { useEffect, useState, useCallback, useMemo } from 'react';
|
||||
import { Modal, Table, Form, Input, Button, Pagination } from 'antd';
|
||||
import Upload from 'military/components/Upload';
|
||||
import { readyCheckPapers, proofAdd } from "../../api";
|
||||
import { httpUrl } from 'military/fetch';
|
||||
import '../../index.scss';
|
||||
import './index.scss';
|
||||
|
||||
export default Form.create()(props => {
|
||||
const { changeVisible, taskId, taskModeId, visible, form, showNotification, reloadList } = props;
|
||||
const { getFieldDecorator, validateFields, setFieldsValue, getFieldsValue } = form;
|
||||
|
||||
const pageSize = props.pageSize || 10;
|
||||
const [searchObj, setSearchObj] = useState({});
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [curPage, setCurPage] = useState(1);
|
||||
const [total, setTotal] = useState(0);
|
||||
const [dataList, setDataList] = useState([]);
|
||||
|
||||
const [fileList, setFileList] = useState([]);
|
||||
const [selectedRows, setSelectedRows] = useState([]);
|
||||
|
||||
// 获取成果列表
|
||||
useEffect(() => {
|
||||
setLoading(true);
|
||||
let params = {
|
||||
...searchObj,
|
||||
taskId,
|
||||
checkStatus: '1',
|
||||
pageSize,
|
||||
curPage,
|
||||
status: '',
|
||||
}
|
||||
taskId && readyCheckPapers(params).then(data => {
|
||||
if (data && Array.isArray(data.rows)) {
|
||||
for (const item of data.rows) {
|
||||
item.detail = item.paperDetail && item.paperDetail.content;
|
||||
}
|
||||
}
|
||||
setDataList(data.rows || []);
|
||||
setLoading(false);
|
||||
setTotal(data.total);
|
||||
});
|
||||
}, [taskId, curPage, searchObj]);
|
||||
|
||||
|
||||
const helper = useCallback(
|
||||
(name, rules, widget) => (
|
||||
<Form.Item>
|
||||
{getFieldDecorator(name, { rules, validateFirst: true, })(widget)}
|
||||
</Form.Item>
|
||||
), []);
|
||||
|
||||
function onSearch() {
|
||||
let values = getFieldsValue(['number', 'userName']);
|
||||
setSearchObj(values);
|
||||
setCurPage(1);
|
||||
}
|
||||
|
||||
function clearSearch() {
|
||||
setFieldsValue({
|
||||
number: '',
|
||||
userName: '',
|
||||
});
|
||||
setSearchObj({});
|
||||
setCurPage(1);
|
||||
}
|
||||
|
||||
// 上传附件后得到的文件数组
|
||||
function UploadFunc(fileList, files) {
|
||||
setFileList(fileList);
|
||||
setFieldsValue({
|
||||
files
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
const columns = useMemo(() => {
|
||||
return [{
|
||||
title: '作者',
|
||||
dataIndex: 'name',
|
||||
render: (text, record) => {
|
||||
return record.user ? record.user.nickname || record.user.login : ''
|
||||
}
|
||||
},
|
||||
{
|
||||
title: '成果物编号',
|
||||
dataIndex: 'number',
|
||||
},
|
||||
{
|
||||
title: '更新时间',
|
||||
dataIndex: 'updatedAt',
|
||||
},
|
||||
{
|
||||
title: '操作',
|
||||
dataIndex: 'action',
|
||||
render: (text, record) => {
|
||||
// return <Link className="line_1 color-grey3" to={`/task/taskDetail/${record.task.id}`}>查看详情</Link>
|
||||
return <a className="line_1 color-grey3" onClick={(e) => { goToDeatil(e, record.task.id) }}> 查看详情</a >
|
||||
}
|
||||
}];
|
||||
}, [taskId]);
|
||||
|
||||
const rowSelection = useMemo(() => {
|
||||
return {
|
||||
type: taskModeId === 1 ? 'radio' : 'checkbox',
|
||||
onChange: (selectedRowKeys, selectedRows) => {
|
||||
setSelectedRows(selectedRows);
|
||||
},
|
||||
}
|
||||
}, [taskModeId]);
|
||||
|
||||
function goToDeatil(e, taskId) {
|
||||
e.stopPropagation();
|
||||
window.location.href = `/task/taskDetail/${taskId}`;
|
||||
}
|
||||
|
||||
const handleRow = record => {
|
||||
return {
|
||||
onClick: event => {
|
||||
let chooseDom = event.currentTarget.getElementsByClassName("ant-checkbox-wrapper")[0] || event.currentTarget.getElementsByClassName("ant-radio-wrapper")[0];
|
||||
chooseDom && chooseDom.click();
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
function proofItem() {
|
||||
if (!selectedRows.length) {
|
||||
showNotification("请至少选择一条数据!");
|
||||
return;
|
||||
}
|
||||
|
||||
validateFields((err, values) => {
|
||||
if (!err) {
|
||||
let paperNumber = [];
|
||||
let winnerIds = [];
|
||||
let winnerName = [];
|
||||
|
||||
for (const item of selectedRows) {
|
||||
paperNumber.push(item.number);
|
||||
winnerIds.push(item.user.id);
|
||||
winnerName.push(item.user.nickname || item.user.login);
|
||||
}
|
||||
|
||||
let params = {
|
||||
paperNumber: paperNumber.join(),
|
||||
winnerIds: winnerIds.join(),
|
||||
winnerName: winnerName.join(),
|
||||
proofFileNumbers: values.files,
|
||||
status: 2,
|
||||
taskId,
|
||||
};
|
||||
proofAdd(params).then(res => {
|
||||
if (res && res.message === 'success') {
|
||||
changeVisible(false);
|
||||
reloadList();
|
||||
} else {
|
||||
showNotification((res && res.message) || "评选提交失败");
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
return (
|
||||
<Modal
|
||||
title="上传评选佐证材料"
|
||||
visible={visible}
|
||||
onOk={proofItem}
|
||||
onCancel={() => { changeVisible(false) }}
|
||||
className="proof-modal"
|
||||
draggable={true}
|
||||
>
|
||||
<h3 className="margin10">选出胜出者<span className="color-red">*</span></h3>
|
||||
<div className="center-right-but">
|
||||
{helper(
|
||||
"number",
|
||||
[{ max: 20, message: '长度不能超过20个字符' }],
|
||||
<Input
|
||||
placeholder="请输入成果编号进行检索"
|
||||
/>
|
||||
)}
|
||||
|
||||
{helper(
|
||||
"userName",
|
||||
[{ max: 20, message: '长度不能超过20个字符' }],
|
||||
<Input
|
||||
placeholder="请输入作者名称进行检索"
|
||||
/>
|
||||
)}
|
||||
<Button className="mr10" type="primary" onClick={onSearch}>搜索</Button>
|
||||
<Button className="mr10" type="" onClick={clearSearch}>清除</Button>
|
||||
</div>
|
||||
<Table
|
||||
loading={loading}
|
||||
rowKey={(row) => row.id}
|
||||
dataSource={dataList}
|
||||
columns={columns}
|
||||
pagination={false}
|
||||
rowSelection={rowSelection}
|
||||
onRow={handleRow}
|
||||
/>
|
||||
{total > 10 &&
|
||||
<Pagination
|
||||
onChange={(page) => { setCurPage(page) }}
|
||||
current={curPage}
|
||||
total={total}
|
||||
/>}
|
||||
|
||||
<Form.Item className="upload-form" label="上传附件" required={true} >
|
||||
<Upload
|
||||
className="commentStyle"
|
||||
load={UploadFunc}
|
||||
size={50}
|
||||
showNotification={showNotification}
|
||||
actionUrl={httpUrl}
|
||||
fileList={fileList}
|
||||
/>
|
||||
{getFieldDecorator('files', {
|
||||
rules: [{ required: visible, message: "请上传文件" }],
|
||||
validateFirst: true
|
||||
})(<Input style={{ display: 'none' }} />)}
|
||||
</Form.Item>
|
||||
</Modal>
|
||||
|
||||
)
|
||||
}
|
||||
)
|
|
@ -0,0 +1,34 @@
|
|||
.proof-modal {
|
||||
min-width: 800px;
|
||||
width: 80vw;
|
||||
.ant-form-item-control {
|
||||
width: 200px;
|
||||
}
|
||||
.center-right-but {
|
||||
.ant-form-item {
|
||||
margin: 0 1rem 0 0;
|
||||
}
|
||||
}
|
||||
.ant-table-thead > tr > th,
|
||||
tr > td {
|
||||
text-align: center;
|
||||
}
|
||||
.commentStyle {
|
||||
.ant-upload {
|
||||
max-width: 500px;
|
||||
width: 60vw;
|
||||
margin-top: 1rem ;
|
||||
}
|
||||
.ant-upload-list{
|
||||
max-width: 500px;
|
||||
width: 60vw;
|
||||
}
|
||||
|
||||
}
|
||||
.ant-form-item{
|
||||
margin-bottom: 0;
|
||||
}
|
||||
.upload-form .ant-form-item-label{
|
||||
padding-top:.5rem;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,128 @@
|
|||
import React, { useCallback, useEffect, useState } from 'react';
|
||||
import { Input, Button } from 'antd';
|
||||
|
||||
import ItemDelayManage from '../components/itemDelayManage';
|
||||
import StatusNav from '../../components/statusNav';
|
||||
import { delayTaskArr, delayDealArr } from '../static';
|
||||
import { delayList, } from '../api';
|
||||
import '../index.scss';
|
||||
|
||||
const { Search } = Input;
|
||||
|
||||
export default ({ current_user, showNotification, history }) => {
|
||||
const [operationStatus, setOperationStatus] = useState(0);
|
||||
const [publishMode, setPublishMode] = useState('');
|
||||
const [cancelStatus, setCancelStatus] = useState('');
|
||||
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [searchInput, setSearchInput] = useState('');
|
||||
const [searchInputCurrent, setSearchInputCurrent] = useState('');
|
||||
const [status, setStatus] = useState('');
|
||||
const [curPage, setCurPage] = useState(1);
|
||||
const [total, setTotal] = useState(0);
|
||||
const [taskList, setTaskList] = useState([]);
|
||||
|
||||
const [reload, setReload] = useState(0);
|
||||
|
||||
useEffect(() => {
|
||||
const params = {
|
||||
searchInput:searchInputCurrent,
|
||||
operationStatus,
|
||||
status,
|
||||
curPage,
|
||||
pageSize: 10,
|
||||
publishMode,
|
||||
cancelStatus,
|
||||
};
|
||||
setLoading(true);
|
||||
delayList(params).then(data => {
|
||||
if (data) {
|
||||
setTaskList(data.rows);
|
||||
setTotal(data.total);
|
||||
}
|
||||
setLoading(false);
|
||||
})
|
||||
}, [reload, searchInput, operationStatus, publishMode, cancelStatus, status, curPage,]);
|
||||
|
||||
|
||||
const changeTaskStatus = useCallback((option) => {
|
||||
setStatus(option.dicItemCode.toString() || '');
|
||||
setCurPage(1);
|
||||
setCancelStatus('');
|
||||
}, []);
|
||||
|
||||
const changeDealStatus = useCallback((option) => {
|
||||
setCancelStatus(option.dicItemCode.toString() || '');
|
||||
setCurPage(1);
|
||||
setStatus('');
|
||||
}, []);
|
||||
|
||||
function changeOperationStatus(operationStatus) {
|
||||
setOperationStatus(operationStatus);
|
||||
setCurPage(1);
|
||||
setStatus('');
|
||||
}
|
||||
|
||||
const reloadList = useCallback(() => {
|
||||
setReload(Math.random());
|
||||
}, [])
|
||||
|
||||
return (
|
||||
<div className="centerbox task-manage">
|
||||
|
||||
<div className="center-screen" >
|
||||
<div className="center-left-but">
|
||||
<Button className="circle-button" type={operationStatus === 0 ? 'primary' : ''} onClick={() => { changeOperationStatus(0) }}>待处理</Button>
|
||||
<Button className="circle-button" type={operationStatus === 1 ? 'primary' : ''} onClick={() => { changeOperationStatus(1) }}>已处理</Button>
|
||||
</div>
|
||||
|
||||
<div className="center-right-but">
|
||||
<Search
|
||||
maxLength={20}
|
||||
style={{ width: "300px" }}
|
||||
placeholder="请输入任务编号/任务名称关键字"
|
||||
onChange={(e) => setSearchInputCurrent(e.target.value)}
|
||||
onSearch={(value) => { setSearchInput(value); setCurPage(1); }}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="center-screen flex-column" >
|
||||
<div className="center-left-but">
|
||||
<Button className="circle-button" type={publishMode === '' ? 'primary' : ''} onClick={() => { setPublishMode('') }}>全部</Button>
|
||||
<Button className="circle-button" type={publishMode === 1 ? 'primary' : ''} onClick={() => { setPublishMode(1) }}>统筹任务</Button>
|
||||
<Button className="circle-button" type={publishMode === 0 ? 'primary' : ''} onClick={() => { setPublishMode(0) }}>自主提交任务</Button>
|
||||
</div>
|
||||
|
||||
{
|
||||
operationStatus === 0 ? <StatusNav
|
||||
key={'status'}
|
||||
type={'status'}
|
||||
options={delayTaskArr}
|
||||
changeOptionId={changeTaskStatus}
|
||||
/> : <StatusNav
|
||||
key={'dealStatus'}
|
||||
type={'dealStatus'}
|
||||
options={delayDealArr}
|
||||
changeOptionId={changeDealStatus}
|
||||
/>
|
||||
}
|
||||
</div>
|
||||
|
||||
<div className="center-content">
|
||||
<ItemDelayManage
|
||||
list={taskList}
|
||||
curPage={curPage}
|
||||
total={total}
|
||||
changePage={(page) => { setCurPage(page) }}
|
||||
loading={loading}
|
||||
showNotification={showNotification}
|
||||
reloadList={reloadList}
|
||||
/>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
)
|
||||
}
|
Binary file not shown.
After Width: | Height: | Size: 66 KiB |
Binary file not shown.
After Width: | Height: | Size: 1.6 KiB |
Binary file not shown.
After Width: | Height: | Size: 8.4 KiB |
|
@ -0,0 +1,107 @@
|
|||
// 本功能模块公告样式
|
||||
.task-manage {
|
||||
margin-top: 1.25rem;
|
||||
.status-list {
|
||||
margin: 0 1.5rem;
|
||||
}
|
||||
|
||||
.center-screen {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
margin: 1.25rem 0;
|
||||
padding: 1rem 0;
|
||||
background-color: #fff;
|
||||
|
||||
.ant-form-item {
|
||||
margin: 0 1rem 0 0;
|
||||
}
|
||||
.ant-form-item-control-wrapper {
|
||||
display: inline-block;
|
||||
}
|
||||
.status-item{
|
||||
margin-right: 2rem;
|
||||
}
|
||||
}
|
||||
.center-left-but {
|
||||
.circle-button {
|
||||
border-radius: 1rem;
|
||||
margin-right: 2rem;
|
||||
}
|
||||
}
|
||||
|
||||
.flex-column{
|
||||
flex-direction: column;
|
||||
.status-list{
|
||||
padding-bottom: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.ant-select {
|
||||
min-width: 200px;
|
||||
}
|
||||
.ant-table-thead th {
|
||||
text-align: center;
|
||||
// &:first-child {
|
||||
// text-align: left;
|
||||
// }
|
||||
}
|
||||
td {
|
||||
text-align: center;
|
||||
color: #333;
|
||||
&:first-child {
|
||||
// text-align: left;
|
||||
font-size: 1rem;
|
||||
}
|
||||
}
|
||||
|
||||
.text-ellipsis-2 {
|
||||
text-overflow: -o-ellipsis-lastline;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
display: -webkit-box;
|
||||
-webkit-line-clamp: 2;
|
||||
line-clamp: 2;
|
||||
-webkit-box-orient: vertical;
|
||||
}
|
||||
}
|
||||
|
||||
span.list-yellow {
|
||||
background: #fa6400;
|
||||
}
|
||||
span.list-red {
|
||||
background: #fe0e36;
|
||||
}
|
||||
span.list-orange {
|
||||
background: #ffb121;
|
||||
}
|
||||
span.list-done {
|
||||
background: #35d77e;
|
||||
}
|
||||
span.list-pay {
|
||||
background: #1ad757;
|
||||
}
|
||||
span.list-error {
|
||||
background: #f56c6c;
|
||||
}
|
||||
span.list-gray {
|
||||
background: #bababa;
|
||||
}
|
||||
|
||||
.ant-pagination {
|
||||
margin: 2rem auto;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.text-ellipsis {
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
word-break: break-all;
|
||||
}
|
||||
|
||||
.upload-form {
|
||||
display: flex;
|
||||
.ant-form-item-control-wrapper {
|
||||
max-width: 80%;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,191 @@
|
|||
import React, { useCallback, useEffect, useState } from 'react';
|
||||
import { Tabs, Input, } from 'antd';
|
||||
import StatusNav from '../../components/statusNav';
|
||||
import ItemListMyTask from '../components/itemListMyTask';
|
||||
import JoinTask from './joinTask';
|
||||
import { taskStatusAllArr, } from '../static';
|
||||
import { getTaskCategory, getMyTaskList } from '../api';
|
||||
import './index.scss';
|
||||
const Search = Input.Search;
|
||||
const { TabPane } = Tabs;
|
||||
|
||||
const publishStatusArr = taskStatusAllArr.slice(3, 9);
|
||||
const unpublishStatusArr = taskStatusAllArr.slice(0, 3);
|
||||
unpublishStatusArr.push({ dicItemCode: '9', name: "待修缮", dicItemName: "待修缮" });
|
||||
|
||||
const statusArr = [];
|
||||
for (const item of taskStatusAllArr) {
|
||||
statusArr[item.dicItemCode] = item.dicItemName;
|
||||
}
|
||||
|
||||
export default ({ location, history, current_user, showNotification }) => {
|
||||
console.log(current_user);
|
||||
let defaultValue = decodeURI(location.search.split("=")[1] || "");
|
||||
|
||||
const [identity, setIdentity] = useState('1');
|
||||
const [taskCategoryValueArr, setTaskCategoryValueArr] = useState([]);
|
||||
|
||||
const [statusType, setStatusType] = useState(() => {
|
||||
return defaultValue === 'false' ? '2' : '1';
|
||||
});
|
||||
const [statusString, setStatusString] = useState(() => {
|
||||
return defaultValue === 'false' ? '0,1,2,9' : '3,4,5,6,7,8';
|
||||
});
|
||||
|
||||
const [searchInput, setSearchInput] = useState('');
|
||||
const [curPage, setCurPage] = useState(1);
|
||||
const [total, setTotal] = useState(0);
|
||||
const [myTaskList, setMyTaskList] = useState([]);
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [reload, setReload] = useState(0);
|
||||
|
||||
// 获取任务领域数组
|
||||
useEffect(() => {
|
||||
getTaskCategory().then(data => {
|
||||
if (data) {
|
||||
const taskCategoryValueArr = [];
|
||||
for (const item of data) {
|
||||
taskCategoryValueArr[item.id] = item.name;
|
||||
}
|
||||
setTaskCategoryValueArr(taskCategoryValueArr);
|
||||
}
|
||||
});
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
const params = {
|
||||
statusString,
|
||||
searchInput,
|
||||
orderBy: 'createdAtDesc',
|
||||
curPage,
|
||||
pageSize: 10,
|
||||
};
|
||||
setLoading(true);
|
||||
getMyTaskList(params).then(data => {
|
||||
if (data) {
|
||||
setMyTaskList(data.rows);
|
||||
setTotal(data.total);
|
||||
}
|
||||
setLoading(false);
|
||||
})
|
||||
}, [statusString, searchInput, curPage, reload]);
|
||||
|
||||
function taskClick(id) {
|
||||
history.push(`/task/taskDetail/${id}`);
|
||||
}
|
||||
|
||||
const changeOptionId = useCallback((option, type) => {
|
||||
if (type === 'publishStatus') {
|
||||
setStatusString(option.dicItemCode.toString() || '3,4,5,6,7,8');
|
||||
} else if (type === 'unpublishStatus') {
|
||||
setStatusString(option.dicItemCode.toString() || '0,1,2,9');
|
||||
}
|
||||
setCurPage(1);
|
||||
}, [])
|
||||
|
||||
function changeIdentity(key) {
|
||||
setIdentity(key);
|
||||
if (key === '1') {
|
||||
setStatusString('3,4,5,6,7,8');
|
||||
} else {
|
||||
setStatusString('0,1,2,9');
|
||||
}
|
||||
setCurPage(1);
|
||||
}
|
||||
|
||||
function changeStatusType(key) {
|
||||
if (key === '1') {
|
||||
setStatusString('3,4,5,6,7,8');
|
||||
} else {
|
||||
setStatusString('0,1,2,9');
|
||||
}
|
||||
setCurPage(1);
|
||||
setStatusType(key);
|
||||
}
|
||||
|
||||
const reloadList = useCallback(() => {
|
||||
setReload(Math.random());
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<div className="centerbox my-task">
|
||||
<Tabs defaultActiveKey={identity} onChange={changeIdentity}>
|
||||
<TabPane tab="我是雇主" key="1">
|
||||
|
||||
<Tabs className="childTab"
|
||||
activeKey={statusType}
|
||||
onChange={changeStatusType}
|
||||
tabBarExtraContent={
|
||||
<Search
|
||||
maxLength={20}
|
||||
style={{ width: "300px" }}
|
||||
placeholder="请输入任务编号/任务名称关键字"
|
||||
onSearch={(value) => { setSearchInput(value); setCurPage(1) }}
|
||||
/>
|
||||
}
|
||||
>
|
||||
<TabPane tab="我发布的任务" key="1">
|
||||
{
|
||||
identity === '1' && statusType === '1' && <StatusNav
|
||||
key={'publishStatus'}
|
||||
type={'publishStatus'}
|
||||
options={publishStatusArr}
|
||||
changeOptionId={changeOptionId}
|
||||
/>
|
||||
}
|
||||
|
||||
<ItemListMyTask
|
||||
list={myTaskList}
|
||||
itemClick={taskClick}
|
||||
curPage={curPage}
|
||||
total={total}
|
||||
taskCategoryValueArr={taskCategoryValueArr}
|
||||
changePage={(page) => { setCurPage(page) }}
|
||||
loading={loading}
|
||||
publish={true}
|
||||
showNotification={showNotification}
|
||||
reloadList={reloadList}
|
||||
/>
|
||||
</TabPane>
|
||||
|
||||
<TabPane tab="任务草稿" key="2">
|
||||
{
|
||||
identity === '1' && statusType === '2' && <StatusNav
|
||||
key={'unpublishStatus'}
|
||||
type={'unpublishStatus'}
|
||||
options={unpublishStatusArr}
|
||||
changeOptionId={changeOptionId}
|
||||
/>
|
||||
}
|
||||
|
||||
<ItemListMyTask
|
||||
list={myTaskList}
|
||||
itemClick={taskClick}
|
||||
curPage={curPage}
|
||||
total={total}
|
||||
taskCategoryValueArr={taskCategoryValueArr}
|
||||
changePage={(page) => { setCurPage(page) }}
|
||||
loading={loading}
|
||||
showNotification={showNotification}
|
||||
reloadList={reloadList}
|
||||
|
||||
/>
|
||||
</TabPane>
|
||||
</Tabs>
|
||||
|
||||
</TabPane>
|
||||
|
||||
|
||||
<TabPane tab="我是创客" key="2">
|
||||
|
||||
<JoinTask
|
||||
taskCategoryValueArr={taskCategoryValueArr}
|
||||
showNotification={showNotification}
|
||||
/>
|
||||
</TabPane>
|
||||
|
||||
</Tabs>
|
||||
|
||||
</div>
|
||||
)
|
||||
}
|
|
@ -0,0 +1,62 @@
|
|||
.my-task {
|
||||
margin-top: 1.25rem;
|
||||
.ant-tabs-top-bar {
|
||||
background: #fff;
|
||||
text-align: center;
|
||||
}
|
||||
.ant-tabs-tab {
|
||||
height: 4.5rem;
|
||||
line-height: 3rem;
|
||||
font-size: 1.15rem;
|
||||
font-weight: 500;
|
||||
}
|
||||
.ant-tabs-extra-content {
|
||||
line-height: 4.5rem;
|
||||
}
|
||||
|
||||
.childTab {
|
||||
background: #fff;
|
||||
.ant-tabs-top-bar {
|
||||
padding: 0 1.8rem 0 0.8rem;
|
||||
background: #fff;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.ant-tabs-tab {
|
||||
height: 4.5rem;
|
||||
line-height: 3rem;
|
||||
font-size: 1rem;
|
||||
font-weight: normal;
|
||||
}
|
||||
.ant-tabs-ink-bar {
|
||||
visibility: hidden;
|
||||
}
|
||||
.ant-tabs-tabpane {
|
||||
padding: 0 1.8rem 1rem;
|
||||
line-height: 2;
|
||||
}
|
||||
}
|
||||
|
||||
.ant-table-thead th{
|
||||
text-align: center;
|
||||
&:first-child{
|
||||
text-align: left;
|
||||
}
|
||||
}
|
||||
td{
|
||||
text-align: center;
|
||||
color: #333;
|
||||
&:first-child{
|
||||
text-align: left;
|
||||
font-weight: bold;
|
||||
font-size: 1rem;
|
||||
}
|
||||
}
|
||||
.action-td{
|
||||
// display: flex;
|
||||
// flex-flow: column nowrap;
|
||||
.ant-btn{
|
||||
margin:.25rem;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,283 @@
|
|||
import React, { useCallback, useEffect, useState, useMemo } from 'react';
|
||||
import { Tabs, Input, Table, Pagination, Modal, Button } from 'antd';
|
||||
import { Link } from "react-router-dom";
|
||||
import ChooseNav from '../../components/chooseNav';
|
||||
import ItemListMyTask from '../components/itemListMyTask';
|
||||
import AgreementModal from '../components/agreementModal';
|
||||
import ComplainModal from '../components/complainModal';
|
||||
import { applyStatusAllArr, paperCheckStatusArr, applyStatusArr, publishModeArr, taskStatusAllArr } from '../static';
|
||||
import { getJoinTaskList, myPapers, confirmReceipt } from '../api';
|
||||
import './index.scss';
|
||||
const Search = Input.Search;
|
||||
const { TabPane } = Tabs;
|
||||
|
||||
const publishStatusArr = taskStatusAllArr.slice(3, 9);
|
||||
|
||||
const statusArr = [];
|
||||
for (const item of applyStatusAllArr) {
|
||||
statusArr[item.dicItemCode] = item.dicItemName;
|
||||
}
|
||||
|
||||
const paperCheckStatus = [];
|
||||
for (const item of paperCheckStatusArr) {
|
||||
paperCheckStatus[item.dicItemCode] = item.dicItemName;
|
||||
}
|
||||
|
||||
export default ({ taskCategoryValueArr, showNotification }) => {
|
||||
|
||||
const [paperStatusString, setPaperStatusString] = useState('0,1,2,3,4');
|
||||
const [taskStatusString, setTaskStatusString] = useState('3,4,5,6,7,8');
|
||||
|
||||
const [requirePaper, setRequirePaper] = useState('1');
|
||||
const [searchInput, setSearchInput] = useState('');
|
||||
const [curPage, setCurPage] = useState(1);
|
||||
const [total, setTotal] = useState(0);
|
||||
const [taskList, setTaskList] = useState([]);
|
||||
const [loading, setLoading] = useState(false);
|
||||
|
||||
const [curPagePaper, setCurPagePaper] = useState(1);
|
||||
const [totalPaper, setTotalPaper] = useState(0);
|
||||
const [paperList, setPaperList] = useState([]);
|
||||
|
||||
const [checkedItem, setCheckedItem] = useState({});
|
||||
const [complainVisible, setComplainVisible] = useState(false);
|
||||
const [agreeVisible, setAgreeVisible] = useState(false);
|
||||
|
||||
const [reload, setReload] = useState(0);
|
||||
|
||||
useEffect(() => {
|
||||
if (requirePaper === '1') {
|
||||
const params = {
|
||||
paperStatusString,
|
||||
taskStatusString,
|
||||
searchInput,
|
||||
curPage,
|
||||
pageSize: 10,
|
||||
};
|
||||
setLoading(true);
|
||||
getJoinTaskList(params).then(data => {
|
||||
if (data) {
|
||||
setTaskList(data.rows);
|
||||
setTotal(data.total);
|
||||
}
|
||||
setLoading(false);
|
||||
});
|
||||
}
|
||||
}, [requirePaper, paperStatusString, taskStatusString, searchInput, curPage]);
|
||||
|
||||
useEffect(() => {
|
||||
if (requirePaper === '2') {
|
||||
const params = {
|
||||
status: paperStatusString,
|
||||
searchInput,
|
||||
curPage,
|
||||
pageSize: 10,
|
||||
};
|
||||
setLoading(true);
|
||||
myPapers(params).then(data => {
|
||||
if (data) {
|
||||
setPaperList(data.rows);
|
||||
setTotalPaper(data.total);
|
||||
}
|
||||
setLoading(false);
|
||||
})
|
||||
}
|
||||
}, [requirePaper, paperStatusString, searchInput, curPagePaper, reload]);
|
||||
|
||||
|
||||
const columns = useMemo(() => {
|
||||
return [
|
||||
{
|
||||
title: '任务/编号名称',
|
||||
dataIndex: 'name',
|
||||
width: '30%',
|
||||
render: (text, record) => {
|
||||
return <Link className="color-grey3 font-16 font-bd" to={`/task/taskDetail/${record.task.id}`}>{record.task.number + " " + record.task.name}</Link>
|
||||
}
|
||||
},
|
||||
{
|
||||
title: '成果编号',
|
||||
dataIndex: 'number',
|
||||
},
|
||||
{
|
||||
title: '上传文件',
|
||||
dataIndex: 'files',
|
||||
render: (text) => {
|
||||
return text ? text.split(',').length : 0
|
||||
}
|
||||
},
|
||||
{
|
||||
title: '提交时间',
|
||||
dataIndex: 'createdAt',
|
||||
},
|
||||
{
|
||||
title: '应征状态',
|
||||
dataIndex: 'status',
|
||||
render: (text, record) => {
|
||||
return text === 0 ? paperCheckStatus[record.checkStatus] : statusArr[text]
|
||||
}
|
||||
},
|
||||
{
|
||||
title: '操作',
|
||||
key: 'action',
|
||||
className: 'action-td',
|
||||
render: (text, record) => (
|
||||
<React.Fragment>
|
||||
{/* <Link className="line_1 color-grey3" to={`/task/taskDetail/${record.task.id}`}>查看详情</Link> */}
|
||||
<Button size="small" onClick={() => { window.location.href = `/task/taskDetail/${record.task.id}` }}>查看详情</Button>
|
||||
|
||||
{((record.needComplain && record.task.status === 3) || (record.task.status === 5 && record.publicTaskComplain && record.status !== 2)) &&
|
||||
<Button type="danger" size="small" onClick={() => { setComplainVisible(true); setCheckedItem(record) }}>申诉</Button>
|
||||
}
|
||||
|
||||
{record.status === 2 && record.task.status === 6 && (!record.sign) && (record.canApplicantSign || record.canApplicantSignByPlatform) &&
|
||||
< Button type="primary" size="small" onClick={() => { setAgreeVisible(true); setCheckedItem(record) }}>签订协议</Button>
|
||||
}
|
||||
|
||||
{
|
||||
record.status === 2 && (!record.pay) && record.task.status === 7 && record.task.agreementSigning === 1 &&
|
||||
<Button type="primary" size="small" onClick={() => { confirmReceiptModal(record.id) }}>确认收款</Button>
|
||||
}
|
||||
</React.Fragment >
|
||||
),
|
||||
},
|
||||
];
|
||||
}, [taskCategoryValueArr, publishModeArr, statusArr]);
|
||||
|
||||
|
||||
function confirmReceiptModal(paperId) {
|
||||
Modal.confirm({
|
||||
title: '确认收款',
|
||||
content: '确认已经收到任务报酬',
|
||||
onOk: () => {
|
||||
confirmReceipt(paperId).then(res => {
|
||||
if (res && res.message === "success") {
|
||||
showNotification("您已确认收款!");
|
||||
reloadList();
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
const changeOptionId = useCallback((option, type) => {
|
||||
if (type === 'taskStatus') {
|
||||
setTaskStatusString(option.dicItemCode.toString() || '3,4,5,6,7,8');
|
||||
} else if (type === 'applyStatus') {
|
||||
setPaperStatusString(option.dicItemCode.toString() || '0,1,2,3,4');
|
||||
}
|
||||
setCurPage(1);
|
||||
}, [])
|
||||
|
||||
function changeRequirePaper(key) {
|
||||
if (key === '1') {
|
||||
setPaperStatusString('0,1,2,3,4');
|
||||
} else {
|
||||
setTaskStatusString('3,4,5,6,7,8');
|
||||
setPaperStatusString('0,1,2,3,4');
|
||||
}
|
||||
setCurPage(1);
|
||||
setRequirePaper(key);
|
||||
}
|
||||
|
||||
const reloadList = useCallback(() => {
|
||||
setReload(Math.random());
|
||||
}, [])
|
||||
|
||||
return (
|
||||
|
||||
<Tabs className="childTab"
|
||||
activeKey={requirePaper}
|
||||
onChange={changeRequirePaper}
|
||||
tabBarExtraContent={
|
||||
<Search
|
||||
maxLength={20}
|
||||
style={{ width: "300px" }}
|
||||
placeholder="请输入任务编号/任务名称关键字"
|
||||
onSearch={(value) => { setSearchInput(value); setCurPage(1); }}
|
||||
/>
|
||||
}
|
||||
>
|
||||
<TabPane tab="我参加的任务" key="1">
|
||||
|
||||
{requirePaper === '1' &&
|
||||
<React.Fragment>
|
||||
<ChooseNav
|
||||
key={'taskStatus'}
|
||||
type={'taskStatus'}
|
||||
title={'任务状态:'}
|
||||
options={publishStatusArr}
|
||||
changeOptionId={changeOptionId}
|
||||
/>
|
||||
|
||||
<ChooseNav
|
||||
key={'applyStatus'}
|
||||
type={'applyStatus'}
|
||||
title={'应征状态:'}
|
||||
options={applyStatusArr}
|
||||
changeOptionId={changeOptionId}
|
||||
/>
|
||||
</React.Fragment>
|
||||
}
|
||||
|
||||
|
||||
<ItemListMyTask
|
||||
list={taskList}
|
||||
curPage={curPage}
|
||||
total={total}
|
||||
taskCategoryValueArr={taskCategoryValueArr}
|
||||
changePage={(page) => { setCurPage(page) }}
|
||||
loading={loading}
|
||||
joinTask={true}
|
||||
/>
|
||||
</TabPane>
|
||||
|
||||
<TabPane tab="我的成果" key="2">
|
||||
{
|
||||
requirePaper === '2' && <ChooseNav
|
||||
key={'applyStatus'}
|
||||
type={'applyStatus'}
|
||||
title={'应征状态:'}
|
||||
options={applyStatusArr}
|
||||
changeOptionId={changeOptionId}
|
||||
/>
|
||||
}
|
||||
|
||||
<Table
|
||||
loading={loading}
|
||||
rowKey={(row) => row.id}
|
||||
dataSource={paperList}
|
||||
columns={columns}
|
||||
pagination={false}
|
||||
className="mt10"
|
||||
/>
|
||||
{taskList.length > 10 &&
|
||||
<Pagination
|
||||
onChange={(page) => { setCurPagePaper(page) }}
|
||||
current={curPage}
|
||||
total={totalPaper}
|
||||
/>}
|
||||
|
||||
<ComplainModal
|
||||
visible={complainVisible}
|
||||
setVisible={setComplainVisible}
|
||||
checkedItem={checkedItem}
|
||||
detailStatus={checkedItem.task && checkedItem.task.status}
|
||||
showNotification={showNotification}
|
||||
reloadList={reloadList}
|
||||
/>
|
||||
|
||||
{agreeVisible && <AgreementModal
|
||||
checkedItem={checkedItem}
|
||||
visible={agreeVisible}
|
||||
setVisible={setAgreeVisible}
|
||||
showNotification={showNotification}
|
||||
reloadList={reloadList}
|
||||
/>}
|
||||
|
||||
</TabPane>
|
||||
</Tabs>
|
||||
|
||||
)
|
||||
}
|
|
@ -0,0 +1,263 @@
|
|||
import React, { useCallback, useMemo, useEffect, useState } from 'react';
|
||||
import { Input, Button, Form, Table, Pagination, Modal } from 'antd';
|
||||
import { Link } from "react-router-dom";
|
||||
|
||||
import StatusNav from '../../components/statusNav';
|
||||
import { complainPaperList, checkComplain } from '../api';
|
||||
import { paperComplainStatusArr } from '../static';
|
||||
import { httpUrl } from 'military/fetch';
|
||||
|
||||
import '../index.scss';
|
||||
|
||||
const TextArea = Input.TextArea;
|
||||
|
||||
const paperComplainStatus = [];
|
||||
for (const item of paperComplainStatusArr) {
|
||||
paperComplainStatus[item.dicItemCode] = item.dicItemName;
|
||||
}
|
||||
const paperComplain = paperComplainStatusArr.slice(0, 2);
|
||||
|
||||
export default Form.create()(({ form, showNotification, history}) => {
|
||||
|
||||
const { getFieldDecorator, validateFields, setFieldsValue, } = form;
|
||||
|
||||
const [approve, setApprove] = useState(1);
|
||||
const [loading, setLoading] = useState(false);
|
||||
// const [searchObj, setSearchObj] = useState({});
|
||||
const [curPage, setCurPage] = useState(1);
|
||||
const [total, setTotal] = useState(0);
|
||||
const [taskList, setTaskList] = useState([]);
|
||||
|
||||
const [reload, setReload] = useState(0);
|
||||
const [visible, setVisible] = useState(false);
|
||||
const [activeId, setActiveId] = useState('');
|
||||
const [status, setStatus] = useState('2');
|
||||
|
||||
useEffect(() => {
|
||||
const params = {
|
||||
// ...searchObj,
|
||||
status,
|
||||
curPage,
|
||||
pageSize: 10,
|
||||
};
|
||||
setLoading(true);
|
||||
complainPaperList(params).then(data => {
|
||||
if (data) {
|
||||
setTaskList(data.rows);
|
||||
setTotal(data.total);
|
||||
}
|
||||
setLoading(false);
|
||||
})
|
||||
|
||||
}, [reload, status, curPage]);
|
||||
|
||||
|
||||
|
||||
const helper = useCallback(
|
||||
(name, rules, widget) => (
|
||||
<Form.Item>
|
||||
{getFieldDecorator(name, { rules, validateFirst: true, })(widget)}
|
||||
</Form.Item>
|
||||
), []);
|
||||
|
||||
|
||||
// function onSearch() {
|
||||
// validateFields((err, values) => {
|
||||
// if (!err) {
|
||||
// setSearchObj({ numberInput: values.numberInput });
|
||||
// }
|
||||
// });
|
||||
// }
|
||||
|
||||
// function clearSearch() {
|
||||
// setFieldsValue({
|
||||
// numberInput: '',
|
||||
// });
|
||||
// setSearchObj({});
|
||||
// }
|
||||
|
||||
|
||||
function changeApprove(approve) {
|
||||
setApprove(approve);
|
||||
setCurPage(1);
|
||||
if (approve === 1) {
|
||||
setStatus('2');
|
||||
} else {
|
||||
setStatus('0,1');
|
||||
}
|
||||
}
|
||||
|
||||
function downFile(item) {
|
||||
let url = httpUrl + '/busiAttachments/download/' + item.id;
|
||||
window.open(url);
|
||||
}
|
||||
|
||||
const columns = useMemo(() => {
|
||||
return [
|
||||
{
|
||||
title: '序号',
|
||||
dataIndex: 'index',
|
||||
render: (text, record, index) => {
|
||||
return index + 1
|
||||
}
|
||||
},
|
||||
{
|
||||
title: '申诉内容',
|
||||
dataIndex: 'content',
|
||||
width: "30%",
|
||||
},
|
||||
{
|
||||
title: '申诉文件',
|
||||
dataIndex: 'materials',
|
||||
width: "20%",
|
||||
render: (text, record) => {
|
||||
return <div>
|
||||
{
|
||||
Array.isArray(record.materials) && record.materials.map(item => {
|
||||
return <div className="file-list-box" key={item.id}>
|
||||
<a onClick={() => { downFile(item) }}><i className="iconfont icon-fujian color-green font-14 mr3"></i>
|
||||
{item.fileName} </a>
|
||||
<span className="ml10 color-grey-9">({item.fileSizeString})</span>
|
||||
</div>
|
||||
})
|
||||
}
|
||||
</div>
|
||||
}
|
||||
|
||||
},
|
||||
{
|
||||
title: '提交者',
|
||||
dataIndex: 'user',
|
||||
render: (text, record) => {
|
||||
return record.user.nickname || record.user.login
|
||||
}
|
||||
},
|
||||
{
|
||||
title: '提交时间',
|
||||
dataIndex: 'createdAt',
|
||||
},
|
||||
{
|
||||
title: '审核状态',
|
||||
dataIndex: 'status',
|
||||
render: (text, record) => {
|
||||
return text !== 2 ? paperComplainStatus[text] : <React.Fragment>
|
||||
<Button className="mr5 font-12" type="primary" size="small" onClick={() => { checkPaperItem(record.id, 1) }}>通过</Button>
|
||||
<Button className="mr5 font-12" type="info" size="small" onClick={() => { setActiveId(record.id); setVisible(true) }}>不通过</Button>
|
||||
</React.Fragment>
|
||||
}
|
||||
},
|
||||
{
|
||||
title: '操作',
|
||||
key: 'action',
|
||||
render: (text, record) => (
|
||||
<Link className="line_1 color-grey3" to={`/task/taskDetail/${record.taskId}`}>查看详情</Link>
|
||||
),
|
||||
},
|
||||
]
|
||||
}, []);
|
||||
|
||||
function checkPaperItem(paperId, pass, message) {
|
||||
setLoading(true);
|
||||
checkComplain({
|
||||
paperId,
|
||||
auditingVo: {
|
||||
pass,
|
||||
message,
|
||||
}
|
||||
}).then(res => {
|
||||
if (res && res.message === 'success') {
|
||||
setReload(Math.random());
|
||||
setVisible(false);
|
||||
}
|
||||
setLoading(false);
|
||||
});
|
||||
}
|
||||
|
||||
function refuse() {
|
||||
validateFields((err, values) => {
|
||||
if (!err) {
|
||||
checkPaperItem(activeId, 0, values.message);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
const changeOptionId = useCallback((option) => {
|
||||
setStatus(option.dicItemCode.toString() || '0,1');
|
||||
setCurPage(1);
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<div className="centerbox task-manage">
|
||||
|
||||
|
||||
<div className="center-screen" >
|
||||
<div className="center-left-but">
|
||||
<Button className="circle-button" type={approve === 1 ? 'primary' : ''} onClick={() => { changeApprove(1) }}>待审批</Button>
|
||||
<Button className="circle-button" type={approve === 2 ? 'primary' : ''} onClick={() => { changeApprove(2) }}>已审批</Button>
|
||||
</div>
|
||||
|
||||
{/* <div className="center-right-but">
|
||||
{helper(
|
||||
"numberInput",
|
||||
[{ max: 20, message: '长度不能超过20个字符' }],
|
||||
<Input
|
||||
placeholder="输入任务编号进行检索"
|
||||
/>
|
||||
)}
|
||||
|
||||
<Button className="mr10" type="primary" onClick={onSearch}>搜索</Button>
|
||||
<Button className="mr10" type="" onClick={clearSearch}>清除</Button>
|
||||
|
||||
</div> */}
|
||||
</div>
|
||||
|
||||
|
||||
<div className="center-content">
|
||||
{
|
||||
approve === 2 && <StatusNav
|
||||
key={'status'}
|
||||
type={'status'}
|
||||
options={paperComplain}
|
||||
changeOptionId={changeOptionId}
|
||||
/>
|
||||
}
|
||||
|
||||
<Table
|
||||
loading={loading}
|
||||
rowKey={(row) => row.id}
|
||||
dataSource={taskList}
|
||||
columns={columns}
|
||||
pagination={false}
|
||||
className="mt10"
|
||||
/>
|
||||
{total > 10 &&
|
||||
<Pagination
|
||||
onChange={(page) => { setCurPage(page) }}
|
||||
current={curPage}
|
||||
total={total}
|
||||
/>}
|
||||
</div>
|
||||
|
||||
|
||||
<Modal
|
||||
title="不通过的原因"
|
||||
visible={visible}
|
||||
onOk={refuse}
|
||||
onCancel={() => { setVisible(false) }}
|
||||
className="form-edit-modal"
|
||||
>
|
||||
{helper(
|
||||
"message",
|
||||
[{ required: visible, message: '请给出不通过的原因' }],
|
||||
<TextArea
|
||||
placeholder="(必填)我想给点什么意见呢,200字以内"
|
||||
autoSize={{ minRows: 6 }}
|
||||
className="applyText"
|
||||
maxLength={200}
|
||||
/>
|
||||
)}
|
||||
</Modal>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
)
|
|
@ -0,0 +1,331 @@
|
|||
import React, { useCallback, useEffect, useState, useMemo } from 'react';
|
||||
import { Input, Radio, Select, Button, Form, DatePicker, Table, Pagination, Modal } from 'antd';
|
||||
import { Link } from "react-router-dom";
|
||||
import { paperCheckStatusArr } from '../static';
|
||||
import { readyCheckPapers, checkPaper, } from '../api';
|
||||
import '../index.scss';
|
||||
const format = "YYYY-MM-DD HH:mm:ss";
|
||||
const Option = Select.Option;
|
||||
const TextArea = Input.TextArea;
|
||||
|
||||
|
||||
const checkStatusArr = [];
|
||||
for (const item of paperCheckStatusArr) {
|
||||
checkStatusArr[item.dicItemCode] = item.dicItemName;
|
||||
}
|
||||
export default Form.create()(({ current_user, form, showNotification, match, history }) => {
|
||||
|
||||
|
||||
const { getFieldDecorator, validateFields, setFieldsValue, getFieldsValue } = form;
|
||||
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [searchObj, setSearchObj] = useState({
|
||||
checkStatus: '0',
|
||||
parentId: 0,
|
||||
});
|
||||
const [curPage, setCurPage] = useState(1);
|
||||
const [total, setTotal] = useState(0);
|
||||
const [taskList, setTaskList] = useState([]);
|
||||
|
||||
const [reload, setReload] = useState(0);
|
||||
const [visible, setVisible] = useState(false);
|
||||
const [activeId, setActiveId] = useState('');
|
||||
|
||||
|
||||
useEffect(() => {
|
||||
const params = {
|
||||
curPage,
|
||||
pageSize: 10,
|
||||
...searchObj,
|
||||
};
|
||||
setLoading(true);
|
||||
readyCheckPapers(params).then(data => {
|
||||
if (data) {
|
||||
setTaskList(data.rows);
|
||||
setTotal(data.total);
|
||||
}
|
||||
setLoading(false);
|
||||
})
|
||||
}, [reload, curPage, searchObj]);
|
||||
|
||||
|
||||
const helper = useCallback(
|
||||
(label, name, rules, widget, initialValue) => (
|
||||
<Form.Item label={label}>
|
||||
{getFieldDecorator(name, { rules, initialValue, validateFirst: true, })(widget)}
|
||||
</Form.Item>
|
||||
), []);
|
||||
|
||||
|
||||
function onSearch() {
|
||||
let values = getFieldsValue(['checkStatus', 'endCreatedAt', 'startCreatedAt', 'parentId']);
|
||||
if (values.startCreatedAt) values.startCreatedAt = values.startCreatedAt.format(format);
|
||||
if (values.endCreatedAt) values.endCreatedAt = values.endCreatedAt.format(format);
|
||||
if (values.checkStatus === '0,1,2') values.checkStatus = '';
|
||||
setSearchObj(values);
|
||||
}
|
||||
|
||||
function clearSearch() {
|
||||
setFieldsValue({
|
||||
startCreatedAt: '',
|
||||
endCreatedAt: '',
|
||||
checkStatus: '0,1,2'
|
||||
});
|
||||
setSearchObj({});
|
||||
}
|
||||
|
||||
function checkPaperItem(paperId, passStatus) {
|
||||
validateFields((err, values) => {
|
||||
if (!err) {
|
||||
setLoading(true);
|
||||
checkPaper({
|
||||
paperId,
|
||||
auditingVo: {
|
||||
pass: passStatus ? 1 : values.pass,
|
||||
message: values.message,
|
||||
}
|
||||
}).then(res => {
|
||||
setLoading(false);
|
||||
if (res && res.message === 'success') {
|
||||
setReload(Math.random());
|
||||
setVisible(false);
|
||||
setFieldsValue({
|
||||
pass: '',
|
||||
message: '',
|
||||
})
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
const columns = useMemo(() => {
|
||||
return [
|
||||
{
|
||||
title: '序号',
|
||||
dataIndex: 'index',
|
||||
render: (text, record, index) => {
|
||||
return <div style={{ textAlign: 'center' }}>{index + 1}</div>
|
||||
}
|
||||
},
|
||||
{
|
||||
title: '来源任务',
|
||||
dataIndex: 'name',
|
||||
width: "20%",
|
||||
render: (text, record) => (
|
||||
<span>
|
||||
<Link className="line_1 color-grey3" to={`/task/taskDetail/${record.taskId}`}>{record.task && record.task.name}</Link>
|
||||
</span >
|
||||
),
|
||||
},
|
||||
{
|
||||
title: '评论/成果内容',
|
||||
dataIndex: 'content',
|
||||
width: "30%",
|
||||
render: (text, record) => {
|
||||
return record.paperDetail ? <div dangerouslySetInnerHTML={{ __html: record.paperDetail.content }}></div> : ''
|
||||
}
|
||||
},
|
||||
{
|
||||
title: '提交者',
|
||||
dataIndex: 'user',
|
||||
render: (text, record) => {
|
||||
return record.user.nickname || record.user.login
|
||||
}
|
||||
},
|
||||
{
|
||||
title: '提交时间',
|
||||
dataIndex: 'createdAt',
|
||||
},
|
||||
{
|
||||
title: '审核状态',
|
||||
dataIndex: 'checkStatus',
|
||||
render: (text, record) => {
|
||||
return text === 0 ? <React.Fragment>
|
||||
<Button className="mr5 font-12" type="primary" size="small" onClick={() => { checkPaperItem(record.id, true) }}>通过</Button>
|
||||
<Button className="mr5 font-12" type="info" size="small" onClick={() => { disagree(record) }}>不通过</Button>
|
||||
</React.Fragment> : checkStatusArr[text]
|
||||
}
|
||||
},
|
||||
{
|
||||
title: '操作',
|
||||
key: 'action',
|
||||
render: (text, record) => (
|
||||
<React.Fragment>
|
||||
<Link className="line_1 color-grey3" to={`/task/taskDetail/${record.taskId}`}>查看</Link>
|
||||
</React.Fragment>
|
||||
),
|
||||
},
|
||||
]
|
||||
}, []);
|
||||
|
||||
// 不通过评论或者成果
|
||||
function disagree(item) {
|
||||
if (!item.parentId) {
|
||||
setActiveId(item.id); setVisible(true);
|
||||
} else {
|
||||
Modal.confirm({
|
||||
title: '此条评论不通过?',
|
||||
onOk() {
|
||||
setLoading(true);
|
||||
checkPaper({
|
||||
paperId: item.id,
|
||||
auditingVo: {
|
||||
pass: 0,
|
||||
message: '不通过',
|
||||
}
|
||||
}).then(res => {
|
||||
setLoading(false);
|
||||
if (res && res.message === 'success') {
|
||||
setReload(Math.random());
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function changeStatus(e) {
|
||||
setSearchObj({
|
||||
...searchObj,
|
||||
checkStatus: e,
|
||||
});
|
||||
setCurPage(1);
|
||||
}
|
||||
|
||||
function changeType(e) {
|
||||
setSearchObj({
|
||||
...searchObj,
|
||||
parentId: e,
|
||||
});
|
||||
setCurPage(1);
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="centerbox task-manage">
|
||||
<div className="center-screen" >
|
||||
<div className="center-left-but">
|
||||
{helper(
|
||||
"",
|
||||
"checkStatus",
|
||||
[],
|
||||
<Select
|
||||
showArrow
|
||||
placeholder="请选择审核状态"
|
||||
onChange={changeStatus}
|
||||
>
|
||||
<Option key={'0,1,2'}>{'所有状态'}</Option>
|
||||
{
|
||||
paperCheckStatusArr.map(item => {
|
||||
return <Option key={item.dicItemCode}>{item.dicItemName}</Option>
|
||||
})
|
||||
}
|
||||
</Select>,
|
||||
'0'
|
||||
)}
|
||||
|
||||
{helper(
|
||||
"",
|
||||
"parentId",
|
||||
[],
|
||||
<Select
|
||||
showArrow
|
||||
placeholder="请选择需要审核的类型"
|
||||
onChange={changeType}
|
||||
>
|
||||
<Option key={0} value={0}>成果</Option>
|
||||
<Option key={1} value={1}>评论</Option>
|
||||
</Select>,
|
||||
0
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div className="center-right-but">
|
||||
|
||||
{helper(
|
||||
"发布时间:",
|
||||
"startCreatedAt",
|
||||
[],
|
||||
<DatePicker
|
||||
showTime
|
||||
format={format}
|
||||
placeholder="请选择开始时间"
|
||||
/>
|
||||
)}
|
||||
|
||||
{helper(
|
||||
"",
|
||||
"endCreatedAt",
|
||||
[],
|
||||
<DatePicker
|
||||
showTime
|
||||
format={format}
|
||||
placeholder="请选择结束时间"
|
||||
/>
|
||||
)}
|
||||
|
||||
<Button className="mr10" type="primary" onClick={onSearch}>搜索</Button>
|
||||
<Button className="mr10" type="" onClick={clearSearch}>清除</Button>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div className="center-content">
|
||||
|
||||
<Table
|
||||
loading={loading}
|
||||
rowKey={(row) => row.id}
|
||||
dataSource={taskList}
|
||||
columns={columns}
|
||||
pagination={false}
|
||||
className="mt10"
|
||||
/>
|
||||
{total > 10 &&
|
||||
<Pagination
|
||||
onChange={(page) => { setCurPage(page) }}
|
||||
current={curPage}
|
||||
total={total}
|
||||
/>}
|
||||
|
||||
</div>
|
||||
|
||||
<Modal
|
||||
title="不通过的原因"
|
||||
visible={visible}
|
||||
onOk={() => { checkPaperItem(activeId, false) }}
|
||||
onCancel={() => { setVisible(false); setFieldsValue({ pass: 2, message: '' }); }}
|
||||
className="form-edit-modal"
|
||||
>
|
||||
{helper(
|
||||
"",
|
||||
"pass",
|
||||
[{ required: visible, message: '请选择是否允许申诉' }],
|
||||
<Radio.Group
|
||||
className="mb10"
|
||||
>
|
||||
<Radio value={2}>允许申诉</Radio>
|
||||
<Radio value={0}>不允许申诉</Radio>
|
||||
</Radio.Group>,
|
||||
2
|
||||
)
|
||||
}
|
||||
|
||||
{helper(
|
||||
"",
|
||||
"message",
|
||||
[{ required: visible, message: '请输入拒绝的原因' }],
|
||||
<TextArea
|
||||
placeholder="(必填)我想说点什么呢,200字以内"
|
||||
autoSize={{ minRows: 6 }}
|
||||
className="applyText"
|
||||
maxLength={200}
|
||||
/>
|
||||
)
|
||||
}
|
||||
</Modal>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
)
|
|
@ -0,0 +1,138 @@
|
|||
import React, { useCallback, forwardRef, useEffect, useState } from 'react';
|
||||
import { Input, Button, Form } from 'antd';
|
||||
import ItemPayProof from '../components/itemPayProof';
|
||||
|
||||
// import StatusNav from '../../components/statusNav';
|
||||
import { agreementArr } from '../static';
|
||||
import { uploadPayProofList } from '../api';
|
||||
import '../index.scss';
|
||||
|
||||
agreementArr.splice(1,1);
|
||||
export default Form.create()(({ current_user, form, showNotification, match, history }) => {
|
||||
const { getFieldDecorator, validateFields, setFieldsValue, } = form;
|
||||
|
||||
const [approve, setApprove] = useState(1);
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [searchObj, setSearchObj] = useState({});
|
||||
const [curPage, setCurPage] = useState(1);
|
||||
const [total, setTotal] = useState(0);
|
||||
const [taskList, setTaskList] = useState([]);
|
||||
|
||||
const [reload, setReload] = useState(0);
|
||||
|
||||
useEffect(() => {
|
||||
const params = {
|
||||
...searchObj,
|
||||
status:approve,
|
||||
type:'',
|
||||
currentPage:curPage,
|
||||
pageSize: 10,
|
||||
};
|
||||
setLoading(true);
|
||||
uploadPayProofList(params).then(data => {
|
||||
if (data) {
|
||||
setTaskList(data.rows);
|
||||
setTotal(data.total);
|
||||
}
|
||||
setLoading(false);
|
||||
})
|
||||
}, [reload, approve, curPage, searchObj]);
|
||||
|
||||
|
||||
const helper = useCallback(
|
||||
(name, rules, widget) => (
|
||||
<Form.Item>
|
||||
{getFieldDecorator(name, { rules, validateFirst: true, })(widget)}
|
||||
</Form.Item>
|
||||
), []);
|
||||
|
||||
|
||||
function onSearch() {
|
||||
validateFields((err, values) => {
|
||||
if (!err) {
|
||||
setSearchObj(values);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
function changeApprove(approve) {
|
||||
setApprove(approve);
|
||||
setCurPage(1);
|
||||
}
|
||||
|
||||
function clearSearch() {
|
||||
setFieldsValue({
|
||||
numberInput: '',
|
||||
nameInput: '',
|
||||
enterpriseNameInput: ''
|
||||
});
|
||||
setSearchObj({});
|
||||
}
|
||||
|
||||
const reloadList = useCallback(() => {
|
||||
setReload(Math.random());
|
||||
}, [])
|
||||
|
||||
return (
|
||||
<div className="centerbox task-manage">
|
||||
|
||||
|
||||
<div className="center-screen" >
|
||||
<div className="center-left-but">
|
||||
<Button className="circle-button" type={approve === 1 ? 'primary' : ''} onClick={() => { changeApprove(1) }}>待上传</Button>
|
||||
<Button className="circle-button" type={approve === 2 ? 'primary' : ''} onClick={() => { changeApprove(2) }}>已上传</Button>
|
||||
</div>
|
||||
|
||||
<div className="center-right-but">
|
||||
{helper(
|
||||
"numberInput",
|
||||
[{ max: 20, message: '长度不能超过20个字符' }],
|
||||
<Input
|
||||
placeholder="输入任务编号进行检索"
|
||||
/>
|
||||
)}
|
||||
|
||||
{helper(
|
||||
"nameInput",
|
||||
[{ max: 20, message: '长度不能超过20个字符' }],
|
||||
<Input
|
||||
placeholder="输入任务名称进行检索"
|
||||
/>
|
||||
)}
|
||||
|
||||
{helper(
|
||||
"enterpriseNameInput",
|
||||
[{ max: 20, message: '长度不能超过20个字符' }],
|
||||
<Input
|
||||
placeholder="输入发布主体名称进行检索"
|
||||
/>
|
||||
)}
|
||||
|
||||
<Button className="mr10" type="primary" onClick={onSearch}>搜索</Button>
|
||||
<Button className="mr10" type="" onClick={clearSearch}>清除</Button>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div className="center-content">
|
||||
|
||||
|
||||
<ItemPayProof
|
||||
list={taskList}
|
||||
curPage={curPage}
|
||||
total={total}
|
||||
changePage={(page) => { setCurPage(page) }}
|
||||
loading={loading}
|
||||
showNotification={showNotification}
|
||||
reloadList={reloadList}
|
||||
/>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
)
|
||||
}
|
||||
)
|
|
@ -0,0 +1,153 @@
|
|||
import React, { useCallback, forwardRef, useEffect, useState } from 'react';
|
||||
import { Input, Button, Form } from 'antd';
|
||||
|
||||
import ItemProofManage from '../components/itemProofManage';
|
||||
import StatusNav from '../../components/statusNav';
|
||||
import { proofArr } from '../static';
|
||||
import { proofList, } from '../api';
|
||||
import '../index.scss';
|
||||
|
||||
const proofArrCheck = proofArr.slice(0, 2);
|
||||
export default Form.create()(({ current_user, form, showNotification, match, history }) => {
|
||||
const { getFieldDecorator, validateFields, setFieldsValue } = form;
|
||||
const [approve, setApprove] = useState(1);
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [searchObj, setSearchObj] = useState({});
|
||||
const [proofStatusString, setProofStatusString] = useState('2');
|
||||
const [curPage, setCurPage] = useState(1);
|
||||
const [total, setTotal] = useState(0);
|
||||
const [taskList, setTaskList] = useState([]);
|
||||
|
||||
const [reload, setReload] = useState(0);
|
||||
|
||||
useEffect(() => {
|
||||
const params = {
|
||||
...searchObj,
|
||||
proofStatusString,
|
||||
orderBy: 'createdAtDesc',
|
||||
curPage,
|
||||
pageSize: 10,
|
||||
};
|
||||
setLoading(true);
|
||||
proofList(params).then(data => {
|
||||
if (data) {
|
||||
setTaskList(data.rows);
|
||||
setTotal(data.total);
|
||||
}
|
||||
setLoading(false);
|
||||
})
|
||||
}, [reload, proofStatusString, curPage, searchObj]);
|
||||
|
||||
|
||||
const helper = useCallback(
|
||||
(name, rules, widget) => (
|
||||
<Form.Item>
|
||||
{getFieldDecorator(name, { rules, validateFirst: true, })(widget)}
|
||||
</Form.Item>
|
||||
), []);
|
||||
|
||||
|
||||
function onSearch() {
|
||||
validateFields((err, values) => {
|
||||
if (!err) {
|
||||
setSearchObj(values);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
const changeOptionId = useCallback((option) => {
|
||||
setProofStatusString(option.dicItemCode.toString() || '0,1');
|
||||
setCurPage(1);
|
||||
}, []);
|
||||
|
||||
function changeApprove(approve) {
|
||||
setApprove(approve);
|
||||
setCurPage(1);
|
||||
if (approve === 1) {
|
||||
setProofStatusString('2');
|
||||
} else {
|
||||
setProofStatusString('0,1');
|
||||
}
|
||||
}
|
||||
|
||||
function clearSearch() {
|
||||
setFieldsValue({
|
||||
numberInput: '',
|
||||
nameInput: '',
|
||||
enterpriseNameInput: ''
|
||||
});
|
||||
setSearchObj({});
|
||||
}
|
||||
|
||||
const reloadList = useCallback(() => {
|
||||
setReload(Math.random());
|
||||
}, [])
|
||||
|
||||
return (
|
||||
<div className="centerbox task-manage">
|
||||
|
||||
<div className="center-screen" >
|
||||
<div className="center-left-but">
|
||||
<Button className="circle-button" type={approve === 1 ? 'primary' : ''} onClick={() => { changeApprove(1) }}>待审批</Button>
|
||||
<Button className="circle-button" type={approve === 2 ? 'primary' : ''} onClick={() => { changeApprove(2) }}>已审批</Button>
|
||||
</div>
|
||||
|
||||
<div className="center-right-but">
|
||||
{helper(
|
||||
"numberInput",
|
||||
[{ max: 20, message: '长度不能超过20个字符' }],
|
||||
<Input
|
||||
placeholder="输入任务编号进行检索"
|
||||
/>
|
||||
)}
|
||||
|
||||
{helper(
|
||||
"nameInput",
|
||||
[{ max: 20, message: '长度不能超过20个字符' }],
|
||||
<Input
|
||||
placeholder="输入任务名称进行检索"
|
||||
/>
|
||||
)}
|
||||
|
||||
{helper(
|
||||
"enterpriseNameInput",
|
||||
[{ max: 20, message: '长度不能超过20个字符' }],
|
||||
<Input
|
||||
placeholder="输入发布主体名称进行检索"
|
||||
/>
|
||||
)}
|
||||
|
||||
<Button className="mr10" type="primary" onClick={onSearch}>搜索</Button>
|
||||
<Button className="mr10" type="" onClick={clearSearch}>清除</Button>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div className="center-content">
|
||||
|
||||
{
|
||||
approve === 2 && <StatusNav
|
||||
key={'approveStatus'}
|
||||
type={'approveStatus'}
|
||||
options={proofArrCheck}
|
||||
changeOptionId={changeOptionId}
|
||||
/>
|
||||
}
|
||||
<ItemProofManage
|
||||
list={taskList}
|
||||
curPage={curPage}
|
||||
total={total}
|
||||
changePage={(page) => { setCurPage(page) }}
|
||||
loading={loading}
|
||||
showNotification={showNotification}
|
||||
reloadList={reloadList}
|
||||
/>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
)
|
||||
}
|
||||
)
|
|
@ -0,0 +1,130 @@
|
|||
import React, { useCallback, useEffect, useState } from 'react';
|
||||
import { Input, Button, Form } from 'antd';
|
||||
|
||||
import ItemPublicityComplain from '../components/itemPublicityComplain';
|
||||
import StatusNav from '../../components/statusNav';
|
||||
import { publicityArr } from '../static';
|
||||
import { publicityComplainList, } from '../api';
|
||||
import '../index.scss';
|
||||
|
||||
export default Form.create()(({ current_user, form, showNotification, match, history }) => {
|
||||
const { getFieldDecorator, validateFields, setFieldsValue } = form;
|
||||
const [approve, setApprove] = useState(1);
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [searchObj, setSearchObj] = useState({});
|
||||
const [status, setStatus] = useState('2');
|
||||
const [curPage, setCurPage] = useState(1);
|
||||
const [total, setTotal] = useState(0);
|
||||
const [taskList, setTaskList] = useState([]);
|
||||
|
||||
const [reload, setReload] = useState(0);
|
||||
|
||||
useEffect(() => {
|
||||
const params = {
|
||||
...searchObj,
|
||||
status,
|
||||
orderBy: 'createdAtDesc',
|
||||
curPage,
|
||||
pageSize: 10,
|
||||
};
|
||||
setLoading(true);
|
||||
publicityComplainList(params).then(data => {
|
||||
if (data) {
|
||||
setTaskList(data.rows);
|
||||
setTotal(data.total);
|
||||
}
|
||||
setLoading(false);
|
||||
})
|
||||
}, [reload, status, curPage, searchObj]);
|
||||
|
||||
|
||||
const helper = useCallback(
|
||||
(name, rules, widget) => (
|
||||
<Form.Item>
|
||||
{getFieldDecorator(name, { rules, validateFirst: true, })(widget)}
|
||||
</Form.Item>
|
||||
), []);
|
||||
|
||||
|
||||
function onSearch() {
|
||||
validateFields((err, values) => {
|
||||
if (!err) {
|
||||
setSearchObj(values);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
const changeOptionId = useCallback((option) => {
|
||||
setStatus(option.dicItemCode.toString() || '0,1');
|
||||
setCurPage(1);
|
||||
}, []);
|
||||
|
||||
|
||||
function changeApprove(approve) {
|
||||
setApprove(approve);
|
||||
setCurPage(1);
|
||||
if (approve === 1) {
|
||||
setStatus('2');
|
||||
} else {
|
||||
setStatus('0,1');
|
||||
}
|
||||
}
|
||||
|
||||
function clearSearch() {
|
||||
setFieldsValue({
|
||||
numberInput: '',
|
||||
});
|
||||
setSearchObj({});
|
||||
}
|
||||
|
||||
const reloadList = useCallback(() => {
|
||||
setReload(Math.random());
|
||||
}, [])
|
||||
|
||||
return (
|
||||
<div className="centerbox task-manage">
|
||||
|
||||
<div className="center-screen" >
|
||||
<div className="center-left-but">
|
||||
<Button className="circle-button" type={approve === 1 ? 'primary' : ''} onClick={() => { changeApprove(1) }}>待审批</Button>
|
||||
<Button className="circle-button" type={approve === 2 ? 'primary' : ''} onClick={() => { changeApprove(2) }}>已审批</Button>
|
||||
</div>
|
||||
|
||||
<div className="center-right-but">
|
||||
{helper(
|
||||
"numberInput",
|
||||
[{ max: 20, message: '长度不能超过20个字符' }],
|
||||
<Input
|
||||
placeholder="输入成果编号进行检索"
|
||||
/>
|
||||
)}
|
||||
<Button className="mr10" type="primary" onClick={onSearch}>搜索</Button>
|
||||
<Button className="mr10" type="" onClick={clearSearch}>清除</Button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div className="center-content">
|
||||
{
|
||||
approve === 2 && <StatusNav
|
||||
key={'status'}
|
||||
type={'status'}
|
||||
options={publicityArr}
|
||||
changeOptionId={changeOptionId}
|
||||
/>
|
||||
}
|
||||
<ItemPublicityComplain
|
||||
list={taskList}
|
||||
curPage={curPage}
|
||||
total={total}
|
||||
changePage={(page) => { setCurPage(page) }}
|
||||
loading={loading}
|
||||
showNotification={showNotification}
|
||||
reloadList={reloadList}
|
||||
/>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
)
|
||||
}
|
||||
)
|
File diff suppressed because one or more lines are too long
|
@ -0,0 +1,339 @@
|
|||
import React, { useCallback, useEffect, useState, useMemo } from 'react';
|
||||
import classNames from 'classnames';
|
||||
import { Input, Select, Button, Form, DatePicker, Table, Pagination, } from 'antd';
|
||||
import { Link } from "react-router-dom";
|
||||
|
||||
import { paperCheckStatusArr, publishModeArr, taskStatusAllArr, showUserModeArr ,main_web_site_url} from '../static';
|
||||
import { getTaskAdminList, changeShowUserMode } from '../api';
|
||||
import '../index.scss';
|
||||
import './index.scss';
|
||||
const format = "YYYY-MM-DD HH:mm:ss";
|
||||
const Option = Select.Option;
|
||||
|
||||
const statusArr = [];
|
||||
for (const item of taskStatusAllArr) {
|
||||
statusArr[item.dicItemCode] = item.dicItemName;
|
||||
}
|
||||
const checkStatusArr = [];
|
||||
for (const item of paperCheckStatusArr) {
|
||||
checkStatusArr[item.dicItemCode] = item.dicItemName;
|
||||
}
|
||||
|
||||
|
||||
export default Form.create()(({ form, showNotification, match, history }) => {
|
||||
const { getFieldDecorator, setFieldsValue, getFieldsValue } = form;
|
||||
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [statusString, setStatusString] = useState('');
|
||||
const [publishMode, setPublishMode] = useState('');
|
||||
const [showUserMode, setShowUserMode] = useState('');
|
||||
|
||||
const [sort, setSort] = useState('Desc');
|
||||
const [order, setOrder] = useState('createdAt');
|
||||
const [searchObj, setSearchObj] = useState({});
|
||||
const [curPage, setCurPage] = useState(1);
|
||||
const [total, setTotal] = useState(0);
|
||||
const [taskList, setTaskList] = useState([]);
|
||||
|
||||
|
||||
useEffect(() => {
|
||||
const params = {
|
||||
...searchObj,
|
||||
statusString,
|
||||
publishMode: publishMode.length > 1 ? '' : publishMode,
|
||||
showUserMode: showUserMode.length > 1 ? '' : showUserMode,
|
||||
curPage,
|
||||
pageSize: 10,
|
||||
orderBy: order + sort,
|
||||
};
|
||||
setLoading(true);
|
||||
getTaskAdminList(params).then(data => {
|
||||
if (data) {
|
||||
setTaskList(data.rows);
|
||||
setTotal(data.total);
|
||||
}
|
||||
setLoading(false);
|
||||
})
|
||||
}, [statusString, order, sort, publishMode, showUserMode, curPage, searchObj]);
|
||||
|
||||
|
||||
const helper = useCallback(
|
||||
(label, name, rules, widget, initialValue) => (
|
||||
<Form.Item label={label}>
|
||||
{getFieldDecorator(name, { rules, initialValue, validateFirst: true, })(widget)}
|
||||
</Form.Item>
|
||||
), []);
|
||||
|
||||
|
||||
function onSearch() {
|
||||
let values = getFieldsValue(['nameInput', 'endTime', 'startTime', 'enterpriseNameInput']);
|
||||
if (values.startTime) values.startTime = values.startTime.format(format);
|
||||
if (values.endTime) values.endTime = values.endTime.format(format);
|
||||
if (values.checkStatus === '0,1,2') values.checkStatus = '';
|
||||
setSearchObj(values);
|
||||
}
|
||||
|
||||
function clearSearch() {
|
||||
setFieldsValue({
|
||||
startTime: '',
|
||||
endTime: '',
|
||||
nameInput: '',
|
||||
enterpriseNameInput: ''
|
||||
});
|
||||
setSearchObj({});
|
||||
}
|
||||
|
||||
const columns = useMemo(() => {
|
||||
return [
|
||||
{
|
||||
title: '序号',
|
||||
dataIndex: 'index',
|
||||
render: (text, record, index) => {
|
||||
return <div style={{ textAlign: 'center' }}>{index + 1}</div>
|
||||
}
|
||||
},
|
||||
{
|
||||
title: '任务编号',
|
||||
dataIndex: 'number',
|
||||
},
|
||||
{
|
||||
title: '任务名称',
|
||||
dataIndex: 'name',
|
||||
width: "15%",
|
||||
render: (text, record) => (
|
||||
<Link className="line_1 color-grey3" to={`/task/taskDetail/${record.id}`}>{text}</Link>
|
||||
),
|
||||
},
|
||||
{
|
||||
title: <Select
|
||||
className="column-select"
|
||||
showArrow
|
||||
defaultValue={'0,1'}
|
||||
onChange={setPublishMode}
|
||||
>
|
||||
<Option key={'0,1'} >发布方式</Option>
|
||||
<Option key={'0'} >自主提交</Option>
|
||||
<Option key={'1'} >统筹任务</Option>
|
||||
</Select>,
|
||||
dataIndex: 'publishMode',
|
||||
render: (text, record) => {
|
||||
return publishModeArr[text]
|
||||
}
|
||||
},
|
||||
{
|
||||
title: <Select
|
||||
className="column-select"
|
||||
showArrow
|
||||
defaultValue={'0,1,2,3,4,5,6,7,8,9'}
|
||||
onChange={setStatusString}
|
||||
>
|
||||
<Option key={'0,1,2,3,4,5,6,7,8,9'} >任务状态</Option>
|
||||
{
|
||||
taskStatusAllArr.map(item => {
|
||||
return <Option key={item.dicItemCode} >{item.dicItemName}</Option>
|
||||
})
|
||||
}
|
||||
</Select>,
|
||||
width: '10%',
|
||||
dataIndex: 'status',
|
||||
render: (text, record) => {
|
||||
return statusArr[text]
|
||||
}
|
||||
},
|
||||
{
|
||||
title: '稿件数',
|
||||
dataIndex: 'papersCount',
|
||||
},
|
||||
{
|
||||
title: '发布主体',
|
||||
dataIndex: 'enterpriseName',
|
||||
},
|
||||
{
|
||||
title: '发布时间',
|
||||
dataIndex: 'publishedAt',
|
||||
render: (text, record) => {
|
||||
return text || '--'
|
||||
}
|
||||
},
|
||||
{
|
||||
title: '截稿时间',
|
||||
dataIndex: 'collectingEndTime',
|
||||
render: (text, record) => {
|
||||
return text || '--'
|
||||
}
|
||||
},
|
||||
{
|
||||
// title: '应征者名单公示',
|
||||
title: <Select
|
||||
className="column-select"
|
||||
showArrow
|
||||
placeholder="请选择审核状态"
|
||||
defaultValue={'0,1,2'}
|
||||
onChange={setShowUserMode}
|
||||
>
|
||||
<Option key={'0,1,2'}>应征者名单公示</Option>
|
||||
{
|
||||
showUserModeArr.map(item => {
|
||||
return <Option key={item.dicItemCode}>{item.dicItemName}</Option>
|
||||
})
|
||||
}
|
||||
</Select>,
|
||||
dataIndex: 'showUserMode',
|
||||
render: (text, record) => {
|
||||
return <Select
|
||||
className="column-select"
|
||||
showArrow
|
||||
placeholder="请选择审核状态"
|
||||
defaultValue={text}
|
||||
onChange={(key) => { changeStatus(key, record.id) }}
|
||||
>
|
||||
{
|
||||
showUserModeArr.map(item => {
|
||||
return <Option key={item.dicItemCode} value={item.dicItemCode}>{item.dicItemName}</Option>
|
||||
})
|
||||
}
|
||||
</Select>
|
||||
}
|
||||
},
|
||||
// {
|
||||
// title: '操作',
|
||||
// key: 'action',
|
||||
// render: (text, record) => (
|
||||
// <React.Fragment>
|
||||
// {/* <Button className="mr5 font-12" type="danger" size="small" onClick={() => { deletItem(record.id) }}>删除</Button> */}
|
||||
// <Link className="line_1 color-grey3" to={`/task/taskDetail/${record.taskId}`}>查看</Link>
|
||||
// </React.Fragment>
|
||||
// ),
|
||||
// },
|
||||
]
|
||||
}, []);
|
||||
|
||||
function changeStatus(showUserMode, taskId) {
|
||||
changeShowUserMode({
|
||||
taskId,
|
||||
showUserMode
|
||||
}).then(res => {
|
||||
if (res && res.message === 'success') {
|
||||
showNotification('修改成功!');
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
// 改变排序字段
|
||||
const changeSortName = useCallback((sortType) => {
|
||||
setOrder(sortType);
|
||||
setCurPage(1);
|
||||
}, []);
|
||||
|
||||
// 改变排序
|
||||
const changeSort = useCallback((sort) => {
|
||||
setSort(sort);
|
||||
setCurPage(1);
|
||||
}, []);
|
||||
|
||||
function downloadFile() {
|
||||
window.open(main_web_site_url + '/admin/tasks.xlsx');
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="centerbox task-manage-all ">
|
||||
|
||||
<div className="search-screen" >
|
||||
{helper(
|
||||
"任务名称",
|
||||
"nameInput",
|
||||
[{ max: 20, message: '长度不能超过20个字符' }],
|
||||
<Input
|
||||
placeholder="输入任务名称进行检索"
|
||||
/>
|
||||
)}
|
||||
|
||||
{helper(
|
||||
"发布主体名称",
|
||||
"enterpriseNameInput",
|
||||
[{ max: 20, message: '长度不能超过20个字符' }],
|
||||
<Input
|
||||
placeholder="输入发布主体名称进行检索"
|
||||
/>
|
||||
)}
|
||||
|
||||
<div className="center-right-but">
|
||||
|
||||
{helper(
|
||||
"发布时间:",
|
||||
"startTime",
|
||||
[],
|
||||
<DatePicker
|
||||
showTime
|
||||
format={format}
|
||||
placeholder="请选择开始时间"
|
||||
/>
|
||||
)}
|
||||
|
||||
{helper(
|
||||
"",
|
||||
"endTime",
|
||||
[],
|
||||
<DatePicker
|
||||
showTime
|
||||
format={format}
|
||||
placeholder="请选择结束时间"
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
<div className="button-div">
|
||||
{/* <a href="/admin/tasks.xlsx" class="fr edu-default-btn edu-blueback-btn plr30">导出</a> */}
|
||||
<Button className="mr10" type="primary" onClick={onSearch}>搜索</Button>
|
||||
<Button className="mr10" onClick={clearSearch}>清除</Button>
|
||||
<Button className="mr10" type="primary" onClick={downloadFile}>导出</Button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<Form.Item className="inline-form" label="排序">
|
||||
<Select
|
||||
style={{ width: '200px' }}
|
||||
showArrow
|
||||
onChange={changeSortName}
|
||||
defaultValue='createdAt'
|
||||
>
|
||||
<Option key={'createdAt'} >创建时间</Option>
|
||||
<Option key={'publishedAt'} >发布时间</Option>
|
||||
</Select>
|
||||
|
||||
<span className={classNames({ "sort-active": sort === 'Desc', 'sort-icon': true, 'ml10': true })} onClick={() => { changeSort('Desc') }}>
|
||||
<i className="fa fa-long-arrow-down font-16 "></i>
|
||||
</span>
|
||||
<span className={classNames({ "sort-active": sort === 'Asc', 'sort-icon': true })} onClick={() => { changeSort('Asc') }}>
|
||||
<i className="fa fa-long-arrow-up font-16 "></i>
|
||||
</span>
|
||||
|
||||
</Form.Item>
|
||||
|
||||
|
||||
|
||||
|
||||
<div className="center-content">
|
||||
|
||||
<Table
|
||||
loading={loading}
|
||||
rowKey={(row) => row.id}
|
||||
dataSource={taskList}
|
||||
columns={columns}
|
||||
pagination={false}
|
||||
className="mt10"
|
||||
/>
|
||||
{total > 10 &&
|
||||
<Pagination
|
||||
onChange={(page) => { setCurPage(page) }}
|
||||
current={curPage}
|
||||
total={total}
|
||||
/>}
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
)
|
||||
}
|
||||
)
|
|
@ -0,0 +1,66 @@
|
|||
.search-screen {
|
||||
display: flex;
|
||||
flex-flow: row wrap;
|
||||
justify-content: space-between;
|
||||
margin: 1.25rem 0;
|
||||
padding: 1.25rem;
|
||||
background-color: #fff;
|
||||
border-bottom: 1px solid #dedede;
|
||||
|
||||
> .ant-row {
|
||||
min-width: 41%;
|
||||
margin-right: 2rem;
|
||||
.ant-form-item-label {
|
||||
float: left;
|
||||
}
|
||||
.ant-form-item-control-wrapper {
|
||||
overflow: hidden;
|
||||
}
|
||||
}
|
||||
|
||||
.center-right-but {
|
||||
.ant-form-item {
|
||||
margin: 0 1rem 0 0;
|
||||
}
|
||||
.ant-form-item-control-wrapper {
|
||||
display: inline-block;
|
||||
}
|
||||
}
|
||||
.button-div {
|
||||
margin-right: 1.5rem;
|
||||
}
|
||||
}
|
||||
|
||||
.task-manage-all {
|
||||
.column-select {
|
||||
min-width: 100px;
|
||||
.ant-select-selection {
|
||||
background: #fafafa;
|
||||
border: 0;
|
||||
}
|
||||
}
|
||||
.ant-table-thead > tr > th,
|
||||
.ant-table-tbody > tr > td {
|
||||
padding: 1rem 0.2rem;
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
|
||||
.inline-form {
|
||||
margin:-.35rem 0 .5rem 0;
|
||||
text-align: right;
|
||||
.ant-form-item-control-wrapper {
|
||||
display: inline-block;
|
||||
}
|
||||
}
|
||||
|
||||
.sort-icon {
|
||||
color: #ccc;
|
||||
i {
|
||||
padding: 0.1rem 0.25rem;
|
||||
}
|
||||
}
|
||||
|
||||
.sort-active {
|
||||
color: #29bd8b;
|
||||
}
|
|
@ -0,0 +1,136 @@
|
|||
import React from "react";
|
||||
|
||||
import { Route, Switch } from "react-router-dom";
|
||||
import Loadable from "react-loadable";
|
||||
import Loading from "../../Loading";
|
||||
import AdminRouter from "./components/adminRouter";
|
||||
|
||||
|
||||
const TaskManage = Loadable({
|
||||
loader: () => import("./taskManage"),
|
||||
loading: Loading,
|
||||
});
|
||||
|
||||
const PaperManage = Loadable({
|
||||
loader: () => import("./paperManage"),
|
||||
loading: Loading,
|
||||
});
|
||||
|
||||
const PaperComplain = Loadable({
|
||||
loader: () => import("./paperComplain"),
|
||||
loading: Loading,
|
||||
});
|
||||
|
||||
const ProofManage = Loadable({
|
||||
loader: () => import("./proofManage"),
|
||||
loading: Loading,
|
||||
});
|
||||
|
||||
const PublicityComplain = Loadable({
|
||||
loader: () => import("./publicityComplain"),
|
||||
loading: Loading,
|
||||
});
|
||||
|
||||
const AgreementManage = Loadable({
|
||||
loader: () => import("./agreementManage"),
|
||||
loading: Loading,
|
||||
});
|
||||
|
||||
const PayProof = Loadable({
|
||||
loader: () => import("./payProof"),
|
||||
loading: Loading,
|
||||
});
|
||||
|
||||
const TaskAdmin = Loadable({
|
||||
loader: () => import("./taskAdmin"),
|
||||
loading: Loading,
|
||||
});
|
||||
|
||||
const DelayManage = Loadable({
|
||||
loader: () => import("./delayManage"),
|
||||
loading: Loading,
|
||||
});
|
||||
|
||||
const AdminPage = (propsF) => {
|
||||
|
||||
return (
|
||||
<React.Fragment>
|
||||
<AdminRouter {...propsF} />
|
||||
<Switch {...propsF}>
|
||||
{/* 任务管理审核 */}
|
||||
<Route
|
||||
path="/task/taskManage"
|
||||
render={(props) => (
|
||||
<TaskManage {...propsF} {...props} />
|
||||
)}
|
||||
></Route>
|
||||
|
||||
{/* 成果管理审核 */}
|
||||
<Route
|
||||
path="/task/paperManage"
|
||||
render={(props) => (
|
||||
<PaperManage {...propsF} {...props} />
|
||||
)}
|
||||
></Route>
|
||||
|
||||
{/* 成果申诉管理审核 */}
|
||||
<Route
|
||||
path="/task/paperComplain"
|
||||
render={(props) => (
|
||||
<PaperComplain {...propsF} {...props} />
|
||||
)}
|
||||
></Route>
|
||||
|
||||
{/* 公示期成果申诉管理审核 */}
|
||||
<Route
|
||||
path="/task/publicityComplain"
|
||||
render={(props) => (
|
||||
<PublicityComplain {...propsF} {...props} />
|
||||
)}
|
||||
></Route>
|
||||
|
||||
{/* 佐证管理审核 */}
|
||||
<Route
|
||||
path="/task/proofManage"
|
||||
render={(props) => (
|
||||
<ProofManage {...propsF} {...props} />
|
||||
)}
|
||||
></Route>
|
||||
|
||||
{/* 管理员协议审核 */}
|
||||
<Route
|
||||
path="/task/agreementManage"
|
||||
render={(props) => (
|
||||
<AgreementManage {...propsF} {...props} />
|
||||
)}
|
||||
></Route>
|
||||
|
||||
{/* 管理员上传支付凭证 */}
|
||||
<Route
|
||||
path="/task/payProof"
|
||||
render={(props) => (
|
||||
<PayProof {...propsF} {...props} />
|
||||
)}
|
||||
></Route>
|
||||
|
||||
{/* 管理员任务列表 */}
|
||||
<Route
|
||||
path="/task/taskAdmin"
|
||||
render={(props) => (
|
||||
<TaskAdmin {...propsF} {...props} />
|
||||
)}
|
||||
></Route>
|
||||
|
||||
{/* 延期管理 */}
|
||||
<Route
|
||||
path="/task/delayManage"
|
||||
render={(props) => (
|
||||
<DelayManage {...propsF} {...props} />
|
||||
)}
|
||||
></Route>
|
||||
</Switch>
|
||||
</React.Fragment>
|
||||
);
|
||||
}
|
||||
// }
|
||||
export default AdminPage;
|
|
@ -0,0 +1,501 @@
|
|||
import React, { forwardRef, useEffect, useState, useCallback, useMemo } from 'react';
|
||||
import { Form, Input, Button, Modal, Checkbox, Tooltip } from 'antd';
|
||||
import classNames from 'classnames';
|
||||
import moment from 'moment';
|
||||
import { Link } from "react-router-dom";
|
||||
import { formatDuring, getImageUrl } from 'educoder';
|
||||
import Upload from '../../components/Upload';
|
||||
import StatusNav from '../../components/statusNav';
|
||||
import ItemListPaper from '../components/itemListPaper';
|
||||
import ProofModal from '../components/proofModal';
|
||||
import { getTaskDetail, getTaskCategory, getTaskPaper, makePublic, addPaper, getAgreement, agreement, checkAgreement, checkHavePaper } from '../api';
|
||||
import { taskModeIdArr, applyStatusArr, applyStatusAllArr, agreementContent, paperCheckTextArr } from '../static';
|
||||
import { httpUrl } from '../../fetch';
|
||||
import './index.scss';
|
||||
const { TextArea } = Input;
|
||||
|
||||
|
||||
const taskModeNameArr = [];
|
||||
for (const item of taskModeIdArr) {
|
||||
taskModeNameArr[item.dicItemCode] = item.dicItemName;
|
||||
}
|
||||
|
||||
const applyStatusAllNameArr = [];
|
||||
for (const item of applyStatusAllArr) {
|
||||
applyStatusAllNameArr[item.dicItemCode] = item.dicItemName;
|
||||
}
|
||||
|
||||
|
||||
export default Form.create()(
|
||||
forwardRef(({ match, current_user, form, history, showNotification }, ref) => {
|
||||
const id = match.params.taskId;
|
||||
const { getFieldDecorator, validateFields, setFieldsValue } = form;
|
||||
|
||||
const [detailData, setDetailData] = useState({});
|
||||
const [taskCategoryValueArr, setTaskCategoryValueArr] = useState([]);
|
||||
const [fileList, setFileList] = useState(null);
|
||||
|
||||
const [applyModal, setApplyModal] = useState(false);
|
||||
const [applyContent, setApplyContent] = useState({ title: '应征投稿协议内容', content: agreementContent });
|
||||
const [agreementCheckBox, setAgreementCheckBox] = useState(false);
|
||||
const [signAgreement, setSignAgreement] = useState(false);
|
||||
const [isPaper, setIsPaper] = useState(false);
|
||||
const [paperUploadLoading, setPaperUploadLoading] = useState(false);
|
||||
|
||||
const [status, setStatus] = useState('');
|
||||
const [curPage, setCurPage] = useState(1);
|
||||
const [total, setTotal] = useState(0);
|
||||
const [dataList, setDataList] = useState([]);
|
||||
const [loading, setLoading] = useState(false);
|
||||
|
||||
const [reload, setReload] = useState(0);
|
||||
const [relaodChildList, setRelaodChildList] = useState(0);
|
||||
|
||||
const [visibleProofs, setVisibleProofs] = useState(false);
|
||||
|
||||
|
||||
// 获取任务领域配置数据
|
||||
useEffect(() => {
|
||||
getTaskCategory().then(data => {
|
||||
if (data) {
|
||||
const taskCategoryValueArr = [];
|
||||
for (const item of data) {
|
||||
taskCategoryValueArr[item.id] = item.name;
|
||||
}
|
||||
setTaskCategoryValueArr(taskCategoryValueArr);
|
||||
}
|
||||
});
|
||||
}, []);
|
||||
|
||||
// 获取本任务详情
|
||||
useEffect(() => {
|
||||
id && getTaskDetail(id).then(data => {
|
||||
setDetailData(data || {});
|
||||
})
|
||||
}, [id, reload]);
|
||||
|
||||
// 检查用户是否同意协议
|
||||
useEffect(() => {
|
||||
current_user.user_id && id && checkAgreement(id).then(res => {
|
||||
if (res && res.data && res.data.status === 1) {
|
||||
setSignAgreement(true);
|
||||
}
|
||||
})
|
||||
}, [current_user.user_id]);
|
||||
|
||||
// 检查用户是否上传成果
|
||||
useEffect(() => {
|
||||
current_user.user_id && id && checkHavePaper(id).then(res => {
|
||||
if (res && res.data && res.data.status === 1) {
|
||||
setIsPaper(true);
|
||||
}
|
||||
})
|
||||
}, [current_user.user_id]);
|
||||
|
||||
const taskLimit = useMemo(() => {
|
||||
if (current_user.admin) {
|
||||
return true;
|
||||
}
|
||||
if (detailData.user) {
|
||||
return current_user.login === detailData.user.login
|
||||
}
|
||||
}, [detailData, current_user])
|
||||
|
||||
// 获取协议内容
|
||||
useEffect(() => {
|
||||
applyModal && getAgreement().then(res => {
|
||||
if (res && res.data) {
|
||||
setApplyContent({
|
||||
title: res.data.title,
|
||||
content: res.data.content,
|
||||
});
|
||||
}
|
||||
});
|
||||
}, [applyModal]);
|
||||
|
||||
// 获取成果列表
|
||||
useEffect(() => {
|
||||
// 等加载完成果详情再加载成果列表
|
||||
if (detailData.id) {
|
||||
setLoading(true);
|
||||
let params = {
|
||||
taskId: id,
|
||||
orderBy: '',
|
||||
pageSize: 10,
|
||||
curPage,
|
||||
status,
|
||||
}
|
||||
getTaskPaper(params).then(data => {
|
||||
if (data && Array.isArray(data.rows)) {
|
||||
for (const item of data.rows) {
|
||||
item.detail = item.paperDetail ? item.paperDetail.content : "";
|
||||
}
|
||||
data.rows.sort((a, b) => {
|
||||
return b.status - a.status
|
||||
});
|
||||
}
|
||||
setDataList(data.rows || []);
|
||||
setLoading(false);
|
||||
setTotal(data.total);
|
||||
});
|
||||
}
|
||||
}, [id, status, curPage, reload, relaodChildList, detailData]);
|
||||
|
||||
|
||||
// 流程步骤显示,返回剩余时间
|
||||
const process = useCallback((title, status, days) => {
|
||||
let surplusTimetext = '';
|
||||
let surplus;
|
||||
if (detailData.status === status) {
|
||||
switch (status) {
|
||||
case 3:
|
||||
surplus = detailData.collectingDays * 24 * 3600 - (new Date() - new Date(detailData.publishedAt || detailData.createdAt)) / 1000;
|
||||
break;
|
||||
case 4:
|
||||
surplus = detailData.choosingDays * 24 * 3600 - (new Date() - new Date(detailData.collectingCompleteAt)) / 1000;
|
||||
break;
|
||||
case 5:
|
||||
surplus = detailData.makePublicDays * 24 * 3600 - (new Date() - new Date(detailData.makePublicAt)) / 1000;
|
||||
break;
|
||||
case 6:
|
||||
surplus = detailData.signingDays * 24 * 3600 - (new Date() - new Date(detailData.publicityCompleteAt)) / 1000;
|
||||
break;
|
||||
case 7:
|
||||
surplus = detailData.payingDays * 24 * 3600 - (new Date() - new Date(detailData.signingCompleteAt)) / 1000;
|
||||
break;
|
||||
default:
|
||||
surplus = 0;
|
||||
}
|
||||
surplusTimetext = formatDuring(surplus);
|
||||
}
|
||||
return (
|
||||
<li key={title} className={classNames({ 'active': (detailData.currentStatus !== 9 && detailData.currentStatus >= status), 'except-close': (status === 8 && detailData.exceptClosedBoolean) })} >
|
||||
<span>{title}</span>
|
||||
{detailData.status !== status && days ? <p className="color-grey-6 font-12">{days}天</p> : ''}
|
||||
|
||||
{/* 因为有时只延期几秒或者几分钟时后端没有返回延期,所以这里加一个判断 */}
|
||||
{detailData.status === status && days ? <p className="color-grey-6 font-12">{surplus < 0 ? ('延期' + surplusTimetext) : ('剩余' + surplusTimetext)}</p> : ''}
|
||||
</li>
|
||||
)
|
||||
}, [detailData]);
|
||||
|
||||
|
||||
function downFile(item) {
|
||||
let url = httpUrl + '/busiAttachments/download/' + item.id;
|
||||
window.open(url);
|
||||
}
|
||||
|
||||
const helper = useCallback(
|
||||
(label, name, rules, widget) => (
|
||||
<Form.Item label={label}>
|
||||
{getFieldDecorator(name, { rules, validateFirst: true })(widget)}
|
||||
</Form.Item>
|
||||
),
|
||||
[]
|
||||
);
|
||||
|
||||
// 上传附件后得到的文件数组
|
||||
function UploadFunc(fileList) {
|
||||
setFileList(fileList);
|
||||
let files = [];
|
||||
for (const item of fileList) {
|
||||
files.push(item.id || (item.response.data && item.response.data.id));
|
||||
}
|
||||
setFieldsValue({
|
||||
files: files.join()
|
||||
});
|
||||
}
|
||||
|
||||
// 提交成果
|
||||
function saveItem() {
|
||||
validateFields((error, values) => {
|
||||
if (!error) {
|
||||
let params = {
|
||||
...values,
|
||||
taskId: id
|
||||
}
|
||||
setPaperUploadLoading(true);
|
||||
addPaper(params).then((res) => {
|
||||
setPaperUploadLoading(false);
|
||||
if (res.message === 'success') {
|
||||
showNotification('成果提交成功');
|
||||
setIsPaper(true);
|
||||
setReload(Math.random());
|
||||
setCurPage(1);
|
||||
}
|
||||
});
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
function changeOptionId(option) {
|
||||
setStatus(option.dicItemCode.toString() || '');
|
||||
setCurPage(1);
|
||||
}
|
||||
|
||||
// 签订协议
|
||||
function agreementSign() {
|
||||
if (!agreementCheckBox) {
|
||||
showNotification("请阅读并同意本电子协议内容!");
|
||||
return;
|
||||
}
|
||||
agreement(id).then(res => {
|
||||
if (res.message === 'success') {
|
||||
Modal.success({
|
||||
content: '签订成功!',
|
||||
});
|
||||
setApplyModal(false);
|
||||
setSignAgreement(true);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function showUser() {
|
||||
if (dataList.length === 0) {
|
||||
Modal.info({
|
||||
title: '提示',
|
||||
content: '暂无应征者提交',
|
||||
});
|
||||
} else {
|
||||
Modal.confirm({
|
||||
title: '提示',
|
||||
content: '确认公示应征者信息',
|
||||
onOk: () => {
|
||||
makePublic(id).then(res => {
|
||||
if (res && res.message === 'success') {
|
||||
setReload(Math.random());
|
||||
} else {
|
||||
showNotification('操作失败');
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
const reloadList = useCallback(() => {
|
||||
setRelaodChildList(Math.random());
|
||||
});
|
||||
|
||||
const reloadDetail = useCallback(() => {
|
||||
setReload(Math.random());
|
||||
}, []);
|
||||
|
||||
const signContent = useCallback(() => {
|
||||
if (signAgreement && isPaper) {
|
||||
let checkStatustext = paperCheckTextArr[0];
|
||||
for (const item of dataList) {
|
||||
if (item.user.login === current_user.login) {
|
||||
checkStatustext = paperCheckTextArr[item.checkStatus];
|
||||
}
|
||||
}
|
||||
return <div className="edu-back-white padding30 mt20 font-16 color-orange text-center">
|
||||
{checkStatustext}
|
||||
</div>
|
||||
} else if (signAgreement) {
|
||||
return (<div className="edu-back-white padding30 mt20">
|
||||
<div className="font-16 font-bd">我要应征投稿:</div>
|
||||
{helper(
|
||||
"",
|
||||
"content",
|
||||
[{ required: true, message: "请根据具体要求提交有效的稿件,才能打动需求方哟!成果描述不能超过250字哟!" },
|
||||
{ max: 250, message: '长度不能超过250个字符' }],
|
||||
<TextArea
|
||||
placeholder="请根据具体要求提交有效的稿件,才能打动需求方哟!"
|
||||
autoSize={{ minRows: 6 }}
|
||||
className="applyText"
|
||||
/>
|
||||
)}
|
||||
<Form.Item >
|
||||
<Upload
|
||||
className="commentStyle"
|
||||
load={UploadFunc}
|
||||
size={50}
|
||||
showNotification={showNotification}
|
||||
actionUrl={httpUrl}
|
||||
fileList={fileList}
|
||||
/>
|
||||
{getFieldDecorator('files', {
|
||||
validateFirst: true
|
||||
})(<Input style={{ display: 'none' }} />)}
|
||||
</Form.Item>
|
||||
<Button className="mr20" type={"primary"} loading={paperUploadLoading} onClick={() => { saveItem() }}>提交</Button>
|
||||
</div>
|
||||
)
|
||||
} else if (detailData.user && (current_user.login !== detailData.user.login)) {
|
||||
return <div className="edu-back-white padding30 mt20 text-center">
|
||||
<Button className="mr20" type={"primary"} onClick={() => { setApplyModal(true) }}>我要应征投稿</Button>
|
||||
</div>
|
||||
}
|
||||
}, [signAgreement, isPaper, current_user, detailData, dataList]);
|
||||
|
||||
function goUser(login) {
|
||||
window.location.href = `/users/${login}`;
|
||||
}
|
||||
|
||||
function goUserProfiles() {
|
||||
window.open(`/users/${current_user.login}/profiles`);
|
||||
}
|
||||
|
||||
function backPublicEnd(makePublicAt, makePublicDays) {
|
||||
return moment(new Date(makePublicAt).getTime() + makePublicDays * 24 * 3600 * 1000).format('YYYY-MM-DD HH:mm:ss');
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="centerbox task-detail">
|
||||
<div className="head-navigation">
|
||||
<Link to="/task">创客空间 ></Link>
|
||||
<Link to="/task">任务大厅 ></Link>
|
||||
任务编号:{detailData.number}
|
||||
</div>
|
||||
|
||||
<div className="edu-back-white padding30">
|
||||
<div className="df mb20">
|
||||
<div className="mr30">
|
||||
<a onClick={() => { goUser(detailData.user.login) }} alt="用户头像">
|
||||
<img alt="头像加载失败" className="bor-radius-all" height="60" src={detailData.user && getImageUrl(detailData.user.logo)} width="60" />
|
||||
</a>
|
||||
<p className="lineh-20 mt10 edu-txt-center">{detailData && detailData.user && (detailData.user.nickname || detailData.user.login)}</p>
|
||||
</div>
|
||||
<div className="flex1">
|
||||
<ul className="clearfix mb20">
|
||||
<li className="font-18 mr20 font-bd task-hide lineh-20 fl" style={{ maxWidth: "800px" }}>{detailData.name}</li>
|
||||
<span className="task_tag">{taskCategoryValueArr[detailData.categoryId]}</span>
|
||||
</ul>
|
||||
<div className="clearfix">
|
||||
<ul className="fl">
|
||||
<li><span className="mr10 color-grey9">悬赏模式:</span><span className="color-grey3">{taskModeNameArr[detailData.taskModeId]}</span></li>
|
||||
<li><span className="mr10 color-grey9">任务编号:</span><span className="color-grey3">{detailData.number}</span></li>
|
||||
<li><span className="mr10 color-grey9">发布时间:</span><span className="color-grey3">{detailData.publishedAt || detailData.createdAt}</span></li>
|
||||
</ul>
|
||||
<ul className="fr edu-txt-right">
|
||||
<li className="color-orange font-bd lineh-30"><span className="font-18">¥</span><span className="font-28">{detailData.bounty}</span></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{
|
||||
detailData.status === 5 &&
|
||||
<p className="color-orange mb10 task_tip fl">
|
||||
<i className="iconfont icon-laba fl mr5 color-orange font-15"></i>该任务已选稿,作品公示期为{detailData.makePublicDays}天接受监督和举报,于{backPublicEnd(detailData.makePublicAt, detailData.makePublicDays)}公示期满后签订协议
|
||||
</p>}
|
||||
|
||||
<div className="clearfix tasks_status_father mb30" style={{ background: "#FAFAFA" }}>
|
||||
|
||||
<ul className="tasks_status clearfix">
|
||||
<li className="active"><span>发布任务</span></li>
|
||||
|
||||
{process('成果提交', 3, detailData.collectingDays)}
|
||||
|
||||
{process('成果评选', 4, detailData.choosingDays)}
|
||||
|
||||
{process('结果公示', 5, detailData.makePublicDays)}
|
||||
|
||||
{process('任务协议签订', 6, detailData.signingDays)}
|
||||
|
||||
{process('支付', 7, detailData.payingDays)}
|
||||
|
||||
{
|
||||
detailData.exceptClosedBoolean ? process('任务关闭', 8) : process('任务完成', 8)
|
||||
}
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div className="font-16 font-bd">任务详情:</div>
|
||||
|
||||
{/* 富文本内容插入 */}
|
||||
<div className="content-text editor-w-text" dangerouslySetInnerHTML={{ __html: detailData.description }}></div>
|
||||
|
||||
{detailData.uploadFileNumbers && <React.Fragment>
|
||||
<div className="font-16 font-bd">任务文件:</div>
|
||||
{
|
||||
detailData.tasksAttachments && detailData.tasksAttachments.map(item => {
|
||||
return <div className="file-list-box" key={item.id}>
|
||||
<a onClick={() => { downFile(item) }}><i className="iconfont icon-fujian color-green font-14 mr3"></i>
|
||||
{item.fileName} </a>
|
||||
<span className="ml10 color-grey-9">({item.fileSizeString})</span>
|
||||
</div>
|
||||
})
|
||||
}
|
||||
</React.Fragment>
|
||||
}
|
||||
|
||||
<div className="font-16 font-bd mt10">知识产权说明:</div>
|
||||
<p className="color-grey-6 lineh-20 padding10-15 mb10">
|
||||
1、参赛作品一经采用,其所有权、修改权和使用权均归主办方所有,设计者不得再在任何地方使用;<br />
|
||||
2、应征者所提交的作品必须由应征者本人创作或参与创作,应征者应确认其作品的原创性,主办单位不承担因作品侵犯他人(或单位)的权利而产生的法律责任,其法律责任由应征者本人承担。
|
||||
</p>
|
||||
<div className="font-16 font-bd">交稿声明:</div>
|
||||
<p className="color-grey-6 lineh-20 padding10-15 mb10">
|
||||
应征者提交的稿件必须是设计作品,广告等无效交稿一律不采用!
|
||||
</p>
|
||||
</div>
|
||||
|
||||
{!current_user.enterpriseCertification && <div className="edu-back-white padding30 mt20 font-16 text-center mb50">
|
||||
<a onClick={goUserProfiles} className="color-blue_4C">请先完善主体信息</a>
|
||||
</div>}
|
||||
|
||||
{current_user.enterpriseCertification && detailData.status === 3 && (!detailData.exceptClosedBoolean) && signContent()}
|
||||
|
||||
<div className="applyList edu-back-white padding30 mt20">
|
||||
<div className="font-16 font-bd">交稿({dataList.length})
|
||||
{!detailData.showUserStatus && <Tooltip placement="top" title={"不公示应征者姓名"}>
|
||||
<i data-tip-down="不公示应征者姓名" className="iconfont icon-yincang1 color-grey9 font-20"></i>
|
||||
</Tooltip>}
|
||||
{detailData.status === 4 && dataList.length && (!detailData.isProofBoolean) && detailData.user && (current_user.admin || current_user.login === detailData.user.login) ?
|
||||
<a className="line_1 color-blue fr ml20" onClick={() => { setVisibleProofs(true) }}>上传佐证材料</a> : ''}
|
||||
{dataList.length > 0 && taskLimit && <a className="line_1 color-blue fr ml20" onClick={() => { window.open(`${httpUrl}/api/paper/papers/download/${id}`) }}>一键导出成果物 >></a>}
|
||||
{(!detailData.showUserStatus) && taskLimit && <a className="fr color-orange ml20" onClick={showUser}>应征者名单公示 >></a>}
|
||||
</div>
|
||||
<StatusNav
|
||||
key={'applyStatus'}
|
||||
type={'applyStatus'}
|
||||
options={applyStatusArr}
|
||||
changeOptionId={changeOptionId}
|
||||
/>
|
||||
|
||||
<ItemListPaper
|
||||
current_user={current_user}
|
||||
list={dataList}
|
||||
itemClick={dataList}
|
||||
curPage={curPage}
|
||||
total={total}
|
||||
changePage={(page) => { setCurPage(page) }}
|
||||
loading={loading}
|
||||
applyStatusAllNameArr={applyStatusAllNameArr}
|
||||
reloadList={reloadList}
|
||||
showNotification={showNotification}
|
||||
detailStatus={detailData.status}
|
||||
agreementSigning={detailData.agreementSigning}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<Modal
|
||||
title={applyContent.title}
|
||||
visible={applyModal}
|
||||
onOk={agreementSign}
|
||||
onCancel={() => { setApplyModal(false) }}
|
||||
className="form-edit-modal"
|
||||
width='60vw'
|
||||
>
|
||||
<div className="new_li markdown-body editormd-html-preview agreement-content" dangerouslySetInnerHTML={{ __html: applyContent.content }}></div>
|
||||
<div className="mt5 mb10 pl20 pr20 ml15">
|
||||
<Checkbox checked={agreementCheckBox} onChange={(e) => { setAgreementCheckBox(e.target.checked) }}>我已阅读并同意本电子协议内容</Checkbox>
|
||||
</div>
|
||||
</Modal>
|
||||
|
||||
{
|
||||
visibleProofs && <ProofModal
|
||||
taskId={id}
|
||||
taskModeId={detailData.taskModeId}
|
||||
visible={visibleProofs}
|
||||
changeVisible={setVisibleProofs}
|
||||
showNotification={showNotification}
|
||||
reloadList={reloadDetail}
|
||||
/>}
|
||||
</div>
|
||||
|
||||
)
|
||||
})
|
||||
)
|
|
@ -0,0 +1,164 @@
|
|||
.centerbox {
|
||||
position: relative;
|
||||
margin-top: 40px;
|
||||
.head-navigation {
|
||||
span {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
&:hover {
|
||||
color: #409eff;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.head-navigation {
|
||||
position: absolute;
|
||||
top: -2.3em;
|
||||
}
|
||||
|
||||
.task_tag {
|
||||
padding: 0px 12px;
|
||||
background: #f1f8ff;
|
||||
border-radius: 4px;
|
||||
float: left;
|
||||
color: #459be6;
|
||||
height: 1.25rem;
|
||||
line-height: 1.25rem;
|
||||
}
|
||||
|
||||
.task_tip {
|
||||
padding: 0px 20px;
|
||||
border-radius: 15px;
|
||||
line-height: 30px;
|
||||
background: #FFF8F5;
|
||||
}
|
||||
|
||||
|
||||
.tasks_status{
|
||||
display: flex;
|
||||
justify-content: space-around;
|
||||
padding: 1rem;
|
||||
}
|
||||
|
||||
.tasks_status li {
|
||||
position: relative;
|
||||
background: #ebebeb;
|
||||
width: 12.4%;
|
||||
height: 35px;
|
||||
line-height: 35px;
|
||||
color: #05101a;
|
||||
text-align: center;
|
||||
margin-bottom: 32px;
|
||||
}
|
||||
.tasks_status li:not(:last-child){
|
||||
margin-right: 20px;
|
||||
}
|
||||
|
||||
.tasks_status li.active {
|
||||
background: #4cacff;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.tasks_status li:not(:first-child):before {
|
||||
width: 0;
|
||||
height: 0;
|
||||
border-width: 17px;
|
||||
content: "";
|
||||
position: absolute;
|
||||
left: 0px;
|
||||
border-style: solid;
|
||||
top: 0px;
|
||||
border-color: transparent transparent #fafafa transparent;
|
||||
transform: rotate(90deg);
|
||||
}
|
||||
|
||||
.tasks_status li:not(:last-child):after {
|
||||
width: 0;
|
||||
height: 0;
|
||||
border-width: 17px;
|
||||
content: "";
|
||||
position: absolute;
|
||||
right: -34px;
|
||||
border-style: solid;
|
||||
top: 0px;
|
||||
border-color: transparent transparent #ebebeb transparent;
|
||||
transform: rotate(90deg);
|
||||
}
|
||||
|
||||
.tasks_status li.active:after {
|
||||
border-color: transparent transparent #4cacff transparent;
|
||||
transform: rotate(90deg);
|
||||
}
|
||||
|
||||
.file-list-box {
|
||||
padding: 0 1.25rem;
|
||||
}
|
||||
|
||||
.content-text {
|
||||
padding: 1.25rem;
|
||||
}
|
||||
|
||||
.content-download {
|
||||
color: #409eff;
|
||||
}
|
||||
|
||||
|
||||
|
||||
.applyText {
|
||||
margin-top: 0.5rem;
|
||||
border-radius: 3px;
|
||||
font-family: "微软雅黑", "宋体";
|
||||
font-size: 14px;
|
||||
line-height: 1.9;
|
||||
border: 1px solid #eaeaea;
|
||||
background: #ffffff;
|
||||
color: #05101a;
|
||||
resize: none;
|
||||
}
|
||||
|
||||
.applyList {
|
||||
table {
|
||||
width: 100%;
|
||||
border: 1px solid #eee;
|
||||
border-bottom: none;
|
||||
background: #fff;
|
||||
color: #888;
|
||||
cursor: default;
|
||||
}
|
||||
.ant-table-body tbody tr {
|
||||
height: 90px;
|
||||
}
|
||||
.ant-table-thead
|
||||
> tr.ant-table-row-hover:not(.ant-table-expanded-row):not(.ant-table-row-selected)
|
||||
> td,
|
||||
.ant-table-tbody
|
||||
> tr.ant-table-row-hover:not(.ant-table-expanded-row):not(.ant-table-row-selected)
|
||||
> td,
|
||||
.ant-table-thead
|
||||
> tr:hover:not(.ant-table-expanded-row):not(.ant-table-row-selected)
|
||||
> td,
|
||||
.ant-table-tbody
|
||||
> tr:hover:not(.ant-table-expanded-row):not(.ant-table-row-selected)
|
||||
> td {
|
||||
background: #fff;
|
||||
}
|
||||
}
|
||||
|
||||
.task-detail{
|
||||
.ant-btn-primary{
|
||||
background-color:#409eff;
|
||||
border-color: #409eff;
|
||||
}
|
||||
}
|
||||
|
||||
.agreement-content{
|
||||
box-sizing: border-box;
|
||||
padding: 0px 20px;
|
||||
height: 50vh;
|
||||
overflow-y: scroll;
|
||||
}
|
||||
|
||||
li.except-close{
|
||||
background: #fa6400;
|
||||
color: #fff;
|
||||
}
|
|
@ -0,0 +1,543 @@
|
|||
import React, { forwardRef, useCallback, useEffect, useState } from 'react';
|
||||
import { Form, Radio, Input, InputNumber, Icon, Button, Modal } from 'antd';
|
||||
import classNames from 'classnames';
|
||||
import moment from 'moment';
|
||||
import ReactWEditor from 'wangeditor-for-react';
|
||||
import { Link } from "react-router-dom";
|
||||
import Upload from '../../components/Upload';
|
||||
import { httpUrl } from '../../fetch';
|
||||
import { getTaskDetail, addTask, updateTask, getTaskCategory, getCompanyInfo } from '../api';
|
||||
import { formItemLayout, formModalLayout } from '../static';
|
||||
import { editorConfig } from '../../components/config';
|
||||
import './index.scss';
|
||||
|
||||
const { info } = Modal;
|
||||
|
||||
|
||||
function getSomeDayAfter(nDay) {
|
||||
return moment(new Date().setDate(new Date().getDate() + nDay)).format('YYYY-MM-DD HH:mm');
|
||||
}
|
||||
|
||||
export default Form.create()(forwardRef(({ current_user, form, showNotification, match, history }, ref) => {
|
||||
|
||||
console.log(current_user);
|
||||
|
||||
const [taskCategoryArr, setTaskCategoryArr] = useState([]);
|
||||
const [fileList, setFileList] = useState(null);
|
||||
|
||||
const [publishMode, setPublishMode] = useState('0');
|
||||
const [categoryId, setCategoryId] = useState('7');
|
||||
const [descriptionHtml, setDescriptionHtml] = useState('');
|
||||
const [enterpriseName, setEnterpriseName] = useState('');
|
||||
const [displayTime, setDisplayTime] = useState(() => {
|
||||
return {
|
||||
collectingTime: getSomeDayAfter(30),
|
||||
choosingTime: getSomeDayAfter(30 + 15),
|
||||
makePublicTime: getSomeDayAfter(30 + 15 + 7),
|
||||
signingTime: getSomeDayAfter(30 + 15 + 7 + 15),
|
||||
payingTime: getSomeDayAfter(30 + 15 + 7 + 15 + 15)
|
||||
}
|
||||
});
|
||||
const [visible, setVisible] = useState(false);
|
||||
const [num, setNum] = useState(0) // 倒计时
|
||||
const [isSend, setIsSend] = useState(false) // 是否发送验证码
|
||||
|
||||
const id = match.params.taskId;
|
||||
const { getFieldDecorator, validateFields, setFieldsValue, getFieldsValue } = form;
|
||||
|
||||
// 根据是否传id判断是新增还是修改
|
||||
useEffect(() => {
|
||||
if (id) {
|
||||
getTaskDetail(id).then(data => {
|
||||
let formValue = {
|
||||
name: data.name,
|
||||
contactName: data.contactName,
|
||||
contactPhone: data.contactPhone,
|
||||
uploadFileNumbers: data.uploadFileNumbers,
|
||||
|
||||
bounty: data.bounty,
|
||||
taskModeId: data.taskModeId,
|
||||
collectionMode: data.collectionMode,
|
||||
publishMode: data.publishMode + '',
|
||||
|
||||
description: data.description,
|
||||
collectingDays: data.collectingDays,
|
||||
choosingDays: data.choosingDays,
|
||||
makePublicDays: data.makePublicDays,
|
||||
signingDays: data.signingDays,
|
||||
payingDays: data.payingDays,
|
||||
};
|
||||
if (data.tasksAttachments && data.tasksAttachments.length) {
|
||||
for (const item of data.tasksAttachments) {
|
||||
item.name = item.fileName;
|
||||
item.size = item.fileSize;
|
||||
item.uid = "rc-upload" + item.id
|
||||
}
|
||||
setFileList(data.tasksAttachments);
|
||||
}
|
||||
setFieldsValue(formValue);
|
||||
setEnterpriseName(data.enterpriseName);
|
||||
setCategoryId(data.categoryId);
|
||||
setDescriptionHtml(data.description);
|
||||
setPublishMode(data.publishMode + '');
|
||||
|
||||
let collectingTime = getSomeDayAfter(data.collectingDays);
|
||||
let choosingTime = getSomeDayAfter(data.collectingDays + data.choosingDays);
|
||||
let makePublicTime = getSomeDayAfter(data.collectingDays + data.choosingDays + data.makePublicDays);
|
||||
let signingTime = getSomeDayAfter(data.collectingDays + data.choosingDays + data.makePublicDays + data.signingDays);
|
||||
let payingTime = getSomeDayAfter(data.collectingDays + data.choosingDays + data.makePublicDays + data.signingDays + data.payingDays);
|
||||
setDisplayTime({ collectingTime, choosingTime, makePublicTime, signingTime, payingTime });
|
||||
});
|
||||
} else {
|
||||
let formValue = {
|
||||
contactName: current_user.username || current_user.login,
|
||||
contactPhone: current_user.contactPhone,
|
||||
taskModeId: 1,
|
||||
collectionMode: 1,
|
||||
publishMode: '0',
|
||||
collectingDays: 30,
|
||||
choosingDays: 15,
|
||||
makePublicDays: 7,
|
||||
signingDays: 15,
|
||||
payingDays: 15,
|
||||
};
|
||||
setFieldsValue(formValue);
|
||||
setCategoryId('7');
|
||||
}
|
||||
}, [id]);
|
||||
|
||||
useEffect(() => {
|
||||
getCompanyInfo().then(res => {
|
||||
if (res && res.message === 'success') {
|
||||
setEnterpriseName(res.data.enterpriseName);
|
||||
setFieldsValue({
|
||||
contactPhone:res.data.phone,
|
||||
contactName:res.data.userName,
|
||||
})
|
||||
}else{
|
||||
showNotification(res.message);
|
||||
}
|
||||
});
|
||||
},[]);
|
||||
|
||||
useEffect(() => {
|
||||
getTaskCategory().then(data => {
|
||||
if (data) {
|
||||
for (const item of data) {
|
||||
item.dicItemCode = item.id;
|
||||
item.dicItemName = item.name;
|
||||
}
|
||||
setTaskCategoryArr(data);
|
||||
}
|
||||
});
|
||||
}, []);
|
||||
|
||||
/** 倒计时显示*/
|
||||
useEffect(() => {
|
||||
let timer = 0;
|
||||
if (isSend && num !== 0) {
|
||||
timer = setInterval(() => {
|
||||
setNum(n => {
|
||||
if (n === 1) {
|
||||
setIsSend(false)
|
||||
clearInterval(timer)
|
||||
}
|
||||
return n - 1;
|
||||
});
|
||||
}, 1000);
|
||||
}
|
||||
return () => {
|
||||
// 组件销毁时,清除定时器
|
||||
clearInterval(timer)
|
||||
};
|
||||
}, [isSend]);
|
||||
|
||||
function getCode() {
|
||||
setIsSend(true);
|
||||
setNum(60);
|
||||
}
|
||||
|
||||
// 上传附件后得到的文件数组
|
||||
function UploadFunc(fileList) {
|
||||
setFileList(fileList);
|
||||
let files = [];
|
||||
for (const item of fileList) {
|
||||
if (item) {
|
||||
let itemId = (item.response && item.response.data && item.response.data.id) || item.id;
|
||||
itemId && files.push(itemId);
|
||||
}
|
||||
}
|
||||
setFieldsValue({
|
||||
uploadFileNumbers: files.join()
|
||||
});
|
||||
}
|
||||
|
||||
const helper = useCallback(
|
||||
(label, name, rules, widget, initialValue, rightComponent) => (
|
||||
<Form.Item label={label}>
|
||||
{getFieldDecorator(name, { rules, initialValue, validateFirst: true, })(widget)}
|
||||
{rightComponent}
|
||||
</Form.Item>
|
||||
), []);
|
||||
|
||||
const helperNoLabel = useCallback(
|
||||
(title, name, rules, widget, displayTime) => (
|
||||
<div className="timing_task" key={name}>
|
||||
<div className="mbt10 color-grey-9 lineh-35"><span className="inline-span">{title}</span></div>
|
||||
<Form.Item className="no-label">
|
||||
{getFieldDecorator(name, { rules, validateFirst: true, })(widget)}
|
||||
</Form.Item>
|
||||
<span className="days-word color-grey-9 ">天</span>
|
||||
{publishMode == '0' && <p className="display-time">{displayTime}</p>}
|
||||
</div>
|
||||
), [publishMode]);
|
||||
|
||||
// 新增或者修改后的处理函数
|
||||
const publishDeal = useCallback((status, publishMode, res) => {
|
||||
if (res && res.data) {
|
||||
showNotification("任务保存成功!");
|
||||
if (!status) {
|
||||
history.push("/task/myTask?published=false")
|
||||
} else if (publishMode == '1') {
|
||||
info({
|
||||
title: '提示',
|
||||
content: <div>
|
||||
<h4>发布申请已提交,请等待管理员的审核</h4>
|
||||
<p>我们将在1-2个工作日内完成审核</p>
|
||||
</div>,
|
||||
onOk() {
|
||||
history.push("/task/myTask?published=false");
|
||||
},
|
||||
});
|
||||
} else {
|
||||
history.push("/task/myTask");
|
||||
}
|
||||
} else {
|
||||
showNotification(res.message);
|
||||
}
|
||||
}, []);
|
||||
|
||||
// 保存
|
||||
function saveItem(status) {
|
||||
validateFields((error, values) => {
|
||||
if (!error) {
|
||||
let params = {
|
||||
...values,
|
||||
status,
|
||||
enterpriseName: enterpriseName,
|
||||
categoryId,
|
||||
};
|
||||
let dateSum = params.collectingDays + params.choosingDays + params.makePublicDays + params.signingDays + params.payingDays;
|
||||
if (dateSum > 180) {
|
||||
showNotification("任务天数总和不得超过180天!");
|
||||
return;
|
||||
}
|
||||
if (id) {
|
||||
// 编辑
|
||||
params.id = id;
|
||||
updateTask(params).then(res => {
|
||||
publishDeal(status, publishMode, res);
|
||||
});
|
||||
} else {
|
||||
// 新增
|
||||
addTask(params).then(res => {
|
||||
publishDeal(status, publishMode, res);
|
||||
});
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
function changeDate(v, field) {
|
||||
if (typeof v !== 'number' || v < 0) {
|
||||
return;
|
||||
}
|
||||
let values = getFieldsValue();
|
||||
values[field] = v;
|
||||
let collectingTime = getSomeDayAfter(values.collectingDays);
|
||||
let choosingTime = getSomeDayAfter(values.collectingDays + values.choosingDays);
|
||||
let makePublicTime = getSomeDayAfter(values.collectingDays + values.choosingDays + values.makePublicDays);
|
||||
let signingTime = getSomeDayAfter(values.collectingDays + values.choosingDays + values.makePublicDays + values.signingDays);
|
||||
let payingTime = getSomeDayAfter(values.collectingDays + values.choosingDays + values.makePublicDays + values.signingDays + values.payingDays);
|
||||
|
||||
setDisplayTime({ collectingTime, choosingTime, makePublicTime, signingTime, payingTime });
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="centerbox">
|
||||
<div className="head-navigation">
|
||||
<Link to="/task">创客空间 ></Link>
|
||||
<Link to="/task">任务大厅 ></Link>
|
||||
<span >发布任务 </span>
|
||||
</div>
|
||||
<p className="font-18 font-bd mb15">任务提交</p>
|
||||
|
||||
<div className="edu-back-white mb30">
|
||||
<div className="padding30 bor-bottom-greyE">
|
||||
<p className="partTitle">联系方式<span className="color-red font-14">(*必填)</span></p>
|
||||
|
||||
<Form {...formItemLayout}>
|
||||
<Form.Item label='主体信息:'>
|
||||
{enterpriseName}
|
||||
</Form.Item>
|
||||
|
||||
{helper(
|
||||
"联系人:",
|
||||
"contactName",
|
||||
[{ required: true, message: "请输入联系人" }],
|
||||
<Input
|
||||
className="contact-input"
|
||||
placeholder="请输入联系人"
|
||||
/>
|
||||
)}
|
||||
|
||||
{helper(
|
||||
"联系电话:",
|
||||
"contactPhone",
|
||||
[{ required: true, message: "请输入联系电话" }],
|
||||
<Input
|
||||
className="contact-input"
|
||||
placeholder="请输入联系电话"
|
||||
disabled
|
||||
/>, '', <Icon className="editPhone" type="edit" onClick={() => { setVisible(true) }} />
|
||||
)}
|
||||
|
||||
</Form>
|
||||
</div>
|
||||
|
||||
<div className="padding30 bor-bottom-greyE">
|
||||
<p className="partTitle">任务内容<span className="color-red font-14">(*必填)</span>
|
||||
<span>
|
||||
<a href="http://117.50.100.12:8000/attachments/download/523/%E5%88%9B%E5%AE%A2%E4%BB%BB%E5%8A%A1%E5%88%97%E8%A1%A8_2019-07-26_20-53.xlsx" className="icon icon-attachment font-13 color-blue" length="32" target="_blank">创客任务列表_2019-07-26_20-53.xlsx</a>
|
||||
</span><span className="color-grey-9 ml5 font-12 ">点击下载示例模版</span>
|
||||
</p>
|
||||
|
||||
<div className="pl15 task-edit-content">
|
||||
<p className="color-grey3 mb20">选择任务所在领域</p>
|
||||
|
||||
<div className="mb20 clearfix areaDiv" >
|
||||
{
|
||||
taskCategoryArr.map(item => {
|
||||
return <button
|
||||
className={classNames({ "choose-button": true, "active": item.dicItemCode == categoryId })}
|
||||
key={item.dicItemCode}
|
||||
onClick={() => { setCategoryId(item.dicItemCode) }}
|
||||
>{item.dicItemName}</button>
|
||||
})
|
||||
}
|
||||
</div>
|
||||
|
||||
{helper(
|
||||
"",
|
||||
"name",
|
||||
[{ required: true, message: "请用一句话概括您要做什么?比如:开源项目网站开发,最大限制60个字符" },
|
||||
{ max: 60, message: '长度不能超过60个字符' }],
|
||||
<Input
|
||||
placeholder="请用一句话概括您要做什么?比如:开源项目网站开发,最大限制60个字符"
|
||||
/>
|
||||
)}
|
||||
|
||||
<Form.Item >
|
||||
{(!id || (id && descriptionHtml)) && <ReactWEditor
|
||||
defaultValue={descriptionHtml}
|
||||
config={{
|
||||
...editorConfig,
|
||||
placeholder: "把您的任务内容补充详细一些吧,越清晰具体,任务完成质量越高哟~",
|
||||
}}
|
||||
onChange={(html) => { setFieldsValue({ description: html }) }}
|
||||
/>}
|
||||
{/* 用一个隐藏的input实现上必填校验 */}
|
||||
{getFieldDecorator('description', {
|
||||
rules: [{ required: true, message: "把您的任务内容补充详细一些吧,越清晰具体,任务完成质量越高哟~" }],
|
||||
validateFirst: true
|
||||
})(<Input style={{ display: 'none' }} />)}
|
||||
</Form.Item>
|
||||
|
||||
<p className="color-grey3 mb10 mt20">
|
||||
<span className="color-orange mr2 ">*</span>
|
||||
注:任务发布之后,将会公开展示在交易中心。不要把与项目、客户相关等隐私信息,以及QQ号、微信号、电话号码等联系方式填写在任务中。
|
||||
</p>
|
||||
|
||||
<Form.Item >
|
||||
<Upload
|
||||
className="commentStyle"
|
||||
load={UploadFunc}
|
||||
size={50}
|
||||
showNotification={showNotification}
|
||||
actionUrl={httpUrl}
|
||||
fileList={fileList}
|
||||
/>
|
||||
{getFieldDecorator('uploadFileNumbers', {
|
||||
validateFirst: true
|
||||
})(<Input style={{ display: 'none' }} />)}
|
||||
</Form.Item>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="padding30 ">
|
||||
<p className="partTitle">选择任务周期、价格和发布模式<span className="color-red font-14">(*必填)</span></p>
|
||||
<Form className="gray-form" {...formItemLayout}>
|
||||
{helper(
|
||||
"赏金:",
|
||||
"bounty",
|
||||
[{ required: true, message: "您打算支付多少赏金呢" }],
|
||||
<InputNumber
|
||||
min={1}
|
||||
max={99999999}
|
||||
className="number-input"
|
||||
placeholder="您打算支付多少赏金呢"
|
||||
formatter={value => `${value}¥`}
|
||||
/>
|
||||
)}
|
||||
|
||||
{helper(
|
||||
"悬赏模式:",
|
||||
"taskModeId",
|
||||
[{ required: true, message: "请选择悬赏模式" }],
|
||||
<Radio.Group>
|
||||
<Radio value={1}>单人悬赏,只设置一个中标者</Radio>
|
||||
<Radio value={2}>多人悬赏,设置多分中标分享赏金</Radio>
|
||||
<Radio value={3}>计件悬赏,合格一稿,支付一稿(稿件数量≥2件)</Radio>
|
||||
</Radio.Group>
|
||||
)}
|
||||
|
||||
{helper(
|
||||
"征集方式:",
|
||||
"collectionMode",
|
||||
[{ required: true, message: "请选择征集方式" }],
|
||||
<Radio.Group>
|
||||
<Radio value={1}>创意征集,应征者以开放讨论的形式参与</Radio>
|
||||
<Radio value={0}>物化成果征集,应征者以各自提交成果物的形式参与</Radio>
|
||||
</Radio.Group>
|
||||
)}
|
||||
|
||||
{helper(
|
||||
"发布方式:",
|
||||
"publishMode",
|
||||
[{ required: true, message: "请选择发布方式" }],
|
||||
<Radio.Group onChange={(e) => { setPublishMode(e.target.value) }}>
|
||||
<Radio value={'0'}>自主提交方式,由发布方自行支付赏金,一键自助发布</Radio>
|
||||
<Radio value={'1'}>统筹任务,由平台支付赏金,需经过平台遴选方能发布</Radio>
|
||||
</Radio.Group>
|
||||
)}
|
||||
|
||||
<div className="task-setting-days">
|
||||
<div className="timing_task">
|
||||
<div className="mbt10 color-grey-9 lineh-35"><span className="inline-span active">发布任务</span></div>
|
||||
<div className="color-grey-9 ">自主提交:立即发布</div>
|
||||
<div className="color-grey-9 ">统筹任务:遴选后发布</div>
|
||||
</div>
|
||||
|
||||
{helperNoLabel(
|
||||
"成果提交",
|
||||
"collectingDays",
|
||||
[{ required: true, message: "请输入天数" }],
|
||||
<InputNumber
|
||||
className="date-input"
|
||||
onChange={(v) => { changeDate(v, 'collectingDays') }}
|
||||
min={1}
|
||||
max={180}
|
||||
/>,
|
||||
displayTime.collectingTime
|
||||
)}
|
||||
{/* <div className="color-grey-9 format-time-days-1 format-time-day-show">2021-06-16 07:10</div> */}
|
||||
{/* <div className="days-error"><span className="color-red none">成果提交时间不能为空</span></div> */}
|
||||
|
||||
{helperNoLabel(
|
||||
"成果评选",
|
||||
"choosingDays",
|
||||
[{ required: true, message: "请输入天数" }],
|
||||
<InputNumber
|
||||
className="date-input"
|
||||
onChange={(v) => { changeDate(v, 'choosingDays') }}
|
||||
min={1}
|
||||
max={180}
|
||||
/>,
|
||||
displayTime.choosingTime
|
||||
)}
|
||||
|
||||
{helperNoLabel(
|
||||
"结果公示",
|
||||
"makePublicDays",
|
||||
[{ required: true, message: "请输入天数" }],
|
||||
<InputNumber
|
||||
className="date-input"
|
||||
onChange={(v) => { changeDate(v, 'makePublicDays') }}
|
||||
min={1}
|
||||
max={180}
|
||||
/>,
|
||||
displayTime.makePublicTime
|
||||
)}
|
||||
|
||||
{helperNoLabel(
|
||||
"任务协议签订",
|
||||
"signingDays",
|
||||
[{ required: true, message: "请输入天数" }],
|
||||
<InputNumber
|
||||
className="date-input"
|
||||
onChange={(v) => { changeDate(v, 'signingDays') }}
|
||||
min={1}
|
||||
max={180}
|
||||
/>,
|
||||
displayTime.signingTime
|
||||
)}
|
||||
|
||||
{helperNoLabel(
|
||||
"支付",
|
||||
"payingDays",
|
||||
[{ required: true, message: "请输入天数" }],
|
||||
<InputNumber
|
||||
className="date-input"
|
||||
onChange={(v) => { changeDate(v, 'payingDays') }}
|
||||
min={1}
|
||||
max={180}
|
||||
/>,
|
||||
displayTime.payingTime
|
||||
)}
|
||||
|
||||
<div className="timing_task">
|
||||
<div className="mbt10 color-grey-9 lineh-35"><span className="inline-span">任务完成</span></div>
|
||||
<div className="color-grey-9 ">支付确认后,任务完成</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<p className="color-grey3 mb10 ml40 mt20">
|
||||
<span className="color-orange mr2 ">*</span>
|
||||
注:任务天数总和不得超过180天。
|
||||
</p>
|
||||
</Form>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<Button className="mr20" type={"primary"} onClick={() => { saveItem(1) }}>发布</Button>
|
||||
<Button className="mr20" type={"primary"} onClick={() => { saveItem(0) }}>保存</Button>
|
||||
<Button onClick={() => { history.go(-1) }}>取消</Button>
|
||||
|
||||
<Modal
|
||||
title="修改联系电话"
|
||||
visible={visible}
|
||||
// onOk={checkItem}
|
||||
onCancel={() => { setVisible(false) }}
|
||||
className="form-edit-modal"
|
||||
>
|
||||
<Form {...formModalLayout}>
|
||||
<Form.Item label={"新手机号码:"} >
|
||||
<Input
|
||||
className="tel-input"
|
||||
placeholder="请输入11位手机号"
|
||||
/>
|
||||
</Form.Item>
|
||||
<Form.Item label={"验证码:"} >
|
||||
<Input
|
||||
className="code-input"
|
||||
placeholder="请输入验证码"
|
||||
/>
|
||||
<Button className="ml10" type="primary" disabled={num !== 0} onClick={getCode}>{num || '获取验证码'}</Button>
|
||||
</Form.Item>
|
||||
</Form>
|
||||
</Modal>
|
||||
</div>
|
||||
)
|
||||
})
|
||||
)
|
|
@ -0,0 +1,154 @@
|
|||
.achieve-form {
|
||||
padding: 24px 40px 0px 40px;
|
||||
}
|
||||
|
||||
.partTitle {
|
||||
color: #05101a;
|
||||
font-size: 16px;
|
||||
position: relative;
|
||||
height: 20px;
|
||||
line-height: 20px;
|
||||
margin-bottom: 20px !important;
|
||||
}
|
||||
|
||||
.partTitle:before {
|
||||
position: absolute;
|
||||
left: -10px;
|
||||
top: 3px;
|
||||
width: 2px;
|
||||
height: 16px;
|
||||
background: #459be6;
|
||||
content: "";
|
||||
}
|
||||
|
||||
.color-red {
|
||||
color: red;
|
||||
}
|
||||
|
||||
.areaDiv {
|
||||
overflow-y: hidden;
|
||||
}
|
||||
|
||||
.choose-button {
|
||||
float: left;
|
||||
border: 1px solid #eee;
|
||||
border-radius: 0px;
|
||||
height: 28px;
|
||||
line-height: 28px;
|
||||
padding: 0px 12px;
|
||||
color: #656565;
|
||||
margin: 0px 10px 10px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.choose-button.active {
|
||||
color: #4cacff !important;
|
||||
border: 1px solid #4cacff;
|
||||
}
|
||||
|
||||
.gray-form {
|
||||
.ant-form-item-required {
|
||||
color: #999;
|
||||
}
|
||||
}
|
||||
|
||||
.contact-input {
|
||||
max-width: 300px;
|
||||
}
|
||||
|
||||
.editPhone {
|
||||
margin-left: 1rem;
|
||||
padding: 0.25em;
|
||||
font-size: 1rem;
|
||||
color: #fff;
|
||||
background: #1484ef;
|
||||
border-radius: 50%;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.number-input {
|
||||
width: 200px;
|
||||
.ant-input-number-input {
|
||||
padding-right: 1em;
|
||||
text-align: right;
|
||||
}
|
||||
}
|
||||
|
||||
.task-setting-days {
|
||||
display: flex;
|
||||
flex-flow: row wrap;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.timing_task {
|
||||
flex: 1px;
|
||||
position: relative;
|
||||
line-height: 2;
|
||||
&:before {
|
||||
position: absolute;
|
||||
content: "";
|
||||
width: 100%;
|
||||
height: 2px;
|
||||
background: #efefef;
|
||||
top: 0px;
|
||||
left: 0px;
|
||||
}
|
||||
}
|
||||
|
||||
.inline-span:before {
|
||||
position: absolute;
|
||||
content: "";
|
||||
width: 10px;
|
||||
height: 10px;
|
||||
border-radius: 50%;
|
||||
top: -4px;
|
||||
left: 50%;
|
||||
margin-left: -6px;
|
||||
background: #bfbfbf;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.inline-span.active {
|
||||
font-size: 16px;
|
||||
color: #333;
|
||||
|
||||
&:before {
|
||||
background: #4cacff;
|
||||
}
|
||||
}
|
||||
|
||||
.date-input {
|
||||
margin-right: 0.4rem;
|
||||
}
|
||||
|
||||
.tel-input{
|
||||
width: 290px;
|
||||
}
|
||||
.code-input{
|
||||
width: 180px;
|
||||
}
|
||||
|
||||
.no-label {
|
||||
display: inline-block;
|
||||
margin-bottom: 0;
|
||||
.ant-form-explain {
|
||||
position: absolute;
|
||||
white-space: nowrap;
|
||||
bottom: -40px;
|
||||
}
|
||||
}
|
||||
.display-time{
|
||||
position: relative;
|
||||
top:-6px;
|
||||
}
|
||||
.days-word {
|
||||
line-height: 40px;
|
||||
}
|
||||
|
||||
|
||||
.task-edit-content{
|
||||
.ant-form-item-control-wrapper {
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,245 @@
|
|||
import React, { useCallback, useEffect, useState } from 'react';
|
||||
import { Input, Button, Modal } from 'antd';
|
||||
import moment from 'moment';
|
||||
import { formatDuring } from 'educoder';
|
||||
import ChooseNav from '../../components/chooseNav';
|
||||
import SortBox from '../../components/sortBox';
|
||||
import ItemListTask from '../components/itemListTask';
|
||||
import { taskTimeArr, taskStatusArr, sortArr, taskModeIdArr } from '../static';
|
||||
import { getTaskList, getTaskCategory, getCompanyInfo } from '../api';
|
||||
import '../index.scss';
|
||||
const Search = Input.Search;
|
||||
|
||||
export default ({ history, current_user, showLoginDialog }) => {
|
||||
console.log(current_user);
|
||||
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [taskCategoryArr, setTaskCategoryArr] = useState([]);
|
||||
const [categoryId, setCategoryId] = useState('');
|
||||
const [taskModeId, setTaskModeId] = useState('');
|
||||
const [expiredStartTime, setExpiredStartTime] = useState('');
|
||||
const [expiredEndTime, setExpiredEndTime] = useState('');
|
||||
const [statusString, setStatusString] = useState('3,4,5,6,7,8');
|
||||
const [searchInput, setSearchInput] = useState('');
|
||||
const [orderBy, setOrderBy] = useState('');
|
||||
const [curPage, setCurPage] = useState(1);
|
||||
const [total, setTotal] = useState(0);
|
||||
const [taskList, setTaskList] = useState([]);
|
||||
|
||||
// 获取分类数据
|
||||
useEffect(() => {
|
||||
getTaskCategory().then(data => {
|
||||
if (data) {
|
||||
for (const item of data) {
|
||||
item.dicItemCode = item.id;
|
||||
item.dicItemName = item.name;
|
||||
}
|
||||
setTaskCategoryArr(data);
|
||||
}
|
||||
});
|
||||
}, []);
|
||||
|
||||
// 获取任务列表
|
||||
useEffect(() => {
|
||||
const params = {
|
||||
categoryId,
|
||||
taskModeId,
|
||||
expiredStartTime,
|
||||
expiredEndTime,
|
||||
statusString,
|
||||
searchInput,
|
||||
orderBy,
|
||||
curPage,
|
||||
pageSize: 10,
|
||||
};
|
||||
setLoading(true);
|
||||
getTaskList(params).then(data => {
|
||||
if (data) {
|
||||
for (const item of data.rows) {
|
||||
item.delayTime = surplusTime(item);
|
||||
}
|
||||
setTaskList(data.rows);
|
||||
setTotal(data.total);
|
||||
}
|
||||
setLoading(false);
|
||||
})
|
||||
}, [categoryId, taskModeId, expiredStartTime, expiredEndTime, statusString, searchInput, orderBy, curPage]);
|
||||
|
||||
// 改变选项
|
||||
const changeOptionId = useCallback((option, type) => {
|
||||
if (type === 'taskCategory') {
|
||||
setCategoryId(option.dicItemCode);
|
||||
} else if (type === 'taskModeId') {
|
||||
setTaskModeId(option.dicItemCode);
|
||||
} else if (type === 'taskTime') {
|
||||
if (option.dicItemCode) {
|
||||
let nowTime = moment(new Date()).format('YYYY-MM-DD HH:mm:ss');
|
||||
let nextTime = moment(new Date().setDate(new Date().getDate() + option.dicItemCode)).format('YYYY-MM-DD HH:mm:ss');
|
||||
setExpiredStartTime(nowTime);
|
||||
setExpiredEndTime(nextTime);
|
||||
} else {
|
||||
setExpiredStartTime('');
|
||||
setExpiredEndTime('');
|
||||
}
|
||||
} else if (type === 'taskStatus') {
|
||||
setStatusString(option.dicItemCode || '3,4,5,6,7,8');
|
||||
}
|
||||
}, []);
|
||||
|
||||
function surplusTime(item) {
|
||||
let surplus;
|
||||
switch (item.status) {
|
||||
case 3:
|
||||
surplus = item.collectingDays * 24 * 3600 - (new Date() - new Date(item.publishedAt || item.createdAt)) / 1000;
|
||||
break;
|
||||
case 4:
|
||||
surplus = item.choosingDays * 24 * 3600 - (new Date() - new Date(item.collectingCompleteAt)) / 1000;
|
||||
break;
|
||||
case 5:
|
||||
surplus = item.makePublicDays * 24 * 3600 - (new Date() - new Date(item.makePublicAt)) / 1000;
|
||||
break;
|
||||
case 6:
|
||||
surplus = item.signingDays * 24 * 3600 - (new Date() - new Date(item.publicityCompleteAt)) / 1000;
|
||||
break;
|
||||
case 7:
|
||||
surplus = item.payingDays * 24 * 3600 - (new Date() - new Date(item.signingCompleteAt)) / 1000;
|
||||
break;
|
||||
default:
|
||||
surplus = 0;
|
||||
}
|
||||
|
||||
let surplusTimetext = formatDuring(surplus);
|
||||
return surplus > 0 ? '剩余' + surplusTimetext : '延期' + surplusTimetext;
|
||||
}
|
||||
|
||||
// 改变排序
|
||||
const changeSort = useCallback((sortType) => {
|
||||
let sortValue = '';
|
||||
if (sortType.type !== 'default') {
|
||||
if (sortType.desc) {
|
||||
sortValue = sortType.type + 'Desc';
|
||||
} else {
|
||||
sortValue = sortType.type + 'Asc';
|
||||
}
|
||||
}
|
||||
setOrderBy(sortValue);
|
||||
setCurPage(1);
|
||||
}, []);
|
||||
|
||||
function taskClick(id) {
|
||||
if (!current_user.user_id) {
|
||||
showLoginDialog();
|
||||
return;
|
||||
}
|
||||
history.push(`/task/taskDetail/${id}`);
|
||||
}
|
||||
|
||||
// 新增校验
|
||||
function goAdd() {
|
||||
if (!current_user.user_id) {
|
||||
showLoginDialog();
|
||||
return;
|
||||
}
|
||||
getCompanyInfo().then(res => {
|
||||
if (res) {
|
||||
if (res.message === 'success') {
|
||||
history.push("/task/taskAdd");
|
||||
} else if (res.message === '主体信息未认证') {
|
||||
Modal.info({
|
||||
title: '因为以下原因,您暂时不能进行本操作',
|
||||
content: <div className="mt10">
|
||||
<p>完成条件后,重新点击查看您的最新参与资格</p>
|
||||
<div className="inline mt10">
|
||||
<span className="mr30"> <i className="iconfont icon-mingpian"></i> <span className="color-red">主体信息未认证</span> </span>
|
||||
</div>
|
||||
</div>,
|
||||
onOk: () => {
|
||||
window.location.href = `/users/${current_user.login}/profiles`;
|
||||
},
|
||||
okText: '立即完善',
|
||||
});
|
||||
} else {
|
||||
Modal.info({
|
||||
content: '您没有权限发布任务'
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="centerbox" style={{ marginTop: '20px' }}>
|
||||
<div className="nav-content">
|
||||
<ChooseNav
|
||||
key={'taskCategory'}
|
||||
type={'taskCategory'}
|
||||
title={'任务领域:'}
|
||||
options={taskCategoryArr}
|
||||
changeOptionId={changeOptionId}
|
||||
size='big'
|
||||
/>
|
||||
|
||||
<ChooseNav
|
||||
key={'taskModeId'}
|
||||
type={'taskModeId'}
|
||||
title={'任务模式:'}
|
||||
options={taskModeIdArr}
|
||||
changeOptionId={changeOptionId}
|
||||
size='big'
|
||||
/>
|
||||
|
||||
<ChooseNav
|
||||
key={'taskTime'}
|
||||
type={'taskTime'}
|
||||
title={'任务时限:'}
|
||||
options={taskTimeArr}
|
||||
changeOptionId={changeOptionId}
|
||||
size='big'
|
||||
/>
|
||||
|
||||
<ChooseNav
|
||||
key={'taskStatus'}
|
||||
type={'taskStatus'}
|
||||
title={'任务状态:'}
|
||||
options={taskStatusArr}
|
||||
changeOptionId={changeOptionId}
|
||||
size='big'
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="center-content">
|
||||
<div className="centerScreen" >
|
||||
|
||||
<SortBox
|
||||
options={sortArr}
|
||||
changeOptionId={changeSort}
|
||||
/>
|
||||
|
||||
<div className="center-right-but">
|
||||
<Search
|
||||
maxLength={20}
|
||||
style={{ width: "300px" }}
|
||||
placeholder="请输入任务编号/任务名称关键字"
|
||||
onSearch={(value) => { setSearchInput(value); setCurPage(1); }}
|
||||
/>
|
||||
|
||||
<Button className="mr20 font-12" type="primary" onClick={goAdd}><i className="iconfont icon-zaibianji font-12 mr3"></i>发布任务</Button>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<ItemListTask
|
||||
list={taskList}
|
||||
itemClick={taskClick}
|
||||
curPage={curPage}
|
||||
total={total}
|
||||
changePage={(page) => { setCurPage(page) }}
|
||||
loading={loading}
|
||||
/>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
)
|
||||
}
|
|
@ -0,0 +1,166 @@
|
|||
import React, { useCallback, forwardRef, useEffect, useState } from 'react';
|
||||
import { Input, Button, Form } from 'antd';
|
||||
import ItemTaskManage from '../components/itemTaskManage';
|
||||
import StatusNav from '../../components/statusNav';
|
||||
import { approveArr, main_web_site_url } from '../static';
|
||||
import { getTaskAdminList, getTaskCategory } from '../api';
|
||||
import '../index.scss';
|
||||
|
||||
export default Form.create()(({ current_user, form, showNotification, match, history }) => {
|
||||
const { getFieldDecorator, validateFields, setFieldsValue, getFieldsValue } = form;
|
||||
const [categoryArr, setCategoryArr] = useState([]);
|
||||
|
||||
const [approve, setApprove] = useState(1);
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [searchObj, setSearchObj] = useState({});
|
||||
const [statusString, setStatusString] = useState('1');
|
||||
const [curPage, setCurPage] = useState(1);
|
||||
const [total, setTotal] = useState(0);
|
||||
const [taskList, setTaskList] = useState([]);
|
||||
|
||||
const [reload, setReload] = useState(0);
|
||||
|
||||
useEffect(() => {
|
||||
getTaskCategory().then(data => {
|
||||
if (data) {
|
||||
let categoryArr = [];
|
||||
for (const item of data) {
|
||||
categoryArr[item.id] = item.name;
|
||||
}
|
||||
setCategoryArr(categoryArr);
|
||||
}
|
||||
});
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
const params = {
|
||||
...searchObj,
|
||||
statusString,
|
||||
orderBy: 'createdAtDesc',
|
||||
curPage,
|
||||
pageSize: 10,
|
||||
publishMode: 1
|
||||
};
|
||||
setLoading(true);
|
||||
getTaskAdminList(params).then(data => {
|
||||
if (data) {
|
||||
setTaskList(data.rows);
|
||||
setTotal(data.total);
|
||||
}
|
||||
setLoading(false);
|
||||
})
|
||||
}, [reload, statusString, curPage, searchObj]);
|
||||
|
||||
|
||||
const helper = useCallback(
|
||||
(name, rules, widget) => (
|
||||
<Form.Item>
|
||||
{getFieldDecorator(name, { rules, validateFirst: true, })(widget)}
|
||||
</Form.Item>
|
||||
), []);
|
||||
|
||||
|
||||
function onSearch() {
|
||||
validateFields((err, values) => {
|
||||
if (!err) {
|
||||
setSearchObj(values);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
const changeOptionId = useCallback((option) => {
|
||||
setStatusString(option.dicItemCode.toString() || '2,3,4,5,6,7,8');
|
||||
setCurPage(1);
|
||||
}, []);
|
||||
|
||||
function changeApprove(approve) {
|
||||
setApprove(approve);
|
||||
setCurPage(1);
|
||||
if (approve === 1) {
|
||||
setStatusString('1');
|
||||
} else {
|
||||
setStatusString('2,3,4,5,6,7,8');
|
||||
}
|
||||
}
|
||||
|
||||
function clearSearch() {
|
||||
setFieldsValue({
|
||||
numberInput: '',
|
||||
nameInput: '',
|
||||
enterpriseNameInput: ''
|
||||
});
|
||||
setSearchObj({});
|
||||
}
|
||||
|
||||
const reloadList = useCallback(() => {
|
||||
setReload(Math.random());
|
||||
}, [])
|
||||
|
||||
return (
|
||||
<div className="centerbox task-manage">
|
||||
<div className="center-screen" >
|
||||
<div className="center-left-but">
|
||||
<Button className="circle-button" type={approve === 1 ? 'primary' : ''} onClick={() => { changeApprove(1) }}>待审批</Button>
|
||||
<Button className="circle-button" type={approve === 2 ? 'primary' : ''} onClick={() => { changeApprove(2) }}>已审批</Button>
|
||||
</div>
|
||||
|
||||
<div className="center-right-but">
|
||||
{helper(
|
||||
"numberInput",
|
||||
[{ max: 20, message: '长度不能超过20个字符' }],
|
||||
<Input
|
||||
placeholder="输入任务编号进行检索"
|
||||
/>
|
||||
)}
|
||||
|
||||
{helper(
|
||||
"nameInput",
|
||||
[{ max: 20, message: '长度不能超过20个字符' }],
|
||||
<Input
|
||||
placeholder="输入任务名称进行检索"
|
||||
/>
|
||||
)}
|
||||
|
||||
{helper(
|
||||
"enterpriseNameInput",
|
||||
[{ max: 20, message: '长度不能超过20个字符' }],
|
||||
<Input
|
||||
placeholder="输入发布主体名称进行检索"
|
||||
/>
|
||||
)}
|
||||
|
||||
<Button className="mr10" type="primary" onClick={onSearch}>搜索</Button>
|
||||
<Button className="mr10" type="" onClick={clearSearch}>清除</Button>
|
||||
<Button className="mr10" type="primary" onClick={() => { window.open(`${main_web_site_url}/admin/tasks/activity_managed_tasks.zip?review_status=reviewing&status_value=0`) }}>导出</Button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div className="center-content">
|
||||
|
||||
{
|
||||
approve === 2 && <StatusNav
|
||||
key={'approveStatus'}
|
||||
type={'approveStatus'}
|
||||
options={approveArr}
|
||||
changeOptionId={changeOptionId}
|
||||
/>
|
||||
}
|
||||
<ItemTaskManage
|
||||
list={taskList}
|
||||
curPage={curPage}
|
||||
total={total}
|
||||
changePage={(page) => { setCurPage(page) }}
|
||||
loading={loading}
|
||||
categoryArr={categoryArr}
|
||||
showNotification={showNotification}
|
||||
reloadList={reloadList}
|
||||
/>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
)
|
||||
}
|
||||
)
|
|
@ -842,6 +842,9 @@ class NewHeader extends Component {
|
|||
<li>
|
||||
<Link to={`/users/${this.props.current_user.login}`}>个人中心</Link>
|
||||
</li>
|
||||
<li>
|
||||
<Link to={`/task/myTask`}>创客管理</Link>
|
||||
</li>
|
||||
{
|
||||
mygetHelmetapi2 && mygetHelmetapi2.new_course && mygetHelmetapi2.new_course.my_courses &&
|
||||
<li><a href={`${mygetHelmetapi2.new_course.my_courses}`} target="_blank">我的课程</a></li>
|
||||
|
|
Loading…
Reference in New Issue