diff --git a/config/router.config.ts b/config/router.config.ts index c4de15a..f1e96f5 100644 --- a/config/router.config.ts +++ b/config/router.config.ts @@ -9,7 +9,7 @@ export default [ ...transfer,//跳转、登陆 //审批单 ...approvalForm, - //党员专题 + //党建攻坚 ...partyMemberTopic, { path: '/userformal', @@ -32,10 +32,15 @@ export default [ ], }, //日历组件暂时用 - { - path: '/Calendar', - component: './MainPage/ProjectManager/components/CalendarForm', - }, + // { + // path: '/Calendar', + // component: './MainPage/ProjectManager/components/CalendarForm', + // }, + //富文本组件 + // { + // path: '/editor', + // component: './MainPage/ProjectManager/components/WangEditor', + // }, //401错误页 { exact: true, @@ -243,7 +248,7 @@ export default [ path: '/Supervision', component: './Project/ProjectManage/Supervision' }, - {//审查人员 项目管理页 + {//审查人员 项目管理页 name: 'Examination', path: '/Examination', component: './Project/ProjectManage/Examination' diff --git a/config/router_partyMemberTopic.ts b/config/router_partyMemberTopic.ts index c8f8d9b..45847b2 100644 --- a/config/router_partyMemberTopic.ts +++ b/config/router_partyMemberTopic.ts @@ -43,6 +43,11 @@ export default [ path: '/partyMemberTopic/newsDetail', component: './PartyMemberTopic/NewsDetail', }, + {//管理端首页 + name: 'manage', + path: '/partyMemberTopic/manage', + component: './PartyMemberTopic/Management/Manage', + }, ] - } + }, ]; \ No newline at end of file diff --git a/src/assets/topic/topic_right_manager.jpg b/src/assets/topic/topic_right_manager.jpg new file mode 100644 index 0000000..7fce1c7 Binary files /dev/null and b/src/assets/topic/topic_right_manager.jpg differ diff --git a/src/components/richText/wang/index.tsx b/src/components/richText/wang/index.tsx index e1151f8..4b4b928 100644 --- a/src/components/richText/wang/index.tsx +++ b/src/components/richText/wang/index.tsx @@ -1,7 +1,10 @@ -import React, { useEffect, useImperativeHandle, useState } from 'react'; +import React, { useEffect, useImperativeHandle, useRef, useState } from 'react'; import AlertMenu from './fullScreen' import E from 'wangeditor'; -import { Button } from 'antd'; +import { Button, message, Spin } from 'antd'; +import { pictureDisplayPath, uploadAttachmentPath } from '@/utils/DownloadUtils'; +import { isEmpty, isNotEmpty } from '@/utils/CommonUtils'; +import { createNewFileBid } from '@/services/download_'; interface WangType { braftRef: any;//挂载 @@ -9,7 +12,9 @@ interface WangType { echo?: any;//回显内容 value?: any; height?: number; - onChange?: (value: any) => void + onChange?: (value: any) => void; + useImage?: boolean;//使用图片上传 + imageId?: string;//图片objectId } let editor: any = null; @@ -21,6 +26,10 @@ const BraftText: React.FC = (props) => { //======================================================================================state const [content, setContent] = useState(''); const [fullScreen, fullScreenSet] = useState(false); + //遮罩 + const [loading, setLoading] = useState(false); + //imageId + const objectId = useRef(null); const { braftRef, echo, @@ -28,12 +37,14 @@ const BraftText: React.FC = (props) => { value, height, onChange, + useImage, + imageId, } = props; const tools = [//工具栏 'head',//标题 'fontSize', //字号 - 'lineHeight', //行高 + // 'lineHeight', //行高 'foreColor', //颜色 'bold', //加粗 'italic', //斜体 @@ -41,12 +52,13 @@ const BraftText: React.FC = (props) => { 'strikeThrough', //文字删除线 'indent', //缩进 'justify', //文字对齐方式 + 'list', //列表 'undo', //撤销 - 'redo', //重做 + 'redo', //恢复 'fullscreen', //全屏 - // 'emoticon',//表情 // 'image',//图片 + // 'emoticon',//表情 // 'video',//视频 // 'table',//表格 // 'todo',//待办 @@ -56,12 +68,14 @@ const BraftText: React.FC = (props) => { useEffect(() => { if (willCreate) { // 注:class写法需要在componentDidMount 创建编辑器 - editor = new E("#div1") + editor = new E("#div1"); + //添加图片上传 + useImage && tools.splice(-3, 0, 'image'); //工具栏 editor.config.menus = tools; //提示 - editor.config.placeholder = '为了能顺利发布,建议您内容去掉下划线等格式,尽量以纯文本形式发布。' + editor.config.placeholder = '为了能顺利发布,建议您内容去掉下划线等格式,尽量以纯文本形式发布。'; // 配置 onchange 回调函数 editor.config.onchange = editorOnChange; // 注册菜单 @@ -73,6 +87,104 @@ const BraftText: React.FC = (props) => { // 设置编辑区域高度为 500px height && (editor.config.height = height); + //关闭网络上传图片 + editor.config.showLinkImg = false; + // 关闭粘贴内容中的样式 + editor.config.pasteFilterStyle = false; + // 忽略粘贴内容中的图片 + editor.config.pasteIgnoreImg = true; + // 上传图片到服务器,对应的是controller层的@RequestMapping("/upload") + editor.config.uploadImgServer = uploadAttachmentPath;//接口名称 + //自定义name,接收的时候图片文件的那么用这个,对应的是参数中的MultipartFile upimg名称,这个名称即上传到浏览器的参数名称 + editor.config.uploadFileName = "multipartFiles";//这个需要和后台商量上传图片的名称 + //设置请求体额外参数 + if (useImage) { + if (isEmpty(imageId)) { + createNewFileBid().then(res => {//获取雪花id + editor.config.uploadImgParams = { + appCode: 'ebtp-cloud-frontend', + objectId: res?.id, + }; + objectId.current = res?.id; + }) + } else { + editor.config.uploadImgParams = { + appCode: 'ebtp-cloud-frontend', + objectId: imageId, + }; + objectId.current = imageId; + } + } + // 将 timeout 时间改为 60s + editor.config.uploadImgTimeout = 60000; + // 将图片大小限制为 600k + editor.config.uploadImgMaxSize = 600 * 1024; + // 限制一次最多上传 1 张图片 + editor.config.uploadImgMaxLength = 1; + //上传图片的错误提示默认使用alert弹出,也可以自定义用户体验更好的提示方式 + editor.config.customAlert = function (info: string) { + const repinfo = info.replace(/0.5859375M/g, '600K'); + // info 是需要提示的内容 + message.error(repinfo); + }; + // 上传图片的结果反馈 + editor.config.uploadImgHooks = { + before: function (xhr: any, editor: any, files: any) { + // 图片上传之前触发 + // xhr 是 XMLHttpRequst 对象,editor 是编辑器对象,files 是选择的图片文件 + // 如果返回的结果是 {prevent: true, msg: 'xxxx'} 则表示用户放弃上传 + // return { + // prevent: true, + // msg: '放弃上传' + // } + // console.log("before:",xhr) + if (isEmpty(objectId.current)) { + return { + prevent: true, + msg: '上传失败,原因:上传参数错误' + } + } + setLoading(true); + return { + prevent: false, + } + }, + success: function (xhr: any, editor: any, result: any) { + // 图片上传并返回结果,图片插入成功之后触发 + // xhr 是 XMLHttpRequst 对象,editor 是编辑器对象,result 是服务器端返回的结果 + // console.log("success:",result) + }, + fail: function (xhr: any, editor: any, result: any) { + // 图片上传并返回结果,但图片插入错误时触发 + // xhr 是 XMLHttpRequst 对象,editor 是编辑器对象,result 是服务器端返回的结果 + }, + error: function (xhr: any, editor: any) { + // 图片上传出错时触发 + // xhr 是 XMLHttpRequst 对象,editor 是编辑器对象 + }, + // 上传图片超时 + timeout: function (xhr: any) { + message.error('服务器超时!'); + setLoading(false); + }, + // 如果服务器端返回的不是 {errno:0, data: [...]} 这种格式,可使用该配置 + // (但是,服务器端返回的必须是一个 JSON 格式字符串!!!否则会报错) + customInsert: function (insertImg: (arg0: any) => void, result: any, editor: any) { + // 图片上传并返回结果,自定义插入图片的事件(而不是编辑器自动插入图片!!!) + // insertImg 是插入图片的函数,参数editor 是编辑器对象,result 是服务器端返回的结果 + // 举例:假如上传图片成功后,服务器端返回的是 {url:'....'} 这种格式,即可这样插入图片: + if (result?.success) { + const url = pictureDisplayPath + '?filePath=' + result.data[0].sysStorageVO.filePath; + insertImg(url); + } else { + message.error('图片上传失败!'); + } + setLoading(false); + // var url = result.result.remote_path; + // insertImg(url); + // result 必须是一个 JSON 格式字符串!!!否则报错 + } + }; /**一定要创建 */ editor.create(); @@ -82,15 +194,18 @@ const BraftText: React.FC = (props) => { willCreate = false; } - // 重新设置编辑器内容 - echo && editor.txt.html(echo); - value && editor.txt.html(value); - return () => { // 组件销毁时销毁编辑器 注:class写法需要在componentWillUnmount中调用 editor.destroy() + setLoading(false); + setContent(''); } - }, [value, echo]); + }, []); + + useEffect(() => { + // 重新设置编辑器内容 + echo && editor.txt.html(echo); + }, [echo]) /** *提供给父级的内容 **/ @@ -99,6 +214,7 @@ const BraftText: React.FC = (props) => { getHtml, getHtml1, makeDis, + getImageId, })); // 获取html方法1 @@ -131,12 +247,17 @@ const BraftText: React.FC = (props) => { const triggerChange = (newHtml: any) => { onChange?.(newHtml); }; + + //获取富文本图片objectId + function getImageId() { + return objectId.current; + } return ( -
- {/* - */} -
-
+ +
+
+
+
) } export default BraftText \ No newline at end of file diff --git a/src/pages/PartyMemberTopic/Home/index.less b/src/pages/PartyMemberTopic/Home/index.less index 8b559f8..1ffaefb 100644 --- a/src/pages/PartyMemberTopic/Home/index.less +++ b/src/pages/PartyMemberTopic/Home/index.less @@ -340,6 +340,10 @@ color: #c9c9c9; } + .right-manager { + margin-top: 12px; + } + // .right-graph { // padding-top: 26px; diff --git a/src/pages/PartyMemberTopic/Home/index.tsx b/src/pages/PartyMemberTopic/Home/index.tsx index 5499f16..a2ecac4 100644 --- a/src/pages/PartyMemberTopic/Home/index.tsx +++ b/src/pages/PartyMemberTopic/Home/index.tsx @@ -11,6 +11,7 @@ import topic_other from '@/assets/topic/topic_other.png' import topic_project_picture from '@/assets/topic/topic_project_picture.jpg' import topic_bottom_button from '@/assets/topic/topic_bottom_button.png' import topic_right_material from '@/assets/topic/topic_right_material.png' +import topic_right_manager from '@/assets/topic/topic_right_manager.jpg' import topic_partymember from '@/assets/topic/topic_partymember.png' import topic_partybranch from '@/assets/topic/topic_partybranch.png' import topic_totalamount from '@/assets/topic/topic_totalamount.png' @@ -25,11 +26,11 @@ import topic_interview from '@/assets/topic/topic_interview.png' import topic_assure from '@/assets/topic/topic_assure.png' import topic_difficult from '@/assets/topic/topic_difficult.png' import { getHomeActivity, getHomeBanner, getHomeContact, getHomeGraceful, getHomeProject, getHomeRight, submitAdvice } from './service'; -import { chunk, formatTime, getImageUrl } from '../utils'; +import { chunk, formatTime, getImageUrl, managerAuthority } from '../utils'; import ExtendUpload from '@/utils/ExtendUpload'; import { getSessionUserData } from '@/utils/session'; -const tagsData = ['集团总部', '北京', '天津', '河北', '山西', '内蒙古', '辽宁', '吉林', '黑龙江', '山东', '河南', '上海', '江苏', '浙江', '安徽', '福建', '江西', '湖北', '湖南', '广东', '广西', '海南', '重庆', '四川', '贵州', '云南', '西藏', '陕西', '甘肃', '青海', '宁夏', '新疆', '数字科技', '联通在线', '智网科技', '支付公司', '财务公司', '融资租赁', '时科(北京)信息']; +const tagsData = ['集团总部', '北京', '天津', '河北', '山西', '内蒙古', '辽宁', '吉林', '黑龙江', '山东', '河南', '上海', '江苏', '浙江', '安徽', '福建', '江西', '湖北', '湖南', '广东', '广西', '海南', '重庆', '四川', '贵州', '云南', '西藏', '陕西', '甘肃', '青海', '宁夏', '新疆', '数字科技', '联通在线', '智网科技', '支付公司', '财务公司', '融资租赁', '时科(北京)信息', '中讯院']; const formItemLayout = { labelCol: { span: 5 }, @@ -589,6 +590,14 @@ const Home: React.FC<{}> = () => { + {managerAuthority("ebtp-party-admin") ? null : ( + <> + +
+ window.open("/partyMemberTopic/manage")} /> +
+ + )}
diff --git a/src/pages/PartyMemberTopic/Management/EventMaintenance/components/EventMaintenanceModal.tsx b/src/pages/PartyMemberTopic/Management/EventMaintenance/components/EventMaintenanceModal.tsx new file mode 100644 index 0000000..a631077 --- /dev/null +++ b/src/pages/PartyMemberTopic/Management/EventMaintenance/components/EventMaintenanceModal.tsx @@ -0,0 +1,200 @@ +import React, { useEffect, useRef, useState } from 'react'; +import { Modal, Col, Form, Input, Row, Select, Spin, message } from 'antd'; +import BraftText from '@/components/richText/wang'; +import ExtendUpload from '@/utils/ExtendUpload'; +import { isEmpty, isNotEmpty } from '@/pages/PartyMemberTopic/utils'; +import { getSessionUserData } from '@/utils/session'; +import moment from 'moment'; +import { saveEventData } from '../service'; + +const layout = { + labelCol: { span: 3 }, + wrapperCol: { span: 21 }, +}; + +const validateMessages = { + required: '请填写此项', +}; + +const modalHeight = window.innerHeight * 96 / 100; + +interface EventMaintenanceModalProps { + modalVisible: boolean; + onCancel: () => void; + record: any; +} + +const EventMaintenanceModal: React.FC = (props) => { + const { modalVisible, onCancel, record } = props; + const [form] = Form.useForm(); + const { Option } = Select; + const { TextArea } = Input; + const braftRef = useRef(null); + //userData + const userData = getSessionUserData(); + //只读 true只读 false编辑 + const readOnly: boolean = record.editCode == "2"; + //上传文件id + const [imageId, setImageId] = useState(''); + //富文本正文图片objectId + const [contentImageId, setContentImageId] = useState(''); + //富文本正文 + const [content, setContent] = useState(''); + //活动类型选择 + const [typeSelect, setTypeSelect] = useState(''); + //loading + const [loading, setLoading] = useState(false); + + //保存 + const onSubmit = () => { + if (isNotEmpty(typeSelect) && typeSelect != "3" && isEmpty(form.getFieldValue("image"))) { + message.error("请上传主图"); + return; + } + if (isEmpty(braftRef.current.getHtml())) { + message.error("请编辑正文内容"); + return; + } + form.validateFields().then(values => { + const data = { + banner: null, + createBy: null, + id: null, + image: null, + secordTitle: null, + sendTime: null, + sort: null, + status: null, + title: null, + type: null, + ...values, + content: braftRef.current.getHtml(), + contentImageId: braftRef.current.getImageId(), + createTime: null, + } + setLoading(true); + saveEventData(data).then(res => { + if (res?.code == 200) { + message.success('保存成功'); + onCancel(); + } + }).finally(() => { + setLoading(false); + }) + }) + }; + const onTypeChage = (value: any) => { + setTypeSelect(value); + }; + + useEffect(() => { + if (record.editCode == "0") {//新建 + form.setFieldsValue({ + id: null, + createBy: userData?.fullName, + createTime: moment().format("YYYY-MM-DD HH:mm:ss"), + }); + } else if (record.editCode == "1" || record.editCode == "2") {//编辑 查看 + form.setFieldsValue(record); + setImageId(record?.image); + setContentImageId(record?.contentImageId); + setContent(record?.content); + onTypeChage(record?.type); + } + return () => { + setImageId(''); + setContentImageId(''); + setTypeSelect(''); + setContent(''); + setLoading(false); + }; + }, [record?.id]) + + return ( + onCancel()} + onOk={() => onSubmit()} + okButtonProps={{ loading: loading, hidden: readOnly }} + okText="保存" + maskClosable={false} + style={{ maxHeight: modalHeight }} + bodyStyle={{ maxHeight: modalHeight - 108, overflowY: 'auto', }} + centered + cancelText="返回" + width={'70%'} + > + +
+ + + + + + + + {typeSelect == "2" && +