diff --git a/docs/university.md b/docs/university.md
index 68242f9b3..6fabdcaab 100644
--- a/docs/university.md
+++ b/docs/university.md
@@ -2478,23 +2478,23 @@ jsjxy.hbut.edu.cn 证书链不全,自建 RSSHub 可设置环境变量 NODE_TLS
## 上海大学
-### 上海大学官网信息
+### 官网信息
-| 综合新闻 | 科研动态 | 通知公告 |
-| -------- | -------- | -------- |
-| news | research | notice |
+| 综合新闻 | 科研动态 | 通知公告 | 重要新闻 |
+| -------- | -------- | -------- | --------- |
+| news | research | notice | important |
-### 上海大学教务处通知公告
+### 教务处通知公告
-
+
-| 通知通告 | 新闻 |
-| -------- | ---- |
-| notice | news |
+| 通知通告 | 新闻 | 政策文件 |
+| -------- | ---- | -------- |
+| notice | news | policy |
diff --git a/lib/router.js b/lib/router.js
index a210fdfd0..11524bf96 100644
--- a/lib/router.js
+++ b/lib/router.js
@@ -744,8 +744,9 @@ router.get('/zjut/:type', lazyloadRouteHandler('./routes/universities/zjut/index
router.get('/zjut/design/:type', lazyloadRouteHandler('./routes/universities/zjut/design'));
// 上海大学
-router.get('/shu/:type?', lazyloadRouteHandler('./routes/universities/shu/index'));
-router.get('/shu/jwc/:type?', lazyloadRouteHandler('./routes/universities/shu/jwc'));
+// router.get('/shu/:type?', lazyloadRouteHandler('./routes/universities/shu/index'));
+// router.get('/shu/jwc/:type?', lazyloadRouteHandler('./routes/universities/shu/jwc'));
+// router.get('/shu/jwb/:type?', lazyloadRouteHandler('./routes/universities/shu/jwc'));
// 北京科技大学天津学院
// router.get('/ustb/tj/news/:type?', lazyloadRouteHandler('./routes/universities/ustb/tj/news'));
diff --git a/lib/routes/universities/shu/index.js b/lib/routes/universities/shu/index.js
deleted file mode 100644
index be09c4da6..000000000
--- a/lib/routes/universities/shu/index.js
+++ /dev/null
@@ -1,75 +0,0 @@
-const got = require('@/utils/got');
-const cheerio = require('cheerio');
-const url = require('url');
-
-const host = 'https://www.shu.edu.cn/';
-
-const config = {
- news: {
- link: 'https://www.shu.edu.cn/index/zhxw.htm',
- title: '综合新闻',
- },
- research: {
- link: 'https://www.shu.edu.cn/index/kydt1.htm',
- title: '科研动态',
- },
- notice: {
- link: 'https://www.shu.edu.cn/index/tzgg.htm',
- title: '通知公告',
- },
-};
-
-module.exports = async (ctx) => {
- const type = ctx.params.type ? ctx.params.type : 'news';
- const link = type === 'news' ? config.news.link : type === 'research' ? config.research.link : config.notice.link;
- const title = type === 'news' ? config.news.title : type === 'research' ? config.research.title : config.notice.title;
- const respond = await got.get(link);
- const $ = cheerio.load(respond.data);
- const list = $('.list-con')
- .find('li')
- .slice(0, 10)
- .map((index, ele) => ({
- title: $(ele).find('.list-txt-1').text(),
- link: $(ele).find('a').attr('href'),
- date: $(ele).find('.list-date').text(),
- }))
- .get();
-
- const all = await Promise.all(
- list.map(async (item) => {
- const itemUrl = url.resolve(host, item.link);
- const cache = await ctx.cache.get(itemUrl);
- if (cache) {
- return Promise.resolve(JSON.parse(cache));
- }
- let desc = '';
- const respond = await got.get(itemUrl);
- const $ = cheerio.load(respond.data);
- if (type === 'notice') {
- desc = $('.content-con').text();
- } else {
- desc = $('#vsb_content_2').text();
- if (desc.length > 256) {
- desc = desc.slice(0, 256) + '...';
- }
- }
- const date = new Date(item.date);
- const time_zone = 8;
- const server_offset = date.getTimezoneOffset() / 60;
- const single = {
- title: item.title,
- link: itemUrl,
- pubDate: new Date(date.getTime() - 60 * 60 * 1000 * (time_zone + server_offset)).toUTCString(),
- description: desc || item.title,
- };
- ctx.cache.set(itemUrl, JSON.stringify(single));
- return Promise.resolve(single);
- })
- );
-
- ctx.state.data = {
- title: title + ' - 上海大学',
- link: 'https://www.shu.edu.cn/',
- item: all,
- };
-};
diff --git a/lib/routes/universities/shu/jwc.js b/lib/routes/universities/shu/jwc.js
deleted file mode 100644
index b5fcd3b9e..000000000
--- a/lib/routes/universities/shu/jwc.js
+++ /dev/null
@@ -1,62 +0,0 @@
-const got = require('@/utils/got');
-const cheerio = require('cheerio');
-const url = require('url');
-
-const host = 'http://www.jwc.shu.edu.cn';
-
-const config = {
- notice: {
- link: 'http://www.jwc.shu.edu.cn/nry.jsp?urltype=tree.TreeTempUrl&wbtreeid=1015',
- type: 'notice',
- title: '通知通告',
- },
- news: {
- link: 'http://www.jwc.shu.edu.cn/nry.jsp?urltype=tree.TreeTempUrl&wbtreeid=1016',
- type: 'news',
- title: '新闻',
- },
-};
-
-module.exports = async (ctx) => {
- let type = ctx.params.type;
- type = type ? type : 'notice';
- const link = type === 'news' ? config.news.link : config.notice.link;
- const title = type === 'news' ? config.news.title : config.notice.title;
- const respond = await got.get(link);
- const $ = cheerio.load(respond.data);
- const list = $('#dnn_ctr43516_ArticleList__ctl0_ArtDataList__ctl1_titleLink1')
- .slice(0, 10)
- .map((index, ele) => ({
- title: $(ele).attr('title'),
- link: $(ele).attr('href'),
- date: $('#dnn_ctr43516_ArticleList__ctl0_ArtDataList__ctl1_Label6').text(),
- }))
- .get();
-
- const all = await Promise.all(
- list.map(async (item) => {
- const itemUrl = url.resolve(host, item.link);
- const cache = await ctx.cache.get(itemUrl);
- if (cache) {
- return Promise.resolve(JSON.parse(cache));
- }
- const respond = await got.get(itemUrl);
- const $ = cheerio.load(respond.data);
- const single = {
- title: item.title,
- link: itemUrl,
- author: $('.normal').next().text().trim().slice(0, -3),
- guid: itemUrl,
- pubDate: new Date(new Date(...$('.normal').text().slice(0, 10).split('-')).getTime() - 60 * 60 * 24 * 30 * 1000).toUTCString(),
- description: item.title,
- };
- ctx.cache.set(itemUrl, JSON.stringify(single));
- return Promise.resolve(single);
- })
- );
- ctx.state.data = {
- title: '上海大学教务处--' + title,
- link: 'http://www.jwc.shu.edu.cn/',
- item: all,
- };
-};
diff --git a/lib/v2/shu/index.js b/lib/v2/shu/index.js
new file mode 100644
index 000000000..bef5e95ec
--- /dev/null
+++ b/lib/v2/shu/index.js
@@ -0,0 +1,48 @@
+const got = require('@/utils/got');
+const cheerio = require('cheerio');
+const { parseDate } = require('@/utils/parse-date');
+
+const host = 'https://www.shu.edu.cn/';
+const alias = new Map([
+ ['news', 'zhxw'], // 综合新闻
+ ['research', 'kydt1'], // 科研动态
+ ['kydt', 'kydt1'], // 科研动态
+ ['notice', 'tzgg'], // 通知公告
+ ['important', 'zyxw'], // 重要新闻
+]);
+
+module.exports = async (ctx) => {
+ const type = ctx.params.type || 'news';
+ const link = `https://www.shu.edu.cn/${alias.get(type) || type}.htm`;
+ const respond = await got.get(link);
+ const $ = cheerio.load(respond.data);
+ const title = $('title').text();
+ const list = $('.ej_main .list')
+ .find('li')
+ .slice(0, 5)
+ .toArray()
+ .map((ele) => ({
+ title: $(ele).find('.bt').text(),
+ link: new URL($(ele).find('a').attr('href'), host).href,
+ date: $(ele).find('.sj').text(),
+ }));
+
+ const all = await Promise.all(
+ list.map((item) =>
+ ctx.cache.tryGet(item.link, async () => {
+ const response = await got.get(item.link);
+ const $ = cheerio.load(response.data);
+ item.author = $('.xx>:nth-child(2)').text().trim().slice(3); // 投稿:xxx
+ item.pubDate = parseDate(item.date, 'YYYY.MM.DD');
+ item.description = $('.v_news_content').html() || item.title;
+ return item;
+ })
+ )
+ );
+
+ ctx.state.data = {
+ title,
+ link,
+ item: all,
+ };
+};
diff --git a/lib/v2/shu/jwb.js b/lib/v2/shu/jwb.js
new file mode 100644
index 000000000..803cada7e
--- /dev/null
+++ b/lib/v2/shu/jwb.js
@@ -0,0 +1,45 @@
+const got = require('@/utils/got');
+const cheerio = require('cheerio');
+const { parseDate } = require('@/utils/parse-date');
+
+const host = 'https://jwb.shu.edu.cn/';
+const alias = new Map([
+ ['notice', 'tzgg'], // 通知公告
+ ['news', 'xw'], // 新闻动态
+ ['policy', 'zcwj'], // 政策文件
+]);
+
+module.exports = async (ctx) => {
+ const type = ctx.params.type || 'notice';
+ const link = `https://jwb.shu.edu.cn/index/${alias.get(type) || type}.htm`;
+ const respond = await got.get(link);
+ const $ = cheerio.load(respond.data);
+ const title = $('title').text();
+ const list = $('.only-list')
+ .find('li')
+ .slice(0, 10)
+ .toArray()
+ .map((ele) => ({
+ title: $(ele).find('a').text(),
+ link: new URL($(ele).find('a').attr('href'), host).href,
+ date: $(ele).children('span').text(),
+ }));
+
+ const all = await Promise.all(
+ list.map((item) =>
+ ctx.cache.tryGet(item.link, async () => {
+ const response = await got.get(item.link);
+ const $ = cheerio.load(response.data);
+ item.author = $('[id$=_lblUser]').text().trim();
+ item.pubDate = parseDate(item.date, 'YYYY年MM月DD日');
+ item.description = $('.v_news_content').html() || item.title;
+ return item;
+ })
+ )
+ );
+ ctx.state.data = {
+ title,
+ link,
+ item: all,
+ };
+};
diff --git a/lib/v2/shu/maintainer.js b/lib/v2/shu/maintainer.js
new file mode 100644
index 000000000..060f905c8
--- /dev/null
+++ b/lib/v2/shu/maintainer.js
@@ -0,0 +1,4 @@
+module.exports = {
+ '/:type?': ['lonelyion'],
+ '/jwb/:type?': ['tuxinghuan'],
+};
diff --git a/lib/v2/shu/radar.js b/lib/v2/shu/radar.js
new file mode 100644
index 000000000..7a2d5435a
--- /dev/null
+++ b/lib/v2/shu/radar.js
@@ -0,0 +1,21 @@
+module.exports = {
+ 'shu.edu.cn': {
+ _name: '上海大学',
+ jwb: [
+ {
+ title: '教务处通知公告',
+ docs: 'https://docs.rsshub.app/university.html#shang-hai-da-xue',
+ source: ['/index/:type'],
+ target: '/shu/jwb/:type',
+ },
+ ],
+ www: [
+ {
+ title: '官网信息',
+ docs: 'https://docs.rsshub.app/university.html#shang-hai-da-xue',
+ source: ['/:type'],
+ target: '/shu/:type',
+ },
+ ],
+ },
+};
diff --git a/lib/v2/shu/router.js b/lib/v2/shu/router.js
new file mode 100644
index 000000000..67b07a967
--- /dev/null
+++ b/lib/v2/shu/router.js
@@ -0,0 +1,5 @@
+module.exports = (router) => {
+ router.get('/:type?', require('./index'));
+ router.get('/jwc/:type?', require('./jwb')); // TODO: deprecated, remove this line when someone update this file next time
+ router.get('/jwb/:type?', require('./jwb'));
+};