Commit c080970da51be466601206a110f09c20a5bd39a5

Authored by Min
1 parent fd564a27

1.企业公告发布的内容。需要窗口弹出。即登录进去弹出公告内容,内容强制查看,确认已查看,未确认不能关闭,

src/components/Common/PersonCenter/PersonCenter.js
@@ -15,9 +15,12 @@ import { @@ -15,9 +15,12 @@ import {
15 } from '@ant-design/icons'; 15 } from '@ant-design/icons';
16 16
17 import { Form } from '@ant-design/compatible'; 17 import { Form } from '@ant-design/compatible';
18 -// import '@ant-design/compatible/assets/index.css'; 18 +import '@ant-design/compatible/assets/index.css';
19 19
20 -import { Button, Input, Modal, Menu, Badge, message, Dropdown, Space, notification, Popover, Tabs } from 'antd-v4'; 20 +import BraftEditor from 'braft-editor';
  21 +import 'braft-editor/dist/index.css';
  22 +
  23 +import { Button, Input, Modal, Menu, Badge, message, Dropdown, Space, notification, Popover, Tabs, Checkbox } from 'antd';
21 import styles from '@/routes/indexPage.less'; 24 import styles from '@/routes/indexPage.less';
22 import config from '@/utils/config'; 25 import config from '@/utils/config';
23 import * as commonUtils from '@/utils/utils'; 26 import * as commonUtils from '@/utils/utils';
@@ -54,6 +57,8 @@ class PersonCenter extends Component { @@ -54,6 +57,8 @@ class PersonCenter extends Component {
54 addFaceVisible: false, 57 addFaceVisible: false,
55 sUserName: props.app.userinfo.sUserName, 58 sUserName: props.app.userinfo.sUserName,
56 menuSearchPopoverVisible: false, 59 menuSearchPopoverVisible: false,
  60 + noticeVisible: false, // 新增:公告弹窗显示状态
  61 + noticeChecked: false, // 新增:复选框选中状态
57 }; 62 };
58 } 63 }
59 componentWillMount() { 64 componentWillMount() {
@@ -67,6 +72,8 @@ class PersonCenter extends Component { @@ -67,6 +72,8 @@ class PersonCenter extends Component {
67 72
68 message.warn(changePwd, 10); 73 message.warn(changePwd, 10);
69 } 74 }
  75 + // 检查是否有公告数据需要显示
  76 + this.checkNoticeData();
70 } 77 }
71 78
72 componentWillReceiveProps(nextProps) { 79 componentWillReceiveProps(nextProps) {
@@ -77,6 +84,8 @@ class PersonCenter extends Component { @@ -77,6 +84,8 @@ class PersonCenter extends Component {
77 audio.play(); 84 audio.play();
78 } 85 }
79 } 86 }
  87 + // 检查是否有新的公告数据
  88 + this.checkNoticeData(nextProps);
