From 72f77fb6b8fee2ce0902d6e2a2a52d63402b296c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=BD=95=E7=AB=A5=E5=B4=87?= <792998983@qq.com> Date: Thu, 8 Dec 2022 14:52:50 +0800 Subject: [PATCH 01/12] =?UTF-8?q?=E5=88=9D=E5=A7=8B=E5=8C=96=E6=88=90?= =?UTF-8?q?=E6=9E=9C=E5=BA=93?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package.json | 3 + src/App.js | 16 +- src/managements/achievement/api.js | 80 +++++ src/managements/achievement/index.css | 42 +++ src/managements/achievement/index.jsx | 67 ++++ .../achievement/noticeDetail/index.jsx | 84 +++++ .../achievement/noticeDetail/index.scss | 22 ++ .../achievement/noticeEdit/index.jsx | 322 ++++++++++++++++++ .../achievement/noticeList/index.jsx | 302 ++++++++++++++++ .../achievement/noticeList/index.scss | 7 + .../achievement/noticeReader/index.jsx | 105 ++++++ .../achievement/noticeReader/index.scss | 25 ++ src/managements/index.js | 13 + src/military/achievement/api.js | 49 +++ .../achievement/components/itemList/index.jsx | 23 ++ .../components/itemList/index.scss | 47 +++ src/military/achievement/fetch.js | 10 + src/military/achievement/image/banner.png | Bin 0 -> 171640 bytes .../achievement/noticeDetail/index.jsx | 172 ++++++++++ .../achievement/noticeDetail/index.scss | 102 ++++++ src/military/achievement/noticeList/index.jsx | 267 +++++++++++++++ .../achievement/noticeList/index.scss | 215 ++++++++++++ src/military/achievement/static.js | 22 ++ src/military/achievement/svg.js | 73 ++++ 24 files changed, 2067 insertions(+), 1 deletion(-) create mode 100644 src/managements/achievement/api.js create mode 100644 src/managements/achievement/index.css create mode 100644 src/managements/achievement/index.jsx create mode 100644 src/managements/achievement/noticeDetail/index.jsx create mode 100644 src/managements/achievement/noticeDetail/index.scss create mode 100644 src/managements/achievement/noticeEdit/index.jsx create mode 100644 src/managements/achievement/noticeList/index.jsx create mode 100644 src/managements/achievement/noticeList/index.scss create mode 100644 src/managements/achievement/noticeReader/index.jsx create mode 100644 src/managements/achievement/noticeReader/index.scss create mode 100644 src/military/achievement/api.js create mode 100644 src/military/achievement/components/itemList/index.jsx create mode 100644 src/military/achievement/components/itemList/index.scss create mode 100644 src/military/achievement/fetch.js create mode 100644 src/military/achievement/image/banner.png create mode 100644 src/military/achievement/noticeDetail/index.jsx create mode 100644 src/military/achievement/noticeDetail/index.scss create mode 100644 src/military/achievement/noticeList/index.jsx create mode 100644 src/military/achievement/noticeList/index.scss create mode 100644 src/military/achievement/static.js create mode 100644 src/military/achievement/svg.js diff --git a/package.json b/package.json index c2a43e1a..3d06be6d 100644 --- a/package.json +++ b/package.json @@ -221,5 +221,8 @@ "uglifyjs-webpack-plugin": "^2.2.0", "webpack": "^4.42.1", "webpack-bundle-analyzer": "^3.7.0" + }, + "volta": { + "node": "14.17.3" } } diff --git a/src/App.js b/src/App.js index 53d55bc0..88037b11 100644 --- a/src/App.js +++ b/src/App.js @@ -59,6 +59,11 @@ const Notice = Loadable({ loader: () => import('./military/notice'), loading: Loading, }) +// 成果库 +const Achievement = Loadable({ + loader: () => import('./military/achievement'), + loading: Loading, +}) //任务/需求 const Task = Loadable({ loader: () => import('./military/task'), @@ -156,7 +161,7 @@ const Managements = Loadable({ // }) // 此处仅维护前端可能的一级路由,不用进行项目或者组织判断的字段。 -const keyWord = ["explore", "settings", "setting", "mulan", "wiki", "issues", "setting", "trending", "code", "projects", "pulls", "mine", "login", "register", "email", "export", "nopage", "404", "403", "500", "501", "search", "organize", "login", "register", "resetPassword", "aboutus","educoder","task","notice","managements","expert","competition","administration", "needs"]; +const keyWord = ["explore", "settings", "setting", "mulan", "wiki", "issues", "setting", "trending", "code", "projects", "pulls", "mine", "login", "register", "email", "export", "nopage", "404", "403", "500", "501", "search", "organize", "login", "register", "resetPassword", "aboutus","educoder","task","notice","achievement","managements","expert","competition","administration", "needs"]; class App extends Component { constructor(props) { @@ -388,6 +393,15 @@ class App extends Component { } }> + {/*成果*/} + { + return () + } + }> + {/*任务*/} {/*专家评审*/} diff --git a/src/managements/achievement/api.js b/src/managements/achievement/api.js new file mode 100644 index 00000000..b04d90dc --- /dev/null +++ b/src/managements/achievement/api.js @@ -0,0 +1,80 @@ +import fetch from 'military/notice/fetch'; +import showNotification from '../components/ShowNotification'; + + +// 公告列表查询 +export async function getNoticeList(params) { + let res = await fetch({ + url: '/api/announcements/', + method: 'get', + params, + }); + if (res.message === 'success') { + return res.data; + } else { + showNotification(res.message || '请求错误'); + } +} + +//新增公告 +export function addNotice(data) { + return fetch({ + url: '/api/announcements/add', + method: 'post', + data: data + }); +} + +//删除公告 +export function deleteNotice(id) { + return fetch({ + url: '/api/announcements/' + id, + method: 'DELETE', + }); +} + +//更新公告 +export function editNotice(data) { + return fetch({ + url: '/api/announcements/update', + method: 'put', + data: data + }); +} + +//审核公告 +export function checkNotice(data) { + return fetch({ + url: '/api/announcements/check', + method: 'put', + data: data + }); +} + +// 公告详情查询 +export async function getNoticeDetail(id) { + let res = await fetch({ + url: '/api/announcements/' + id, + method: 'get', + }); + if (res.data) { + return res.data; + } else { + showNotification(res.message || '请求错误'); + } +} + +// 公告密文查看人详情 +export async function getNoticeReader(params) { + let res = await fetch({ + url: '/api/request_contact_reader_info/', + method: 'get', + params, + }); + if (res.data) { + return res.data; + } else { + showNotification(res.message || '请求错误'); + } +} + diff --git a/src/managements/achievement/index.css b/src/managements/achievement/index.css new file mode 100644 index 00000000..a7b79a1a --- /dev/null +++ b/src/managements/achievement/index.css @@ -0,0 +1,42 @@ +.notice-content { + min-height: 50vh; + margin: 1em; + background: #fff; + border-radius: 1em; + box-shadow: 0 1px 2px #d9d9d9; + padding-bottom: 1vh; +} + +.notice-title { + padding: 0.75em; + border-bottom: 1px solid #e5e5e5; +} + +.notice-form .edit-input{ + max-width:450px; +} + +.my-search-button{ + margin-top:4px; +} + +.encrypt-item{ + margin-top: -24px; +} + +.encrypt-item .ant-form-item-label{ + visibility: hidden; +} + +.ant-radio-checked .ant-radio-inner{ + border-color: #4154f1; +} +.ant-radio-inner::after{ + background-color: #4154f1; +} +.ant-radio-wrapper:hover .ant-radio, .ant-radio:hover .ant-radio-inner, .ant-radio-input:focus + .ant-radio-inner{ + border-color: #4154f1; +} +.ant-radio-checked::after{ + border: 1px solid #4154f1; +} \ No newline at end of file diff --git a/src/managements/achievement/index.jsx b/src/managements/achievement/index.jsx new file mode 100644 index 00000000..31f6f06a --- /dev/null +++ b/src/managements/achievement/index.jsx @@ -0,0 +1,67 @@ +import React from "react"; +import { Route, Switch } from "react-router-dom"; +import Loadable from "react-loadable"; +import Loading from "../../Loading"; + +// 公告管理 +const NoticeList = Loadable({ + loader: () => import("./noticeList"), + loading: Loading, +}); +// 公告管理详情 +const NoticeDetail = Loadable({ + loader: () => import("./noticeDetail"), + loading: Loading, +}); +// 公告管理编辑 +const NoticeEdit = Loadable({ + loader: () => import("./noticeEdit"), + loading: Loading, +}); +// 公告reader +const NoticeReader = Loadable({ + loader: () => import("./noticeReader"), + loading: Loading, +}); + +export default (propsF)=>{ + return ( + + {/* 公告列表 */} + ( + + )} + > + {/* 公告详情 */} + ( + + )} + > + {/* 公告编辑 */} + ( + + )} + > + {/* 公告新增 */} + ( + + )} + > + {/* 公告预览 */} + ( + + )} + > + + ) +} \ No newline at end of file diff --git a/src/managements/achievement/noticeDetail/index.jsx b/src/managements/achievement/noticeDetail/index.jsx new file mode 100644 index 00000000..7ce85cd4 --- /dev/null +++ b/src/managements/achievement/noticeDetail/index.jsx @@ -0,0 +1,84 @@ +import React, { useCallback, useEffect, useState } from 'react'; +import { Button, Descriptions, Icon } from 'antd'; +import ShowNotification from '../../components/ShowNotification'; +import { noticeType, noticeChecked } from '../../common/static'; +import { getNoticeDetail, checkNotice } from '../api'; +import '../index.css'; +import './index.scss'; + +const noticeTypeArr = []; +for (const item of noticeType) { + noticeTypeArr[item.code] = (item.name); +} +const noticeCheckedArr = []; +for (const item of noticeChecked) { + noticeCheckedArr[item.code] = (item.name); +} + +const IndexPage = ({ match, history, current_user: { admin } }) => { + const [noticeData, setNoticeData] = useState({}); + const id = match.params.noticeId; + + useEffect(() => { + id && getNoticeDetail(id).then(data => { + setNoticeData(data || {}); + }) + }, [id]); + + // 审核 + function checkItem(isChecked) { + checkNotice({ + id: noticeData.id, + isChecked, + }).then(res => { + if (res && res.code == '1') { + ShowNotification("操作成功"); + history.go(-1); + } else { + ShowNotification(res.message || "操作失败"); + history.go(-1); + } + }) + } + + function download(url) { + if (window.location.href.indexOf('localhost') > -1) { + url = 'http://106.75.31.211:58088' + url; + } + window.open(url); + } + + return ( +
+

