#P10002. CodeFun2000二次开发教程(二)会员系列(2)专栏页面
-
ID: 21
Type: Default
1000ms
256MiB
Tried: 0
Accepted: 0
Difficulty: (None)
Uploaded By:
TaZi
Tags>塔子哥OJ开发
CodeFun2000二次开发教程(二)会员系列(2)专栏页面
1.B站视频
2.相关文档
2.本节课的代码
index.ts
import {
Context, ForbiddenError, RecordModel, Time , SystemModel , Handler , SettingModel ,
} from 'hydrooj';
//声明全局变量
declare module 'hydrooj' {
// 在SystemKeys中插入一个键,用来代表vip页面的系统设置的名称
interface SystemKeys {
'codefun2000.vip': string;
}
}
//----------------------Handler层:处理前端响应--------------------------
// VIPPageHandler 处理VIPPage整个路由的请求
// koa 框架
class VIPPageHandler extends Handler {
noCheckPermView = true;
async get() {
// 1.获取md内容
let raw = SystemModel.get('codefun2000.vip') || '';
raw = raw.replace(/{{ name }}/g, this.domain.ui?.name || SystemModel.get('server.name')).trim();
const lines = raw.split('\n');
// 定义sections
const sections: { id: string, title: string, content: string }[] = [];
// 一级标题用于区分板块
for (const line of lines) {
// 如果是一级标题
if (line.startsWith('# ')) {
// 获取id
const id = line.split(' ')[1];
// 新建一个sections
sections.push({
id,
title: line.split(id)[1].trim(),
content: '',
});
} else sections[sections.length - 1].content += `${line}\n`;
}
// 给前端传body
this.response.template = 'vip.html';
this.response.body = { sections };
}
}
// vip页面默认内容
// 约定俗成:一级标题用于区分板块 , 并且格式是: id 标题名
const defaultInfo = `
# test1 测试1
这是 VIP 公告。
一级标题用于区分板块。 \`# ID 标题\`
# test2 测试2
支持 Markdown。
`;
var submittedLimit : number = 3;
export async function apply(ctx: Context) {
// -----------第二节课:显示vip页面--------------
// 1.注册路由
// 参数1:路由名称 《vip》
// 参数2:路由路径 《/vip》
// 一一映射的关系。比如说前端要跳转路由,这么写:url('vip') -> xxxx/vip
// 参数3:对应Handler类
// >是处理整个路由的Handler类 前后端交互,用来直接处理前端的post,get等请求
// 参数4:访问该路由需要的权限
// >例如:PRIV.PRIV_EDIT_SYSTEM 代表编辑系统设置的权限
ctx.Route('vip', '/vip', VIPPageHandler);
// 2.插入导航栏
// 参数1:要插入的组件的名称 'Nav'
// 参数2:路由名称:'vip' => url('vip')
// 参数3:插入规则
// 代表放到training_main(路由名称)之前。 view-source:
ctx.inject('Nav', 'vip', { before: 'training_main' });
// 3.定义多国语言
ctx.i18n.load('zh', {
vip: '会员',
});
ctx.i18n.load('en', {
vip: 'VIP',
});
//4.系统设置:会员页面 内容
ctx.using(['setting'], (c: any) => {
// c.setting.SystemSetting() : 往系统设置中加 组件
// SettingModel.Setting() : 初始化一个组件
c.setting.SystemSetting(
// 参数1:?
// 参数2:设置名称
// 参数3:默认内容
// 参数4:文本类型 markdown , txt , password , yaml等 , 看源码
// 参数5:提示文本
SettingModel.Setting('setting_info', 'codefun2000.vip', defaultInfo, 'markdown', 'vip page'),
);
});
// -----------第一节课:限制提交次数--------------
ctx.on('handler/before/ProblemSubmit', async (that) => {
const after = Time.getObjectID(new Date(Date.now() - Time.day));
const submitted = await RecordModel.count('system', {
uid: that.user._id,
input: { $exists: false },
_id: { $gt: after },
});
if (submitted >= submittedLimit && that.user.role !== 'vip') {
throw new ForbiddenError(`非会员每日仅能进行${submittedLimit}次提交。`);
}
});
}
vip.html
{% extends "layout/basic.html" %}
{% block content %}
<div class="row" data-sticky-parent>
<div class="medium-9 columns">
{% set name = handler.domain.ui.name|default(model.system.get('server.name')) %}
{%- for section in sections -%}
<div class="section" data-heading-extract-to="#menu-item-vip">
<div class="section__header">
<h1 class="section__title" id="{{ section.id }}" data-heading>{{ section.title }}</h1>
</div>
<div class="section__body typo">
{{ section.content|markdown|safe }}
</div>
</div>
{%- endfor -%}
</div>
<div class="medium-3 columns"><div data-sticky="large">
<div class="section side">
<ol class="menu">
{{ sidemenu.render_item('info', 'vip') }}
</ol>
</div>
</div></div>
</div>
{% endblock %}
- 湘ICP备2023007293号
- Worker 0, 153ms
- Powered by Hydro v4.14.1 Community
Don't have an account?
By signing up a CodeFun2000 universal account, you can submit code and join discussions in all online judging services provided by us.