Files
shz-backend/sql/news_info.sql
lapuda c1a7aa3532 feat: Add news information management module with API and database support
- Introduced new API endpoints for querying and managing news information in the CMS.
- Implemented data model for NewsInfo and NewsInfoQuery with validation.
- Created NewsInfoMapper for database interactions and corresponding XML mappings.
- Developed INewsInfoService interface and its implementation for business logic.
- Added RichTextSanitizer utility for cleaning HTML content to prevent XSS attacks.
- Created unit tests for RichTextSanitizer to ensure proper functionality.
- Updated database schema with news_info table and necessary fields, including status and module.
- Added migration scripts for setting up the news information module in the database.
- Integrated jsoup library for HTML sanitization.
2026-07-20 14:54:15 +08:00

213 lines
7.9 KiB
PL/PgSQL
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

-- 新闻资讯:数据表、业务字典与 CMS 菜单权限。
-- 执行目标:测试/生产 HighGo 数据库的 shz schema。
-- 可重复执行:表/索引、字典类型/字典项、菜单/按钮均做幂等处理。
BEGIN;
-- 显式创建序列以兼容生产 HighGo生产环境不识别 BIGSERIAL 类型别名)。
CREATE SEQUENCE IF NOT EXISTS "shz"."news_info_id_seq"
START WITH 1 INCREMENT BY 1 NO MINVALUE NO MAXVALUE CACHE 1;
CREATE TABLE IF NOT EXISTS "shz"."news_info" (
"id" BIGINT NOT NULL DEFAULT nextval('shz.news_info_id_seq'::regclass) PRIMARY KEY,
"module" VARCHAR(100) NOT NULL,
"title" VARCHAR(200) NOT NULL,
"content" TEXT NOT NULL,
"status" CHAR(1) NOT NULL DEFAULT '1',
"create_by" VARCHAR(64) NOT NULL DEFAULT '',
"create_time" TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
"update_by" VARCHAR(64) NOT NULL DEFAULT '',
"update_time" TIMESTAMP,
"del_flag" CHAR(1) NOT NULL DEFAULT '0',
"remark" VARCHAR(500) NOT NULL DEFAULT '',
CONSTRAINT "chk_news_info_status" CHECK ("status" IN ('0', '1')),
CONSTRAINT "chk_news_info_del_flag" CHECK ("del_flag" IN ('0', '2'))
);
COMMENT ON TABLE "shz"."news_info" IS '新闻资讯表';
COMMENT ON COLUMN "shz"."news_info"."id" IS '新闻资讯ID';
COMMENT ON COLUMN "shz"."news_info"."module" IS '资讯模块,对应业务字典 news_module 的 dict_value';
COMMENT ON COLUMN "shz"."news_info"."title" IS '标题';
COMMENT ON COLUMN "shz"."news_info"."content" IS '富文本正文经过服务端白名单清理的HTML';
COMMENT ON COLUMN "shz"."news_info"."status" IS '上下架状态0上架 1下架';
COMMENT ON COLUMN "shz"."news_info"."create_by" IS '创建者';
COMMENT ON COLUMN "shz"."news_info"."create_time" IS '创建时间';
COMMENT ON COLUMN "shz"."news_info"."update_by" IS '更新者';
COMMENT ON COLUMN "shz"."news_info"."update_time" IS '更新时间';
COMMENT ON COLUMN "shz"."news_info"."del_flag" IS '删除标志0存在 2删除';
COMMENT ON COLUMN "shz"."news_info"."remark" IS '备注';
CREATE INDEX IF NOT EXISTS "idx_news_info_module"
ON "shz"."news_info" ("module");
CREATE INDEX IF NOT EXISTS "idx_news_info_status_created"
ON "shz"."news_info" ("status", "create_time" DESC)
WHERE "del_flag" = '0';
-- 资讯模块使用“业务字典”,资讯表只保存 dict_value管理员可在现有业务字典页面继续添加模块项。
INSERT INTO "shz"."bussiness_dict_type" (
"dict_id", "dict_name", "dict_type", "status", "create_by", "create_time", "remark"
)
SELECT
(SELECT COALESCE(MAX("dict_id"), 0) + 1 FROM "shz"."bussiness_dict_type"),
'新闻资讯模块',
'news_module',
'0',
'system',
CURRENT_TIMESTAMP,
'新闻资讯模块,资讯表保存 dict_value可在业务字典中扩展'
WHERE NOT EXISTS (
SELECT 1
FROM "shz"."bussiness_dict_type"
WHERE "dict_type" = 'news_module'
);
WITH seed("dict_sort", "dict_label", "dict_value", "list_class", "is_default") AS (
VALUES
(1, '求职资讯', 'job_information', 'primary', 'Y'),
(2, '面试技巧', 'interview_tips', 'success', 'N'),
(3, '简历指南', 'resume_guide', 'warning', 'N'),
(4, '行业指南', 'industry_guide', 'info', 'N'),
(5, '政策法规', 'policy_regulations', 'danger', 'N')
),
new_rows AS (
SELECT
ROW_NUMBER() OVER (ORDER BY seed."dict_sort") AS rn,
seed.*
FROM seed
WHERE NOT EXISTS (
SELECT 1
FROM "shz"."bussiness_dict_data" data
WHERE data."dict_type" = 'news_module'
AND data."dict_value" = seed."dict_value"
)
),
base AS (
SELECT COALESCE(MAX("dict_code"), 0) AS max_code
FROM "shz"."bussiness_dict_data"
)
INSERT INTO "shz"."bussiness_dict_data" (
"dict_code", "dict_sort", "dict_label", "dict_value", "dict_type",
"css_class", "list_class", "is_default", "status", "create_by", "create_time", "remark"
)
SELECT
base.max_code + new_rows.rn,
new_rows."dict_sort",
new_rows."dict_label",
new_rows."dict_value",
'news_module',
NULL,
new_rows."list_class",
new_rows."is_default",
'0',
'system',
CURRENT_TIMESTAMP,
'新闻资讯模块'
FROM new_rows
CROSS JOIN base;
-- CMS 一级目录。
INSERT INTO "shz"."sys_menu" (
"menu_name", "parent_id", "order_num", "path", "component", "query", "route_name",
"is_frame", "is_cache", "menu_type", "visible", "status", "perms", "icon",
"create_by", "create_time", "update_by", "update_time", "remark", "menu_id"
)
SELECT
'新闻资讯', 0, 8, 'news-information', '', '', 'NewsInformation',
1, 0, 'M', '0', '0', '', 'ReadOutlined',
'system', CURRENT_TIMESTAMP, '', NULL, '新闻资讯管理目录', ids."menu_id"
FROM (
SELECT COALESCE(MAX("menu_id"), 0) + 1 AS "menu_id"
FROM "shz"."sys_menu"
) ids
WHERE NOT EXISTS (
SELECT 1
FROM "shz"."sys_menu"
WHERE "parent_id" = 0 AND "path" = 'news-information'
);
-- CMS 资讯管理页面;页面权限同时作为列表权限。
INSERT INTO "shz"."sys_menu" (
"menu_name", "parent_id", "order_num", "path", "component", "query", "route_name",
"is_frame", "is_cache", "menu_type", "visible", "status", "perms", "icon",
"create_by", "create_time", "update_by", "update_time", "remark", "menu_id"
)
SELECT
'资讯管理', parent."menu_id", 1, 'news-info', 'NewsInfo/index', '', 'NewsInfo',
1, 0, 'C', '0', '0', 'cms:newsInfo:list', 'ProfileOutlined',
'system', CURRENT_TIMESTAMP, '', NULL, '新闻资讯管理页面', ids."menu_id"
FROM (
SELECT "menu_id"
FROM "shz"."sys_menu"
WHERE "parent_id" = 0 AND "path" = 'news-information'
ORDER BY "menu_id"
LIMIT 1
) parent
CROSS JOIN (
SELECT COALESCE(MAX("menu_id"), 0) + 1 AS "menu_id"
FROM "shz"."sys_menu"
) ids
WHERE NOT EXISTS (
SELECT 1
FROM "shz"."sys_menu"
WHERE "perms" = 'cms:newsInfo:list'
);
-- 页面按钮权限。
WITH parent AS (
SELECT "menu_id"
FROM "shz"."sys_menu"
WHERE "perms" = 'cms:newsInfo:list'
ORDER BY "menu_id"
LIMIT 1
),
seed("order_num", "menu_name", "perms", "remark") AS (
VALUES
(1, '新闻资讯查询', 'cms:newsInfo:query', '查询新闻资讯详情'),
(2, '新闻资讯新增', 'cms:newsInfo:add', '新增新闻资讯'),
(3, '新闻资讯修改', 'cms:newsInfo:edit', '修改新闻资讯'),
(4, '新闻资讯删除', 'cms:newsInfo:remove', '删除新闻资讯'),
(5, '新闻资讯上下架', 'cms:newsInfo:status', '新闻资讯上架或下架')
),
new_rows AS (
SELECT
ROW_NUMBER() OVER (ORDER BY seed."order_num") AS rn,
seed.*
FROM seed
WHERE NOT EXISTS (
SELECT 1
FROM "shz"."sys_menu" existing
WHERE existing."perms" = seed."perms"
)
),
base AS (
SELECT COALESCE(MAX("menu_id"), 0) AS max_id
FROM "shz"."sys_menu"
)
INSERT INTO "shz"."sys_menu" (
"menu_id", "menu_name", "parent_id", "order_num", "path", "component", "query", "route_name",
"is_frame", "is_cache", "menu_type", "visible", "status", "perms", "icon",
"create_by", "create_time", "update_by", "update_time", "remark"
)
SELECT
base.max_id + new_rows.rn,
new_rows."menu_name",
parent."menu_id",
new_rows."order_num",
'', '', '', '',
1, 0, 'F', '0', '0', new_rows."perms", '#',
'system', CURRENT_TIMESTAMP, '', NULL, new_rows."remark"
FROM new_rows
CROSS JOIN parent
CROSS JOIN base;
COMMIT;
-- 说明:管理员角色通过 *:*:* 自动拥有全部权限;其他角色请在 CMS“角色管理”中按需分配“新闻资讯”。
-- 验证:
-- SELECT column_name, data_type FROM information_schema.columns
-- WHERE table_schema = 'shz' AND table_name = 'news_info' ORDER BY ordinal_position;
-- SELECT dict_label, dict_value FROM shz.bussiness_dict_data
-- WHERE dict_type = 'news_module' ORDER BY dict_sort;
-- SELECT menu_id, menu_name, parent_id, menu_type, perms FROM shz.sys_menu
-- WHERE path = 'news-information' OR perms LIKE 'cms:newsInfo:%' ORDER BY menu_id;