{ history.go(-1) }}>返回公告详情

+ + + {noticeData.status == 1 ? noticeCheckedArr[noticeData.isChecked] : '草稿'} + {noticeData.title} + {noticeTypeArr[noticeData.type]} + {noticeData.publisher} +
+ {[4, 5, 6].includes(noticeData.type) &&
') }}>
} + +
{ download(noticeData.fileDownloadPath) }}>{noticeData.fileName}
+
+ {noticeData.createdAt} + {noticeData.publishDate && {noticeData.publishDate}} + {noticeData.closingDate} + + {admin && noticeData.status == 1 && noticeData.isChecked == 2 && + + + + + + } + +
+ +
+ ) +} + + +export default IndexPage; diff --git a/src/managements/achievement/noticeDetail/index.scss b/src/managements/achievement/noticeDetail/index.scss new file mode 100644 index 00000000..094d94ce --- /dev/null +++ b/src/managements/achievement/noticeDetail/index.scss @@ -0,0 +1,22 @@ +.itemContent { + padding: 10px 10px 0 30px; +} +.statusColor{ + color: #1890ff; +} +.alignTop{ + display: flex; + align-items: flex-start; +} +.backList{ + margin-right:1em; + &:hover{ + color: #1890ff; + } +} + +:global{ + .ant-descriptions-item-label{ + min-width: 5em; + } +} diff --git a/src/managements/achievement/noticeEdit/index.jsx b/src/managements/achievement/noticeEdit/index.jsx new file mode 100644 index 00000000..796e2234 --- /dev/null +++ b/src/managements/achievement/noticeEdit/index.jsx @@ -0,0 +1,322 @@ +import React, { forwardRef, Fragment, useCallback, useEffect, useState } from 'react'; +import ReactWEditor from 'wangeditor-for-react'; +import { Form, Input, Button, Radio, Checkbox, DatePicker } from 'antd'; +import moment from 'moment'; +import { noticeType } from '../../common/static'; +import Upload from '../../components/Upload'; +import ShowNotification from '../../components/ShowNotification'; +import { getNoticeDetail, addNotice, editNotice } from '../api'; +import { httpUrl } from 'military/notice/fetch'; + +import '../index.css'; +const format = "YYYY-MM-DD HH:mm:ss"; +const { TextArea } = Input; + +let actionUrl = httpUrl; +// if (window.location.href.indexOf('localhost') > -1) { +// actionUrl = httpUrl; +// } else { +// actionUrl = "https://info.osredm.com"; +// } + +const NoticeEdit = Form.create()(forwardRef(({ form, match, history }, ref) => { + + const [fileList, setFileList] = useState(null); + const [noticeHtml, setNoticeHtml] = useState(''); + const id = match.params.noticeId; + const { getFieldDecorator, validateFields, setFieldsValue } = form; + const [typeValue, setTypeValue] = useState(4); + const [isSecret, setIsSecret] = useState(); + + useEffect(() => { + id && getNoticeDetail(id).then(data => { + const formValue = { + type: data.type, + title: data.title, + publisher: data.publisher, + text: data.text, + closingDate: data.closingDate && moment(data.closingDate), + contactInfo: data.contactInfo, + }; + setFieldsValue(formValue); + setNoticeHtml(data.text || ''); + setIsSecret(Boolean(data.isSecret)); + if (data.fileName) { + setFileList([{ + name: data.fileName, + fileName: data.fileName, + fileDownloadPath: data.fileDownloadPath, + uid: "rc-upload" + data.id + }]) + } + }) + }, [id]); + + // 上传附件后得到的文件数组 + function UploadFunc(fileList) { + setFileList(fileList); + } + + const helper = useCallback( + (label, name, rules, widget, initialValue) => ( + + {getFieldDecorator(name, { rules, initialValue, validateFirst: true })(widget)} + + ), + [] + ); + + const editor = useCallback(() => ( + + {(!id || (id && noticeHtml)) && + { + changeHtml(html); + }} + />} + + {getFieldDecorator('text', { + rules: [{ required: true, message: "请输入公告描述" }], + validateFirst: true + })()} + + ), [noticeHtml]) + + const formItemLayout = { + labelCol: { + xs: { span: 10 }, + sm: { span: 8 }, + lg: { span: 3 }, + }, + wrapperCol: { + xs: { span: 14 }, + sm: { span: 16 }, + lg: { span: 16 }, + }, + }; + + const tailFormItemLayout = { + wrapperCol: { + xs: { + span: 20, + offset: 4, + }, + sm: { + span: 20, + offset: 4, + }, + }, + }; + + // 修改 + function saveItem(status) { + validateFields((error, values) => { + if (!error) { + let params = { + ...values, + status, + fileDownloadPath: '', + fileName: '', + + templateUrl: '', + }; + params.closingDate = params.closingDate.format(format); + params.isSecret = Number(params.isSecret); + if (fileList && fileList.length) { + params.fileName = fileList[0].fileName || fileList[0].response.data.fileName; + params.fileDownloadPath = fileList[0].fileDownloadPath || `${actionUrl}/busiAttachments/download/${fileList[0].response.data.id}`; + } + if (id) { + // 编辑 + params.id = id; + editNotice(params).then(res => { + if (res.message === 'success') { + ShowNotification("操作成功!"); + if (status == 1) { + history.push('/managements/notice/list/2'); + } else { + history.push('/managements/notice/list/draft'); + } + } else { + ShowNotification(res.message); + } + }); + } else { + // 新增 + addNotice(params).then(res => { + if (res.message === 'success') { + ShowNotification("公告新增成功!"); + if (status == 1) { + history.push('/managements/notice/list/2'); + } else { + history.push('/managements/notice/list/draft'); + } + } else { + ShowNotification(res.message); + } + }); + } + } + }) + } + + function changeClosingDate(val) { + if (val) { + let nextTime = moment(new Date().setDate(new Date().getDate() + val)).format('YYYY-MM-DD'); + nextTime += ' 23:59:59'; + setFieldsValue({ + closingDate: moment(nextTime) + }); + } + } + + function changeHtml(html) { + setFieldsValue({ + text: html + }); + // setNoticeHtml(html); + } + + return ( +
+

{id ? '修改' : '发布'}公告

+
+ + {helper( + "公告类型:", + "type", + [{ required: true, message: "请选择公告类型" }], + { setTypeValue(e.target.value) }} + > + { + noticeType.map(item => { + return {item.name} + }) + } + , + 4 + )} + + {helper( + "公告标题:", + "title", + [{ required: true, message: "请输入公告标题" }, + { max: 50, message: '长度不能超过50个字符' }], + + )} + + {helper( + "发布单位:", + "publisher", + [{ required: true, message: "请输入发布单位" }, + { max: 50, message: '长度不能超过50个字符' }], + + )} + + {editor()} + + {[4, 5, 6].includes(typeValue) && + {helper( + "联系方式:", + "contactInfo", + [{ max: 5000, message: '长度不能超过5000个字符' }], +