update 通知公告强化
This commit is contained in:
@@ -76,16 +76,17 @@ namespace Ewide.Core.Service.Notice
|
|||||||
if (input.Status != (int)NoticeStatus.DRAFT && input.Status != (int)NoticeStatus.PUBLIC)
|
if (input.Status != (int)NoticeStatus.DRAFT && input.Status != (int)NoticeStatus.PUBLIC)
|
||||||
throw Oops.Oh(ErrorCode.D7000);
|
throw Oops.Oh(ErrorCode.D7000);
|
||||||
|
|
||||||
var notice = input.Adapt<SysNotice>();
|
var config = new TypeAdapterConfig().ForType<AddNoticeInput, SysNotice>()
|
||||||
|
.Map(target => target.Attachments, src => String.Join(",", src.Attachments))
|
||||||
|
.Config;
|
||||||
|
var notice = input.Adapt<SysNotice>(config);
|
||||||
var id = System.Guid.NewGuid().ToString().ToLower();
|
var id = System.Guid.NewGuid().ToString().ToLower();
|
||||||
notice.Id = id;
|
notice.Id = id;
|
||||||
if (input.Attachments!=null)
|
|
||||||
notice.Attachments = string.Join(",", input.Attachments);
|
|
||||||
await UpdatePublicInfo(notice);
|
await UpdatePublicInfo(notice);
|
||||||
// 如果是发布,则设置发布时间
|
// 如果是发布,则设置发布时间
|
||||||
if (input.Status == (int)NoticeStatus.PUBLIC)
|
if (input.Status == (int)NoticeStatus.PUBLIC)
|
||||||
notice.PublicTime = DateTime.Now;
|
notice.PublicTime = DateTime.Now;
|
||||||
var newItem = await notice.InsertAsync();
|
await notice.InsertAsync();
|
||||||
|
|
||||||
// 通知到的人
|
// 通知到的人
|
||||||
var noticeUserIdList = input.NoticeUserIdList;
|
var noticeUserIdList = input.NoticeUserIdList;
|
||||||
|
|||||||
@@ -98,6 +98,9 @@
|
|||||||
"sysUser:updateInfo",
|
"sysUser:updateInfo",
|
||||||
"sysUser:updatePwd",
|
"sysUser:updatePwd",
|
||||||
"sysUser:updateAvatar",
|
"sysUser:updateAvatar",
|
||||||
|
"sysUser:checkBindcode",
|
||||||
|
"sysUser:getPwdRule",
|
||||||
|
"sysUser:sendCode",
|
||||||
"sysNotice:received",
|
"sysNotice:received",
|
||||||
"sysNotice:unread",
|
"sysNotice:unread",
|
||||||
"sysNotice:detail",
|
"sysNotice:detail",
|
||||||
|
|||||||
@@ -7,8 +7,9 @@ export { default as ComponentDynamic } from './component-dynamic'
|
|||||||
export { default as Container } from './container'
|
export { default as Container } from './container'
|
||||||
export { default as IconSelector } from './icon-selector'
|
export { default as IconSelector } from './icon-selector'
|
||||||
export { default as Image } from './image'
|
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 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 PhotoPreview } from './photo-preview'
|
||||||
export { default as QueryList } from './query-list'
|
export { default as QueryList } from './query-list'
|
||||||
export { default as QueryTable } from './query-table'
|
export { default as QueryTable } from './query-table'
|
||||||
|
|||||||
@@ -1,45 +1,34 @@
|
|||||||
import React, { Component } from 'react'
|
import React, { Component } from 'react'
|
||||||
import { Spin, Divider, Modal, Row, Form, Upload } from 'antd'
|
import { Col, Divider, Modal, Row, Spin, Upload } from 'antd'
|
||||||
import { api } from 'common/api'
|
|
||||||
import { AntIcon } from 'components'
|
import { AntIcon } from 'components'
|
||||||
|
import { api } from 'common/api'
|
||||||
import { BlobToBase64, GetFileName, PreviewFile } from 'util/file'
|
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 = {
|
state = {
|
||||||
detailVisible: false,
|
detailVisible: false,
|
||||||
detailLoading: false,
|
detailLoading: false,
|
||||||
detailData: {},
|
detailData: {},
|
||||||
fileValue: false,
|
fileList: [],
|
||||||
}
|
}
|
||||||
|
|
||||||
filedu = React.createRef()
|
onOpenDetail = async id => {
|
||||||
/**
|
|
||||||
* mount后回调
|
|
||||||
*/
|
|
||||||
componentDidMount() {
|
|
||||||
this.props.created && this.props.created(this)
|
|
||||||
}
|
|
||||||
|
|
||||||
async onOpenDetail(id) {
|
|
||||||
this.setState({ detailLoading: true, detailVisible: true })
|
this.setState({ detailLoading: true, detailVisible: true })
|
||||||
const { data } = await api.sysNoticeDetail({ id })
|
const { data } = await api.sysNoticeDetail({ id })
|
||||||
|
|
||||||
this.setState({
|
let fileList = []
|
||||||
detailLoading: false,
|
|
||||||
detailData: data,
|
|
||||||
fileValue: false,
|
|
||||||
})
|
|
||||||
|
|
||||||
if (data) {
|
if (data) {
|
||||||
const { attachments } = data
|
const { attachments } = data
|
||||||
if (attachments) {
|
if (attachments) {
|
||||||
const fileValue = []
|
const fileIds = attachments.split(',')
|
||||||
const fileList = attachments.split(',')
|
for (const fileId of fileIds) {
|
||||||
for (const fileId of fileList) {
|
|
||||||
try {
|
try {
|
||||||
const file = await PreviewFile(fileId)
|
const file = await PreviewFile(fileId)
|
||||||
const base64 = await BlobToBase64(file)
|
const base64 = await BlobToBase64(file)
|
||||||
fileValue.push({
|
fileList.push({
|
||||||
uid: fileId,
|
uid: fileId,
|
||||||
response: fileId,
|
response: fileId,
|
||||||
name: file.name,
|
name: file.name,
|
||||||
@@ -48,7 +37,7 @@ export default class form extends Component {
|
|||||||
})
|
})
|
||||||
} catch {
|
} catch {
|
||||||
const { data: file } = await api.sysFileInfoDetail({ id: fileId })
|
const { data: file } = await api.sysFileInfoDetail({ id: fileId })
|
||||||
fileValue.push({
|
fileList.push({
|
||||||
uid: fileId,
|
uid: fileId,
|
||||||
response: '文件已丢失',
|
response: '文件已丢失',
|
||||||
name: file.fileOriginName,
|
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) {
|
async onFileDownload(file) {
|
||||||
@@ -74,14 +75,16 @@ export default class form extends Component {
|
|||||||
window.URL.revokeObjectURL(url)
|
window.URL.revokeObjectURL(url)
|
||||||
a.remove()
|
a.remove()
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { detailLoading, detailVisible, detailData } = this.state
|
const { detailLoading, detailVisible, detailData, fileList } = this.state
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Modal
|
<Modal
|
||||||
width={1000}
|
width={1000}
|
||||||
footer={false}
|
footer={false}
|
||||||
visible={detailVisible}
|
visible={detailVisible}
|
||||||
onCancel={() => this.setState({ detailVisible: false, detailData: {} })}
|
onCancel={() => this.onCloseDetail()}
|
||||||
>
|
>
|
||||||
<Spin spinning={detailLoading} indicator={<AntIcon type="loading" />}>
|
<Spin spinning={detailLoading} indicator={<AntIcon type="loading" />}>
|
||||||
<div className="h3 mt-lg">{detailData.title}</div>
|
<div className="h3 mt-lg">{detailData.title}</div>
|
||||||
@@ -91,21 +94,23 @@ export default class form extends Component {
|
|||||||
dangerouslySetInnerHTML={{ __html: detailData.content }}
|
dangerouslySetInnerHTML={{ __html: detailData.content }}
|
||||||
></div>
|
></div>
|
||||||
<Divider />
|
<Divider />
|
||||||
{this.state.fileValue && (
|
{!!fileList.length && (
|
||||||
<Row>
|
<>
|
||||||
<span>
|
<Row align="top">
|
||||||
查看附件
|
<span className="text-gray mt-sm mr-xs">附件</span>
|
||||||
<Upload
|
<Col flex="1">
|
||||||
fileList={this.state.fileValue}
|
<Upload
|
||||||
showUploadList={{
|
fileList={fileList}
|
||||||
showDownloadIcon: true,
|
showUploadList={{
|
||||||
}}
|
showDownloadIcon: true,
|
||||||
onDownload={file => this.onFileDownload(file)}
|
}}
|
||||||
></Upload>
|
onDownload={file => this.onFileDownload(file)}
|
||||||
</span>
|
/>
|
||||||
</Row>
|
</Col>
|
||||||
|
</Row>
|
||||||
|
<Divider />
|
||||||
|
</>
|
||||||
)}
|
)}
|
||||||
<Divider />
|
|
||||||
<Row justify="space-between" className="text-gray">
|
<Row justify="space-between" className="text-gray">
|
||||||
<span>发布人:{detailData.publicUserName}</span>
|
<span>发布人:{detailData.publicUserName}</span>
|
||||||
<span>发布时间:{detailData.publicTime} </span>
|
<span>发布时间:{detailData.publicTime} </span>
|
||||||
@@ -78,7 +78,7 @@ export default class form extends Component {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
this.record.Attachments = fileValue
|
this.record.attachments = fileValue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//#endregion
|
//#endregion
|
||||||
@@ -94,6 +94,34 @@ export default class form extends Component {
|
|||||||
//加载 BraftEditor 富文本插件
|
//加载 BraftEditor 富文本插件
|
||||||
this.state.funloader()
|
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)
|
window.URL.revokeObjectURL(url)
|
||||||
a.remove()
|
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
|
//#endregion
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
@@ -207,7 +207,7 @@ export default class form extends Component {
|
|||||||
</Form.Item>
|
</Form.Item>
|
||||||
<Form.Item
|
<Form.Item
|
||||||
label="上传附件"
|
label="上传附件"
|
||||||
name="Attachments"
|
name="attachments"
|
||||||
valuePropName="fileList"
|
valuePropName="fileList"
|
||||||
getValueFromEvent={e => {
|
getValueFromEvent={e => {
|
||||||
if (Array.isArray(e)) {
|
if (Array.isArray(e)) {
|
||||||
|
|||||||
@@ -20,8 +20,7 @@ const apiAction = {
|
|||||||
add: api.sysNoticeAdd,
|
add: api.sysNoticeAdd,
|
||||||
edit: api.sysNoticeEdit,
|
edit: api.sysNoticeEdit,
|
||||||
delete: api.sysNoticeDelete,
|
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 {
|
export default class index extends Component {
|
||||||
state = {
|
state = {
|
||||||
@@ -99,7 +98,7 @@ export default class index extends Component {
|
|||||||
constructor(props) {
|
constructor(props) {
|
||||||
super(props)
|
super(props)
|
||||||
|
|
||||||
const flag = auth({ [authName]: [['edit'], ['goBack'], ['publish'], ['delete']] })
|
const flag = auth({ [authName]: [['edit'], ['changeStatus']] })
|
||||||
|
|
||||||
if (flag) {
|
if (flag) {
|
||||||
this.columns.push({
|
this.columns.push({
|
||||||
@@ -111,7 +110,7 @@ export default class index extends Component {
|
|||||||
{record.status === 1 ? (
|
{record.status === 1 ? (
|
||||||
<Auth
|
<Auth
|
||||||
key={this.subUniqueKey(record.id, 1)}
|
key={this.subUniqueKey(record.id, 1)}
|
||||||
auth={{ [authName]: 'goBack' }}
|
auth={{ [authName]: 'changeStatus' }}
|
||||||
>
|
>
|
||||||
<Popconfirm
|
<Popconfirm
|
||||||
placement="topRight"
|
placement="topRight"
|
||||||
@@ -133,7 +132,7 @@ export default class index extends Component {
|
|||||||
</Auth>,
|
</Auth>,
|
||||||
<Auth
|
<Auth
|
||||||
key={this.subUniqueKey(record.id, 3)}
|
key={this.subUniqueKey(record.id, 3)}
|
||||||
auth={{ [authName]: 'publish' }}
|
auth={{ [authName]: 'changeStatus' }}
|
||||||
>
|
>
|
||||||
<Popconfirm
|
<Popconfirm
|
||||||
placement="topRight"
|
placement="topRight"
|
||||||
@@ -145,7 +144,7 @@ export default class index extends Component {
|
|||||||
</Auth>,
|
</Auth>,
|
||||||
<Auth
|
<Auth
|
||||||
key={this.subUniqueKey(record.id, 4)}
|
key={this.subUniqueKey(record.id, 4)}
|
||||||
auth={{ [authName]: 'delete' }}
|
auth={{ [authName]: 'changeStatus' }}
|
||||||
>
|
>
|
||||||
<Popconfirm
|
<Popconfirm
|
||||||
placement="topRight"
|
placement="topRight"
|
||||||
@@ -263,21 +262,21 @@ export default class index extends Component {
|
|||||||
* @param {*} id
|
* @param {*} id
|
||||||
*/
|
*/
|
||||||
onDelete(id) {
|
onDelete(id) {
|
||||||
this.onAction(apiAction.Status({ id, status: 3 }), '删除成功')
|
this.onAction(apiAction.status({ id, status: 3 }), '删除成功')
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* 发布
|
* 发布
|
||||||
* @param {*} id
|
* @param {*} id
|
||||||
*/
|
*/
|
||||||
onPublish(id) {
|
onPublish(id) {
|
||||||
this.onAction(apiAction.Status({ id, status: 1 }), '发布成功')
|
this.onAction(apiAction.status({ id, status: 1 }), '发布成功')
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* 撤回
|
* 撤回
|
||||||
* @param {*} id
|
* @param {*} id
|
||||||
*/
|
*/
|
||||||
onGoBack(id) {
|
onGoBack(id) {
|
||||||
this.onAction(apiAction.Status({ id, status: 2 }), '撤回成功')
|
this.onAction(apiAction.status({ id, status: 2 }), '撤回成功')
|
||||||
} //
|
} //
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
|
|||||||
@@ -1,19 +1,18 @@
|
|||||||
import React, { Component } from 'react'
|
import React, { Component } from 'react'
|
||||||
import { Card, Form, message as Message, Input, Select } from 'antd'
|
import { Card, Form, Input, Select } from 'antd'
|
||||||
import { Auth, Container, QueryTable } from 'components'
|
import { Auth, Container, NoticeDetail, QueryTable } from 'components'
|
||||||
import { api } from 'common/api'
|
import { api } from 'common/api'
|
||||||
import auth from 'components/authorized/handler'
|
import auth from 'components/authorized/handler'
|
||||||
import { isEqual } from 'lodash'
|
import { isEqual } from 'lodash'
|
||||||
import getDictData from 'util/dic'
|
import getDictData from 'util/dic'
|
||||||
import { toCamelCase } from 'util/format'
|
import { toCamelCase } from 'util/format'
|
||||||
import FormBody from './form'
|
|
||||||
import { getSearchInfo, QueryType } from 'util/query'
|
import { getSearchInfo, QueryType } from 'util/query'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 统一配置权限标识
|
* 统一配置权限标识
|
||||||
* [必要]
|
* [必要]
|
||||||
*/
|
*/
|
||||||
const authName = '/**/'
|
const authName = 'sysNotice'
|
||||||
|
|
||||||
export default class index extends Component {
|
export default class index extends Component {
|
||||||
state = {
|
state = {
|
||||||
@@ -27,8 +26,7 @@ export default class index extends Component {
|
|||||||
// 表格实例
|
// 表格实例
|
||||||
table = React.createRef()
|
table = React.createRef()
|
||||||
|
|
||||||
// 编辑窗口实例
|
detail = React.createRef()
|
||||||
editForm = React.createRef()
|
|
||||||
|
|
||||||
columns = [
|
columns = [
|
||||||
{
|
{
|
||||||
@@ -75,15 +73,15 @@ export default class index extends Component {
|
|||||||
*/
|
*/
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
super(props)
|
super(props)
|
||||||
const flag = auth({ [authName]: [['show']] })
|
const flag = auth({ [authName]: 'received' })
|
||||||
if (flag) {
|
if (flag) {
|
||||||
this.columns.push({
|
this.columns.push({
|
||||||
title: '操作',
|
title: '操作',
|
||||||
width: 150,
|
width: 150,
|
||||||
dataIndex: 'actions',
|
dataIndex: 'actions',
|
||||||
render: (text, record) => (
|
render: (text, record) => (
|
||||||
<Auth auth={{ [authName]: 'show' }}>
|
<Auth auth={{ [authName]: 'received' }}>
|
||||||
<a onClick={() => this.onOpen(this.editForm, record.id)}>查看</a>
|
<a onClick={() => this.detail.current.onOpenDetail(record.id)}>查看</a>
|
||||||
</Auth>
|
</Auth>
|
||||||
),
|
),
|
||||||
})
|
})
|
||||||
@@ -179,7 +177,7 @@ export default class index extends Component {
|
|||||||
loadData={this.loadData}
|
loadData={this.loadData}
|
||||||
columns={this.columns}
|
columns={this.columns}
|
||||||
query={
|
query={
|
||||||
<Auth auth={{ [authName]: 'page' }}>
|
<Auth auth={{ [authName]: 'received' }}>
|
||||||
<Form.Item label="关键字" name="title">
|
<Form.Item label="关键字" name="title">
|
||||||
<Input
|
<Input
|
||||||
autoComplete="off"
|
autoComplete="off"
|
||||||
@@ -213,7 +211,7 @@ export default class index extends Component {
|
|||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
</Card>
|
</Card>
|
||||||
<FormBody ref={this.editForm} />
|
<NoticeDetail ref={this.detail} />
|
||||||
</Container>
|
</Container>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import user from './user'
|
|||||||
import layout from './layout'
|
import layout from './layout'
|
||||||
import nav from './nav'
|
import nav from './nav'
|
||||||
import dictData from './dict-data'
|
import dictData from './dict-data'
|
||||||
|
import notice from './notice'
|
||||||
import business from './business'
|
import business from './business'
|
||||||
|
|
||||||
const combine = combineReducers({
|
const combine = combineReducers({
|
||||||
@@ -10,6 +11,7 @@ const combine = combineReducers({
|
|||||||
layout,
|
layout,
|
||||||
nav,
|
nav,
|
||||||
dictData,
|
dictData,
|
||||||
|
notice,
|
||||||
business
|
business
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
40
web-react/src/store/reducer/notice.js
Normal file
40
web-react/src/store/reducer/notice.js
Normal file
@@ -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
|
||||||
@@ -1,28 +1,41 @@
|
|||||||
import React, { Component } from 'react'
|
import React, { Component } from 'react'
|
||||||
import { Badge, Button, Divider, List, Menu, Modal, Popover, Row, Spin, Upload, Tag } from 'antd'
|
import { Badge, Button, List, Popover, Spin, Tag } from 'antd'
|
||||||
import { AntIcon, Image } from 'components'
|
import { AntIcon, Image, NoticeDetail } from 'components'
|
||||||
import { api } from 'common/api'
|
import { api } from 'common/api'
|
||||||
import InfiniteScroll from 'react-infinite-scroller'
|
import InfiniteScroll from 'react-infinite-scroller'
|
||||||
import { BlobToBase64, GetFileName, PreviewFile } from 'util/file'
|
|
||||||
import moment from 'moment'
|
import moment from 'moment'
|
||||||
|
import store from 'store'
|
||||||
|
|
||||||
|
const { getState, dispatch, subscribe } = store
|
||||||
|
|
||||||
export default class notice extends Component {
|
export default class notice extends Component {
|
||||||
state = {
|
state = {
|
||||||
count: 0,
|
...getState('notice'),
|
||||||
list: [],
|
|
||||||
|
|
||||||
loading: false,
|
loading: false,
|
||||||
hasMore: true,
|
hasMore: true,
|
||||||
|
}
|
||||||
|
|
||||||
detailVisible: false,
|
detail = React.createRef()
|
||||||
detailLoading: false,
|
|
||||||
detailData: {},
|
constructor(props) {
|
||||||
fileValue: false,
|
super(props)
|
||||||
|
|
||||||
|
this.unsubscribe = subscribe('notice', notice => {
|
||||||
|
this.setState({ ...notice })
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
async componentDidMount() {
|
async componentDidMount() {
|
||||||
const { data: count } = await api.sysNoticeUnread()
|
const { data: count } = await api.sysNoticeUnread()
|
||||||
this.setState({ count })
|
dispatch({
|
||||||
|
type: 'SET_NOTICE_COUNT',
|
||||||
|
count,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
componentWillUnmount() {
|
||||||
|
this.unsubscribe()
|
||||||
}
|
}
|
||||||
|
|
||||||
finish() {
|
finish() {
|
||||||
@@ -48,65 +61,16 @@ export default class notice extends Component {
|
|||||||
return this.finish()
|
return this.finish()
|
||||||
}
|
}
|
||||||
|
|
||||||
this.setState({
|
dispatch({
|
||||||
|
type: 'SET_NOTICE_LIST',
|
||||||
list: [...list, ...items],
|
list: [...list, ...items],
|
||||||
|
})
|
||||||
|
|
||||||
|
this.setState({
|
||||||
loading: false,
|
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() {
|
renderList() {
|
||||||
const { list, loading, hasMore } = this.state
|
const { list, loading, hasMore } = this.state
|
||||||
return (
|
return (
|
||||||
@@ -125,20 +89,24 @@ export default class notice extends Component {
|
|||||||
avatar={<Image id={item.avatar} type="avatar" />}
|
avatar={<Image id={item.avatar} type="avatar" />}
|
||||||
title={
|
title={
|
||||||
<>
|
<>
|
||||||
<a onClick={() => this.onOpenDetail(item.id)}>
|
{item.readStatus ? (
|
||||||
|
<Tag color="#2db7f5">已读</Tag>
|
||||||
|
) : (
|
||||||
|
<Tag color="#f50">未读</Tag>
|
||||||
|
)}
|
||||||
|
<a
|
||||||
|
onClick={() =>
|
||||||
|
this.detail.current.onOpenDetail(item.id)
|
||||||
|
}
|
||||||
|
>
|
||||||
{item.title}
|
{item.title}
|
||||||
</a>
|
</a>
|
||||||
<small className="text-normal ml-xs">
|
|
||||||
{moment(item.createdTime || item.publicTime).fromNow()}
|
|
||||||
</small>
|
|
||||||
</>
|
</>
|
||||||
}
|
}
|
||||||
description={
|
description={
|
||||||
item.readStatus == 0 ? (
|
<span className="text-normal ml-xs">
|
||||||
<Tag color="#f50">未读</Tag>
|
{moment(item.createdTime || item.publicTime).fromNow()}
|
||||||
) : (
|
</span>
|
||||||
<Tag color="#2db7f5">已读</Tag>
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
<div className="ellipsis-3 text-gray">{item.content}</div>
|
<div className="ellipsis-3 text-gray">{item.content}</div>
|
||||||
@@ -152,7 +120,13 @@ export default class notice extends Component {
|
|||||||
)}
|
)}
|
||||||
</List>
|
</List>
|
||||||
{!hasMore && (
|
{!hasMore && (
|
||||||
<Button type="text" block>
|
<Button
|
||||||
|
type="text"
|
||||||
|
block
|
||||||
|
onClick={() =>
|
||||||
|
window.openContentWindowByMenuName('sys_notice_mgr_received')
|
||||||
|
}
|
||||||
|
>
|
||||||
查看全部
|
查看全部
|
||||||
</Button>
|
</Button>
|
||||||
)}
|
)}
|
||||||
@@ -161,7 +135,7 @@ export default class notice extends Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { count, detailLoading, detailVisible, detailData } = this.state
|
const { count } = this.state
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Popover
|
<Popover
|
||||||
@@ -177,42 +151,7 @@ export default class notice extends Component {
|
|||||||
<AntIcon type="message" />
|
<AntIcon type="message" />
|
||||||
</Badge>
|
</Badge>
|
||||||
</span>
|
</span>
|
||||||
|
<NoticeDetail ref={this.detail} />
|
||||||
<Modal
|
|
||||||
width={1000}
|
|
||||||
footer={false}
|
|
||||||
visible={detailVisible}
|
|
||||||
onCancel={() => this.setState({ detailVisible: false, detailData: {} })}
|
|
||||||
>
|
|
||||||
<Spin spinning={detailLoading} indicator={<AntIcon type="loading" />}>
|
|
||||||
<div className="h3 mt-lg">{detailData.title}</div>
|
|
||||||
<Divider />
|
|
||||||
<div
|
|
||||||
className="pt-lg pb-lg"
|
|
||||||
dangerouslySetInnerHTML={{ __html: detailData.content }}
|
|
||||||
></div>
|
|
||||||
<Divider />
|
|
||||||
{this.state.fileValue && (
|
|
||||||
<Row className="text-gray">
|
|
||||||
<span>
|
|
||||||
查看附件
|
|
||||||
<Upload
|
|
||||||
fileList={this.state.fileValue}
|
|
||||||
showUploadList={{
|
|
||||||
showDownloadIcon: true,
|
|
||||||
}}
|
|
||||||
onDownload={file => this.onFileDownload(file)}
|
|
||||||
></Upload>
|
|
||||||
</span>
|
|
||||||
</Row>
|
|
||||||
)}
|
|
||||||
<Divider />
|
|
||||||
<Row justify="space-between" className="text-gray">
|
|
||||||
<span>发布人:{detailData.publicUserName}</span>
|
|
||||||
<span>发布时间:{detailData.publicTime} </span>
|
|
||||||
</Row>
|
|
||||||
</Spin>
|
|
||||||
</Modal>
|
|
||||||
</Popover>
|
</Popover>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user