29 changed files with 1658 additions and 36 deletions
@ -0,0 +1,68 @@ |
|||||||
|
"use strict"; |
||||||
|
var __extends = (this && this.__extends) || (function () { |
||||||
|
var extendStatics = function (d, b) { |
||||||
|
extendStatics = Object.setPrototypeOf || |
||||||
|
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || |
||||||
|
function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; }; |
||||||
|
return extendStatics(d, b); |
||||||
|
}; |
||||||
|
return function (d, b) { |
||||||
|
extendStatics(d, b); |
||||||
|
function __() { this.constructor = d; } |
||||||
|
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); |
||||||
|
}; |
||||||
|
})(); |
||||||
|
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) { |
||||||
|
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; |
||||||
|
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); |
||||||
|
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; |
||||||
|
return c > 3 && r && Object.defineProperty(target, key, r), r; |
||||||
|
}; |
||||||
|
var __metadata = (this && this.__metadata) || function (k, v) { |
||||||
|
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v); |
||||||
|
}; |
||||||
|
exports.__esModule = true; |
||||||
|
var TypeORM = require("typeorm"); |
||||||
|
var common_1 = require("./common"); |
||||||
|
var Classify = /** @class */ (function (_super) { |
||||||
|
__extends(Classify, _super); |
||||||
|
function Classify() { |
||||||
|
return _super !== null && _super.apply(this, arguments) || this; |
||||||
|
} |
||||||
|
Classify.cache = true; |
||||||
|
__decorate([ |
||||||
|
TypeORM.PrimaryGeneratedColumn(), |
||||||
|
__metadata("design:type", Number) |
||||||
|
], Classify.prototype, "id"); |
||||||
|
__decorate([ |
||||||
|
TypeORM.Index({ unique: true }), |
||||||
|
TypeORM.Column({ unique: true, nullable: true, type: "varchar", length: 20 }), |
||||||
|
__metadata("design:type", String) |
||||||
|
], Classify.prototype, "name"); |
||||||
|
__decorate([ |
||||||
|
TypeORM.Column({ nullable: true, type: "varchar", length: 100 }), |
||||||
|
__metadata("design:type", String) |
||||||
|
], Classify.prototype, "intro"); |
||||||
|
__decorate([ |
||||||
|
TypeORM.Column({ type: "integer" }), |
||||||
|
__metadata("design:type", Number) |
||||||
|
], Classify.prototype, "problem_num"); |
||||||
|
__decorate([ |
||||||
|
TypeORM.Column({ type: "integer" }), |
||||||
|
__metadata("design:type", Number) |
||||||
|
], Classify.prototype, "order"); |
||||||
|
__decorate([ |
||||||
|
TypeORM.Column({ nullable: true, type: "integer" }), |
||||||
|
__metadata("design:type", Number) |
||||||
|
], Classify.prototype, "update_time"); |
||||||
|
__decorate([ |
||||||
|
TypeORM.Column({ nullable: true, type: "integer" }), |
||||||
|
__metadata("design:type", Number) |
||||||
|
], Classify.prototype, "create_time"); |
||||||
|
Classify = __decorate([ |
||||||
|
TypeORM.Entity() |
||||||
|
], Classify); |
||||||
|
return Classify; |
||||||
|
}(common_1["default"])); |
||||||
|
exports["default"] = Classify; |
||||||
|
//# sourceMappingURL=classify.js.map
|
@ -0,0 +1 @@ |
|||||||
|
{"version":3,"file":"classify.js","sourceRoot":"","sources":["../models/classify.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;AAAA,iCAAmC;AACnC,mCAA6B;AAM7B;IAAsC,4BAAK;IAA3C;;IAwBA,CAAC;IAvBU,cAAK,GAAG,IAAI,CAAC;IAGpB;QADC,OAAO,CAAC,sBAAsB,EAAE;;gCACtB;IAIX;QAFC,OAAO,CAAC,KAAK,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC;QAC/B,OAAO,CAAC,MAAM,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,IAAI,EAAE,SAAS,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC;;kCACjE;IAGb;QADC,OAAO,CAAC,MAAM,CAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,IAAI,EAAE,SAAS,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC;;mCACnD;IAGd;QADC,OAAO,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC;;yCAChB;IAGpB;QADC,OAAO,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC;;mCACtB;IAGd;QADC,OAAO,CAAC,MAAM,CAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC;;yCAChC;IAGpB;QADC,OAAO,CAAC,MAAM,CAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC;;yCAChC;IAvBH,QAAQ;QAD5B,OAAO,CAAC,MAAM,EAAE;OACI,QAAQ,CAwB5B;IAAD,eAAC;CAAA,AAxBD,CAAsC,mBAAK,GAwB1C;qBAxBoB,QAAQ"} |
@ -0,0 +1,53 @@ |
|||||||
|
"use strict"; |
||||||
|
var __extends = (this && this.__extends) || (function () { |
||||||
|
var extendStatics = function (d, b) { |
||||||
|
extendStatics = Object.setPrototypeOf || |
||||||
|
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || |
||||||
|
function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; }; |
||||||
|
return extendStatics(d, b); |
||||||
|
}; |
||||||
|
return function (d, b) { |
||||||
|
extendStatics(d, b); |
||||||
|
function __() { this.constructor = d; } |
||||||
|
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); |
||||||
|
}; |
||||||
|
})(); |
||||||
|
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) { |
||||||
|
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; |
||||||
|
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); |
||||||
|
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; |
||||||
|
return c > 3 && r && Object.defineProperty(target, key, r), r; |
||||||
|
}; |
||||||
|
var __metadata = (this && this.__metadata) || function (k, v) { |
||||||
|
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v); |
||||||
|
}; |
||||||
|
exports.__esModule = true; |
||||||
|
var TypeORM = require("typeorm"); |
||||||
|
var common_1 = require("./common"); |
||||||
|
var ClassifyToProblem = /** @class */ (function (_super) { |
||||||
|
__extends(ClassifyToProblem, _super); |
||||||
|
function ClassifyToProblem() { |
||||||
|
return _super !== null && _super.apply(this, arguments) || this; |
||||||
|
} |
||||||
|
ClassifyToProblem.cache = true; |
||||||
|
__decorate([ |
||||||
|
TypeORM.PrimaryGeneratedColumn(), |
||||||
|
__metadata("design:type", Number) |
||||||
|
], ClassifyToProblem.prototype, "id"); |
||||||
|
__decorate([ |
||||||
|
TypeORM.Index(), |
||||||
|
TypeORM.Column({ nullable: true, type: "integer" }), |
||||||
|
__metadata("design:type", Number) |
||||||
|
], ClassifyToProblem.prototype, "c_id"); |
||||||
|
__decorate([ |
||||||
|
TypeORM.Index(), |
||||||
|
TypeORM.Column({ nullable: true, type: "integer" }), |
||||||
|
__metadata("design:type", Number) |
||||||
|
], ClassifyToProblem.prototype, "p_id"); |
||||||
|
ClassifyToProblem = __decorate([ |
||||||
|
TypeORM.Entity() |
||||||
|
], ClassifyToProblem); |
||||||
|
return ClassifyToProblem; |
||||||
|
}(common_1["default"])); |
||||||
|
exports["default"] = ClassifyToProblem; |
||||||
|
//# sourceMappingURL=classify_to_problem.js.map
|
@ -0,0 +1 @@ |
|||||||
|
{"version":3,"file":"classify_to_problem.js","sourceRoot":"","sources":["../models/classify_to_problem.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;AAAA,iCAAmC;AACnC,mCAA6B;AAG7B;IAA+C,qCAAK;IAApD;;IAaA,CAAC;IAZU,uBAAK,GAAG,IAAI,CAAC;IAGpB;QADC,OAAO,CAAC,sBAAsB,EAAE;;yCACtB;IAIX;QAFC,OAAO,CAAC,KAAK,EAAE;QACf,OAAO,CAAC,MAAM,CAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC;;2CACvC;IAIb;QAFC,OAAO,CAAC,KAAK,EAAE;QACf,OAAO,CAAC,MAAM,CAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC;;2CACvC;IAZI,iBAAiB;QADrC,OAAO,CAAC,MAAM,EAAE;OACI,iBAAiB,CAarC;IAAD,wBAAC;CAAA,AAbD,CAA+C,mBAAK,GAanD;qBAboB,iBAAiB"} |
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -0,0 +1,73 @@ |
|||||||
|
"use strict"; |
||||||
|
var __extends = (this && this.__extends) || (function () { |
||||||
|
var extendStatics = function (d, b) { |
||||||
|
extendStatics = Object.setPrototypeOf || |
||||||
|
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || |
||||||
|
function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; }; |
||||||
|
return extendStatics(d, b); |
||||||
|
}; |
||||||
|
return function (d, b) { |
||||||
|
extendStatics(d, b); |
||||||
|
function __() { this.constructor = d; } |
||||||
|
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); |
||||||
|
}; |
||||||
|
})(); |
||||||
|
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) { |
||||||
|
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; |
||||||
|
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); |
||||||
|
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; |
||||||
|
return c > 3 && r && Object.defineProperty(target, key, r), r; |
||||||
|
}; |
||||||
|
var __metadata = (this && this.__metadata) || function (k, v) { |
||||||
|
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v); |
||||||
|
}; |
||||||
|
exports.__esModule = true; |
||||||
|
var TypeORM = require("typeorm"); |
||||||
|
var common_1 = require("./common"); |
||||||
|
var UserToPractice = /** @class */ (function (_super) { |
||||||
|
__extends(UserToPractice, _super); |
||||||
|
function UserToPractice() { |
||||||
|
return _super !== null && _super.apply(this, arguments) || this; |
||||||
|
} |
||||||
|
UserToPractice.cache = true; |
||||||
|
__decorate([ |
||||||
|
TypeORM.PrimaryGeneratedColumn(), |
||||||
|
__metadata("design:type", Number) |
||||||
|
], UserToPractice.prototype, "id"); |
||||||
|
__decorate([ |
||||||
|
TypeORM.Index(), |
||||||
|
TypeORM.Column({ nullable: true, type: "integer" }), |
||||||
|
__metadata("design:type", Number) |
||||||
|
], UserToPractice.prototype, "u_id"); |
||||||
|
__decorate([ |
||||||
|
TypeORM.Index(), |
||||||
|
TypeORM.Column({ nullable: true, type: "integer" }), |
||||||
|
__metadata("design:type", Number) |
||||||
|
], UserToPractice.prototype, "c_id"); |
||||||
|
__decorate([ |
||||||
|
TypeORM.Index(), |
||||||
|
TypeORM.Column({ nullable: true, type: "integer" }), |
||||||
|
__metadata("design:type", Number) |
||||||
|
], UserToPractice.prototype, "p_id"); |
||||||
|
__decorate([ |
||||||
|
TypeORM.Index(), |
||||||
|
TypeORM.Column({ type: "integer" }), |
||||||
|
__metadata("design:type", Number) |
||||||
|
], UserToPractice.prototype, "is_practice"); |
||||||
|
__decorate([ |
||||||
|
TypeORM.Index(), |
||||||
|
TypeORM.Column({ type: "integer" }), |
||||||
|
__metadata("design:type", Number) |
||||||
|
], UserToPractice.prototype, "is_finished"); |
||||||
|
__decorate([ |
||||||
|
TypeORM.Index(), |
||||||
|
TypeORM.Column({ type: "integer" }), |
||||||
|
__metadata("design:type", Number) |
||||||
|
], UserToPractice.prototype, "practice_num"); |
||||||
|
UserToPractice = __decorate([ |
||||||
|
TypeORM.Entity() |
||||||
|
], UserToPractice); |
||||||
|
return UserToPractice; |
||||||
|
}(common_1["default"])); |
||||||
|
exports["default"] = UserToPractice; |
||||||
|
//# sourceMappingURL=user_to_practice.js.map
|
@ -0,0 +1 @@ |
|||||||
|
{"version":3,"file":"user_to_practice.js","sourceRoot":"","sources":["../models/user_to_practice.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;AAAA,iCAAmC;AACnC,mCAA6B;AAG7B;IAA4C,kCAAK;IAAjD;;IA6BA,CAAC;IA5BU,oBAAK,GAAG,IAAI,CAAC;IAGpB;QADC,OAAO,CAAC,sBAAsB,EAAE;;sCACtB;IAIX;QAFC,OAAO,CAAC,KAAK,EAAE;QACf,OAAO,CAAC,MAAM,CAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC;;wCACvC;IAIb;QAFC,OAAO,CAAC,KAAK,EAAE;QACf,OAAO,CAAC,MAAM,CAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC;;wCACvC;IAIb;QAFC,OAAO,CAAC,KAAK,EAAE;QACf,OAAO,CAAC,MAAM,CAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC;;wCACvC;IAIb;QAFC,OAAO,CAAC,KAAK,EAAE;QACf,OAAO,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC;;+CAChB;IAIpB;QAFC,OAAO,CAAC,KAAK,EAAE;QACf,OAAO,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC;;+CAChB;IAIpB;QAFC,OAAO,CAAC,KAAK,EAAE;QACf,OAAO,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC;;gDACf;IA5BJ,cAAc;QADlC,OAAO,CAAC,MAAM,EAAE;OACI,cAAc,CA6BlC;IAAD,qBAAC;CAAA,AA7BD,CAA4C,mBAAK,GA6BhD;qBA7BoB,cAAc"} |
@ -0,0 +1,32 @@ |
|||||||
|
import * as TypeORM from "typeorm"; |
||||||
|
import Model from "./common"; |
||||||
|
import JudgeState from "./judge_state"; |
||||||
|
import Article from "./article"; |
||||||
|
import UserPrivilege from "./user_privilege"; |
||||||
|
|
||||||
|
@TypeORM.Entity() |
||||||
|
export default class Classify extends Model { |
||||||
|
static cache = true; |
||||||
|
|
||||||
|
@TypeORM.PrimaryGeneratedColumn() |
||||||
|
id: number; |
||||||
|
|
||||||
|
@TypeORM.Index({ unique: true }) |
||||||
|
@TypeORM.Column({ unique: true, nullable: true, type: "varchar", length: 20 }) |
||||||
|
name: string; |
||||||
|
|
||||||
|
@TypeORM.Column({ nullable: true, type: "varchar", length: 100 }) |
||||||
|
intro: string; |
||||||
|
|
||||||
|
@TypeORM.Column({ type: "integer" }) |
||||||
|
problem_num: number; |
||||||
|
|
||||||
|
@TypeORM.Column({ type: "integer" }) |
||||||
|
order: number; |
||||||
|
|
||||||
|
@TypeORM.Column({ nullable: true, type: "integer" }) |
||||||
|
update_time: number; |
||||||
|
|
||||||
|
@TypeORM.Column({ nullable: true, type: "integer" }) |
||||||
|
create_time: number; |
||||||
|
} |
@ -0,0 +1,18 @@ |
|||||||
|
import * as TypeORM from "typeorm"; |
||||||
|
import Model from "./common"; |
||||||
|
|
||||||
|
@TypeORM.Entity() |
||||||
|
export default class ClassifyToProblem extends Model { |
||||||
|
static cache = true; |
||||||
|
|
||||||
|
@TypeORM.PrimaryGeneratedColumn() |
||||||
|
id: number; |
||||||
|
|
||||||
|
@TypeORM.Index() |
||||||
|
@TypeORM.Column({ nullable: true, type: "integer" }) |
||||||
|
c_id: number; |
||||||
|
|
||||||
|
@TypeORM.Index() |
||||||
|
@TypeORM.Column({ nullable: true, type: "integer" }) |
||||||
|
p_id: number; |
||||||
|
} |
@ -0,0 +1,34 @@ |
|||||||
|
import * as TypeORM from "typeorm"; |
||||||
|
import Model from "./common"; |
||||||
|
|
||||||
|
@TypeORM.Entity() |
||||||
|
export default class UserToPractice extends Model { |
||||||
|
static cache = true; |
||||||
|
|
||||||
|
@TypeORM.PrimaryGeneratedColumn() |
||||||
|
id: number; |
||||||
|
|
||||||
|
@TypeORM.Index() |
||||||
|
@TypeORM.Column({ nullable: true, type: "integer" }) |
||||||
|
u_id: number; |
||||||
|
|
||||||
|
@TypeORM.Index() |
||||||
|
@TypeORM.Column({ nullable: true, type: "integer" }) |
||||||
|
c_id: number; |
||||||
|
|
||||||
|
@TypeORM.Index() |
||||||
|
@TypeORM.Column({ nullable: true, type: "integer" }) |
||||||
|
p_id: number; |
||||||
|
|
||||||
|
@TypeORM.Index() |
||||||
|
@TypeORM.Column({ type: "integer" }) |
||||||
|
is_practice: number; |
||||||
|
|
||||||
|
@TypeORM.Index() |
||||||
|
@TypeORM.Column({ type: "integer" }) |
||||||
|
is_finished: number; |
||||||
|
|
||||||
|
@TypeORM.Index() |
||||||
|
@TypeORM.Column({ type: "integer" }) |
||||||
|
practice_num: number; |
||||||
|
} |
@ -0,0 +1,366 @@ |
|||||||
|
let Classify = syzoj.model('classify'); |
||||||
|
let Problem = syzoj.model('problem'); |
||||||
|
let CToP = syzoj.model('classify_to_problem'); |
||||||
|
let Article = syzoj.model('article'); |
||||||
|
let User = syzoj.model('user'); |
||||||
|
let UToP = syzoj.model('user_to_practice'); |
||||||
|
|
||||||
|
app.get('/practice', async (req, res) => { |
||||||
|
if (!res.locals.user) { |
||||||
|
res.render('error', { |
||||||
|
err: new ErrorMessage('请先登录。') |
||||||
|
}); |
||||||
|
} else { |
||||||
|
async function getUserInfo(userId) { |
||||||
|
let userQuery = await User.createQueryBuilder(); |
||||||
|
const currentUserInfo = await userQuery.where("id = :id", { id: userId }).getOne(); |
||||||
|
return currentUserInfo.current_p_id; |
||||||
|
} |
||||||
|
try { |
||||||
|
let classifyQuery = Classify.createQueryBuilder(); |
||||||
|
let utopQuery = UToP.createQueryBuilder(); |
||||||
|
let result = await Classify.queryAll(classifyQuery); |
||||||
|
let userQuery = await User.createQueryBuilder(); |
||||||
|
const userId = res.locals.user.id; |
||||||
|
let currentPId = await getUserInfo(userId); |
||||||
|
const unFinishedIdArray = []; |
||||||
|
if (!currentPId) { |
||||||
|
// 用户第一次进入练习板块
|
||||||
|
await userQuery.update(User).set({current_p_id: 1}).where("id = :id", { id:userId }).execute(); |
||||||
|
} else { |
||||||
|
await result.forEachAsync(async resultItem => { |
||||||
|
const c_id = resultItem.id; |
||||||
|
let utopInfo = await utopQuery.where('c_id=:c_id',{c_id}).andWhere('u_id=:u_id',{u_id:userId}).andWhere("is_finished=1").getMany(); |
||||||
|
resultItem.ac_num = utopInfo.length || 0; |
||||||
|
if (resultItem.ac_num === resultItem.problem_num) { |
||||||
|
if (resultItem.order < result.length ) { |
||||||
|
currentPId = resultItem.order + 1 |
||||||
|
await userQuery.update(User).set({current_p_id: currentPId}).where("id = :id", { id:userId }).execute(); |
||||||
|
} |
||||||
|
} else { |
||||||
|
test.push(resultItem.order); |
||||||
|
} |
||||||
|
}); |
||||||
|
} |
||||||
|
if (unFinishedIdArray.length !== 0) { |
||||||
|
const minOrder = Math.min.apply(null,unFinishedIdArray); |
||||||
|
currentPId = minOrder; |
||||||
|
await userQuery.update(User).set({current_p_id: minOrder}).where("id = :id", { id:userId }).execute(); |
||||||
|
} |
||||||
|
result.sort(function(a,b) { |
||||||
|
return a.order - b.order; |
||||||
|
}); |
||||||
|
result.forEach(function(item) { |
||||||
|
if (item.order <= currentPId) { |
||||||
|
item.href = `/practice/classify/${item.id}`; |
||||||
|
} |
||||||
|
item.isNow = item.order === currentPId; |
||||||
|
}); |
||||||
|
let userACArray = await utopQuery.where('u_id=:u_id',{u_id:userId}).andWhere("is_finished=1").getMany(); |
||||||
|
if (syzoj.config.practice_rating) { |
||||||
|
const originRating = syzoj.config.default.user.rating; |
||||||
|
const newRating = originRating + userACArray.length * syzoj.config.practice_rating; |
||||||
|
await userQuery.update(User).set({rating: newRating}).where('id=:u_id',{u_id:userId}).execute(); |
||||||
|
} |
||||||
|
res.render('practice', { |
||||||
|
user:res.locals.user, |
||||||
|
result, |
||||||
|
newRating |
||||||
|
}) |
||||||
|
} catch (e) { |
||||||
|
syzoj.log(e); |
||||||
|
res.render('error', { |
||||||
|
err: e |
||||||
|
}); |
||||||
|
} |
||||||
|
} |
||||||
|
}); |
||||||
|
|
||||||
|
app.get('/practice/classify/:cid/problem/:pid', async (req, res) => { |
||||||
|
try { |
||||||
|
let id = parseInt(req.params.pid); |
||||||
|
let cid = parseInt(req.params.cid); |
||||||
|
let problem = await Problem.findById(id); |
||||||
|
if (!problem) throw new ErrorMessage('无此题目。'); |
||||||
|
|
||||||
|
if (!await problem.isAllowedUseBy(res.locals.user)) { |
||||||
|
throw new ErrorMessage('您没有权限进行此操作。'); |
||||||
|
} |
||||||
|
|
||||||
|
problem.allowedEdit = await problem.isAllowedEditBy(res.locals.user); |
||||||
|
problem.allowedManage = await problem.isAllowedManageBy(res.locals.user); |
||||||
|
|
||||||
|
if (problem.is_public || problem.allowedEdit) { |
||||||
|
await syzoj.utils.markdown(problem, ['description', 'input_format', 'output_format', 'example', 'limit_and_hint']); |
||||||
|
} else { |
||||||
|
throw new ErrorMessage('您没有权限进行此操作。'); |
||||||
|
} |
||||||
|
|
||||||
|
let state = await problem.getJudgeState(res.locals.user, false); |
||||||
|
|
||||||
|
problem.tags = await problem.getTags(); |
||||||
|
await problem.loadRelationships(); |
||||||
|
|
||||||
|
let testcases = await syzoj.utils.parseTestdata(problem.getTestdataPath(), problem.type === 'submit-answer'); |
||||||
|
|
||||||
|
let discussionCount = await Article.count({ problem_id: id }); |
||||||
|
|
||||||
|
res.render('practice_problem', { |
||||||
|
problem: problem, |
||||||
|
state: state, |
||||||
|
lastLanguage: res.locals.user ? await res.locals.user.getLastSubmitLanguage() : null, |
||||||
|
testcases: testcases, |
||||||
|
discussionCount: discussionCount, |
||||||
|
pid: id, |
||||||
|
cid |
||||||
|
}); |
||||||
|
} catch (e) { |
||||||
|
syzoj.log(e); |
||||||
|
res.render('error', { |
||||||
|
err: e |
||||||
|
}); |
||||||
|
} |
||||||
|
}); |
||||||
|
|
||||||
|
app.get('/practice/classify/:id', async (req, res) => { |
||||||
|
try { |
||||||
|
const c_id = parseInt(req.params.id); |
||||||
|
const u_id = res.locals.user.id; |
||||||
|
let ctopQuery = CToP.createQueryBuilder(); |
||||||
|
let query = await Problem.createQueryBuilder(); |
||||||
|
let utopQuery = UToP.createQueryBuilder(); |
||||||
|
let problemArray = await ctopQuery.where("c_id = :id", { id:c_id }).getMany(); |
||||||
|
let utopResult = await utopQuery.where("c_id = :c_id", { c_id }).andWhere("u_id=:u_id", {u_id}).getMany(); |
||||||
|
let problems = await problemArray.mapAsync(async problemArrayInfo => query.where('id=:id', {id: problemArrayInfo.p_id}).getOne()); |
||||||
|
problems.forEach(function(problemItem) { |
||||||
|
const obj = utopResult.find(function(item){return parseInt(item.p_id) === parseInt(problemItem.id)}); |
||||||
|
problemItem.href = `/practice/classify/${c_id}/problem/${problemItem.id}`; |
||||||
|
if (obj) { |
||||||
|
problemItem.statusStr = obj.is_practice && obj.is_finished ? '已练习且已通过' : '已练习但未通过'; |
||||||
|
} else { |
||||||
|
problemItem.statusStr = '尚未练习' |
||||||
|
} |
||||||
|
}); |
||||||
|
problems.sort(function(a, b){ |
||||||
|
return a.id - b.id; |
||||||
|
}) |
||||||
|
res.render('practice_classify', { |
||||||
|
user:res.locals.user, |
||||||
|
problems |
||||||
|
}) |
||||||
|
} catch (e) { |
||||||
|
syzoj.log(e); |
||||||
|
res.render('error', { |
||||||
|
err: e |
||||||
|
}); |
||||||
|
} |
||||||
|
}); |
||||||
|
|
||||||
|
app.get('/api/practice/classify/:id', async (req, res) => { |
||||||
|
try { |
||||||
|
let id = parseInt(req.params.id); |
||||||
|
let query = await Classify.createQueryBuilder(); |
||||||
|
let classifyInfo = await query.where('id=:id',{id}).getOne(); |
||||||
|
let problem = await CToP.queryBy({c_id: id}); |
||||||
|
res.send({ classifyInfo, problem:problem.map(function(item){return item.p_id}) }); |
||||||
|
} catch(e) { |
||||||
|
res.send({ error_code: e.errno, error_msg: '失败' }); |
||||||
|
} |
||||||
|
}); |
||||||
|
|
||||||
|
app.get('/api/pass/:cid/:pid',async (req, res) => { |
||||||
|
try { |
||||||
|
const c_id = parseInt(req.params.cid); |
||||||
|
const p_id = parseInt(req.params.pid); |
||||||
|
const u_id = res.locals.user.id; |
||||||
|
let utopQuery = UToP.createQueryBuilder(); |
||||||
|
let query = Classify.createQueryBuilder(); |
||||||
|
let userQuery = User.createQueryBuilder(); |
||||||
|
let classify = await Classify.queryAll(query); |
||||||
|
classify.sort(function(a,b) { |
||||||
|
return a.order - b.order; |
||||||
|
}); |
||||||
|
let utopResult = await utopQuery.where("c_id = :c_id", { c_id }).andWhere("u_id=:u_id", {u_id}).andWhere("p_id=:p_id", {p_id}).getOne(); |
||||||
|
// 查询到结果了
|
||||||
|
if (utopResult ) { |
||||||
|
// mock答题通过了
|
||||||
|
await utopQuery.update(UToP).set({is_finished: 1, practice_num: utopResult.practice_num + 1}).where("c_id = :c_id", { c_id }).andWhere("u_id=:u_id", {u_id}).andWhere("p_id=:p_id", {p_id}).execute(); |
||||||
|
// 说明两个题都练习过了
|
||||||
|
} else { |
||||||
|
let utop = await UToP.create({ |
||||||
|
u_id, |
||||||
|
c_id, |
||||||
|
p_id, |
||||||
|
is_practice: 1, |
||||||
|
is_finished: 1, |
||||||
|
practice_num: 1 |
||||||
|
}); |
||||||
|
await utop.save(); |
||||||
|
} |
||||||
|
res.send(); |
||||||
|
} catch(e) { |
||||||
|
res.send({ error_code: e.errno, error_msg: '练习失败,请稍后重试' }); |
||||||
|
} |
||||||
|
}); |
||||||
|
|
||||||
|
app.get('/api/practice/nopass/:cid/:pid',async (req, res) => { |
||||||
|
try { |
||||||
|
const c_id = parseInt(req.params.cid); |
||||||
|
const p_id = parseInt(req.params.pid); |
||||||
|
const u_id = res.locals.user.id; |
||||||
|
let utopQuery = UToP.createQueryBuilder(); |
||||||
|
let query = Classify.createQueryBuilder(); |
||||||
|
let utopResult = await utopQuery.where("c_id = :c_id", { c_id }).andWhere("u_id=:u_id", {u_id}).andWhere("p_id=:p_id", {p_id}).getOne(); |
||||||
|
// 查询到结果了
|
||||||
|
if (utopResult) { |
||||||
|
// mock答题通过了
|
||||||
|
await utopQuery.update(UToP).set({is_practice:1, is_finished: 0, practice_num: utopResult.practice_num + 1}).where("c_id = :c_id", { c_id }).andWhere("u_id=:u_id", {u_id}).andWhere("p_id=:p_id", {p_id}).execute(); |
||||||
|
// 说明两个题都练习过了
|
||||||
|
} else { |
||||||
|
let utop = await UToP.create({ |
||||||
|
u_id, |
||||||
|
c_id, |
||||||
|
p_id, |
||||||
|
is_practice: 1, |
||||||
|
practice_num: 1, |
||||||
|
is_finished: 0 |
||||||
|
}); |
||||||
|
await utop.save(); |
||||||
|
} |
||||||
|
res.send(); |
||||||
|
} catch(e) { |
||||||
|
res.send({ error_code: e.errno, error_msg: '练习失败,请稍后重试' }); |
||||||
|
} |
||||||
|
}); |
||||||
|
|
||||||
|
app.put('/api/practice/classify/update/:id', async (req, res) => { |
||||||
|
try { |
||||||
|
let id = parseInt(req.params.id); |
||||||
|
let u_id = parseInt(res.locals.user.id); |
||||||
|
let utopQuery = UToP.createQueryBuilder(); |
||||||
|
let classifyQuery = await Classify.createQueryBuilder(); |
||||||
|
let ctopQuery = await CToP.createQueryBuilder(); |
||||||
|
const {name, intro, problemIdArray, order} = req.body; |
||||||
|
let classifyInfo = await classifyQuery.where('id=:id',{id}).getOne(); |
||||||
|
// 新增题
|
||||||
|
if (problemIdArray.length > classifyInfo.problem_num) { |
||||||
|
/* |
||||||
|
* 把当前练习的阶段设置为新增题的阶段,因为新增题后,当前阶段的题目就没答完。 |
||||||
|
* */ |
||||||
|
|
||||||
|
} |
||||||
|
// 删除题
|
||||||
|
if (problemIdArray.length < classifyInfo.problem_num) { |
||||||
|
// 1。找出两个数组的差异
|
||||||
|
function findDifference(source, target){ |
||||||
|
const parseIntTarget = target.map(function(item){ |
||||||
|
return parseInt(item); |
||||||
|
}) |
||||||
|
return source.filter(function(item){ |
||||||
|
return !parseIntTarget.includes(item); |
||||||
|
}) |
||||||
|
} |
||||||
|
let ctopInfo = await ctopQuery.where('c_id=:id',{id}).getMany(); |
||||||
|
const targetArray = ctopInfo.map(function(ctopInfoItem){ |
||||||
|
return ctopInfoItem.p_id; |
||||||
|
}) |
||||||
|
// 2.从utop表里清除被删除题目的练习记录
|
||||||
|
const differenceArray = findDifference(targetArray, problemIdArray); |
||||||
|
differenceArray.forEachAsync(async differenceItem => { |
||||||
|
await utopQuery.delete().from(UToP).where("c_id = :id", { id }).andWhere("u_id=:u_id",{u_id}).andWhere("p_id=:p_id",{p_id:differenceItem}).execute(); |
||||||
|
}) |
||||||
|
} |
||||||
|
let updateClassifyInfo = await classifyQuery.update(Classify).set({name, intro, order, problem_num: problemIdArray.length}).where("id = :id", { id }).execute(); |
||||||
|
await ctopQuery.delete().from(CToP).where("c_id = :id", { id }).execute(); |
||||||
|
problemIdArray.forEach(async function (item) { |
||||||
|
let ctop = await CToP.create({ |
||||||
|
c_id: id, |
||||||
|
p_id: item |
||||||
|
}); |
||||||
|
await ctop.save(); |
||||||
|
}) |
||||||
|
res.send({ updateClassifyInfo }); |
||||||
|
} catch(e) { |
||||||
|
res.send({ error_code: e.errno, error_msg: '失败' }); |
||||||
|
} |
||||||
|
}); |
||||||
|
|
||||||
|
app.get('/api/getProblem/:id', async (req, res) => { |
||||||
|
let id = parseInt(req.params.id); |
||||||
|
try { |
||||||
|
let query = await Problem.createQueryBuilder(); |
||||||
|
let problemInfo = await query.where('id=:id', {id}).getOne() |
||||||
|
res.send({ problemInfo}); |
||||||
|
} catch(e) { |
||||||
|
res.send({ error_code: e.errno, error_msg: '失败' }); |
||||||
|
} |
||||||
|
}); |
||||||
|
|
||||||
|
app.get('/api/practice/all', async (req, res) => { |
||||||
|
try { |
||||||
|
let classifyQuery = Classify.createQueryBuilder(); |
||||||
|
let ctopQuery = CToP.createQueryBuilder(); |
||||||
|
let result = await Classify.queryAll(classifyQuery); |
||||||
|
result.sort(function(a,b) { |
||||||
|
return a.order - b.order; |
||||||
|
}) |
||||||
|
// if (result.length !== 0) {
|
||||||
|
// const currentClassifyId = result[0].id;
|
||||||
|
//
|
||||||
|
// }
|
||||||
|
let problem = await CToP.queryAll(ctopQuery); |
||||||
|
res.send({ result, problem}); |
||||||
|
} catch(e) { |
||||||
|
res.send({ error_code: e.errno, error_msg: '失败' }); |
||||||
|
} |
||||||
|
}); |
||||||
|
|
||||||
|
app.get('/api/admin/practice/all', async (req, res) => { |
||||||
|
try { |
||||||
|
let classifyQuery = Classify.createQueryBuilder(); |
||||||
|
let result = await Classify.queryAll(classifyQuery); |
||||||
|
res.send({ result }); |
||||||
|
} catch(e) { |
||||||
|
res.send({ error_code: e.errno, error_msg: '失败' }); |
||||||
|
} |
||||||
|
}); |
||||||
|
|
||||||
|
app.post('/api/practice/create', async (req, res) => { |
||||||
|
try { |
||||||
|
const {name, intro, problemIdArray, order} = req.body; |
||||||
|
let classify = await Classify.create({ |
||||||
|
name, |
||||||
|
intro, |
||||||
|
order, |
||||||
|
problem_num: problemIdArray.length || 0, |
||||||
|
updateTime: parseInt((new Date()).getTime() / 1000, 10), |
||||||
|
createTime: parseInt((new Date()).getTime() / 1000) |
||||||
|
}); |
||||||
|
await classify.save(); |
||||||
|
let query = Classify.createQueryBuilder(); |
||||||
|
let recordArray = await Classify.queryAll(query); |
||||||
|
let lastRecordId = recordArray[recordArray.length - 1].id; |
||||||
|
problemIdArray.forEach(async function (item) { |
||||||
|
let ctop = await CToP.create({ |
||||||
|
c_id: lastRecordId, |
||||||
|
p_id: item |
||||||
|
}) |
||||||
|
await ctop.save(); |
||||||
|
}) |
||||||
|
res.send(); |
||||||
|
} catch(e) { |
||||||
|
res.send({ error_code: e.errno, error_msg: '创建失败' }); |
||||||
|
} |
||||||
|
}); |
||||||
|
|
||||||
|
app.get('/api/problem/all', async (req, res) => { |
||||||
|
try { |
||||||
|
let query = Problem.createQueryBuilder(); |
||||||
|
let result = await Problem.querySomeColumn(query); |
||||||
|
res.send({ result }); |
||||||
|
} catch(e) { |
||||||
|
res.send({ error_code: e.errno, error_msg: '失败' }); |
||||||
|
} |
||||||
|
}); |
||||||
|
|
||||||
|
|
@ -0,0 +1,290 @@ |
|||||||
|
<% this.adminPage = 'classify'; %> |
||||||
|
<% include admin_header %> |
||||||
|
<style> |
||||||
|
[v-cloak] { |
||||||
|
display: none; |
||||||
|
} |
||||||
|
.current-classify{ |
||||||
|
margin-bottom: 20px; |
||||||
|
} |
||||||
|
</style> |
||||||
|
<div id="classify" v-cloak> |
||||||
|
<div class="ui modal classify"> |
||||||
|
<i class="close icon"></i> |
||||||
|
<div class="header"> |
||||||
|
{{calcModalTitle}} |
||||||
|
</div> |
||||||
|
<div class="content"> |
||||||
|
<div class="ui form"> |
||||||
|
<div class="field required" :class="{ error: classifyName.length > 20 }"> |
||||||
|
<label>练习阶段名称(20字以内)</label> |
||||||
|
<input type="text" v-model="classifyName" placeholder="请输入分类名称"> |
||||||
|
</div> |
||||||
|
<div class="field required" :class="{ error: classifyName.length > 100 }"> |
||||||
|
<label>练习阶段简介(100字以内)</label> |
||||||
|
<input type="text" v-model="classifyIntro" placeholder="请输入分类简介"> |
||||||
|
</div> |
||||||
|
<div class="field required" > |
||||||
|
<label>练习阶段顺序</label> |
||||||
|
<el-input-number disabled v-model="order" :min="1" :max="calcOrderMax" label="练习阶段顺序"></el-input-number> |
||||||
|
</div> |
||||||
|
<div class="field required" :class="{ error: problemIdArray.length === 0 }"> |
||||||
|
<label>题目选择(至少包含一道题)</label> |
||||||
|
<el-select |
||||||
|
style="width:100%" |
||||||
|
v-model="problemIdArray" |
||||||
|
multiple |
||||||
|
filterable |
||||||
|
remote |
||||||
|
reserve-keyword |
||||||
|
placeholder="请输入关键词" |
||||||
|
:remote-method="remoteMethod" |
||||||
|
:loading="loading"> |
||||||
|
<el-option |
||||||
|
v-for="item in problemOptions" |
||||||
|
:key="item.value" |
||||||
|
:label="item.label" |
||||||
|
:disabled="item.disabled" |
||||||
|
:value="item.value"> |
||||||
|
</el-option> |
||||||
|
</el-select> |
||||||
|
</div> |
||||||
|
<button class="ui button" @click="submitInfo">{{calcModalTitle}}</button> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
<div v-if="classifyArray.length === 0"> |
||||||
|
<div class="ui placeholder segment"> |
||||||
|
<div class="ui icon header"> |
||||||
|
<i class="sticky note icon"></i> |
||||||
|
暂无练习阶段 |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
<div v-else> |
||||||
|
<div class="current-classify"> |
||||||
|
<h4>目前练习阶段</h4> |
||||||
|
<div class="ui cards"> |
||||||
|
<div class="card" v-for="item in classifyArray"> |
||||||
|
<div class="content"> |
||||||
|
<div class="header">{{item.name}}</div> |
||||||
|
<div class="description"> |
||||||
|
{{item.intro}} |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
<div class="ui bottom attached button" @click="show(item.id)"> |
||||||
|
<i class="add icon"></i> |
||||||
|
编辑练习阶段信息 |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
<div class="ui labeled button" tabindex="0" @click="show()"> |
||||||
|
<div class="ui button"> |
||||||
|
<i class="plus icon"></i> 新增练习阶段 |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
<link rel="stylesheet" href="https://unpkg.com/element-ui/lib/theme-chalk/index.css"> |
||||||
|
<!-- 引入组件库 --> |
||||||
|
<script src="https://cdn.jsdelivr.net/npm/vue"></script> |
||||||
|
<script src="https://unpkg.com/element-ui/lib/index.js"></script> |
||||||
|
<script> |
||||||
|
new window.Vue({ |
||||||
|
el: '#classify', |
||||||
|
data: { |
||||||
|
problemIdArray: [], |
||||||
|
order: 1, |
||||||
|
classifyName: '', |
||||||
|
classifyIntro: '', |
||||||
|
classifyArray: [], |
||||||
|
classifyId: -1, |
||||||
|
problemOptions: [], |
||||||
|
loading: false, |
||||||
|
}, |
||||||
|
created: function() { |
||||||
|
this.getClassifyInfo(); |
||||||
|
}, |
||||||
|
methods: { |
||||||
|
remoteMethod(query) { |
||||||
|
let that = this; |
||||||
|
if (query !== '') { |
||||||
|
if (this.usedProblemId.includes(parseInt(query))) { |
||||||
|
this.$message({ |
||||||
|
message: '这道题已经分配过', |
||||||
|
type: 'warning' |
||||||
|
}); |
||||||
|
} else { |
||||||
|
this.loading = true; |
||||||
|
setTimeout(() => { |
||||||
|
$.ajax({ |
||||||
|
url: `/api/v2/search/problems/${query}`, |
||||||
|
type: 'GET', |
||||||
|
success: function (data) { |
||||||
|
that.problemOptions = data.results.map((item) => { |
||||||
|
return { |
||||||
|
id: item.value, |
||||||
|
label: item.name, |
||||||
|
value: item.value, |
||||||
|
} |
||||||
|
}) |
||||||
|
}, |
||||||
|
error: function (XMLHttpRequest, textStatus, errorThrown) { |
||||||
|
alert('创建失败'); |
||||||
|
} |
||||||
|
}); |
||||||
|
this.loading = false; |
||||||
|
}, 200); |
||||||
|
} |
||||||
|
} else { |
||||||
|
this.options = []; |
||||||
|
} |
||||||
|
}, |
||||||
|
getClassifyInfo: function() { |
||||||
|
let that = this; |
||||||
|
$.ajax({ |
||||||
|
url: '/api/practice/all', |
||||||
|
type: 'GET', |
||||||
|
success: function (data) { |
||||||
|
that.classifyArray = data.result; |
||||||
|
that.usedProblemId = data.problem.map(function(item){return item.p_id}); |
||||||
|
}, |
||||||
|
error: function (XMLHttpRequest, textStatus, errorThrown) { |
||||||
|
alert('查询失败'); |
||||||
|
} |
||||||
|
}); |
||||||
|
}, |
||||||
|
resetModal: function() { |
||||||
|
this.classifyName = ''; |
||||||
|
this.classifyIntro = ''; |
||||||
|
this.problemIdArray = []; |
||||||
|
this.classifyId = -1; |
||||||
|
this.problemOptions=[]; |
||||||
|
this.order = this.calcOrderMax; |
||||||
|
}, |
||||||
|
show: function(id){ |
||||||
|
let that = this; |
||||||
|
if (id) { |
||||||
|
this.classifyId = id; |
||||||
|
$.ajax({ |
||||||
|
url: `/api/practice/classify/${id}`, |
||||||
|
type: 'GET', |
||||||
|
success: function (data) { |
||||||
|
if (!data.error_code) { |
||||||
|
const {classifyInfo: {id, intro, name, order}, problem} = data; |
||||||
|
that.classifyName = name; |
||||||
|
that.classifyIntro = intro; |
||||||
|
that.problemIdArray = problem; |
||||||
|
that.order = order; |
||||||
|
problem.forEach(function(problemId) { |
||||||
|
$.ajax({ |
||||||
|
url: `/api/v2/search/problems/${problemId}`, |
||||||
|
type: 'GET', |
||||||
|
success: function (data) { |
||||||
|
that.problemOptions = data.results.map((item) => { |
||||||
|
return { |
||||||
|
id: item.value, |
||||||
|
label: item.name, |
||||||
|
disabled: true, |
||||||
|
value: item.value, |
||||||
|
} |
||||||
|
}) |
||||||
|
}, |
||||||
|
error: function (XMLHttpRequest, textStatus, errorThrown) { |
||||||
|
alert('创建失败'); |
||||||
|
} |
||||||
|
}); |
||||||
|
}) |
||||||
|
} |
||||||
|
}, |
||||||
|
error: function (XMLHttpRequest, textStatus, errorThrown) { |
||||||
|
alert('创建失败'); |
||||||
|
} |
||||||
|
}); |
||||||
|
} else { |
||||||
|
this.resetModal(); |
||||||
|
} |
||||||
|
$('.ui.modal.classify') |
||||||
|
.modal('show') |
||||||
|
}, |
||||||
|
checkStringLength: function(string, maxLen) { |
||||||
|
return string.length > 0 && string.length <= maxLen; |
||||||
|
}, |
||||||
|
submitInfo: function() { |
||||||
|
let that = this; |
||||||
|
let name = this.classifyName; |
||||||
|
let intro = this.classifyIntro; |
||||||
|
if(this.checkStringLength(name, 20) && this.checkStringLength(intro, 100) && this.problemIdArray.length > 0) { |
||||||
|
const obj = { |
||||||
|
name: this.classifyName, |
||||||
|
intro: this.classifyIntro, |
||||||
|
order: this.order, |
||||||
|
problemIdArray: this.problemIdArray |
||||||
|
} |
||||||
|
if (this.classifyId === -1) { |
||||||
|
$.ajax({ |
||||||
|
url: '/api/practice/create', |
||||||
|
type: 'POST', |
||||||
|
async: true, |
||||||
|
data: obj, |
||||||
|
success: function (data) { |
||||||
|
if (data.error_code) { |
||||||
|
alert('创建失败'); |
||||||
|
} else { |
||||||
|
alert('添加成功'); |
||||||
|
that.resetModal(); |
||||||
|
$('.ui.modal.classify') |
||||||
|
.modal('hide') |
||||||
|
that.getClassifyInfo(); |
||||||
|
} |
||||||
|
}, |
||||||
|
error: function (XMLHttpRequest, textStatus, errorThrown) { |
||||||
|
alert('创建失败'); |
||||||
|
} |
||||||
|
}); |
||||||
|
} else { |
||||||
|
$.ajax({ |
||||||
|
url: `/api/practice/classify/update/${that.classifyId}`, |
||||||
|
type: 'PUT', |
||||||
|
async: true, |
||||||
|
data: obj, |
||||||
|
success: function (data) { |
||||||
|
if (data.error_code) { |
||||||
|
alert('更新失败'); |
||||||
|
} else { |
||||||
|
alert('更新成功'); |
||||||
|
that.resetModal(); |
||||||
|
$('.ui.modal.classify') |
||||||
|
.modal('hide') |
||||||
|
that.getClassifyInfo(); |
||||||
|
} |
||||||
|
}, |
||||||
|
error: function (XMLHttpRequest, textStatus, errorThrown) { |
||||||
|
alert('更新时发生错误'); |
||||||
|
} |
||||||
|
}); |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
|
} |
||||||
|
}, |
||||||
|
computed: { |
||||||
|
calcModalTitle: function(){ |
||||||
|
if (this.classifyId === -1) { |
||||||
|
return '新增练习阶段'; |
||||||
|
} else { |
||||||
|
return '编辑练习阶段' |
||||||
|
} |
||||||
|
}, |
||||||
|
calcOrderMax: function() { |
||||||
|
if (this.classifyId === -1) { |
||||||
|
return this.classifyArray.length + 1; |
||||||
|
} else { |
||||||
|
return this.classifyArray.length |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
}) |
||||||
|
</script> |
||||||
|
<% include admin_footer %> |
@ -0,0 +1,40 @@ |
|||||||
|
<% this.title = '练习' %> |
||||||
|
<style> |
||||||
|
#practice{ |
||||||
|
width: 100%; |
||||||
|
} |
||||||
|
</style> |
||||||
|
<% include header %> |
||||||
|
<div id="practice"> |
||||||
|
<% if(result.length === 0) { %> <div class="ui placeholder segment"> |
||||||
|
<div class="ui icon header"> |
||||||
|
<i class="sticky note icon"></i> |
||||||
|
暂无题目处于可练习的状态下 |
||||||
|
</div> |
||||||
|
</div> <% } else { %> <table class="ui very basic center aligned table"> |
||||||
|
<thead> |
||||||
|
<tr> |
||||||
|
<th>练习阶段名称</th> |
||||||
|
<th>练习阶段介绍</th> |
||||||
|
<th>练习阶段包含题目数量</th> |
||||||
|
<th>已完成题目数量</th> |
||||||
|
<th>练习阶段状态</th> |
||||||
|
<th>是否是当前阶段</th> |
||||||
|
</tr> |
||||||
|
</thead> |
||||||
|
<tbody> |
||||||
|
<% for (let resultItem of result){%> |
||||||
|
<tr> |
||||||
|
<% if(resultItem.href) { %> <td><a href="<%= resultItem.href%>"><%= resultItem.name%></a></td> <% } else { %> <td><%= resultItem.name%></td> <% } %> |
||||||
|
<td><%= resultItem.intro%></td> |
||||||
|
<td><%= resultItem.problem_num%></td> |
||||||
|
<td><%= resultItem.ac_num%></td> |
||||||
|
<% if(resultItem.href) { %> <td>可练习</td> <% } else { %> <td>目前不可练习,完成当前阶段后解锁</td> <% } %> |
||||||
|
<% if(resultItem.isNow) { %> <td>是</td> <% } else { %> <td>否</td> <% } %> |
||||||
|
</tr> |
||||||
|
<%}%> |
||||||
|
</tbody> |
||||||
|
</table> <% } %> |
||||||
|
|
||||||
|
</div> |
||||||
|
<% include footer %> |
@ -0,0 +1,26 @@ |
|||||||
|
<% this.title = '练习' %> |
||||||
|
<style> |
||||||
|
</style> |
||||||
|
<% include header %> |
||||||
|
<div id="practice_classify"> |
||||||
|
<table class="ui selectable celled table"> |
||||||
|
<thead> |
||||||
|
<tr> |
||||||
|
<th>题目</th> |
||||||
|
<th>状态</th> |
||||||
|
</tr> |
||||||
|
</thead> |
||||||
|
<tbody> |
||||||
|
<% for (let problemItem of problems){%> |
||||||
|
<tr> |
||||||
|
<td><a href="<%= problemItem.href %>"><%= problemItem.title %></a></td> |
||||||
|
<td><%= problemItem.statusStr %></td> |
||||||
|
</tr> |
||||||
|
<%}%> |
||||||
|
</tbody> |
||||||
|
</table> |
||||||
|
</div> |
||||||
|
|
||||||
|
<script> |
||||||
|
</script> |
||||||
|
<% include footer %> |
@ -0,0 +1,392 @@ |
|||||||
|
<% include util %> |
||||||
|
<% |
||||||
|
if (typeof contest === 'undefined') contest = null; |
||||||
|
if (contest) { |
||||||
|
this.title = this.alpha(pid) + '. ' + syzoj.utils.removeTitleTag(problem.title) + ' - ' + contest.title + ' - 比赛'; |
||||||
|
} else { |
||||||
|
this.title = problem.title + ' - 题目'; |
||||||
|
} |
||||||
|
%> |
||||||
|
<% include header %> |
||||||
|
<style> |
||||||
|
#languages-menu::-webkit-scrollbar, #testcase-menu::-webkit-scrollbar { |
||||||
|
width: 0px; |
||||||
|
background: transparent; |
||||||
|
} |
||||||
|
|
||||||
|
#languages-menu .item::after, #testcase-menu .item::after { |
||||||
|
display: none; |
||||||
|
} |
||||||
|
</style> |
||||||
|
|
||||||
|
<% include monaco-editor %> |
||||||
|
|
||||||
|
<div class="ui center aligned grid"> |
||||||
|
<div class="row"> |
||||||
|
<h1 class="ui header"> |
||||||
|
<% if (contest) { %> |
||||||
|
<%= this.alpha(pid) %>. <%= syzoj.utils.removeTitleTag(problem.title) %> |
||||||
|
<% } else { %> |
||||||
|
#<%= problem.id %>. <%= problem.title %><% if (problem.allowedEdit && !problem.is_public) { %><span class="ui tiny red label">未公开</span><% } %> |
||||||
|
<% } %> |
||||||
|
</h1> |
||||||
|
</div> |
||||||
|
<% if (problem.type !== 'submit-answer') { %> |
||||||
|
<div class="row" style="margin-top: -15px"> |
||||||
|
<span class="ui label">内存限制:<%= problem.memory_limit %> MiB</span> |
||||||
|
<span class="ui label">时间限制:<%= problem.time_limit %> ms</span> |
||||||
|
<% if (problem.type === 'interaction') { %> |
||||||
|
<span class="ui label">题目类型:交互</span> |
||||||
|
<% } else if (problem.file_io) { %> |
||||||
|
<span class="ui label">输入文件:<%= problem.file_io_input_name %></span> |
||||||
|
<span class="ui label">输出文件:<%= problem.file_io_output_name %></span> |
||||||
|
<% } else { %> |
||||||
|
<span class="ui label">标准输入输出</span> |
||||||
|
<% } %> |
||||||
|
</div> |
||||||
|
<% } %> |
||||||
|
<% if (problem.type !== 'interaction') { %> |
||||||
|
<div class="row" style="margin-top: -<%= problem.type === 'submit-answer' ? 15 : 23 %>px"> |
||||||
|
<span class="ui label">题目类型:<%= { 'submit-answer': '答案提交', 'interaction': '交互', 'traditional': '传统' }[problem.type] %></span> |
||||||
|
<span class="ui label">评测方式:<%= (testcases && !testcases.error) ? (testcases.spj ? 'Special Judge' : '文本比较') : '无测试数据' %></span> |
||||||
|
</div> |
||||||
|
<% } %> |
||||||
|
<% if (!contest) { %> |
||||||
|
<div class="row" style="margin-top: -23px"> |
||||||
|
<span class="ui label">上传者: |
||||||
|
<% if (problem.is_anonymous && !problem.allowedManage) { %> |
||||||
|
匿名 |
||||||
|
<% } else { %> |
||||||
|
<a href="<%= syzoj.utils.makeUrl(['user', problem.user_id]) %>"><%= problem.user.username %></a> |
||||||
|
<% } %> |
||||||
|
</span> |
||||||
|
<% if (problem.allowedManage) { %> |
||||||
|
<span class="ui label">公开者: |
||||||
|
<% if (problem.publicizer) { %> |
||||||
|
<a href="<%= syzoj.utils.makeUrl(['user', problem.publicizer_id]) %>"><%= problem.publicizer.username %></a> |
||||||
|
<% } else { %> |
||||||
|
未知 |
||||||
|
<% } %> |
||||||
|
</span> |
||||||
|
<% } %> |
||||||
|
</div> |
||||||
|
<% } %> |
||||||
|
</div> |
||||||
|
<div class="ui grid"> |
||||||
|
<div class="row"> |
||||||
|
<div class="column"> |
||||||
|
<div class="ui buttons"> |
||||||
|
<% if (typeof contest !== 'undefined' && contest) { %> |
||||||
|
<% if (!contest.ended) { %> |
||||||
|
<a class="small ui primary button" href="#submit_code">提交</a> |
||||||
|
<% } else { %> |
||||||
|
<a class="small ui primary button" href="<%= syzoj.utils.makeUrl(['problem', problem.id]) %>">转到题库</a> |
||||||
|
<% } %> |
||||||
|
<a class="small ui positive button" href="<%= syzoj.utils.makeUrl(['contest', contest.id, 'submissions'], { problem_id: pid }) %>">提交记录</a> |
||||||
|
<% if (problem.additional_file) { %> |
||||||
|
<a class="small ui teal button" href="<%= syzoj.utils.makeUrl(['contest', contest.id, pid, 'download', 'additional_file']) %>">附加文件</a> |
||||||
|
<% } %> |
||||||
|
<a href="<%= syzoj.utils.makeUrl(['contest', contest.id]) %>" class="ui orange button">返回比赛</a> |
||||||
|
<% } else { %> |
||||||
|
<% if (testcases && !testcases.error) { %> |
||||||
|
<a class="small ui primary button" href="#submit_code">提交</a> |
||||||
|
<% } %> |
||||||
|
<a class="small ui positive button" href="<%= syzoj.utils.makeUrl(['submissions'], { problem_id: problem.id }) %>">提交记录</a> |
||||||
|
<a class="small ui orange button" href="<%= syzoj.utils.makeUrl(['problem', problem.id, 'statistics', problem.type === 'submit-answer' ? 'shortest' : 'fastest']) %>">统计</a> |
||||||
|
<a class="small ui yellow button" href="<%= syzoj.utils.makeUrl(['problem', problem.id, 'testdata']) %>">测试数据</a> |
||||||
|
<% if (problem.additional_file) { %> |
||||||
|
<a class="small ui teal button" href="<%= syzoj.utils.makeUrl(['problem', problem.id, 'download', 'additional_file']) %>">附加文件</a> |
||||||
|
<% } %> |
||||||
|
<a class="small ui brown button" href="<%= syzoj.utils.makeUrl(['discussion', 'problem', problem.id]) %>" style="position: relative; "> |
||||||
|
讨论 |
||||||
|
<% if (discussionCount) { %> |
||||||
|
<div class="floating ui red tiny circular label" style="background-color: #8c5633 !important; top: -0.6em; "><%= discussionCount %></div> |
||||||
|
<% } %> |
||||||
|
</a> |
||||||
|
<% } %> |
||||||
|
</div> |
||||||
|
<% if (!contest) { %> |
||||||
|
<div class="ui buttons right floated"> |
||||||
|
<% if (problem.allowedEdit) { %> |
||||||
|
<a class="small ui button" href="<%= syzoj.utils.makeUrl(['problem', problem.id, 'edit']) %>">编辑</a> |
||||||
|
<a class="small ui button" href="<%= syzoj.utils.makeUrl(['problem', problem.id, 'manage']) %>">管理</a> |
||||||
|
<% } %> |
||||||
|
<% if (problem.allowedManage) { %> |
||||||
|
<% if (problem.is_public) { %> |
||||||
|
<a class="small ui button" id="dis_public" href-post="<%= syzoj.utils.makeUrl(['problem', problem.id, 'dis_public']) %>">取消公开</a> |
||||||
|
<% } else { %> |
||||||
|
<a class="small ui button" id="public" href-post="<%= syzoj.utils.makeUrl(['problem', problem.id, 'public']) %>">公开</a> |
||||||
|
<% } %> |
||||||
|
<div class="ui basic modal" id="modal-delete"> |
||||||
|
<div class="ui icon header"> |
||||||
|
<i class="trash icon"></i> |
||||||
|
<p style="margin-top: 15px; ">删除题目</p> |
||||||
|
</div> |
||||||
|
<div class="content" style="text-align: center; "> |
||||||
|
<p>确认删除此题目吗?提交记录、讨论以及测试数据将一并删除。<br> |
||||||
|
删除题目导致的修改用户提交、通过数量可能会耗费一些时间。</p> |
||||||
|
<b>警告:删除比赛中的题目会导致系统错乱!请确认没有比赛使用此题目。</b> |
||||||
|
</div> |
||||||
|
<div class="actions"> |
||||||
|
<div class="ui red basic cancel inverted button"> |
||||||
|
<i class="remove icon"></i> |
||||||
|
否 |
||||||
|
</div> |
||||||
|
<a class="ui green ok inverted button" href-post="<%= syzoj.utils.makeUrl(['problem', problem.id, 'delete']) %>"> |
||||||
|
<i class="checkmark icon"></i> |
||||||
|
是 |
||||||
|
</a> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
<div class="small ui red button" onclick="$('#modal-delete').modal('show')">删除</div> |
||||||
|
<% } %> |
||||||
|
</div> |
||||||
|
<% } %> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
<% if (problem.description) { %> |
||||||
|
<div class="row"> |
||||||
|
<div class="column"> |
||||||
|
<h4 class="ui top attached block header">题目描述</h4> |
||||||
|
<div class="ui bottom attached segment font-content"><%- problem.description %></div> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
<% } %> |
||||||
|
<% if (problem.input_format) { %> |
||||||
|
<div class="row"> |
||||||
|
<div class="column"> |
||||||
|
<h4 class="ui top attached block header">输入格式</h4> |
||||||
|
<div class="ui bottom attached segment font-content"><%- problem.input_format %></div> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
<% } %> |
||||||
|
<% if (problem.output_format) { %> |
||||||
|
<div class="row"> |
||||||
|
<div class="column"> |
||||||
|
<h4 class="ui top attached block header">输出格式</h4> |
||||||
|
<div class="ui bottom attached segment font-content"><%- problem.output_format %></div> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
<% } %> |
||||||
|
<% if (problem.example) { %> |
||||||
|
<div class="row"> |
||||||
|
<div class="column"> |
||||||
|
<h4 class="ui top attached block header">样例</h4> |
||||||
|
<div class="ui bottom attached segment font-content"><%- problem.example %></div> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
<% } %> |
||||||
|
<% if (problem.limit_and_hint) { %> |
||||||
|
<div class="row"> |
||||||
|
<div class="column"> |
||||||
|
<h4 class="ui top attached block header">数据范围与提示</h4> |
||||||
|
<div class="ui bottom attached segment font-content"><%- problem.limit_and_hint %></div> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
<% } %> |
||||||
|
<% if (problem.tags && problem.tags.length && (typeof contest === 'undefined' || !contest)) { %> |
||||||
|
<div class="row"> |
||||||
|
<div class="column"> |
||||||
|
<h4 class="ui block header" id="show_tag_title_div" style="margin-bottom: 0; margin-left: -1px; margin-right: -1px; "><a href="#" id="show_tag_button" style="color: #000; ">显示分类标签</a></h4> |
||||||
|
<div class="ui bottom attached segment" style="display: none; " id="show_tag_div"> |
||||||
|
<% for (let tag of problem.tags) { %> |
||||||
|
<a href="<%= syzoj.utils.makeUrl(['problems', 'tag', tag.id]) %>" class="ui medium <%= tag.color %> label"> |
||||||
|
<%= tag.name %> |
||||||
|
</a> |
||||||
|
<% } %> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
<script> |
||||||
|
$(function () { |
||||||
|
$('#show_tag_button').click(function (e) { |
||||||
|
e.preventDefault(); |
||||||
|
$('#show_tag_title_div').addClass('top'); |
||||||
|
$('#show_tag_title_div').addClass('top attached'); |
||||||
|
$('#show_tag_title_div').text('分类标签'); |
||||||
|
$('#show_tag_div').css('display', ''); |
||||||
|
}) |
||||||
|
}); |
||||||
|
</script> |
||||||
|
<% } %> |
||||||
|
<% let noSubmit = false; %> |
||||||
|
<% |
||||||
|
if (typeof contest !== 'undefined' && contest && contest.ended || (!testcases || testcases.error)) { |
||||||
|
noSubmit = true; |
||||||
|
} |
||||||
|
%> |
||||||
|
<% if (!noSubmit) { %> |
||||||
|
<div class="row"> |
||||||
|
<div class="column"> |
||||||
|
<% |
||||||
|
const formUrl = syzoj.utils.makeUrl(['problem', 'practice', problem.id, cid, 'submit']); |
||||||
|
%> |
||||||
|
<form action="<%= formUrl %>" method="post" onsubmit="return submit_code()" id="submit_code" enctype="multipart/form-data"> |
||||||
|
<% if (problem.type === 'submit-answer') { %> |
||||||
|
<% |
||||||
|
let cases = []; |
||||||
|
if (testcases && !testcases.error) { |
||||||
|
for (let subtasks of testcases) { |
||||||
|
for (let testcase of subtasks.cases) { |
||||||
|
cases.push(testcase.answer); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
%> |
||||||
|
<script> |
||||||
|
var cases = <%- serializejs(cases) %>, currCase = 0; |
||||||
|
</script> |
||||||
|
<div class="ui grid"> |
||||||
|
<% if (testcases) { %> |
||||||
|
<div class="four wide column" style="margin-right: -25px; "> |
||||||
|
<div class="ui attached vertical fluid pointing menu" id="testcase-menu" style="height: 370px; overflow-y: scroll; overflow-x: hidden; "> |
||||||
|
<% for (let i = 0; i < cases.length; i++) { %> |
||||||
|
<a style="border-radius: 0; " class="item<%= i === 0 ? ' active' : '' %>" data-value="<%= i %>"> |
||||||
|
<%= cases[i] %> |
||||||
|
</a> |
||||||
|
<% } %> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
<div class="twelve wide stretched column" style="position: relative; padding-left: 0; margin-left: calc(-1rem - 1px); width: calc(75% + 1rem + 13px) !important; "> |
||||||
|
<% for (let i = 0; i < cases.length; i++) { %> |
||||||
|
<div id="editor-<%= i %>" class="editor" style="position: absolute; width: 100%; height: calc(100% - 28px); border: 1px solid #D4D4D5; overflow: hidden; <%= i === 0 ? '' : 'visibility: hidden; ' %>"> |
||||||
|
<%- this.showLoadingEditor(); %> |
||||||
|
</div> |
||||||
|
<% } %> |
||||||
|
</div> |
||||||
|
<% } %> |
||||||
|
<input id="answer_by_editor" name="answer_by_editor" type="hidden"> |
||||||
|
<script> |
||||||
|
window.onEditorLoaded(function () { |
||||||
|
window.editors = []; |
||||||
|
for (var i = 0; i < cases.length; i++) { |
||||||
|
var editor = window.createCodeEditor(document.getElementById("editor-" + i)); |
||||||
|
editors[i] = editor; |
||||||
|
} |
||||||
|
|
||||||
|
$(function () { |
||||||
|
$('#testcase-menu .item').click(function() { |
||||||
|
$(this) |
||||||
|
.addClass('active') |
||||||
|
.closest('.ui.menu') |
||||||
|
.find('.item') |
||||||
|
.not($(this)) |
||||||
|
.removeClass('active') |
||||||
|
; |
||||||
|
|
||||||
|
var x = $(this).attr('data-value'); |
||||||
|
if (currCase != x) { |
||||||
|
$('#editor-' + currCase).css('visibility', 'hidden'); |
||||||
|
$('#editor-' + x).css('visibility', 'visible'); |
||||||
|
currCase = x; |
||||||
|
} |
||||||
|
}); |
||||||
|
}); |
||||||
|
}); |
||||||
|
</script> |
||||||
|
<div class="ui form" style="width: 100%; "> |
||||||
|
<div class="inline fields" style="width: 100%; "> |
||||||
|
<div class="field" style="margin: 0 auto; "> |
||||||
|
<label for="answer">或者,上传答案(请使用 ZIP 格式压缩)</label> |
||||||
|
<input type="file" id="answer" name="answer"> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
<div class="ui center aligned vertical segment" style="padding-bottom: 0; "><button type="submit" class="ui labeled icon button"><i class="ui edit icon"></i>提交</button></div> |
||||||
|
<% } else { %> |
||||||
|
<input name="language" type="hidden" id="form"> |
||||||
|
<input name="code" type="hidden"> |
||||||
|
<div class="ui grid"> |
||||||
|
<div class="four wide column" style="margin-right: -25px; "> |
||||||
|
<div class="ui attached vertical fluid pointing menu" id="languages-menu" style="height: 370px; overflow-y: scroll; overflow-x: hidden; "> |
||||||
|
<% |
||||||
|
let language = syzoj.config.enabled_languages[0]; |
||||||
|
if (state) { |
||||||
|
language = state.language; |
||||||
|
} else if (lastLanguage) language = lastLanguage; |
||||||
|
%> |
||||||
|
<% for (lang of syzoj.config.enabled_languages) { %> |
||||||
|
<a style="border-radius: 0; " class="item<%= lang === language ? ' active' : '' %>" data-value="<%= lang %>" data-mode="<%= syzoj.languages[lang].editor %>"> |
||||||
|
<%= syzoj.languages[lang].show %> |
||||||
|
<div class="ui right floated" style="opacity: 0.4; margin-top: 8px; font-size: 0.7em; "><%= syzoj.languages[lang].version %></div> |
||||||
|
</a> |
||||||
|
<% } %> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
<div class="twelve wide stretched column" style="position: relative; padding-left: 0; margin-left: calc(-1rem - 1px); width: calc(75% + 1rem + 13px) !important; "> |
||||||
|
<div id="editor" style="position: absolute; width: 100%; height: calc(100% - 28px); border: 1px solid #D4D4D5; overflow: hidden; " class="editor"> |
||||||
|
<%- this.showLoadingEditor(); %> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
<div class="ui form" style="width: 100%; "> |
||||||
|
<div class="inline fields" style="width: 100%; "> |
||||||
|
<div class="field" style="margin: 0 auto; "> |
||||||
|
<label for="answer">或者,上传代码文件</label> |
||||||
|
<input type="file" id="answer" name="answer"> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
<div class="ui center aligned vertical segment" style="padding-bottom: 0; "> |
||||||
|
<button type="submit" class="ui labeled icon button"><i class="ui edit icon"></i>提交</button> |
||||||
|
</div> |
||||||
|
<% } %> |
||||||
|
</form> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
<% } %> |
||||||
|
</div> |
||||||
|
|
||||||
|
<% if (problem.type !== 'submit-answer') { %> |
||||||
|
<script type="text/javascript"> |
||||||
|
var editor; |
||||||
|
window.onEditorLoaded(function () { |
||||||
|
var editorElement = document.getElementById('editor'); |
||||||
|
var content = ''; |
||||||
|
<% if (state) { %>content = <%- serializejs(state.code) %>;<% } %> |
||||||
|
editor = window.createCodeEditor(editorElement, $('#languages-menu .item.active').data('mode'), content); |
||||||
|
window.editor = editor; |
||||||
|
}); |
||||||
|
|
||||||
|
var lastSubmitted = ''; |
||||||
|
|
||||||
|
function submit_code() { |
||||||
|
if (!$('#submit_code input[name=answer]').val().trim() && !editor.getValue().trim()) return false; |
||||||
|
$('#submit_code input[name=language]').val($('#languages-menu .item.active').data('value')); |
||||||
|
lastSubmitted = editor.getValue(); |
||||||
|
$('#submit_code input[name=code]').val(editor.getValue()); |
||||||
|
return true; |
||||||
|
} |
||||||
|
|
||||||
|
$('#languages-menu')[0].scrollTop = $('#languages-menu .active')[0].offsetTop - $('#languages-menu')[0].firstElementChild.offsetTop; |
||||||
|
|
||||||
|
$(function () { |
||||||
|
$('#languages-menu .item').click(function() { |
||||||
|
$(this) |
||||||
|
.addClass('active') |
||||||
|
.closest('.ui.menu') |
||||||
|
.find('.item') |
||||||
|
.not($(this)) |
||||||
|
.removeClass('active') |
||||||
|
; |
||||||
|
monaco.editor.setModelLanguage(editor.getModel(), $(this).data('mode')); |
||||||
|
}); |
||||||
|
}); |
||||||
|
</script> |
||||||
|
|
||||||
|
<% } else { %> |
||||||
|
<script> |
||||||
|
function submit_code() { |
||||||
|
var a = []; |
||||||
|
for (var i = 0; i < cases.length; i++) { |
||||||
|
a.push({ |
||||||
|
filename: cases[i], |
||||||
|
data: editors[i].getValue() |
||||||
|
}); |
||||||
|
} |
||||||
|
$('#answer_by_editor').val(JSON.stringify(a)); |
||||||
|
} |
||||||
|
</script> |
||||||
|
<% } %> |
||||||
|
<% include footer %> |
Loading…
Reference in new issue