diff --git a/Api/Ewide.Core/Service/Notice/SysNoticeService.cs b/Api/Ewide.Core/Service/Notice/SysNoticeService.cs index b182d18..d5312ee 100644 --- a/Api/Ewide.Core/Service/Notice/SysNoticeService.cs +++ b/Api/Ewide.Core/Service/Notice/SysNoticeService.cs @@ -76,16 +76,17 @@ namespace Ewide.Core.Service.Notice if (input.Status != (int)NoticeStatus.DRAFT && input.Status != (int)NoticeStatus.PUBLIC) throw Oops.Oh(ErrorCode.D7000); - var notice = input.Adapt(); + var config = new TypeAdapterConfig().ForType() + .Map(target => target.Attachments, src => String.Join(",", src.Attachments)) + .Config; + var notice = input.Adapt(config); var id = System.Guid.NewGuid().ToString().ToLower(); notice.Id = id; - if (input.Attachments!=null) - notice.Attachments = string.Join(",", input.Attachments); await UpdatePublicInfo(notice); // 如果是发布,则设置发布时间 if (input.Status == (int)NoticeStatus.PUBLIC) notice.PublicTime = DateTime.Now; - var newItem = await notice.InsertAsync(); + await notice.InsertAsync(); // 通知到的人 var noticeUserIdList = input.NoticeUserIdList; diff --git a/Api/Ewide.Core/applicationconfig.json b/Api/Ewide.Core/applicationconfig.json index 78a776a..1aaef5a 100644 --- a/Api/Ewide.Core/applicationconfig.json +++ b/Api/Ewide.Core/applicationconfig.json @@ -98,6 +98,9 @@ "sysUser:updateInfo", "sysUser:updatePwd", "sysUser:updateAvatar", + "sysUser:checkBindcode", + "sysUser:getPwdRule", + "sysUser:sendCode", "sysNotice:received", "sysNotice:unread", "sysNotice:detail", diff --git a/web-react/src/components/index.js b/web-react/src/components/index.js index 43eca8f..ca899f1 100644 --- a/web-react/src/components/index.js +++ b/web-react/src/components/index.js @@ -7,8 +7,9 @@ export { default as ComponentDynamic } from './component-dynamic' export { default as Container } from './container' export { default as IconSelector } from './icon-selector' export { default as Image } from './image' -export { default as ModalForm } from './modal-form' export { default as InputNumberRange } from './form/input-number-range' +export { default as ModalForm } from './modal-form' +export { default as NoticeDetail } from './notice-detail' export { default as PhotoPreview } from './photo-preview' export { default as QueryList } from './query-list' export { default as QueryTable } from './query-table' diff --git a/web-react/src/pages/system/noticeReceived/form.jsx b/web-react/src/components/notice-detail/index.jsx similarity index 63% rename from web-react/src/pages/system/noticeReceived/form.jsx rename to web-react/src/components/notice-detail/index.jsx index 44465b1..d06fbb7 100644 --- a/web-react/src/pages/system/noticeReceived/form.jsx +++ b/web-react/src/components/notice-detail/index.jsx @@ -1,45 +1,34 @@ import React, { Component } from 'react' -import { Spin, Divider, Modal, Row, Form, Upload } from 'antd' -import { api } from 'common/api' +import { Col, Divider, Modal, Row, Spin, Upload } from 'antd' import { AntIcon } from 'components' +import { api } from 'common/api' import { BlobToBase64, GetFileName, PreviewFile } from 'util/file' +import store from 'store' -export default class form extends Component { +const { dispatch } = store + +export default class index extends Component { state = { detailVisible: false, detailLoading: false, detailData: {}, - fileValue: false, + fileList: [], } - filedu = React.createRef() - /** - * mount后回调 - */ - componentDidMount() { - this.props.created && this.props.created(this) - } - - async onOpenDetail(id) { + onOpenDetail = async id => { this.setState({ detailLoading: true, detailVisible: true }) const { data } = await api.sysNoticeDetail({ id }) - this.setState({ - detailLoading: false, - detailData: data, - fileValue: false, - }) - + let fileList = [] if (data) { const { attachments } = data if (attachments) { - const fileValue = [] - const fileList = attachments.split(',') - for (const fileId of fileList) { + const fileIds = attachments.split(',') + for (const fileId of fileIds) { try { const file = await PreviewFile(fileId) const base64 = await BlobToBase64(file) - fileValue.push({ + fileList.push({ uid: fileId, response: fileId, name: file.name, @@ -48,7 +37,7 @@ export default class form extends Component { }) } catch { const { data: file } = await api.sysFileInfoDetail({ id: fileId }) - fileValue.push({ + fileList.push({ uid: fileId, response: '文件已丢失', name: file.fileOriginName, @@ -56,11 +45,23 @@ export default class form extends Component { }) } } - this.setState({ - fileValue, - }) } } + + dispatch({ + type: 'READ_NOTICE', + id, + }) + + this.setState({ + detailLoading: false, + detailData: data, + fileList, + }) + } + + onCloseDetail() { + this.setState({ detailVisible: false, detailData: {}, fileList: [] }) } async onFileDownload(file) { @@ -74,14 +75,16 @@ export default class form extends Component { window.URL.revokeObjectURL(url) a.remove() } + render() { - const { detailLoading, detailVisible, detailData } = this.state + const { detailLoading, detailVisible, detailData, fileList } = this.state + return ( this.setState({ detailVisible: false, detailData: {} })} + onCancel={() => this.onCloseDetail()} > }>
{detailData.title}
@@ -91,21 +94,23 @@ export default class form extends Component { dangerouslySetInnerHTML={{ __html: detailData.content }} > - {this.state.fileValue && ( - - - 查看附件 - this.onFileDownload(file)} - > - - + {!!fileList.length && ( + <> + + 附件 + + this.onFileDownload(file)} + /> + + + + )} - 发布人:{detailData.publicUserName} 发布时间:{detailData.publicTime} diff --git a/web-react/src/pages/system/notice/form.jsx b/web-react/src/pages/system/notice/form.jsx index 13c8fe4..2f12894 100644 --- a/web-react/src/pages/system/notice/form.jsx +++ b/web-react/src/pages/system/notice/form.jsx @@ -78,7 +78,7 @@ export default class form extends Component { }) } } - this.record.Attachments = fileValue + this.record.attachments = fileValue } } //#endregion @@ -94,6 +94,34 @@ export default class form extends Component { //加载 BraftEditor 富文本插件 this.state.funloader() } + + /** + * 获取数据 + * 可以对postData进行数据结构调整 + * [异步,必要] + * @returns + */ + async getData() { + const form = this.form.current + const valid = await form.validateFields() + if (valid) { + const postData = form.getFieldsValue() + if (this.record) { + postData.id = this.record.id + postData.status = 0 + } else { + postData.status = 1 + } + //#region 从前段转换后端所需格式 + postData.attachments = postData.attachments.map(item => + item.uid.startsWith('rc-upload') ? item.response : item.uid + ) + //#endregion + return postData + } + } + + //#region 自定义方法 /** * 接受子组件传过来的方法 * 等页面加载完毕后调用 @@ -131,34 +159,6 @@ export default class form extends Component { window.URL.revokeObjectURL(url) a.remove() } - /** - * 获取数据 - * 可以对postData进行数据结构调整 - * [异步,必要] - * @returns - */ - async getData() { - const form = this.form.current - const valid = await form.validateFields() - if (valid) { - const postData = form.getFieldsValue() - if (this.record) { - postData.id = this.record.id - postData.status = 0 - } else { - postData.status = 1 - } - //#region 从前段转换后端所需格式 - const { Attachments } = postData - for (const key in Attachments) { - Attachments[key] = Attachments[key].response - } - //#endregion - return postData - } - } - - //#region 自定义方法 //#endregion render() { @@ -207,7 +207,7 @@ export default class form extends Component { { if (Array.isArray(e)) { diff --git a/web-react/src/pages/system/notice/index.jsx b/web-react/src/pages/system/notice/index.jsx index 0f43dfa..26cfa4a 100644 --- a/web-react/src/pages/system/notice/index.jsx +++ b/web-react/src/pages/system/notice/index.jsx @@ -20,8 +20,7 @@ const apiAction = { add: api.sysNoticeAdd, edit: api.sysNoticeEdit, delete: api.sysNoticeDelete, - Detail: api.sysNoticeDetail, - Status: api.sysNoticeChangeStatus, + status: api.sysNoticeChangeStatus, } /** @@ -34,7 +33,7 @@ const name = '通知公告' * 统一配置权限标识 * [必要] */ -const authName = '/**/' +const authName = 'sysNotice' export default class index extends Component { state = { @@ -99,7 +98,7 @@ export default class index extends Component { constructor(props) { super(props) - const flag = auth({ [authName]: [['edit'], ['goBack'], ['publish'], ['delete']] }) + const flag = auth({ [authName]: [['edit'], ['changeStatus']] }) if (flag) { this.columns.push({ @@ -111,7 +110,7 @@ export default class index extends Component { {record.status === 1 ? ( , , ( - - this.onOpen(this.editForm, record.id)}>查看 + + this.detail.current.onOpenDetail(record.id)}>查看 ), }) @@ -179,7 +177,7 @@ export default class index extends Component { loadData={this.loadData} columns={this.columns} query={ - + - + ) } diff --git a/web-react/src/store/reducer/index.js b/web-react/src/store/reducer/index.js index 17c4c65..506ebbb 100644 --- a/web-react/src/store/reducer/index.js +++ b/web-react/src/store/reducer/index.js @@ -3,6 +3,7 @@ import user from './user' import layout from './layout' import nav from './nav' import dictData from './dict-data' +import notice from './notice' import business from './business' const combine = combineReducers({ @@ -10,6 +11,7 @@ const combine = combineReducers({ layout, nav, dictData, + notice, business }) diff --git a/web-react/src/store/reducer/notice.js b/web-react/src/store/reducer/notice.js new file mode 100644 index 0000000..eaa4370 --- /dev/null +++ b/web-react/src/store/reducer/notice.js @@ -0,0 +1,40 @@ +const defaultState = { + count: 0, + list: [] +} + +const layout = (state = defaultState, action) => { + switch (action.type) { + case 'SET_NOTICE_COUNT': + { + const _state = { + ...state, + count: action.count + } + return _state + } + case 'SET_NOTICE_LIST': + { + const _state = { + ...state, + list: action.list + } + return _state + } + case 'READ_NOTICE': + { + const notice = state.list.find(p => p.id === action.id) + if (notice && !notice.readStatus) { + notice.readStatus = 1 + state.count -= 1 + } + return { + ...state + } + } + default: + return state + } +} + +export default layout \ No newline at end of file diff --git a/web-react/src/views/main/_layout/header/notice.jsx b/web-react/src/views/main/_layout/header/notice.jsx index 58abf17..37b8dab 100644 --- a/web-react/src/views/main/_layout/header/notice.jsx +++ b/web-react/src/views/main/_layout/header/notice.jsx @@ -1,28 +1,41 @@ import React, { Component } from 'react' -import { Badge, Button, Divider, List, Menu, Modal, Popover, Row, Spin, Upload, Tag } from 'antd' -import { AntIcon, Image } from 'components' +import { Badge, Button, List, Popover, Spin, Tag } from 'antd' +import { AntIcon, Image, NoticeDetail } from 'components' import { api } from 'common/api' import InfiniteScroll from 'react-infinite-scroller' -import { BlobToBase64, GetFileName, PreviewFile } from 'util/file' import moment from 'moment' +import store from 'store' + +const { getState, dispatch, subscribe } = store export default class notice extends Component { state = { - count: 0, - list: [], + ...getState('notice'), loading: false, hasMore: true, + } - detailVisible: false, - detailLoading: false, - detailData: {}, - fileValue: false, + detail = React.createRef() + + constructor(props) { + super(props) + + this.unsubscribe = subscribe('notice', notice => { + this.setState({ ...notice }) + }) } async componentDidMount() { const { data: count } = await api.sysNoticeUnread() - this.setState({ count }) + dispatch({ + type: 'SET_NOTICE_COUNT', + count, + }) + } + + componentWillUnmount() { + this.unsubscribe() } finish() { @@ -48,65 +61,16 @@ export default class notice extends Component { return this.finish() } - this.setState({ + dispatch({ + type: 'SET_NOTICE_LIST', list: [...list, ...items], + }) + + this.setState({ loading: false, }) } - async onOpenDetail(id) { - this.setState({ detailLoading: true, detailVisible: true }) - const { data } = await api.sysNoticeDetail({ id }) - this.setState({ - detailLoading: false, - detailData: data, - fileValue: false, - }) - - if (data) { - const { attachments } = data - if (attachments) { - const fileValue = [] - const fileList = attachments.split(',') - for (const fileId of fileList) { - try { - const file = await PreviewFile(fileId) - const base64 = await BlobToBase64(file) - fileValue.push({ - uid: fileId, - response: fileId, - name: file.name, - url: base64, - status: 'done', - }) - } catch { - const { data: file } = await api.sysFileInfoDetail({ id: fileId }) - fileValue.push({ - uid: fileId, - response: '文件已丢失', - name: file.fileOriginName, - status: 'error', - }) - } - } - this.setState({ - fileValue, - }) - } - } - } - async onFileDownload(file) { - const { data, headers } = await api.sysFileInfoDownload({ id: file.response }) - const url = window.URL.createObjectURL(data) - const fileName = GetFileName(headers['content-disposition']) - const a = document.createElement('a') - a.href = url - a.download = fileName - a.click() - window.URL.revokeObjectURL(url) - a.remove() - } - renderList() { const { list, loading, hasMore } = this.state return ( @@ -125,20 +89,24 @@ export default class notice extends Component { avatar={} title={ <> - this.onOpenDetail(item.id)}> + {item.readStatus ? ( + 已读 + ) : ( + 未读 + )} + + this.detail.current.onOpenDetail(item.id) + } + > {item.title} - - {moment(item.createdTime || item.publicTime).fromNow()} - } description={ - item.readStatus == 0 ? ( - 未读 - ) : ( - 已读 - ) + + {moment(item.createdTime || item.publicTime).fromNow()} + } />
{item.content}
@@ -152,7 +120,13 @@ export default class notice extends Component { )} {!hasMore && ( - )} @@ -161,7 +135,7 @@ export default class notice extends Component { } render() { - const { count, detailLoading, detailVisible, detailData } = this.state + const { count } = this.state return ( - - this.setState({ detailVisible: false, detailData: {} })} - > - }> -
{detailData.title}
- -
- - {this.state.fileValue && ( - - - 查看附件 - this.onFileDownload(file)} - > - - - )} - - - 发布人:{detailData.publicUserName} - 发布时间:{detailData.publicTime} - -
-
+
) }