feat(notice): 添加公告模块功能

- 新增公告相关的API接口定义,包括列表、新增、编辑、删除等功能
- 添加公告管理页面,包含列表展示和新增编辑功能
- 实现公告的富文本编辑器功能和发布范围设置
- 集成企业信息获取接口用于公告发布范围选择
- 完成公告模块的权限控制和数据交互逻辑
master
wangyan 2026-02-06 18:37:55 +08:00
parent 8f947d9f49
commit 14430554b0
6 changed files with 382 additions and 0 deletions

24
src/api/Notice/index.js Normal file
View File

@ -0,0 +1,24 @@
import { declareRequest } from "@cqsjjb/jjb-dva-runtime";
export const noticeList = declareRequest(
"noticeLoading",
"Post > @/appmenu/notice/list",
);
export const noticeAdd = declareRequest(
"noticeLoading",
"Post > @/appmenu/notice/save",
);
export const noticeEdit = declareRequest(
"noticeLoading",
"Put > @/appmenu/notice/edit",
);
export const noticeDelete = declareRequest(
"noticeLoading",
"Delete > @/appmenu/notice/{id}",
);
export const noticeBatchDelete = declareRequest(
"noticeLoading",
"Delete > @/appmenu/notice/ids/{ids}",
);
export const noticeInfo = declareRequest("noticeLoading", "Get > /appmenu/notice/{id}");
export const noticeReadStatus = declareRequest("noticeLoading", "Get > /appmenu/notice/readStatus/{noticeId}");

View File

@ -0,0 +1,6 @@
import { declareRequest } from "@cqsjjb/jjb-dva-runtime";
export const corpInfoListAll = declareRequest(
"corpInfoLoading",
"Get > /basicInfo/corpInfo/listAll",
);

View File

@ -6,3 +6,5 @@ import { defineNamespace } from "@cqsjjb/jjb-dva-runtime";
export const NS_GLOBAL = defineNamespace("global");
export const NS_APP_MENU = defineNamespace("appMenu");
export const NS_NOTICE = defineNamespace("Notice");
export const NS_CORPINFO = defineNamespace("corpInfo");

View File

@ -0,0 +1,150 @@
import { Connect } from "@cqsjjb/jjb-dva-runtime";
import { Button, Form, message } from "antd";
import { useEffect, useState } from "react";
import Editor from "zy-react-library/components/Editor";
import FormBuilder from "zy-react-library/components/FormBuilder";
import Page from "zy-react-library/components/Page";
import { FORM_ITEM_RENDER_ENUM } from "zy-react-library/enum/formItemRender";
import useGetUrlQuery from "zy-react-library/hooks/useGetUrlQuery";
import { NS_CORPINFO, NS_NOTICE } from "~/enumerate/namespace";
function Add(props) {
const queryParams = useGetUrlQuery();
const [form] = Form.useForm();
const [corpData, setCorpData] = useState([]);
const contentValue = Form.useWatch("content", form);
const publishScope = Form.useWatch("publishScope", form);
// 当取消勾选分子公司时清空发布部门ID
useEffect(() => {
if (publishScope && !publishScope.includes("2")) {
form.setFieldValue("deptId", undefined);
}
}, [publishScope]);
useEffect(() => {
if (queryParams["id"]) {
props["noticeInfo"]({ id: queryParams["id"] }).then((res) => {
if (res.data) {
form.setFieldsValue(res.data);
}
});
}
}, []);
useEffect(() => {
props["corpInfoListAll"]({ inType: "0,1,2,6", eqUseFlag: 1 }).then((res) => {
if (res.data) {
res.data.forEach((item) => {
item.bianma = item.id;
item.name = item.corpName;
});
}
setCorpData(res.data);
});
}, []);
const onSubmit = async () => {
try {
await form.validateFields(); // 触发表单校验
}
catch {
return; // 阻止后续逻辑
}
const values = await form.validateFields();
if (queryParams["id"]) {
values.id = queryParams["id"];
props["noticeEdit"](values).then((res) => {
if (res.success) {
message.success("编辑成功!");
window.history.back();
}
});
}
else {
props["noticeAdd"](values).then((res) => {
if (res.success) {
message.success("新增成功!");
window.history.back();
}
});
}
};
return (
<Page
headerTitle={queryParams["id"] ? "编辑" : "新增"}
extraActionButtons={(
<div style={{ textAlign: "center", height: 50, marginTop: 15 }} className="no-print">
<Button
type="primary"
style={{ marginRight: 20 }}
onClick={onSubmit}
loading={props.noticeLoading}
>
提交
</Button>
</div>
)}
>
<FormBuilder
loading={props.noticeLoading}
form={form}
span={24}
showActionButtons={false}
onFinish={onSubmit}
options={[
{ name: "title", label: "公告标题", required: true },
{
name: "publishScope",
label: "通知范围",
required: true,
render: FORM_ITEM_RENDER_ENUM.CHECKBOX,
items: [
{ bianma: "1", name: "股份端" },
{ bianma: "2", name: "分子公司" },
{ bianma: "3", name: "相关方" },
],
},
{
name: "deptId",
label: "选择分子公司",
required: publishScope && publishScope.includes("2"),
hidden: !publishScope || !publishScope.includes("2"),
render: FORM_ITEM_RENDER_ENUM.SELECT,
items: corpData,
componentProps: {
mode: "multiple",
},
},
{
name: "requireReply",
label: "是否需要回复",
required: true,
render: "radio",
items: [{ bianma: "1", name: "是" }, { bianma: "0", name: "否" }],
},
{ name: "publishTime", label: "发布时间", required: true, render: FORM_ITEM_RENDER_ENUM.DATETIME },
{
name: "content",
label: "公告正文",
required: true,
customizeRender: true,
render: (
<Form.Item name="content" label="公告正文" labelCol={{ span: 2 }} wrapperCol={{ span: 22 }} rules={[{ required: true }]}>
<Editor
value={contentValue || ""}
onChange={(value) => {
form.setFieldValue("content", value);
}}
/>
</Form.Item>
),
},
]}
/>
</Page>
);
}
export default Connect([NS_NOTICE, NS_CORPINFO], true)(Add);