80 } 89 }
81 shouldComponentUpdate(nextProps) { 90 shouldComponentUpdate(nextProps) {
82 const { pwdVisible } = this.state; 91 const { pwdVisible } = this.state;
@@ -188,6 +197,116 @@ class PersonCenter extends Component { @@ -188,6 +197,116 @@ class PersonCenter extends Component {
188 dispatch({ type: 'app/addPane', payload: { pane } }); 197 dispatch({ type: 'app/addPane', payload: { pane } });
189 }; 198 };
190 199
  200 +
  201 + // 检查公告数据
  202 + checkNoticeData = async (nextProps = null) => {
  203 + const props = nextProps || this.props;
  204 + const { noticeVisible = false } = this.state;
  205 + const msg = props.app.unRead;
  206 + const { sModelsId, formSrcRoute = '' } = props;
  207 + const msgObj = commonUtils.isJSON(msg) ? JSON.parse(msg) : {};
  208 + const msgData = msgObj.data; /* 推送信息 */
  209 +
  210 + // 如果有公告数据且尚未显示过,则显示公告弹窗
  211 + if (commonUtils.isNotEmptyObject(msgData) && commonUtils.isNotEmptyObject(msgData.COPYTO) &&
  212 + msgData.COPYTO.sMsgId && !noticeVisible) {
  213 + /* 根据sMsgId, sSlaveId 获取接口 */
  214 + // eslint-disable-next-line prefer-destructuring
  215 + const sMsgId = msgData.COPYTO.sMsgId;
  216 + const sMsgSlaveId = msgData.COPYTO.sSlaveId;
  217 + // 1. 在调用接口前先检查是否已经显示过该公告
  218 + const noticeKey = `${sMsgId}_${sMsgSlaveId}`;
  219 +
  220 + const shownNotices = JSON.parse(localStorage.getItem('shownNotices') || '[]');
  221 +
  222 + // 如果已经显示过,直接返回,不调用接口
  223 + if (shownNotices.includes(noticeKey)) {
  224 + console.log('公告已显示过,跳过接口调用:', noticeKey);
  225 + return;
  226 + }
  227 +
  228 + const dataUrl = `${commonConfig.server_host}notice/getNoticeDetail?sModelsId=${sModelsId}&sName=${formSrcRoute}`;
  229 + const condition = {
  230 + sMsgId,
  231 + sSlaveId: sMsgSlaveId,
  232 + };
  233 + const configReturn = (await commonServices.postValueService(props.app?.token, condition, dataUrl)).data;
  234 + if (configReturn?.code === 1) {
  235 + const dataReturn = configReturn.dataset.rows;
  236 +
  237 + if (commonUtils.isNotEmptyArr(dataReturn) && commonUtils.isNotEmptyObject(dataReturn[0])) {
  238 + const noticeData = dataReturn[0];
  239 +
  240 + // 3. 再次确认是否已显示(防止并发请求)
  241 + const currentShownNotices = JSON.parse(localStorage.getItem('shownNotices') || '[]');
  242 + console.log('currentShownNotices1', currentShownNotices);
  243 + if (!currentShownNotices.includes(noticeKey)) {
  244 + this.setState({
  245 + noticeVisible: true,
  246 + noticeData,
  247 + noticeTitle: noticeData?.msgData?.sTitle,
  248 + noticeChecked: false,
  249 + sMsgId,
  250 + sMsgSlaveId,
  251 + });
  252 + }
  253 + }
  254 + }
  255 + }
  256 + }
  257 +
  258 + // 处理公告弹窗确定按钮点击
  259 + handleNoticeConfirm = async () => {
  260 + if (this.state.noticeChecked) {
  261 + /* 调用接口把数据更新为已读 */
  262 + const { app } = this.props;
  263 + const { sMsgId, sMsgSlaveId } = this.state;
  264 +
  265 + const { token } = app;
  266 + const configUrl = `${config.server_host}notice/updateNotice?sModelsId=${100}`;
  267 + const condition = {
  268 + sMsgId,
  269 + sSlaveId: sMsgSlaveId,
  270 + };
  271 + const configReturn = (await commonServices.postValueService(token, condition, configUrl)).data;
  272 + if (configReturn?.code === 1) {
  273 + message.success('公告已阅读');
  274 + // 在用户确认阅读后,才将公告记录存储到shownNotices中
  275 + const noticeKey = `${sMsgId}_${sMsgSlaveId}`;
  276 + const currentShownNotices = JSON.parse(localStorage.getItem('shownNotices') || '[]');
  277 +
  278 + if (!currentShownNotices.includes(noticeKey)) {
  279 + currentShownNotices.push(noticeKey);
  280 + // 限制存储最近100条记录,防止localStorage过大
  281 + if (currentShownNotices.length > 100) {
  282 + currentShownNotices.shift();
  283 + }
  284 + localStorage.setItem('shownNotices', JSON.stringify(currentShownNotices));
  285 + }
  286 + } else {
  287 + message.error(configReturn?.msg);
  288 + }
  289 + this.setState({
  290 + noticeVisible: false,
  291 + });
  292 + }
  293 + }
  294 +
  295 + // 处理公告弹窗取消按钮点击
  296 + handleNoticeCancel = () => {
  297 + this.setState({
  298 + noticeVisible: false,
  299 + });
  300 + }
  301 +
  302 + // 处理复选框变化
  303 + handleNoticeCheckChange = (e) => {
  304 + this.setState({
  305 + noticeChecked: e.target.checked,
  306 + });
  307 + }
  308 +
  309 +
191 handleSubmitPwd = (e) => { 310 handleSubmitPwd = (e) => {
192 /* 阻止表单提交动作 */ 311 /* 阻止表单提交动作 */
193 e.preventDefault(); 312 e.preventDefault();
@@ -618,6 +737,14 @@ class PersonCenter extends Component { @@ -618,6 +737,14 @@ class PersonCenter extends Component {
618 handleCancel={this.handleCancel} 737 handleCancel={this.handleCancel}
619 /> 738 />
620 } 739 }
  740 + {/* 新增公告弹窗组件 */}
  741 + <PersonCenterNotice
  742 + {...props}
  743 + {...state}
  744 + handleNoticeConfirm={this.handleNoticeConfirm}
  745 + handleNoticeCancel={this.handleNoticeCancel}
  746 + handleNoticeCheckChange={this.handleNoticeCheckChange}
  747 + />
621 </div> 748 </div>
622 ); 749 );
623 } 750 }
@@ -894,13 +1021,13 @@ const PersonCenterOnlineUser = Form.create({ @@ -894,13 +1021,13 @@ const PersonCenterOnlineUser = Form.create({
894 const gdsconfigformslaveNew = gdsconfigformslave.map(column => { 1021 const gdsconfigformslaveNew = gdsconfigformslave.map(column => {
895 const { sLanguage } = userinfo || {}; 1022 const { sLanguage } = userinfo || {};
896 let showName = column.sChinese; // 默认中文 1023 let showName = column.sChinese; // 默认中文
897 - 1024 +
898 if (sLanguage === 'sEnglish' && column.sEnglishName) { 1025 if (sLanguage === 'sEnglish' && column.sEnglishName) {
899 showName = column.sEnglishName; 1026 showName = column.sEnglishName;
900 } else if (sLanguage === 'sBig5' && column.sBig5Name) { 1027 } else if (sLanguage === 'sBig5' && column.sBig5Name) {
901 showName = column.sBig5Name; 1028 showName = column.sBig5Name;
902 } 1029 }
903 - 1030 +
904 return { 1031 return {
905 ...column, 1032 ...column,
906 showName 1033 showName
@@ -975,4 +1102,226 @@ const PersonCenterOnlineUser = Form.create({ @@ -975,4 +1102,226 @@ const PersonCenterOnlineUser = Form.create({
975 ); 1102 );
976 }); 1103 });
977 1104
  1105 +// 新增公告弹窗组件
  1106 +const PersonCenterNotice = Form.create({
  1107 + mapPropsToFields(props) {
  1108 + },
  1109 +})((props) => {
  1110 + const {
  1111 + handleNoticeConfirm,
  1112 + handleNoticeCancel,
  1113 + handleNoticeCheckChange,
  1114 + noticeVisible,
  1115 + noticeData = {},
  1116 + noticeChecked,
  1117 + app,
  1118 + } = props;
  1119 +
  1120 + const noticeMsgData = noticeData?.msgData ;
  1121 +
  1122 +
  1123 + const noticeFileData = noticeData?.fileData || [] ;
  1124 +
  1125 +
  1126 + const NoticeTitle = noticeMsgData?.sTitle;
  1127 + const NoticeContent = noticeMsgData?.sAbstractfullmemo || '暂无内容';
  1128 +
  1129 + const Confirm = commonUtils.isNotEmptyObject(commonFunc.showMessage(app.commonConst, 'Confirm'))
  1130 + ? commonFunc.showMessage(app.commonConst, 'Confirm')
  1131 + : '确定';
  1132 + const Cancel = commonUtils.isNotEmptyObject(commonFunc.showMessage(app.commonConst, 'Cancel'))
  1133 + ? commonFunc.showMessage(app.commonConst, 'Cancel')
  1134 + : '取消';
  1135 + const NoticeAgree = commonUtils.isNotEmptyObject(commonFunc.showMessage(app.commonConst, 'NoticeAgree'))
  1136 + ? commonFunc.showMessage(app.commonConst, 'NoticeAgree')
  1137 + : '我已阅读并同意';
  1138 +
  1139 + return (
  1140 + <div>
  1141 + {
  1142 + noticeVisible ?
  1143 + <AntdDraggableModal
  1144 + title={NoticeTitle}
  1145 + width={1200}
  1146 + visible={noticeVisible}
  1147 + onCancel={handleNoticeCancel}
  1148 + closable={false}
  1149 + footer={[
  1150 + // 外层容器控制整体边距和左对齐
  1151 + <div
  1152 + style={{
  1153 + display: 'flex',
  1154 + alignItems: 'center',
  1155 + width: '100%',
  1156 + justifyContent: 'flex-start',
  1157 + padding: '0px 24px 16px 16px',
  1158 + margin: '0', // 清除外部默认边距
  1159 + }}
  1160 + >
  1161 + <Checkbox
  1162 + key="agree"
  1163 + checked={noticeChecked}
  1164 + onChange={handleNoticeCheckChange}
  1165 + style={{
  1166 + marginRight: 16,
  1167 + fontSize: 14,
  1168 + color: '#333',
  1169 + // 确保复选框与按钮垂直居中对齐
  1170 + marginTop: -2
  1171 + }}
  1172 + >
  1173 + {NoticeAgree}
  1174 + </Checkbox>
  1175 + <Button
  1176 + key="confirm"
  1177 + type="primary"
  1178 + onClick={handleNoticeConfirm}
  1179 + disabled={!noticeChecked}
  1180 + style={{
  1181 + padding: '0px 20px', // 增加按钮内边距让文字居中更明显
  1182 + fontSize: 14,
  1183 + borderRadius: 4,
  1184 + transition: 'all 0.2s',
  1185 + opacity: noticeChecked ? 1 : 0.6,
  1186 + cursor: noticeChecked ? 'pointer' : 'not-allowed',
  1187 + // 确保按钮文字垂直居中
  1188 + height: 30,
  1189 + lineHeight: '30px'
  1190 + }}
  1191 + >
  1192 + {Confirm}
  1193 + </Button>
  1194 + </div>
  1195 + ]}
  1196 + >
  1197 + <div style={{
  1198 + maxHeight: '800px',
  1199 + overflowY: 'auto',
  1200 + padding: '20px',
  1201 + border: '1px solid #f0f0f0',
  1202 + borderRadius: '8px',
  1203 + backgroundColor: '#f5f7fa',
  1204 + boxShadow: '0 2px 8px rgba(0, 0, 0, 0.05)'
  1205 + }}>
  1206 + {/* 富文本内容区域 */}
  1207 + {NoticeContent ? (
  1208 + <div style={{
  1209 + backgroundColor: '#fff',
  1210 + borderRadius: '8px',
  1211 + padding: '20px',
  1212 + minHeight: '200px',
  1213 + border: '1px solid #e8e8e8',
  1214 + transition: 'border-color 0.3s'
  1215 + }}>
  1216 + <BraftEditor
  1217 + value={BraftEditor.createEditorState(noticeMsgData?.sAbstractfullmemo)}
  1218 + readOnly
  1219 + controls={[]}
  1220 + contentStyle={{
  1221 + height: 'auto',
  1222 + minHeight: '400px',
  1223 + maxHeight: '600px',
  1224 + lineHeight: '1.8',
  1225 + fontSize: '15px'
  1226 + }}
  1227 + style={{
  1228 + border: 'none',
  1229 + borderRadius: '4px'
  1230 + }}
  1231 + />
  1232 + </div>
  1233 + ) : (
  1234 + <div style={{
  1235 + lineHeight: '1.8',
  1236 + fontSize: '15px',
  1237 + whiteSpace: 'pre-wrap',
  1238 + wordBreak: 'break-word',
  1239 + padding: '20px',
  1240 + backgroundColor: '#fff',
  1241 + border: '1px solid #e8e8e8',
  1242 + borderRadius: '8px',
  1243 + minHeight: '200px',
  1244 + color: '#666',
  1245 + textAlign: 'center'
  1246 + }}>
  1247 + 暂无公告内容
  1248 + </div>
  1249 + )}
  1250 +
  1251 + {/* 附件区域 - 与富文本区域明显分隔 */}
  1252 + {commonUtils.isNotEmptyArr(noticeFileData) && (
  1253 + <div style={{
  1254 + marginTop: '20px',
  1255 + padding: '15px 20px',
  1256 + backgroundColor: '#fff',
  1257 + borderRadius: '8px',
  1258 + border: '1px solid #e8e8e8',
  1259 + }}>
  1260 + <div style={{
  1261 + display: 'flex',
  1262 + alignItems: 'center',
  1263 + flexWrap: 'wrap'
  1264 + }}>
  1265 + {/* 左侧"附件"文字 */}
  1266 + <div style={{
  1267 + fontSize: '14px',
  1268 + color: '#333',
  1269 + fontWeight: 500,
  1270 + marginRight: '15px',
  1271 + padding: '3px 0',
  1272 + minWidth: '50px'
  1273 + }}>
  1274 + 附件:
  1275 + </div>
  1276 +
  1277 + {/* 右侧附件链接区域 */}
  1278 + <div style={{
  1279 + display: 'flex',
  1280 + gap: '16px',
  1281 + flexWrap: 'wrap',
  1282 + flexGrow: 1
  1283 + }}>
  1284 + {noticeFileData.map(item => {
  1285 + const {sId: uid, sFileName: name, sPicturePath} = item;
  1286 + const fileUrl = `${commonConfig.server_host}file/download?savePathStr=${sPicturePath}&sModelsId=100`;
  1287 +
  1288 + return (
  1289 + <a
  1290 + key={uid}
  1291 + href={fileUrl}
  1292 + target="_blank"
  1293 + rel="noopener noreferrer"
  1294 + style={{
  1295 + display: 'inline-flex',
  1296 + alignItems: 'center',
  1297 + color: '#1890ff',
  1298 + fontSize: '14px',
  1299 + textDecoration: 'none',
  1300 + padding: '3px 0',
  1301 + transition: 'color 0.2s',
  1302 + whiteSpace: 'nowrap'
  1303 + }}
  1304 + onMouseOver={(e) => e.currentTarget.style.textDecoration = 'underline'}
  1305 + onMouseOut={(e) => e.currentTarget.style.textDecoration = 'none'}
  1306 + >
  1307 + <span style={{marginRight: '5px'}}>
  1308 + <i className="fa fa-file-o" aria-hidden="true"></i>
  1309 + </span>
  1310 + {name}
  1311 + </a>
  1312 + );
  1313 + })}
  1314 + </div>
  1315 + </div>
  1316 + </div>
  1317 + )}
  1318 + </div>
  1319 +
  1320 + </AntdDraggableModal>
  1321 + : ''
  1322 + }
  1323 + </div>
  1324 + );
  1325 +});
  1326 +
978 export default PersonCenter; 1327 export default PersonCenter;