From cc08538bdb72313416ad4a319c00414c0360c557 Mon Sep 17 00:00:00 2001 From: undefined Date: Tue, 25 May 2021 13:30:55 +0800 Subject: [PATCH] =?UTF-8?q?ui:=20=E5=85=81=E8=AE=B8=E8=87=AA=E5=AE=9A?= =?UTF-8?q?=E4=B9=89=E9=A6=96=E9=A1=B5=E5=B8=83=E5=B1=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/hydrooj/locales/zh.yaml | 4 - packages/hydrooj/package.json | 2 +- packages/hydrooj/setting.yaml | 8 + packages/hydrooj/src/handler/home.ts | 85 ++++----- packages/hydrooj/src/model/setting.ts | 4 - packages/ui-default/package.json | 2 +- packages/ui-default/pages/ranking.page.styl | 2 +- packages/ui-default/templates/main.html | 164 +++--------------- .../templates/partials/homepage/contest.html | 40 +++++ .../templates/partials/homepage/homework.html | 42 +++++ .../templates/partials/homepage/ranking.html | 38 ++++ .../templates/partials/homepage/training.html | 45 +++++ 12 files changed, 248 insertions(+), 188 deletions(-) create mode 100644 packages/ui-default/templates/partials/homepage/contest.html create mode 100644 packages/ui-default/templates/partials/homepage/homework.html create mode 100644 packages/ui-default/templates/partials/homepage/ranking.html create mode 100644 packages/ui-default/templates/partials/homepage/training.html diff --git a/packages/hydrooj/locales/zh.yaml b/packages/hydrooj/locales/zh.yaml index 8b60dd97f..54b30c0dc 100644 --- a/packages/hydrooj/locales/zh.yaml +++ b/packages/hydrooj/locales/zh.yaml @@ -156,7 +156,6 @@ contest_edit: 编辑比赛 contest_main: 比赛 contest_scoreboard: 比赛成绩表 Contest: 比赛 -Contests on main: 主页展示的比赛数量 Contests per page: 每页展示的比赛数量 Continue: 继续 Contributed Problems: 贡献的题目 @@ -243,7 +242,6 @@ discussion_edit: 编辑讨论 discussion_main: 讨论 discussion_node: 讨论 Discussion: 讨论 -Discussions on main: 主页展示的讨论数量 Discussions per page: 每页展示的讨论数量 Discussions: 讨论 Display name {1} you want to set is used by others.: 您想要设置的显示名 {1} 已经被其他人使用了。 @@ -367,7 +365,6 @@ homework_main: 作业 homework_scoreboard: 作业成绩表 homework_status: 作业成绩表 Homework: 作业 -Homeworks on main: 主页展示的作业数量 Homeworks per page: 每页展示的作业数量 Host: 主办人 hour(s): 小时 @@ -779,7 +776,6 @@ training_detail: 训练详情 training_edit: 编辑训练 training_main: 训练 Training: 训练 -Trainings on main: 主页展示的训练数量 Trainings per page: 每页展示的训练数量 Type: 类型 UI Language: 用户界面语言 diff --git a/packages/hydrooj/package.json b/packages/hydrooj/package.json index dc4b62fe7..b3c1efff0 100644 --- a/packages/hydrooj/package.json +++ b/packages/hydrooj/package.json @@ -1,6 +1,6 @@ { "name": "hydrooj", - "version": "2.27.0", + "version": "2.27.1", "bin": "bin/hydrooj.js", "main": "dist/loader.js", "typings": "dist/loader.d.ts", diff --git a/packages/hydrooj/setting.yaml b/packages/hydrooj/setting.yaml index 88bbfac6a..c6c4309f7 100644 --- a/packages/hydrooj/setting.yaml +++ b/packages/hydrooj/setting.yaml @@ -1,3 +1,11 @@ +homepage: + type: yaml + desc: Homepage Config + default: + contest: 5 + homework: 10 + training: 10 + discussion: 20 langs: type: yaml desc: Code language settings diff --git a/packages/hydrooj/src/handler/home.ts b/packages/hydrooj/src/handler/home.ts index bb48bd38b..c80c329ba 100644 --- a/packages/hydrooj/src/handler/home.ts +++ b/packages/hydrooj/src/handler/home.ts @@ -30,85 +30,90 @@ import BlackListModel from '../model/blacklist'; const { geoip, useragent } = global.Hydro.lib; class HomeHandler extends Handler { - async homework(domainId: string) { + uids = new Set(); + + collectUser(uids: number[]) { + uids.forEach((uid) => this.uids.add(uid)); + } + + async getHomework(domainId: string, limit: number = 5) { if (this.user.hasPerm(PERM.PERM_VIEW_HOMEWORK)) { const tdocs = await contest.getMulti(domainId, {}, document.TYPE_HOMEWORK) - .sort('beginAt', -1) - .limit(system.get('pagination.homework_main')) - .toArray(); + .sort('beginAt', -1).limit(limit).toArray(); const tsdict = await contest.getListStatus( domainId, this.user._id, tdocs.map((tdoc) => tdoc.docId), document.TYPE_HOMEWORK, ); - return [tdocs, tsdict]; + return ['homework', tdocs, tsdict]; } - return [[], {}]; + return ['homework', [], {}]; } - async contest(domainId: string) { + async getContest(domainId: string, limit: number = 10) { if (this.user.hasPerm(PERM.PERM_VIEW_CONTEST)) { const tdocs = await contest.getMulti(domainId) - .sort('beginAt', -1) - .limit(system.get('pagination.contest_main')) - .toArray(); + .sort('beginAt', -1).limit(limit).toArray(); const tsdict = await contest.getListStatus( domainId, this.user._id, tdocs.map((tdoc) => tdoc.docId), ); - return [tdocs, tsdict]; + return ['contest', tdocs, tsdict]; } - return [[], {}]; + return ['contest', [], {}]; } - async training(domainId: string) { + async getTraining(domainId: string, limit: number = 10) { if (this.user.hasPerm(PERM.PERM_VIEW_TRAINING)) { const tdocs = await training.getMulti(domainId) - .sort('_id', 1) - .limit(system.get('pagination.training_main')) - .toArray(); + .sort('_id', 1).limit(limit).toArray(); const tsdict = await training.getListStatus( domainId, this.user._id, tdocs.map((tdoc) => tdoc.docId), ); - return [tdocs, tsdict]; + return ['training', tdocs, tsdict]; } - return [[], {}]; + return ['training', [], {}]; } - async discussion(domainId: string): Promise<[any[], any]> { + async getDiscussion(domainId: string, limit: number = 20) { if (this.user.hasPerm(PERM.PERM_VIEW_DISCUSSION)) { - const ddocs = await discussion.getMulti(domainId) - .limit(system.get('pagination.discussion_main')) - .toArray(); + const ddocs = await discussion.getMulti(domainId).limit(limit).toArray(); const vndict = await discussion.getListVnodes( domainId, ddocs, this.user.hasPerm(PERM.PERM_VIEW_PROBLEM_HIDDEN), ); - return [ddocs, vndict]; + this.collectUser(ddocs.map((ddoc) => ddoc.owner)); + return ['discussion', ddocs, vndict]; } - return [[], {}]; + return ['discussion', [], {}]; + } + + async getRanking(domainId: string, limit: number = 50) { + if (this.user.hasPerm(PERM.PERM_VIEW_RANKING)) { + const dudocs = await domain.getMultiUserInDomain(domainId) + .sort({ rp: -1 }).project({ uid: 1 }).limit(limit).toArray(); + const uids = dudocs.map((dudoc) => dudoc.uid); + this.collectUser(uids); + return ['ranking', uids]; + } + return ['ranking', []]; } async get({ domainId }) { - const [ - [htdocs, htsdict], [tdocs, tsdict], - [trdocs, trsdict], [ddocs, vndict], - ] = await Promise.all([ - this.homework(domainId), this.contest(domainId), - this.training(domainId), this.discussion(domainId), - ]); + const homepageConfig = system.get('hydrooj.homepage'); + const tasks = []; + const info = yaml.load(homepageConfig) as any; + for (const key in info) { + const func = `get${key.replace(/^[a-z]/, (i) => i.toUpperCase())}`; + if (!this[func]) continue; + tasks.push(this[func](domainId, +info[key])); + } + const contents = await Promise.all(tasks); const [udict, dodoc, vnodes] = await Promise.all([ - user.getList(domainId, ddocs.map((ddoc) => ddoc.owner)), + user.getList(domainId, Array.from(this.uids)), domain.get(domainId), discussion.getNodes(domainId), ]); this.response.template = 'main.html'; this.response.body = { - htdocs, - htsdict, - tdocs, - tsdict, - trdocs, - trsdict, - ddocs, - vndict, + contents, udict, domain: dodoc, vnodes, diff --git a/packages/hydrooj/src/model/setting.ts b/packages/hydrooj/src/model/setting.ts index 375f4988f..e09bc1031 100644 --- a/packages/hydrooj/src/model/setting.ts +++ b/packages/hydrooj/src/model/setting.ts @@ -191,10 +191,6 @@ SystemSetting( Setting('setting_basic', 'pagination.solution', 20, 'number', 'pagination.solution', 'Solutions per page'), Setting('setting_basic', 'pagination.training', 10, 'number', 'pagination.training', 'Trainings per page'), Setting('setting_basic', 'pagination.reply', 50, 'number', 'pagination.reply', 'Replies per page'), - Setting('setting_basic', 'pagination.homework_main', 5, 'number', 'pagination.homework_main', 'Homeworks on main'), - Setting('setting_basic', 'pagination.contest_main', 10, 'number', 'pagination.contest_main', 'Contests on main'), - Setting('setting_basic', 'pagination.training_main', 10, 'number', 'pagination.training_main', 'Trainings on main'), - Setting('setting_basic', 'pagination.discussion_main', 20, 'number', 'pagination.discussion_main', 'Discussions on main'), Setting('setting_session', 'session.keys', [String.random(32)], 'text', 'session.keys', 'session.keys', FLAG_HIDDEN), Setting('setting_session', 'session.secure', false, 'boolean', 'session.secure', 'session.secure'), Setting('setting_session', 'session.saved_expire_seconds', 3600 * 24 * 30, diff --git a/packages/ui-default/package.json b/packages/ui-default/package.json index 74fad88cd..67469558a 100644 --- a/packages/ui-default/package.json +++ b/packages/ui-default/package.json @@ -1,6 +1,6 @@ { "name": "@hydrooj/ui-default", - "version": "4.9.0", + "version": "4.9.1", "author": "undefined ", "license": "AGPL-3.0", "main": "hydro.js", diff --git a/packages/ui-default/pages/ranking.page.styl b/packages/ui-default/pages/ranking.page.styl index 2271bdafb..9f2cf23f6 100644 --- a/packages/ui-default/pages/ranking.page.styl +++ b/packages/ui-default/pages/ranking.page.styl @@ -1,4 +1,4 @@ -.page--ranking +.page--ranking, .page--homepage .col--rank width: rem(70px) position: relative diff --git a/packages/ui-default/templates/main.html b/packages/ui-default/templates/main.html index 32eccc365..0459f0cfb 100644 --- a/packages/ui-default/templates/main.html +++ b/packages/ui-default/templates/main.html @@ -16,145 +16,35 @@ {% endif %}
- {% if tdocs.length %} -
-
-

{{ _('Contest') }}

-
-
    - {%- for tdoc in tdocs -%} -
  1. -
    -
    -
    -
    {{ datetimeSpan(tdoc['beginAt'], false, '%d')|safe }}
    -
    {{ datetimeSpan(tdoc['beginAt'], false, '%Y-%m')|safe }}
    -
    -
    -
    -

    {{ tdoc.title }}

    -
      -
    • - {{ model.contest.RULES[tdoc.rule].TEXT }} -
    • -
    • - {{ contest.render_duration(tdoc) }} {{ _('hour(s)') }} -
    • -
    • - {{ tdoc['attend']|default(0) }} -
    • - {% if tsdict[tdoc.docId]['attend'] == 1 %} -
    • - {{ _('Attended') }} -
    • - {% endif %} -
    + {% for node in contents %} + {% if node[0] == 'contest' %} + {% set tdocs = node[1] %} + {% set tsdict = node[2] %} + {% include "partials/homepage/contest.html" %} + {% elif node[0] == 'homework' %} + {% set htdocs = node[1] %} + {% set htsdict = node[2] %} + {% include "partials/homepage/homework.html" %} + {% elif node[0] == 'training' %} + {% set tdocs = node[1] %} + {% set tsdict = node[2] %} + {% include "partials/homepage/training.html" %} + {% elif node[0] == 'ranking' %} + {% set uids = node[1] %} + {% include "partials/homepage/ranking.html" %} + {% elif node[0] == 'discussion' %} + {% set ddocs = node[1] %} + {% set vndict = node[2] %} + {% if ddocs.length %} +
    +
    +

    {{ _('Discussion') }}

    + {% include "partials/discussion_list.html" %}
    -
  2. - {%- endfor -%} -
-
- {% endif %} - {% if htdocs.length %} -
-
-

{{ _('Homework') }}

-
-
    - {%- for tdoc in htdocs -%} -
  1. -
    -
    -
    -
    {{ datetimeSpan(tdoc['penaltySince'], false, '%d')|safe }}
    -
    {{ datetimeSpan(tdoc['penaltySince'], false, '%Y-%m')|safe }}
    -
    -
    -
    -

    {{ tdoc['title'] }}

    -
      -
    • - {{ _('Status') }}: {{ _(model.contest.statusText(tdoc)) }} -
    • -
    • - {{ _('Open Since') }}: {{ datetimeSpan(tdoc['beginAt'])|safe }} -
    • -
    • - {% if model.contest.isExtended(tdoc) or model.contest.isDone(tdoc) %} - {{ _('Hard Deadline') }}: {{ datetimeSpan(tdoc['endAt'])|safe }} - {% else %} - {{ _('Deadline') }}: {{ datetimeSpan(tdoc['penaltySince'])|safe }} - {% endif %} -
    • - {% if htsdict[tdoc['docId']]['attend'] == 1 %} -
    • - {{ _('Claimed') }} -
    • - {% endif %} -
    -
    -
    -
  2. - {%- endfor -%} -
-
- {% endif %} - {% if trdocs.length %} -
-
-

{{ _('Training') }}

-
- {% set tdocs = trdocs %} - {% set tsdict = trsdict %} -
    - {%- for tdoc in tdocs -%} -
  1. -
    -
    -
    -
    {{ tdoc['enroll']|default(0) }}
    -
    {{ _('Enrolled') }}
    -
    -
    -
    -

    {{ tdoc.title }}

    -
    -

    {{ tdoc['content'] }}

    -
    -
      -
    • - {{ _('{0} sections').format(tdoc['dag']|length) }}, {{ _('{0} problems').format(model.training.getPids(tdoc.dag)|length) }} -
    • -
    • - {% if tsdict[tdoc.docId]['enroll'] %} - {% if not tsdict[tdoc.docId]['done'] %} - - {{ _('Completed') }} {{ (100 * tsdict[tdoc.docId]['donePids']|length / model.training.getPids(tdoc.dag)|length)|round|int }}% - {% else %} - - {{ _('Completed') }} 100% - {% endif %} - {% elif handler.user.hasPriv(PRIV.PRIV_USER_PROFILE) %} - {{ _('Not Enrolled') }} - {% endif %} -
    • -
    -
    -
    -
  2. - {%- endfor -%} -
-
- {% endif %} - {% if ddocs.length %} -
-
-

{{ _('Discussion') }}

-
- {% include "partials/discussion_list.html" %} -
- {% endif %} + {% endif %} + {% endif %} + {% endfor %}
diff --git a/packages/ui-default/templates/partials/homepage/contest.html b/packages/ui-default/templates/partials/homepage/contest.html new file mode 100644 index 000000000..765b01f80 --- /dev/null +++ b/packages/ui-default/templates/partials/homepage/contest.html @@ -0,0 +1,40 @@ +{% if tdocs.length %} +
+
+

{{ _('Contest') }}

+
+
    + {%- for tdoc in tdocs -%} +
  1. +
    +
    +
    +
    {{ datetimeSpan(tdoc['beginAt'], false, '%d')|safe }}
    +
    {{ datetimeSpan(tdoc['beginAt'], false, '%Y-%m')|safe }}
    +
    +
    +
    +

    {{ tdoc.title }}

    +
      +
    • + {{ model.contest.RULES[tdoc.rule].TEXT }} +
    • +
    • + {{ contest.render_duration(tdoc) }} {{ _('hour(s)') }} +
    • +
    • + {{ tdoc['attend']|default(0) }} +
    • + {% if tsdict[tdoc.docId]['attend'] == 1 %} +
    • + {{ _('Attended') }} +
    • + {% endif %} +
    +
    +
    +
  2. + {%- endfor -%} +
+
+{% endif %} \ No newline at end of file diff --git a/packages/ui-default/templates/partials/homepage/homework.html b/packages/ui-default/templates/partials/homepage/homework.html new file mode 100644 index 000000000..523e26f20 --- /dev/null +++ b/packages/ui-default/templates/partials/homepage/homework.html @@ -0,0 +1,42 @@ +{% if htdocs.length %} +
+
+

{{ _('Homework') }}

+
+
    + {%- for tdoc in htdocs -%} +
  1. +
    +
    +
    +
    {{ datetimeSpan(tdoc['penaltySince'], false, '%d')|safe }}
    +
    {{ datetimeSpan(tdoc['penaltySince'], false, '%Y-%m')|safe }}
    +
    +
    +
    +

    {{ tdoc['title'] }}

    +
      +
    • + {{ _('Status') }}: {{ _(model.contest.statusText(tdoc)) }} +
    • +
    • {{ _('Open Since') }}: {{ datetimeSpan(tdoc['beginAt'])|safe }}
    • +
    • + {% if model.contest.isExtended(tdoc) or model.contest.isDone(tdoc) %} + {{ _('Hard Deadline') }}: {{ datetimeSpan(tdoc['endAt'])|safe }} + {% else %} + {{ _('Deadline') }}: {{ datetimeSpan(tdoc['penaltySince'])|safe }} + {% endif %} +
    • + {% if htsdict[tdoc['docId']]['attend'] == 1 %} +
    • + {{ _('Claimed') }} +
    • + {% endif %} +
    +
    +
    +
  2. + {%- endfor -%} +
+
+{% endif %} \ No newline at end of file diff --git a/packages/ui-default/templates/partials/homepage/ranking.html b/packages/ui-default/templates/partials/homepage/ranking.html new file mode 100644 index 000000000..9e15044cd --- /dev/null +++ b/packages/ui-default/templates/partials/homepage/ranking.html @@ -0,0 +1,38 @@ +{% if uids.length %} +
+
+

{{ _('Ranking') }}

+
+
+
+ + + + + + + + + + + + + + + + + {%- for uid in uids -%} + {% set udoc = udict[uid] %} + + + + + + + {%- endfor -%} + +
{{ _('Rank') }}{{ _('Username') }}{{ _('RP') }}{{ _('Bio') }}
{{ loop.index }}{{ user.render_inline(udoc) }}{{ udoc.rp|default(1500)|round(0) }}{{ udoc.bio|default('')|truncate(64, true)|markdownInline|safe }}
+
+
+
+{% endif %} \ No newline at end of file diff --git a/packages/ui-default/templates/partials/homepage/training.html b/packages/ui-default/templates/partials/homepage/training.html new file mode 100644 index 000000000..c4a05bdb1 --- /dev/null +++ b/packages/ui-default/templates/partials/homepage/training.html @@ -0,0 +1,45 @@ +{% if trdocs.length %} +
+
+

{{ _('Training') }}

+
+
    + {%- for tdoc in tdocs -%} +
  1. +
    +
    +
    +
    {{ tdoc['enroll']|default(0) }}
    +
    {{ _('Enrolled') }}
    +
    +
    +
    +

    {{ tdoc.title }}

    +
    +

    {{ tdoc['content'] }}

    +
    +
      +
    • + {{ _('{0} sections').format(tdoc['dag']|length) }}, {{ _('{0} problems').format(model.training.getPids(tdoc.dag)|length) }} +
    • +
    • + {% if tsdict[tdoc.docId]['enroll'] %} + {% if not tsdict[tdoc.docId]['done'] %} + + {{ _('Completed') }} {{ (100 * tsdict[tdoc.docId]['donePids']|length / model.training.getPids(tdoc.dag)|length)|round|int }}% + {% else %} + + {{ _('Completed') }} 100% + {% endif %} + {% elif handler.user.hasPriv(PRIV.PRIV_USER_PROFILE) %} + {{ _('Not Enrolled') }} + {% endif %} +
    • +
    +
    +
    +
  2. + {%- endfor -%} +
+
+{% endif %} \ No newline at end of file