View File

@ -0,0 +1,195 @@
import { Permission } from "@cqsjjb/jjb-common-decorator/permission";
import { Connect } from "@cqsjjb/jjb-dva-runtime";
import { Button, Form, message, Modal, Space } from "antd";
import { useState } from "react";
import AddIcon from "zy-react-library/components/Icon/AddIcon";
import Page from "zy-react-library/components/Page";
import Search from "zy-react-library/components/Search/index";
import Table from "zy-react-library/components/Table/index";
import { FORM_ITEM_RENDER_ENUM } from "zy-react-library/enum/formItemRender";
import useTable from "zy-react-library/hooks/useTable";
import { NS_NOTICE } from "~/enumerate/namespace";
function List(props) {
const [form] = Form.useForm();
const [viewModalVisible, setViewModalVisible] = useState(false);
const [currentId, setCurrentId] = useState([]);
const { tableProps, getData } = useTable(props["noticeList"], {
form,
});
// 临时假权限函数,用于开发测试
const _hasPermission = (permissionCode) => {
// 在开发环境中返回true生产环境可以根据实际权限系统调整
const fakePermissions = [
"notice-add",
"notice-edit",
"notice-remove",
];
return fakePermissions.includes(permissionCode);
};
return (
<Page isShowAllAction={false}>
<Search
labelCol={{ span: 6 }}
form={form}
onFinish={getData}
options={[
{ name: "title", label: "公告名称" },
{ name: "deptName", label: "部门名称" },
{
name: "publishScope",
label: "发布范围",
render: FORM_ITEM_RENDER_ENUM.SELECT,
items: [{ bianma: "0", name: "全部" }, { bianma: "1", name: "股份" }, { bianma: "2", name: "分子公司" }, { bianma: "3", name: "相关方" }],
},
]}
/>
<Table
toolBarRender={() => (
<Space>
{_hasPermission("notice-add") && (
<Button
type="primary"
icon={<AddIcon />}
onClick={() => props.history.push(`./Add`)}
>
新增
</Button>
)}
</Space>
)}
columns={[
{ dataIndex: "title", title: "公告名称" },
{ dataIndex: "publishTime", title: "发布时间" },
{ dataIndex: "deptName", title: "发布部门" },
{ dataIndex: "createName", title: "发布人" },
{
dataIndex: "publishScope",
title: "发布范围",
render: (value) => {
if (!value)
return "";
const scopeMap = { 0: "全部", 1: "股份", 2: "分子公司", 3: "相关方" };
return value.split(",").map(code => scopeMap[code.trim()] || code.trim()).join(", ");
},
},
{
dataIndex: "viewStatus",
title: "查看状态",
render: (_, record) => (
<span
style={{ color: "#00BCD4", cursor: "pointer" }}
onClick={() => {
}}
>
{record.readCount || 0}
/
{record.unreadCount || 0}
</span>
),
},
{
title: "操作",
align: "center",
width: 200,
render: (row, record) => (
<Space>
{_hasPermission("notice-edit") && (
<Button
type="link"
onClick={() => props.history.push(`./Add?id=${record.id}`)}
>
编辑
</Button>
)}
{_hasPermission("notice-remove") && (
<Button
type="link"
danger
onClick={() => {
Modal.confirm({
title: "确定删除吗?",
onOk: async () => {
await props["noticeDelete"]({ id: record.id }).then((res) => {
if (res.success) {
message.success("删除成功");
getData();
}
});
},
});
}}
>
删除
</Button>
)}
</Space>
),
},
]}
{...tableProps}
/>
{viewModalVisible && (
<ViewModal
open={viewModalVisible}
loading={props.noticeLoading}
getData={getData}
currentId={currentId}
noticeReadStatus={props["noticeReadStatus"]}
onCancel={() => {
setViewModalVisible(false);
setCurrentId("");
}}
/>
)}
</Page>
);
}
function ViewModalComponent(props) {
const [form] = Form.useForm();
const { tableProps, getData } = useTable(props["noticeReadStatus"], {
form,
});
const onCancel = () => {
form.resetFields();
props.onCancel();
};
return (
<Modal
maskClosable={false}
open={props.open}
title="查看"
width={800}
onOk={form.submit}
onCancel={onCancel}
loading={props.loading}
>
<Search
labelCol={{ span: 2 }}
form={form}
onFinish={getData}
options={[
{ name: "companyName", label: "企业名称" },
{ name: "deptId", label: "是否阅读" },
]}
/>
<Table
columns={[
{ dataIndex: "companyName", title: "企业名称" },
{ dataIndex: "userName", title: "姓名" },
{ dataIndex: "readStatus", title: "阅读状态" },
{ dataIndex: "readTime", title: "阅读时间" },
{ dataIndex: "replyContent", title: "回复内容" },
]}
{...tableProps}
/>
</Modal>
);
}
const ViewModal = ViewModalComponent;
export default Connect([NS_NOTICE], true)(Permission(List));

View File

@ -0,0 +1,5 @@
function AppMenu(props) {
return props.children;
}
export default AppMenu;