This commit is contained in:
yi-ge 2019-06-30 21:18:31 +08:00
commit db843337ce
31 changed files with 4888 additions and 0 deletions

14
.gitignore vendored Normal file
View File

@ -0,0 +1,14 @@
# CakePHP 3
/vendor/*
/config/app.php
/tmp/*
/logs/*
# CakePHP 2
/app/tmp/*
/app/Config/core.php
/app/Config/database.php
/vendors/*
.idea

20
LICENSE Normal file
View File

@ -0,0 +1,20 @@
The MIT License (MIT)
Copyright (c) 2018 轶哥
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

3
README.md Normal file
View File

@ -0,0 +1,3 @@
# online-php-practice
> 在线 PHP 练习平台

447
api.php Normal file
View File

@ -0,0 +1,447 @@
<?php
error_reporting(0);
require_once 'config.php';
require_once 'medoo.php';
use Medoo\Medoo;
$database = new Medoo($DBCONFIG);
$redis = new Redis();
$redis->connect($REDISCONFIG['host'], $REDISCONFIG['port'], $REDISCONFIG['database']);
$redis->auth($REDISCONFIG['password']);
header('Access-Control-Allow-Headers: Authorization, DNT, User-Agent, Keep-Alive, Origin, X-Requested-With, Content-Type, Accept, x-clientid');
header('Access-Control-Allow-Methods: PUT, POST, GET, DELETE, OPTIONS');
header('Access-Control-Allow-Origin: *');
header('Content-Type: application/json; charset=utf-8');
function action_login($database, $redis)
{
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, 'https://login.yige.ink/info?token=' . $_ENV['API_TOKEN'] . '&code=' . $_GET['code']);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_HEADER, 0);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
$output = curl_exec($ch);
curl_close($ch);
$output_array = json_decode($output, true);
$output_array['privilege'] = json_encode($output_array['privilege']);
$row = $database->select('userinfo', '*', [
'openid' => $output_array['openid'],
]);
if (sizeof($row) != 0) {
$database->update('userinfo', $output_array, [
'openid' => $output_array['openid'],
]);
$output_array['openid'] = null;
echo json_encode([
'status' => 1,
'result' => [
'id' => $row[0]['id'],
'userinfo' => $output_array
]
]);
} else {
$database->insert('userinfo', $output_array);
$output_array['openid'] = null;
echo json_encode([
'status' => 1,
'result' => [
'id' => $database->id(),
'userinfo' => $output_array
]
]);
}
}
function action_listUser($database, $redis)
{
$row = $database->select('userinfo', '*');
echo json_encode([
'status' => 1,
'result' => [
'list' => $row,
]
]);
}
function action_getUserInfo($database, $redis)
{
$row = $database->select('userinfo', '*', [
'id' => $_POST['id'],
]);
echo json_encode([
'status' => 1,
'result' => [
'userinfo' => $row[0]
]
]);
}
function action_setRealName($database, $redis)
{
$database->update('userinfo', [
'realname' => $_POST['realname']
], [
'id' => $_POST['id'],
]);
echo json_encode([
'status' => 1
]);
}
function handleRow($row)
{
foreach ($row as $ro => $val) {
if (is_numeric($ro)) {
unset($row[$ro]);
}
}
if ($row['isAnswer'] == '1') {
$row['isAnswer'] = '有';
} else {
$row['isAnswer'] = '无';
}
$row['passPercent'] = round((float)$row['passPercent'] * 100, 2) . '%';
if ($row['difficulty'] == '1') {
$row['difficulty'] = '简单';
} else if ($row['difficulty'] == '2') {
$row['difficulty'] = '中等';
} else if ($row['difficulty'] == '3') {
$row['difficulty'] = '困难';
}
unset($row['type']);
return array_values($row);
}
function handleSortRows($rows)
{
uksort($rows, function ($a, $b) {
return (int)$a['no'] - (int)$b['no'];
});
}
function action_getProblemsetList($database, $redis)
{
// $rowAll = $database->debug()->select('problemset', [
// "[>]record" => [
// "id" => "problemset_id",
// $_GET['user_id'] => "user_id"
// ],
// ], [
// 'record.is_pass',
// 'problemset.id',
// 'problemset.no',
// 'problemset.name',
// 'problemset.language',
// 'problemset.type',
// 'problemset.isAnswer',
// 'problemset.passPercent',
// 'problemset.difficulty',
// ], [
// "ORDER" => "no"
// ]);
$rowAll = $database->query("SELECT
`record`.`is_pass`,
`problemset`.`id`,
`problemset`.`no`,
`problemset`.`name`,
`problemset`.`language`,
`problemset`.`type`,
`problemset`.`isAnswer`,
`problemset`.`passPercent`,
`problemset`.`difficulty`
FROM
`problemset`
LEFT JOIN `record` ON `problemset`.`id` = `record`.`problemset_id` AND `record`.`user_id` = " . $_GET['user_id'] . " ORDER BY
`no`")->fetchAll();
$rowStage = [];
$rowChallenge = [];
foreach ($rowAll as $row)
if ($row['type'] == '1')
array_push($rowStage, handleRow($row));
else
array_push($rowChallenge, handleRow($row));
handleSortRows($rowStage);
handleSortRows($rowChallenge);
echo json_encode([
'status' => 1,
'result' => [
'stage' => $rowStage,
'challenge' => $rowChallenge,
'test' => $database->log()
]
]);
}
function action_editProblemset($database, $redis)
{
$datas = $_POST;
$database->update('problemset', $datas, [
'id' => $_GET['id']
]);
echo json_encode([
'status' => 1
]);
}
function action_addProblemset($database, $redis)
{
$datas = $_POST;
$datas['no'] = $redis->incr("ids_" . $datas['type']);
$database->insert('problemset', $datas);
echo json_encode([
'status' => 1,
'result' => [
'id' => $database->id(),
'no' => $datas['no']
]
]);
}
function action_getProblemset($database, $redis)
{
if (isset($_GET['id'])) {
$row = $database->select('problemset', '*', [
'id' => $_GET['id']
]);
if (sizeof($row) > 0) {
$row = $row[0];
echo json_encode([
'status' => 1,
'result' => $row
]);
} else {
echo json_encode([
'status' => 2,
'msg' => '没有找到此题目信息'
]);
}
} else {
echo json_encode([
'status' => 0,
'msg' => '缺少必须参数'
]);
}
}
function action_saveTestCode($database, $redis)
{
$datas = $_POST;
$redis->set('testCode_' . $datas['user_id'], $datas['code']);
// if ($database->has("test_record", [
// 'user_id' => $datas['user_id']
// ])) {
// $database->update("test_record", [
// 'code' => $datas['code']
// ], [
// 'user_id' => $datas['user_id']
// ]);
// } else {
// $database->insert('test_record', $datas);
// }
echo json_encode([
'status' => 1
]);
}
function action_getTestCode($database, $redis)
{
$datas = $_POST;
// $row = $database->select("test_record", ["code"], [
// 'user_id' => $datas['user_id']
// ]);
$res = $redis->get('testCode_' . $datas['user_id']);
if ($res == null || $res == "") {
echo json_encode([
'status' => 1,
'code' => '<?php
echo "Hello World!";'
]);
} else {
echo json_encode([
'status' => 1,
'code' => $res
]);
}
}
function addCredit($database, $problemsetId, $userId)
{
$problemsetRow = $database->select("problemset", ['id', 'isCredit', 'credit', 'type', 'no'], [
'id' => $problemsetId
]);
if ($problemsetRow[0]['isCredit'] == '1') {
$userinfoRow = $database->select("userinfo", ['id', "credit"], [
'id' => $userId
]);
$oldCredit = $userinfoRow[0]['credit'];
$addCredit = $problemsetRow[0]['credit'];
$newCredit = (int)$oldCredit + (int)$addCredit;
if (!$database->has("credit_flow", [ // 限制一道题只能获得一次积分
'problemset_id' => $problemsetId
])) {
$theType = '闯关模式';
if ($problemsetRow[0]['type'] == '2') {
$theType = '挑战赛';
}
$log = $theType . '第' . $problemsetRow[0]['no'] . '题得分';
$database->insert('credit_flow', [ // 写入积分变动日志
'log' => $log,
'user_id' => $userId,
'problemset_id' => $problemsetId,
'income' => $addCredit,
'credit' => $newCredit
]);
$database->update('userinfo', [
'credit' => $newCredit
], [
'id' => $userId
]);
}
}
}
function action_addRecord($database, $redis)
{
$datas = $_POST;
$row = $database->select("record", ['is_pass'], [
'user_id' => $datas['user_id'],
'problemset_id' => $datas['problemset_id']
]);
if (sizeof($row) != 0) {
if ($datas['is_pass'] == '1' || $row[0]['is_pass'] != '1') {
$database->update('record', $datas, [
'user_id' => $datas['user_id'],
'problemset_id' => $datas['problemset_id']
]);
}
} else {
$database->insert('record', $datas);
}
echo json_encode([
'status' => 1
]);
fastcgi_finish_request();
// 异步
if ($datas['is_pass'] == '1') { // 增加积分
addCredit($database, $datas['problemset_id'], $datas['user_id']);
}
}
function action_getRecord($database, $redis)
{
$datas = $_POST;
$row = $database->select("record", ['code'], [
'user_id' => $datas['user_id'],
'problemset_id' => $datas['problemset_id']
]);
if (sizeof($row) != 0) {
echo json_encode([
'status' => 1,
'code' => $row[0]['code']
]);
} else {
echo json_encode([
'status' => 2
]);
}
}
function action_getNextNo($database, $redis)
{
$no = (int)$_GET['no'] + 1;
$row = $database->select("problemset", ["id"], [
'no' => $no,
'type' => $_GET['type']
]);
if (sizeof($row) != 0) {
echo json_encode([
'status' => 1,
'id' => $row[0]['id']
]);
} else {
echo json_encode([
'status' => 1,
'id' => 0
]);
}
}
function action_getMyRecordCount($database, $redis)
{
$Allcount = $database->count("problemset", [
"type" => "1"
]);
$passCount = $database->count("record", [
'user_id' => $_GET['user_id'],
'is_pass' => '1'
]);
echo json_encode([
'status' => 1,
'result' => [
'all' => $Allcount,
'pass' => $passCount
]
]);
}
if (isset($_GET['action'])) {
$action = "action_" . $_GET['action'];
$action($database, $redis);
} else {
echo json_encode(['err' => '非法访问']);
}

17
config.php Normal file
View File

@ -0,0 +1,17 @@
<?php
$DBCONFIG = [
'database_type' => 'mysql',
'database_name' => $_ENV['MYSQL_DBNAME'],
'server' => $_ENV['MYSQL_HOST'],
'username' => $_ENV['MYSQL_USERNAME'],
'password' => $_ENV['MYSQL_PASSWORD'],
'charset' => 'utf8mb4',
'port' => $_ENV['MYSQL_PORT'],
];
$REDISCONFIG = [
'host' => $_ENV['REDIS_HOST'],
'port' => $_ENV['REDIS_PORT'],
'password' => $_ENV['REDIS_PASSWORD'],
'database' => 0
];

281
css/common.css Normal file
View File

@ -0,0 +1,281 @@
* {
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
}
html, body {
height: 100%;
width: 100%;
}
a {
text-decoration: none;
color: rgb(61, 146, 201);
}
a:hover,
a:focus {
text-decoration: none;
}
#loading {
position: absolute;
left: 0;
top: 0;
z-index: 9999999;
background: #fff;
width: 100%;
height: 100%;
}
#loading img {
position: absolute;
top: 50%;
left: 50%;
width: 16px;
margin-top: -4px;
margin-left: -4px;
}
.pure-menu-selected .pure-menu-link, .pure-menu-selected .pure-menu-link:visited {
background-color: #373C5A;
color: #adbdad;
}
.pure-menu-heading {
color: #d7d9dc;
}
.pure-menu-link {
color: #adbdad;
}
h3 {
font-weight: 100;
}
/* LAYOUT CSS */
.pure-img-responsive {
max-width: 100%;
height: auto;
}
#layout {
padding: 0;
}
.header {
top: auto;
padding: 0.5em 1em;
margin: 0 0;
position: relative;
text-align: left;
background-color: #252A3A;
}
.header .pure-menu {
border-bottom-color: black;
border-radius: 0;
}
.userinfo {
position: absolute;
top: 0;
right: 50px;
}
#leftPane {
padding: 10px;
}
#rightPane {
padding: 10px;
height: 100%;
}
#avator img {
margin-top: 5px;
width: 40px;
border-radius: 50%;
}
#logout {
position: absolute;
right: 10px;
top: 1em;
}
#avator {
float: right;
}
#nickname {
color: #888;
line-height: 50px;
float: right;
margin-right: 10px;
}
#realname {
color: #888;
line-height: 50px;
float: right;
margin-right: 5px;
}
#container {
width: 100%;
min-height: 300px;
min-width: 300px;
border: 1px solid #eeeeee;
box-sizing: border-box;
}
.footer {
padding: 1em 0;
text-align: center;
}
.footer a {
color: #ccc;
font-size: 80%;
}
.footer .pure-menu a:hover,
.footer .pure-menu a:focus {
background: none;
}
#out {
margin-top: 0;
border: 1px solid #eeeeee;
width: 100%;
height: 100%;
box-sizing: border-box;
}
#run {
margin-top: 10px;
float: right;
}
#testRun {
margin-top: 10px;
float: right;
margin-right: 10px;
}
.auto {
line-height: 60px;
margin-top: 10px;
}
iframe {
border: 0;
background: #fff;
flex: 1 1 auto;
width: 100%;
height: 100%;
}
#rightPane code {
color: #888;
padding: 0 6px;
}
/* index.php */
.index-main {
padding: 10px;
}
.index-main-table {
width: 100%;
}
.horizontal {
list-style: none outside none;
margin: 15px 0;
height: 30px;
}
.horizontal li {
float: left;
margin-right: 10px;
}
.horizontal .active .pure-button {
box-shadow: 0 0 0 1px rgba(0, 0, 0, .15) inset, 0 0 6px rgba(0, 0, 0, .2) inset;
}
.admin {
display: none;
}
#describeView, #answerView, #resultView {
height: 100%;
padding-bottom: 110px;
}
#describeView .cont, #answerView .cont {
border: 1px solid #eeeeee;
height: 100%;
padding: 10px;
overflow-y: auto;
}
#resultView .cont {
height: 100%;
padding: 10px;
overflow-y: auto;
}
.testCase {
min-height: 50px;
}
.testCaseContent, .expectedResultContent {
border: 1px solid #eeeeee;
padding: 5px 10px;
width: 100%;
}
.expectedResult {
min-height: 60px;
}
.resultContent {
height: 100%;
border: 1px solid #eeeeee;
}
#rightPane .cont pre code {
padding: 10px;
}
.dataTable td {
text-align: center;
}
.dataTable .table-pname {
text-align: left;
}
.myCredit {
position: absolute;
right: 50px;
top: 63px;
line-height: 38px;
}
.myRecord {
position: absolute;
right: 150px;
top: 63px;
line-height: 38px;
}
.dataTable .table-is-pass {
text-align: right;
}

82
css/jquery.splitter.css Normal file
View File

@ -0,0 +1,82 @@
/*!
* StyleSheet for JQuery splitter Plugin version 0.27.1
* Copyright (C) 2010-2018 Jakub T. Jankiewicz <https://jcubic.pl/me>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
.splitter_panel {
position: relative;
}
.splitter_panel .vsplitter {
background-color: #f5f5f5;
cursor: col-resize;
z-index: 900;
width: 7px;
}
.splitter_panel .vsplitter:hover {
background-color: #dddddd;
}
.splitter_panel .hsplitter {
background-color: #5F5F5F;
cursor: row-resize;
z-index: 800;
height: 7px;
}
.splitter_panel .vsplitter.splitter-invisible,
.splitter_panel .hsplitter.splitter-invisible {
background: none;
}
.splitter_panel .vsplitter, .splitter_panel .left_panel, .splitter_panel .right_panel,
.splitter_panel .hsplitter, .splitter_panel .top_panel, .splitter_panel .bottom_panel {
position: absolute;
overflow: auto;
}
.splitter_panel .vsplitter, .splitter_panel .left_panel, .splitter_panel .right_panel {
height: 100%;
}
.splitter_panel .hsplitter, .splitter_panel .top_panel, .splitter_panel .bottom_panel {
width: 100%;
}
.splitter_panel .top_panel, .splitter_panel .left_panel, .splitter_panel .vsplitter {
top: 0;
}
.splitter_panel .top_panel, .splitter_panel .bottom_panel, .splitter_panel .left_panel, .splitter_panel .hsplitter {
left: 0;
}
.splitter_panel .bottom_panel {
bottom: 0;
}
.splitter_panel .right_panel {
right: 0;
}
.splitterMask {
position: absolute;
left: 0;
top: 0;
right: 0;
bottom: 0;
z-index: 1000;
}

91
db.sql Normal file
View File

@ -0,0 +1,91 @@
-- 开饭平台用户信息:
-- openid 普通用户的标识,对当前开发者帐号唯一
-- nickname 普通用户昵称
-- sex 普通用户性别1为男性2为女性
-- province 普通用户个人资料填写的省份
-- city 普通用户个人资料填写的城市
-- country 国家如中国为CN
-- headimgurl 用户头像最后一个数值代表正方形头像大小有0、46、64、96、132数值可选0代表640*640正方形头像用户没有头像时该项为空
-- privilege 用户特权信息json数组如微信沃卡用户为chinaunicom
-- unionid 用户统一标识。针对一个微信开放平台帐号下的应用同一用户的unionid是唯一的。
-- 开放平台用户
CREATE TABLE `userinfo`(
`id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
`openid` VARCHAR(64) NULL DEFAULT '' COMMENT '微信openid',
`nickname` VARCHAR(128) NULL COMMENT '用户昵称',
`realname` VARCHAR(20) NULL COMMENT '真实姓名',
`sex` TINYINT(1) NULL COMMENT '用户性别1男性2女性',
`language` VARCHAR(16) NULL COMMENT '语言',
`province` VARCHAR(16) NULL COMMENT '用户个人资料填写的省份',
`city` VARCHAR(16) NULL COMMENT '普通用户个人资料填写的城市',
`country` VARCHAR(32) NULL COMMENT '国家如中国为CN',
`headimgurl` VARCHAR(256) NULL COMMENT '用户头像',
`privilege` TEXT NULL COMMENT '用户特权信息json 数组',
`unionid` VARCHAR(128) NULL COMMENT '微信开放平台用户唯一标识',
`admin` TINYINT(1) NULL DEFAULT 0 COMMENT '是否是管理员1是0不是',
`credit` VARCHAR(128) NULL COMMENT '积分',
`created_time` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`updated_time` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间',
PRIMARY KEY(`id`)
);
-- 题目
CREATE TABLE `problemset`(
`id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
`no` BIGINT UNSIGNED NOT NULL,
`type` VARCHAR(12) NULL COMMENT '分类',
`name` VARCHAR(128) NULL COMMENT '题名',
`isAnswer` VARCHAR(12) NULL COMMENT '是否有解答1有其余无',
`language` VARCHAR(16) NULL COMMENT '编程语言',
`passPercent` VARCHAR(16) NULL COMMENT '通过率',
`difficulty` VARCHAR(16) NULL COMMENT '难度',
`tag` VARCHAR(255) NULL COMMENT '标签',
`mark` VARCHAR(256) NULL COMMENT '备注',
`describe` LONGTEXT NULL COMMENT '题目描述',
`answer` LONGTEXT NULL COMMENT '解答',
`phpCode` LONGTEXT NULL COMMENT 'PHP代码',
`javascriptCode` LONGTEXT NULL COMMENT 'Javascript代码',
`phpUnitCode` LONGTEXT NULL COMMENT 'PHP测试代码',
`testCase` LONGTEXT NULL COMMENT '测试用例',
`expectedResult` LONGTEXT NULL COMMENT '预期结果',
`credit` DECIMAL(8, 2) NULL COMMENT '积分',
`isCredit` VARCHAR(5) NULL DEFAULT '0' COMMENT '是否积分1是0不是',
`created_time` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`updated_time` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间',
PRIMARY KEY(`id`)
);
-- 做题记录
CREATE TABLE `record`(
`id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
`user_id` BIGINT UNSIGNED NOT NULL,
`problemset_id` BIGINT UNSIGNED NOT NULL,
`type` VARCHAR(12) NULL COMMENT '分类',
`code` LONGTEXT NULL COMMENT '代码',
`is_pass` VARCHAR(5) NULL DEFAULT '0' COMMENT '是否通过测试1是0不是',
`created_time` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`updated_time` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间',
PRIMARY KEY(`id`)
);
-- -- 在线测试的记录
-- CREATE TABLE `test_record`(
-- `user_id` BIGINT UNSIGNED NOT NULL,
-- `code` LONGTEXT NULL COMMENT '代码',
-- `created_time` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
-- `updated_time` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间',
-- PRIMARY KEY(`user_id`)
-- );
-- 积分变动(流水)
CREATE TABLE `credit_flow`(
`id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
`user_id` BIGINT UNSIGNED NOT NULL,
`problemset_id` BIGINT UNSIGNED NOT NULL,
`log` VARCHAR(256) NULL COMMENT '事由',
`income` DECIMAL(8) NOT NULL COMMENT '动账',
`credit` DECIMAL(8) NOT NULL COMMENT '当时总积分',
`create_time` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
PRIMARY KEY(`id`)
);

28
footer.php Normal file
View File

@ -0,0 +1,28 @@
</div>
<script src="/js/uniter.js"></script>
<script crossorigin="anonymous" integrity="sha384-tsQFqpEReu7ZLhBV2VZlAu7zcOV+rXbYlF2cqB8txI/8aZajjp4Bqd+V6D5IgvKT"
src="https://lib.baomitu.com/jquery/3.3.1/jquery.min.js"></script>
<script crossorigin="anonymous" integrity="sha384-RnOqe29SFv+Lre8BvIid2hveg/hFrUKA+uLJCbdL0EyEd6DzesjrF3dIhHh2EHsq"
src="https://lib.baomitu.com/jquery.tabslet.js/1.7.3/jquery.tabslet.min.js"></script>
<script crossorigin="anonymous" integrity="sha384-rgWRqC0OFPisxlUvl332tiM/qmaNxnlY46eksSZD84t+s2vZlqGeHrncwIRX7CGp"
src="https://lib.baomitu.com/datatables/1.10.19/js/jquery.dataTables.min.js"></script>
<script crossorigin="anonymous" integrity="sha384-83rBTICYr+FwAC+A5t0ZYsWjTcPXibCe/NBSFLAgMPkwHBvIi02EcE9OShMsGCi3"
src="https://lib.baomitu.com/simplemde/1.11.2/simplemde.min.js"></script>
<script crossorigin="anonymous" integrity="sha384-KpuxVjTC2hfOkg5KV3jSdx1eA6xy0PGS0wNfDrwf4sZBnZdzlIsnkH+LzLkavmH7"
src="https://lib.baomitu.com/showdown/1.9.0/showdown.min.js"></script>
<script crossorigin="anonymous" integrity="sha384-BlPof9RtjBqeJFskKv3sK3dh4Wk70iKlpIe92FeVN+6qxaGUOUu+mZNpALZ+K7ya"
src="https://lib.baomitu.com/highlight.js/9.13.1/highlight.min.js"></script>
<script crossorigin="anonymous" integrity="sha384-heo+KfbBN7U3Mb1E3ZDC1aW97zVBWyXmxIr/HQIgGrtBAUaHD1lBFq4Jlfq86SJe"
src="https://lib.baomitu.com/monaco-editor/0.15.6/min/vs/loader.js"></script>
<script src="/js/jquery.splitter.js"></script>
<script src="/js/common.js"></script>
<script src="/js<?php
if ($nowURL != '/') {
echo substr($nowURL, 0, strlen($nowURL) - 4);
} else {
echo 'index';
}
?>.js"></script>
</body>
</html>

66
header.php Normal file
View File

@ -0,0 +1,66 @@
<?php
//获得当前的脚本网址
function GetCurUrl()
{
return $_SERVER["PHP_SELF"];
}
$nowURL = GetCurUrl();
?>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>在线PHP练习</title>
<link crossorigin="anonymous" integrity="sha384-9Z9AuAj0Xi0z7WFOSgjjow8EnNY9wPNp925TVLlAyWhvZPsf5Ks23Ex0mxIrWJzJ"
href="https://lib.baomitu.com/normalize/8.0.1/normalize.min.css" rel="stylesheet">
<link crossorigin="anonymous" integrity="sha384-GQvMoYnQA47ImcAuL/b527e+tU96IK4h/WH1i8Y2oWVSzAne5jXEPr79FFDjbP2O"
href="https://lib.baomitu.com/pure/1.0.0/base-min.css" rel="stylesheet">
<link crossorigin="anonymous" integrity="sha384-b92sF+wDNTHrfEtRaYo+EpcA8FUyHOSXrdxKc9XB9kaaX1rSQAgMevW6cYeE5Bdv"
href="https://lib.baomitu.com/pure/1.0.0/grids-responsive-min.css" rel="stylesheet">
<link crossorigin="anonymous" integrity="sha384-T7EqrTLlfKxgBXvvj/5Lz2LDKWPwLFsdS/T4MmXC+EjrRKTH9FWtGOn+JHoKWzSJ"
href="https://lib.baomitu.com/pure/1.0.0/menus-min.css" rel="stylesheet">
<link crossorigin="anonymous" integrity="sha384-FmOvPjY6YwQXYea5Ja+3CH7+feIm/+HpUXtRUh8g0F7ybli4aDV//h1GzWLDpwHO"
href="https://lib.baomitu.com/pure/1.0.0/forms-min.css" rel="stylesheet">
<link crossorigin="anonymous" integrity="sha384-fCgQlRnjKz+VWhXVjN344OnXNV9kmKYH2rCqLz4TmMne2vnO1ykQU4Cz1llu+ud8"
href="https://lib.baomitu.com/pure/1.0.0/buttons-min.css" rel="stylesheet">
<link crossorigin="anonymous" integrity="sha384-MIf4KOt3X2OQ4tRxVM7Ygl5hNkkyYabJ8zm0m+TDRw9NYmAkEXXFpst8PVbF2s/9"
href="https://lib.baomitu.com/pure/1.0.0/tables-min.css" rel="stylesheet">
<link crossorigin="anonymous" integrity="sha384-rQdIropf4eQBEB9SkNB4xxukYHlkyXJfKYkpVNUQOLizz+d2q0wo7zjVA2XcYSij"
href="https://lib.baomitu.com/simplemde/1.11.2/simplemde.min.css" rel="stylesheet">
<link crossorigin="anonymous" integrity="sha384-HNGokaYN28H3qifBLVX5/ob64kuuYiIeQfo/b+M/hzijJeueJbsVEAvglj1qvfuY"
href="https://lib.baomitu.com/highlight.js/9.13.1/styles/vs.min.css" rel="stylesheet">
<link crossorigin="anonymous" integrity="sha384-1UXhfqyOyO+W+XsGhiIFwwD3hsaHRz2XDGMle3b8bXPH5+cMsXVShDoHA3AH/y/p"
href="https://lib.baomitu.com/datatables/1.10.19/css/jquery.dataTables.min.css" rel="stylesheet">
<link href="/css/jquery.splitter.css" rel="stylesheet">
<link href="/css/common.css" rel="stylesheet">
</head>
<body>
<div id="loading">
<img src="/loading.gif">
</div>
<div id="layout" class="pure-g">
<div class="header">
<div class="pure-menu pure-menu-horizontal">
<span class="pure-menu-heading">PHP练习</span>
<?php include('menu.php'); ?>
</div>
<div class="userinfo">
<div id="avator"></div>
<div id="nickname"></div>
<div id="realname"></div>
</div>
<div id="logout">
<svg viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink" width="25" height="25">
<path fill="#d7d9dc"
d="M835.669333 554.666667h-473.173333A42.453333 42.453333 0 0 1 320 512a42.666667 42.666667 0 0 1 42.474667-42.666667h473.173333l-161.813333-161.834666a42.666667 42.666667 0 0 1 60.330666-60.330667l234.666667 234.666667a42.666667 42.666667 0 0 1 0 60.330666l-234.666667 234.666667a42.666667 42.666667 0 0 1-60.330666-60.330667L835.669333 554.666667zM554.666667 42.666667a42.666667 42.666667 0 1 1 0 85.333333H149.525333C137.578667 128 128 137.578667 128 149.482667v725.034666C128 886.4 137.6 896 149.525333 896H554.666667a42.666667 42.666667 0 1 1 0 85.333333H149.525333A106.816 106.816 0 0 1 42.666667 874.517333V149.482667A106.773333 106.773333 0 0 1 149.525333 42.666667H554.666667z"></path>
</svg>
</div>
</div>

24
index.php Normal file
View File

@ -0,0 +1,24 @@
<?php include('header.php'); ?>
<div class="myRecord"><button class="pure-button" id="myRecordButton">我的学习统计</button></div>
<div class="myCredit"></div>
<div class='tabs tabs_default'>
<ul class='horizontal'>
<li><a class="pure-button" href="#stage">闯关模式</a></li>
<li><a class="pure-button" href="#challenge">挑战赛</a></li>
<li><a class="pure-button admin" target="_blank" href="/page/user.php">用户管理</a></li>
<li><a class="pure-button pure-button-primary admin" target="_blank" href="/page/edit.php">添加新题目</a></li>
</ul>
<div id='stage'>
<div class="index-main">
<table id="stage-table" class="stripe">
</table>
</div>
</div>
<div id='challenge'>
<div class="index-main">
<table id="challenge-table" class="stripe">
</table>
</div>
</div>
</div>
<?php include('footer.php'); ?>

147
js/common.js Normal file
View File

@ -0,0 +1,147 @@
require.config({paths: {'vs': 'https://lib.baomitu.com/monaco-editor/0.15.6/min/vs'}});
// Before loading vs/editor/editor.main, define a global MonacoEnvironment that overwrites
// the default worker url location (used when creating WebWorkers). The problem here is that
// HTML5 does not allow cross-domain web workers, so we need to proxy the instantiation of
// a web worker through a same-domain script
window.MonacoEnvironment = {
getWorkerUrl: function (workerId, label) {
return '/js/monaco-editor-worker-loader-proxy.js';
}
};
window.isAdmin = false;
function getNowDate() {
var date = new Date();
var sign1 = "-";
var sign2 = ":";
var year = date.getFullYear() // 年
var month = date.getMonth() + 1; // 月
var day = date.getDate(); // 日
var hour = date.getHours(); // 时
var minutes = date.getMinutes(); // 分
var seconds = date.getSeconds() //秒
var weekArr = ['星期一', '星期二', '星期三', '星期四', '星期五', '星期六', '星期天'];
var week = weekArr[date.getDay()];
// 给一位数数据前面加 “0”
if (month >= 1 && month <= 9) {
month = "0" + month;
}
if (day >= 0 && day <= 9) {
day = "0" + day;
}
if (hour >= 0 && hour <= 9) {
hour = "0" + hour;
}
if (minutes >= 0 && minutes <= 9) {
minutes = "0" + minutes;
}
if (seconds >= 0 && seconds <= 9) {
seconds = "0" + seconds;
}
return year + sign1 + month + sign1 + day + " " + hour + sign2 + minutes + sign2 + seconds + " " + week;
}
function GetQueryString(name) {
var reg = new RegExp("(^|&)"+ name +"=([^&]*)(&|$)");
var r = window.location.search.substr(1).match(reg);
if (r!=null) return unescape(r[2]); return '';
}
$(function () {
var id = window.localStorage.id;
if (!id) {
window.location.href = '/login.html'
}
var setRealName = function (id, realname) {
$.ajax({
type: "POST",
url: "/api.php?action=setRealName",
dataType: "json",
cache: !1,
timeout: 6e4,
data: {
id: id,
realname: realname
},
success: function (r) {
if (r.status === 1) {
console.log('保存真实姓名成功!')
} else {
alert('很抱歉,保存真实姓名失败,请稍后刷新重试。')
}
},
error: function () {
alert('很抱歉,出错了,请稍后刷新重试!')
}
})
};
function loadImage(url, callback) {
var img = new Image(); //创建一个Image对象实现图片的预下载
img.crossOrigin = "Anonymous";
img.src = url;
img.onload = function () { //图片下载完毕时异步调用callback函数
callback.call(img);//将回调函数的this替换为Image对象
};
}
var getUserInfo = function (id) {
$.ajax({
type: "POST",
url: "/api.php?action=getUserInfo",
dataType: "json",
cache: !1,
timeout: 6e4,
data: {
id: id
},
success: function (r) {
if (r.status === 1) {
if (!r.result.userinfo) {
window.location.href = "login.html"
}
if (!r.result.userinfo.realname) {
var name = prompt("请输入你的真实姓名,方便大家进行沟通", "");
if (name != null && name !== "") {
r.result.userinfo.realname = name;
setRealName(id, name)
}
}
window.isAdmin = r.result.userinfo.admin === '1';
window.credit = r.result.userinfo.credit;
if ($('.myCredit')) $('.myCredit').text('经验:' + window.credit);
loadImage(r.result.userinfo.headimgurl.replace('http://', 'https://'), function () {
$('#avator').append(this)
});
$('#realname').text(r.result.userinfo.realname);
$('#nickname').text('(' + r.result.userinfo.nickname + ')');
if (window.isAdmin) {
$('.admin').css('display', 'block')
}
} else {
alert('很抱歉,获取用户信息失败,请稍后刷新重试。')
}
},
error: function () {
alert('很抱歉,出错了,请稍后刷新重试!')
}
})
};
$('#logout').click(function () {
window.localStorage.removeItem('id');
window.location.href = "/login.html"
});
getUserInfo(id);
});

187
js/index.js Normal file
View File

@ -0,0 +1,187 @@
$(function () {
var language = {
"sProcessing": "处理中...",
"sLengthMenu": "显示 _MENU_ 项结果",
"sZeroRecords": "没有匹配结果",
"sInfo": "显示第 _START_ 至 _END_ 项结果,共 _TOTAL_ 项",
"sInfoEmpty": "显示第 0 至 0 项结果,共 0 项",
"sInfoFiltered": "(由 _MAX_ 项结果过滤)",
"sInfoPostFix": "",
"sSearch": "搜索:",
"sUrl": "",
"sEmptyTable": "表中数据为空",
"sLoadingRecords": "载入中...",
"sInfoThousands": ",",
"oPaginate": {
"sFirst": "首页",
"sPrevious": "上页",
"sNext": "下页",
"sLast": "末页"
},
"oAria": {
"sSortAscending": ": 以升序排列此列",
"sSortDescending": ": 以降序排列此列"
}
};
var tableInit = function (r) {
$('#stage-table').DataTable({
language: language,
data: r.result.stage,
columns: [
{title: ""},
{title: "ID"},
{title: "No"},
{title: "题名"},
{title: "编程语言"},
{title: "解答"},
{title: "通过率"},
{title: "难度"},
{title: "管理"}
],
"order": [[2, "asc"]],
columnDefs: [
{
"targets": 0,
"orderable": false,
"className": "table-is-pass",
"render": function (data, type, row) {
if (data === '1') {
return '<svg viewBox="0 0 1397 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="27" height="20"><path d="M1396.363636 121.018182c0 0-223.418182 74.472727-484.072727 372.363636-242.036364 269.963636-297.890909 381.672727-390.981818 530.618182C512 1014.690909 372.363636 744.727273 0 549.236364l195.490909-186.181818c0 0 176.872727 121.018182 297.890909 344.436364 0 0 307.2-474.763636 902.981818-707.490909L1396.363636 121.018182 1396.363636 121.018182zM1396.363636 121.018182" fill="#1afa29"></path></svg>';
}
return '';
}
},
{
"targets": 1,
"data": null,
"visible": false,
"orderable": false
},
{
"targets": 3,
"className": "table-pname",
"render": function (data, type, row) {
return '<a href="/page/run.php?id=' + row[1] + '" target="_blank">' + data + '</a>';
}
},
{
"targets": -1,
"data": null,
"visible": window.isAdmin,
"render": function (data, type, row) {
return '<a href="/page/edit.php?id=' + row[1] + '" target="_blank" class="pure-button" style="font-size: 70%;">编辑</a>';
}
}]
});
$('#challenge-table').DataTable({
language: language,
data: r.result.challenge,
columns: [
{title: ""},
{title: "ID"},
{title: "No"},
{title: "题名"},
{title: "编程语言"},
{title: "解答"},
{title: "通过率"},
{title: "难度"},
{title: "管理"}
],
"order": [[2, "asc"]],
columnDefs: [
{
"targets": 0,
"orderable": false,
"render": function (data, type, row) {
return data;
}
},
{
"targets": 1,
"data": null,
"visible": false,
"orderable": false
},
{
"targets": 3,
"className": "table-pname",
"render": function (data, type, row) {
return '<a href="/page/run.php?id=' + row[1] + '" target="_blank">' + data + '</a>';
}
},
{
"targets": -1,
"data": null,
"visible": window.isAdmin,
"render": function (data, type, row) {
return '<a href="/page/edit.php?id=' + row[1] + '" target="_blank" class="pure-button" style="font-size: 70%;">编辑</a>';
}
}]
});
$('.tabs').tabslet({
controls: {
prev: '.prevTab',
next: '.nextTab'
}
});
$('#loading').hide();
};
var checkAdmin = function (r) {
if (window.isAdmin !== null) {
tableInit(r);
} else {
setTimeout(function () {
checkAdmin(r)
}, 50);
}
};
$.ajax({
type: "GET",
url: "/api.php?action=getProblemsetList&user_id=" + window.localStorage.id,
dataType: "json",
cache: !1,
timeout: 6e4,
success: function (r) {
if (r.status === 1) {
checkAdmin(r)
} else {
alert('很抱歉,获取数据失败,请稍后刷新重试。');
$('#loading').hide();
}
},
error: function () {
alert('很抱歉,出错了,请稍后刷新重试!');
$('#loading').hide();
}
});
$('#myRecordButton').click(function() {
$.ajax({
type: "GET",
url: "/api.php?action=getMyRecordCount&user_id=" + window.localStorage.id,
dataType: "json",
cache: !1,
timeout: 6e4,
success: function (r) {
if (r.status === 1) {
if (r.result.all === r.result.pass) {
alert('恭喜您!已完成全部 ' + r.result.all + ' 道闯关题!');
} else {
alert('闯关题共有 ' + r.result.all + ' 道,您已经完成 ' + r.result.pass + '道。');
}
} else {
alert('很抱歉,获取数据失败,请稍后刷新重试。');
}
},
error: function () {
alert('很抱歉,出错了,请稍后刷新重试!');
}
});
});
});

351
js/jquery.splitter.js Normal file
View File

@ -0,0 +1,351 @@
/*!
* JQuery Spliter Plugin version 0.27.1
* Copyright (C) 2010-2018 Jakub T. Jankiewicz <https://jcubic.pl/me>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
(function($, undefined) {
var count = 0;
var splitter_id = null;
var splitters = [];
var current_splitter = null;
$.fn.split = function(options) {
var data = this.data('splitter');
if (data) {
return data;
}
var panel_1;
var panel_2;
var settings = $.extend({
limit: 100,
orientation: 'horizontal',
position: '50%',
invisible: false,
onDragStart: $.noop,
onDragEnd: $.noop,
onDrag: $.noop,
percent: false
}, options || {});
this.settings = settings;
var cls;
var children = this.children();
if (settings.orientation == 'vertical') {
panel_1 = children.first().addClass('left_panel');
panel_2 = panel_1.next().addClass('right_panel');
cls = 'vsplitter';
} else if (settings.orientation == 'horizontal') {
panel_1 = children.first().addClass('top_panel');
panel_2 = panel_1.next().addClass('bottom_panel');
cls = 'hsplitter';
}
if (settings.invisible) {
cls += ' splitter-invisible';
}
var width = this.width();
var height = this.height();
var id = count++;
this.addClass('splitter_panel');
var splitter = $('<div/>').addClass(cls).bind('mouseenter touchstart', function() {
splitter_id = id;
}).bind('mouseleave touchend', function() {
splitter_id = null;
}).insertAfter(panel_1);
var position;
function get_position(position) {
if (typeof position === 'number') {
return position;
} else if (typeof position === 'string') {
var match = position.match(/^([0-9\.]+)(px|%)$/);
if (match) {
if (match[2] == 'px') {
return +match[1];
} else {
if (settings.orientation == 'vertical') {
return (width * +match[1]) / 100;
} else if (settings.orientation == 'horizontal') {
return (height * +match[1]) / 100;
}
}
} else {
//throw position + ' is invalid value';
}
} else {
//throw 'position have invalid type';
}
}
function set_limit(limit) {
if(!isNaN(parseFloat(limit)) && isFinite(limit)){
return {
leftUpper: limit,
rightBottom: limit
};
}
return limit;
}
var self = $.extend(this, {
refresh: function() {
var new_width = this.width();
var new_height = this.height();
if (width != new_width || height != new_height) {
width = this.width();
height = this.height();
self.position(position);
}
},
option: function(name, value) {
if (name === 'position') {
return self.position(value);
} else if (typeof value === 'undefined') {
return settings[name];
} else {
settings[name] = value;
}
return self;
},
position: (function() {
if (settings.orientation == 'vertical') {
return function(n, silent) {
if (n === undefined) {
return position;
} else {
position = get_position(n);
var sw = splitter.width();
var sw2 = sw/2, pw;
var width = self.width();
if (settings.invisible) {
pw = panel_1.width(position).outerWidth();
panel_2.width(width - pw - 27); // 特殊处理
splitter.css('left', pw - sw2);
} else {
if (settings.percent) {
var w1 = (position - sw2) / width * 100;
pw = panel_1.css('width', w1 + '%').outerWidth();
panel_2.css('width', (width-pw-sw) / width * 100 + '%');
splitter.css('left', (pw / width * 100) + '%');
} else {
pw = panel_1.css('width', position - sw2).outerWidth();
panel_2.width(width - pw - sw - 20); // 特殊处理
splitter.css('left', pw);
}
}
panel_1.find('.splitter_panel').eq(0).height(self.height());
panel_2.find('.splitter_panel').eq(0).height(self.height());
}
if (!silent) {
self.trigger('splitter.resize');
self.find('.splitter_panel').trigger('splitter.resize');
}
return self;
};
} else if (settings.orientation == 'horizontal') {
return function(n, silent) {
if (n === undefined) {
return position;
} else {
position = get_position(n);
var sw = splitter.height();
var sw2 = sw / 2, pw;
var height = self.height();
if (settings.invisible) {
pw = panel_1.height(position).outerHeight();
panel_2.height(height - pw);
splitter.css('top', pw - sw2);
} else if (settings.percent) {
var h1 = (position - sw2) / height * 100;
pw = panel_1.css('height', h1 + '%').outerHeight();
panel_2.css('height', ((height - pw - sw) / height * 100) + '%');
splitter.css('top', (pw / height * 100) + '%');
} else {
pw = panel_1.height(position - sw2).outerHeight();
panel_2.height(height - pw - sw);
splitter.css('top', pw);
}
}
if (!silent) {
self.trigger('splitter.resize');
self.find('.splitter_panel').trigger('splitter.resize');
}
return self;
};
} else {
return $.noop;
}
})(),
orientation: settings.orientation,
limit: set_limit(settings.limit),
isActive: function() {
return splitter_id === id;
},
destroy: function() {
self.removeClass('splitter_panel');
splitter.unbind('mouseenter');
splitter.unbind('mouseleave');
splitter.unbind('touchstart');
splitter.unbind('touchmove');
splitter.unbind('touchend');
splitter.unbind('touchleave');
splitter.unbind('touchcancel');
if (settings.orientation == 'vertical') {
panel_1.removeClass('left_panel');
panel_2.removeClass('right_panel');
} else if (settings.orientation == 'horizontal') {
panel_1.removeClass('top_panel');
panel_2.removeClass('bottom_panel');
}
self.unbind('splitter.resize');
self.trigger('splitter.resize');
self.find('.splitter_panel').trigger('splitter.resize');
splitters[id] = null;
count--;
splitter.remove();
self.removeData('splitter');
var not_null = false;
for (var i=splitters.length; i--;) {
if (splitters[i] !== null) {
not_null = true;
break;
}
}
//remove document events when no splitters
if (!not_null) {
$(document.documentElement).unbind('.splitter');
$(window).unbind('resize.splitter');
splitters = [];
count = 0;
}
}
});
self.bind('splitter.resize', function(e) {
var pos = self.position();
if (self.orientation == 'vertical' &&
pos > self.width()) {
pos = self.width() - self.limit.rightBottom-1;
} else if (self.orientation == 'horizontal' &&
pos > self.height()) {
pos = self.height() - self.limit.rightBottom-1;
}
if (pos < self.limit.leftUpper) {
pos = self.limit.leftUpper + 1;
}
e.stopPropagation();
self.position(pos, true);
});
//inital position of splitter
var pos;
if (settings.orientation == 'vertical') {
if (pos > width-settings.limit.rightBottom) {
pos = width-settings.limit.rightBottom;
} else {
pos = get_position(settings.position);
}
} else if (settings.orientation == 'horizontal') {
//position = height/2;
if (pos > height-settings.limit.rightBottom) {
pos = height-settings.limit.rightBottom;
} else {
pos = get_position(settings.position);
}
}
if (pos < settings.limit.leftUpper) {
pos = settings.limit.leftUpper;
}
self.position(pos, true);
var parent = this.closest('.splitter_panel');
if (parent.length) {
this.height(parent.height());
}
// bind events to document if no splitters
if (splitters.filter(Boolean).length === 0) {
$(window).bind('resize.splitter', function() {
$.each(splitters, function(i, splitter) {
if (splitter) {
splitter.refresh();
}
});
});
$(document.documentElement).on('mousedown.splitter touchstart.splitter', function(e) {
if (splitter_id !== null) {
e.preventDefault();
current_splitter = splitters[splitter_id];
setTimeout(function() {
$('<div class="splitterMask"></div>').
css('cursor', current_splitter.children().eq(1).css('cursor')).
insertAfter(current_splitter);
});
current_splitter.settings.onDragStart(e);
}
}).bind('mouseup.splitter touchend.splitter touchleave.splitter touchcancel.splitter', function(e) {
if (current_splitter) {
setTimeout(function() {
$('.splitterMask').remove();
});
current_splitter.settings.onDragEnd(e);
current_splitter = null;
}
}).bind('mousemove.splitter touchmove.splitter', function(e) {
if (current_splitter !== null) {
var leftUpperLimit = current_splitter.limit.leftUpper;
var rightBottomLimit = current_splitter.limit.rightBottom;
var offset = current_splitter.offset();
if (current_splitter.orientation == 'vertical') {
var pageX = e.pageX;
if(e.originalEvent && e.originalEvent.changedTouches){
pageX = e.originalEvent.changedTouches[0].pageX;
}
var x = pageX - offset.left;
if (x <= current_splitter.limit.leftUpper) {
x = current_splitter.limit.leftUpper + 1;
} else if (x >= current_splitter.width() - rightBottomLimit) {
x = current_splitter.width() - rightBottomLimit - 1;
}
if (x > current_splitter.limit.leftUpper &&
x < current_splitter.width()-rightBottomLimit) {
current_splitter.position(x, true);
current_splitter.trigger('splitter.resize');
current_splitter.find('.splitter_panel').
trigger('splitter.resize');
//e.preventDefault();
}
} else if (current_splitter.orientation == 'horizontal') {
var pageY = e.pageY;
if(e.originalEvent && e.originalEvent.changedTouches){
pageY = e.originalEvent.changedTouches[0].pageY;
}
var y = pageY-offset.top;
if (y <= current_splitter.limit.leftUpper) {
y = current_splitter.limit.leftUpper + 1;
} else if (y >= current_splitter.height() - rightBottomLimit) {
y = current_splitter.height() - rightBottomLimit - 1;
}
if (y > current_splitter.limit.leftUpper &&
y < current_splitter.height()-rightBottomLimit) {
current_splitter.position(y, true);
current_splitter.trigger('splitter.resize');
current_splitter.find('.splitter_panel').
trigger('splitter.resize');
//e.preventDefault();
}
}
current_splitter.settings.onDrag(e);
}
});//*/
}
splitters[id] = self;
self.data('splitter', self);
return self;
};
})(jQuery);

View File

@ -0,0 +1,4 @@
self.MonacoEnvironment = {
baseUrl: 'https://lib.baomitu.com/monaco-editor/0.15.6/min/'
};
importScripts('https://lib.baomitu.com/monaco-editor/0.15.6/min/vs/base/worker/workerMain.js');

329
js/page/edit.js Normal file
View File

@ -0,0 +1,329 @@
$(function () {
var jsCode = `'use strict';
var phpEngine = uniter.createEngine('PHP');
phpEngine.expose({
pass: function () {
pass();
return '测试通过';
},
}, 'r');
phpEngine.getStdout().on('data', function (data) {
print(data);
});
phpEngine.getStderr().on('data', function (data) {
print(data);
});
phpEngine.execute(phpCode).fail(function (error) {
// print(error.toString());
});
`;
var testCode = `<?php
$pass = 1;
$m =
if ($m != ) {
$pass = 0;
echo "测试用例:<br>";
echo "输出结果:" . $m . "<br>";
}
if ($pass) {
echo $r->pass();
} else {
echo "<br>测试不通过";
}`;
require(["vs/editor/editor.main"], function () {
window.editor = monaco.editor.create(document.getElementById('phpContainer'), {
value: [
'<?php',
'\tfunction sum($a, $b) {',
'\t\treturn $a + $b;',
'\t}',
'',
'// --------- 测试区域',
''
].join('\n'),
language: 'php'
});
window.jsEditor = monaco.editor.create(document.getElementById('jsContainer'), {
value: jsCode,
language: 'javascript'
});
window.testEditor = monaco.editor.create(document.getElementById('testContainer'), {
value: testCode,
language: 'php'
});
function execMain() {
var javascriptCode = window.jsEditor.getValue(),
phpCode = window.editor.getValue(),
resultIframe = document.getElementById('result'),
resultDocument = resultIframe.contentWindow.document,
resultBody;
function clear() {
resultBody.innerHTML = '';
}
function print(html) {
resultBody.insertAdjacentHTML('beforeEnd', html);
}
function pass() {
console.log('pass')
}
function printText(text) {
resultBody.appendChild(document.createTextNode(text));
}
// Ensure the document has a body for IE9
resultDocument.write('<body></body>');
resultDocument.close();
resultBody = resultDocument.body;
clear();
try {
/*jshint evil: true */
new Function('phpCode, print, resultBody, pass', javascriptCode)(phpCode, print, resultBody, pass);
} catch (error) {
printText('<JavaScript error> ' + error.toString());
}
}
function runUnit() {
var javascriptCode = window.jsEditor.getValue(),
phpCode = window.editor.getValue(),
testCode = window.testEditor.getValue(),
resultIframe = document.getElementById('result'),
resultDocument = resultIframe.contentWindow.document,
resultBody;
if (phpCode.indexOf('// --------- 测试区域') !== -1) {
phpCode = phpCode.substring(0, phpCode.lastIndexOf('// --------- 测试区域')) + testCode.replace('<?php', '');
} else {
phpCode = phpCode + testCode.replace('<?php', '');
}
function clear() {
resultBody.innerHTML = '';
}
function print(html) {
resultBody.insertAdjacentHTML('beforeEnd', html);
}
function pass() {
console.log('测试通过')
}
function printText(text) {
resultBody.appendChild(document.createTextNode(text));
}
// Ensure the document has a body for IE9
resultDocument.write('<body></body>');
resultDocument.close();
resultBody = resultDocument.body;
clear();
try {
/*jshint evil: true */
new Function('phpCode, print, resultBody, pass', javascriptCode)(phpCode, print, resultBody, pass);
} catch (error) {
printText('<JavaScript error> ' + error.toString());
}
}
$('#runMain').click(function () {
execMain()
});
$('#runUnit').click(function () {
runUnit()
});
var contentHeight = window.document.body.clientHeight - 50;
$('#phpContainer').css('height', contentHeight - 70);
$('#jsContainer').css('height', contentHeight - 70);
$('#testContainer').css('height', contentHeight - 70);
$('#article').css('height', contentHeight + 30);
window.editor.layout();
window.jsEditor.layout();
window.testEditor.layout();
window.onresize = function () {
window.editor.layout();
window.jsEditor.layout();
window.testEditor.layout();
};
var describe = new SimpleMDE({ element: $("#describe")[0] });
var answer = new SimpleMDE({ element: $("#answer")[0] });
var testCase = new SimpleMDE({ element: $("#testCase")[0] });
var expectedResult = new SimpleMDE({ element: $("#expectedResult")[0] });
$('#submitForm').click(function () {
// 李永升你应该适配一下大于1时直接加百分号小于1时乘以100再加百分号
var passPercent = $('#passPercent').val();
if (passPercent > 1) {
passPercent = passPercent / 100
}
$('#passPercent').val(passPercent);
var postData = $('#edit-form').serializeArray();
var javascriptCode = window.jsEditor.getValue(),
phpUnitCode = window.testEditor.getValue(),
phpCode = window.editor.getValue();
postData.push({
name: 'javascriptCode',
value: javascriptCode
});
postData.push({
name: 'phpUnitCode',
value: phpUnitCode
});
postData.push({
name: 'phpCode',
value: phpCode
});
postData.push({
name: 'describe',
value: describe.value()
});
postData.push({
name: 'answer',
value: answer.value()
});
postData.push({
name: 'testCase',
value: testCase.value()
});
postData.push({
name: 'expectedResult',
value: expectedResult.value()
});
if (GetQueryString('id')) {
$.ajax({
type: "POST",
url: "/api.php?action=editProblemset&id=" + GetQueryString('id'),
dataType: "json",
cache: !1,
timeout: 6e4,
data: postData,
success: function (r) {
if (r.status === 1) {
window.location.href = '/index.php'
} else {
alert('很抱歉,保存失败,请稍后刷新重试。')
}
},
error: function () {
alert('很抱歉,出错了,请稍后刷新重试!')
}
})
} else {
$.ajax({
type: "POST",
url: "/api.php?action=addProblemset",
dataType: "json",
cache: !1,
timeout: 6e4,
data: postData,
success: function (r) {
if (r.status === 1) {
window.location.href = '/index.php'
} else {
alert('很抱歉,新增题目失败,请稍后刷新重试。')
}
},
error: function () {
alert('很抱歉,出错了,请稍后刷新重试!')
}
})
}
});
if (GetQueryString('id')) {
$.ajax({
type: "GET",
url: "/api.php?action=getProblemset&id=" + GetQueryString('id'),
dataType: "json",
cache: !1,
timeout: 6e4,
success: function (r) {
if (r.status === 1) {
$('#type').val(r.result.type);
$('#name').val(r.result.name);
$('#isAnswer').val(r.result.isAnswer);
$('#language').val(r.result.language);
$('#difficulty').val(r.result.difficulty);
$('#isCredit').val(r.result.isCredit);
$('#passPercent').val(r.result.passPercent);
$('#tag').val(r.result.tag);
$('#credit').val(r.result.credit);
$('#mark').val(r.result.mark);
describe.value(r.result.describe);
answer.value(r.result.answer);
testCase.value(r.result.testCase);
expectedResult.value(r.result.expectedResult);
window.editor.setValue(r.result.phpCode);
window.testEditor.setValue(r.result.phpUnitCode);
window.jsEditor.setValue(r.result.javascriptCode);
$('.tabs').tabslet({
controls: {
prev: '.prevTab',
next: '.nextTab'
}
});
} else {
alert('很抱歉,获取数据失败,请稍后刷新重试。')
}
$('#loading').hide();
},
error: function () {
alert('很抱歉,出错了,请稍后刷新重试!');
$('#loading').hide();
}
})
} else {
$('#loading').hide();
$('.tabs').tabslet({
controls: {
prev: '.prevTab',
next: '.nextTab'
}
});
}
});
});

304
js/page/run.js Normal file
View File

@ -0,0 +1,304 @@
$(function () {
var converter = new showdown.Converter();
var phpUnitCode = "";
var javascriptCode = "";
var theType = "";
var no = "";
var isLoading = false;
require(["vs/editor/editor.main"], function () {
window.editor = monaco.editor.create(document.getElementById('container'), {
value: [
'<?php',
'\techo "Hello world!";'
].join('\n'),
language: 'php'
});
function run (phpCode, oldCode) {
var resultIframe = document.getElementById('result');
var resultDocument = resultIframe.contentWindow.document;
var resultBody = null;
var clear = function () {
resultBody.innerHTML = '';
};
var print = function (html) {
// outExeTime();
resultBody.insertAdjacentHTML('beforeEnd', html);
};
var pass = function () {
console.log('测试通过');
$.ajax({
type: "POST",
url: "/api.php?action=addRecord",
dataType: "json",
cache: !1,
timeout: 6e4,
data: {
user_id: window.localStorage.id,
problemset_id: GetQueryString('id'),
type: theType,
code: oldCode,
is_pass: '1'
},
success: function (r) {
if (r.status === 1) {
console.log('测试通过的结果保存成功');
if (confirm("测试通过,进入下一题?")) {
$.ajax({
type: "GET",
url: "/api.php?action=getNextNo&no=" + no + "&type=" + theType,
dataType: "json",
cache: !1,
timeout: 6e4,
success: function (r) {
if (r.status === 1) {
if (r.id > 0) {
window.location.href = '/page/run.php?id=' + r.id;
} else if (r.id == 0){
alert('恭喜你!已经做完最后一题!');
window.location.href = '/index.php';
} else {
window.location.href = '/index.php';
}
} else {
alert('很抱歉,获取下一题数据失败,请重试。')
}
},
error: function () {
alert('很抱歉,出错了,请重试!');
}
})
}
} else {
alert('很抱歉,保存数据失败,请重试。')
}
},
error: function () {
alert('很抱歉,出错了,请重试!');
}
})
}
var printText = function (text) {
resultBody.appendChild(document.createTextNode(text));
};
// Ensure the document has a body for IE9
resultDocument.write('<body></body>');
resultDocument.close();
resultBody = resultDocument.body;
clear();
try {
/*jshint evil: true */
new Function('phpCode, print, resultBody, pass', javascriptCode)(phpCode, print, resultBody, pass);
} catch (error) {
printText('<JavaScript error> ' + error.toString());
}
}
function exec(test) {
// var start = (new Date()).getTime()
var phpCode = window.editor.getValue();
var oldCode = phpCode;
if (!test) {
if (isLoading) return;
isLoading = true;
if (phpCode.indexOf('// --------- 测试区域') !== -1) {
phpCode = phpCode.substring(0, phpCode.lastIndexOf('// --------- 测试区域')) + phpUnitCode.replace('<?php', '');
} else {
phpCode = phpCode + phpUnitCode.replace('<?php', '');
}
// 每次提交都记录数据, 需要成功返回后再执行,确保数据一致性
$.ajax({
type: "POST",
url: "/api.php?action=addRecord",
dataType: "json",
cache: !1,
timeout: 6e4,
data: {
user_id: window.localStorage.id,
problemset_id: GetQueryString('id'),
type: theType,
code: oldCode,
is_pass: '0'
},
success: function () {
run(phpCode, oldCode);
isLoading = false;
},
error: function () {
alert('很抱歉,出错了,请重试!');
isLoading = false;
}
})
} else {
run(phpCode, oldCode)
}
}
$('#testRun').click(function () {
$('.tabs').trigger('show', '#resultView');
exec(true);
});
$('#run').click(function () {
$('.tabs').trigger('show', '#resultView');
exec(false);
});
var contentHeight = window.document.body.clientHeight - 50;
$('#container').css('height', contentHeight - 70);
var splitter = $('#content').height(contentHeight).split({
orientation: 'vertical',
limit: 10,
position: '40%', // if there is no percentage it interpret it as pixels
onDrag: function (event) {
console.log(splitter.position());
window.editor.layout();
}
});
if (!localStorage.auto) {
localStorage.auto = '1';
}
window.auto = localStorage.auto;
window.editor.onDidChangeModelContent(function () {
if (window.auto === '1') {
exec(true)
}
});
window.editor.layout();
if (window.auto === '1') {
$("#auto").prop("checked", 'true');
exec(true);
} else {
$("#auto").prop("checked", 'false')
}
$("#auto").click(function () {
if ($(this).prop("checked")) {
window.auto = '1';
localStorage.auto = '1'
} else {
window.auto = '2';
localStorage.auto = '2'
}
});
if (GetQueryString('id')) {
$.ajax({
type: "GET",
url: "/api.php?action=getProblemset&id=" + GetQueryString('id'),
dataType: "json",
cache: !1,
timeout: 6e4,
success: function (r) {
if (r.status === 1) {
var typeStr = '挑战赛';
if (r.result.type === '1') {
typeStr = '闯关模式'
}
var difficultyStr = '困难';
if (r.result.difficulty === '1') {
difficultyStr = '简单'
} else if (r.result.difficulty === '2') {
difficultyStr = '中等'
}
$(document).attr('title', r.result.name + ' - ' + typeStr);
$('#describeView .cont').html('<h3 style="font-weight: 600">' + r.result.name + '(' + difficultyStr + ')' + ' - ' + typeStr + '</h3>' + converter.makeHtml(r.result.describe));
$('#answerView .cont').html(converter.makeHtml(r.result.answer));
if (r.result.isAnswer !== '1') {
$('#answerViewButton').hide();
}
window.editor.setValue(r.result.phpCode);
phpUnitCode = r.result.phpUnitCode;
javascriptCode = r.result.javascriptCode;
var testCase = r.result.testCase;
var expectedResult = r.result.expectedResult;
$('.testCaseContent').html(converter.makeHtml(testCase));
$('.expectedResultContent').html(converter.makeHtml(expectedResult));
$('#rightPane pre code').each(function(i, block) {
hljs.highlightBlock(block);
});
theType = r.result.type;
no = r.result.no;
$.ajax({
type: "POST",
url: "/api.php?action=getRecord",
dataType: "json",
cache: !1,
timeout: 6e4,
data: {
user_id: window.localStorage.id,
problemset_id: GetQueryString('id'),
},
success: function (r) {
if (r.status === 1) {
window.editor.setValue(r.code);
}
$('.tabs').tabslet({
controls: {
prev: '.prevTab',
next: '.nextTab'
}
});
$('#loading').hide();
},
error: function () {
alert('很抱歉,出错了,请稍后刷新重试!');
$('#loading').hide();
}
});
} else {
alert('很抱歉,获取数据失败,请稍后刷新重试。')
}
$('#loading').hide();
},
error: function () {
alert('很抱歉,出错了,请稍后刷新重试!');
$('#loading').hide();
}
})
} else {
$('#loading').hide();
$('.tabs').tabslet({
controls: {
prev: '.prevTab',
next: '.nextTab'
}
});
}
});
});

153
js/page/test.js Normal file
View File

@ -0,0 +1,153 @@
$(function () {
var saveTestCode = function (code) {
$.ajax({
type: "POST",
url: "/api.php?action=saveTestCode",
dataType: "json",
cache: !1,
timeout: 6e4,
data: {
user_id: window.localStorage.id,
code: code
}
})
};
require(["vs/editor/editor.main"], function () {
$.ajax({
type: "POST",
url: "/api.php?action=getTestCode",
dataType: "json",
cache: !1,
timeout: 6e4,
data: {
user_id: window.localStorage.id,
},
success: function (r) {
if (r.status === 1) {
window.editor = monaco.editor.create(document.getElementById('container'), {
value: r.code,
language: 'php'
});
function exec() {
// var start = (new Date()).getTime()
var javascriptCode = `'use strict';
var phpEngine = uniter.createEngine('PHP');
phpEngine.getStdout().on('data', function (data) {
print(data);
});
phpEngine.getStderr().on('data', function (data) {
print(data);
});
phpEngine.execute(phpCode).fail(function (error) {
// print(error.toString());
});
`,
phpCode = window.editor.getValue(),
resultIframe = document.getElementById('result'),
resultDocument = resultIframe.contentWindow.document,
resultBody;
saveTestCode(phpCode);
function clear() {
resultBody.innerHTML = '';
}
function print(html) {
// outExeTime();
resultBody.insertAdjacentHTML('beforeEnd', html);
}
function printText(text) {
resultBody.appendChild(document.createTextNode(text));
}
// function outExeTime () {
// // var execTimeString = getNowDate() + '执行结果(' + ((new Date()).getTime() - start) + 'ms)';
// // var headerHtml = '<span style="color: #888;font-weight: 300;font-size: 10px;">' + execTimeString + ':</span><br>'
// // $('#out').html(headerHtml)
// }
// Ensure the document has a body for IE9
resultDocument.write('<body></body>');
resultDocument.close();
resultBody = resultDocument.body;
clear();
try {
/*jshint evil: true */
new Function('phpCode, print, resultBody', javascriptCode)(phpCode, print, resultBody);
} catch (error) {
printText('<JavaScript error> ' + error.toString());
}
}
$('#run').click(function () {
exec()
});
var contentHeight = window.document.body.clientHeight - 50;
$('#container').css('height', contentHeight - 70);
var splitter = $('#content').height(contentHeight).split({
orientation: 'vertical',
limit: 10,
position: '40%', // if there is no percentage it interpret it as pixels
onDrag: function (event) {
console.log(splitter.position());
window.editor.layout();
}
});
if (!localStorage.auto) {
localStorage.auto = '1';
}
window.auto = localStorage.auto;
window.editor.onDidChangeModelContent(function () {
if (window.auto === '1') {
exec()
}
});
window.editor.layout();
if (window.auto === '1') {
$("#auto").prop("checked", 'true')
exec()
} else {
$("#auto").prop("checked", 'false')
}
$("#auto").click(function () {
if ($(this).prop("checked")) {
window.auto = '1';
localStorage.auto = '1'
} else {
window.auto = '2';
localStorage.auto = '2'
}
});
$('#loading').hide();
} else {
alert('很抱歉,获取已保存的代码失败,请稍后刷新重试。')
}
},
error: function () {
alert('很抱歉,出错了,请稍后刷新重试!')
}
});
});
});

3
js/page/user.js Normal file
View File

@ -0,0 +1,3 @@
$(function () {
$('#loading').hide();
});

3
js/page/userinfo.js Normal file
View File

@ -0,0 +1,3 @@
$(function () {
$('#loading').hide();
});

15
js/uniter.js Normal file

File diff suppressed because one or more lines are too long

BIN
loading.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

230
login.html Normal file
View File

@ -0,0 +1,230 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>微信扫码登陆</title>
<style>
* {
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
-ms-box-sizing: border-box;
-o-box-sizing: border-box;
box-sizing: border-box;
}
html {
width: 100%;
height: 100%;
overflow: hidden;
}
body {
width: 100%;
height: 100%;
font-family: 'Open Sans', sans-serif;
background: #092756;
background: -moz-radial-gradient(0% 100%, ellipse cover, rgba(104, 128, 138, .4) 10%, rgba(138, 114, 76, 0) 40%), -moz-linear-gradient(top, rgba(57, 173, 219, .25) 0%, rgba(42, 60, 87, .4) 100%), -moz-linear-gradient(-45deg, #670d10 0%, #092756 100%);
background: -webkit-radial-gradient(0% 100%, ellipse cover, rgba(104, 128, 138, .4) 10%, rgba(138, 114, 76, 0) 40%), -webkit-linear-gradient(top, rgba(57, 173, 219, .25) 0%, rgba(42, 60, 87, .4) 100%), -webkit-linear-gradient(-45deg, #670d10 0%, #092756 100%);
background: -o-radial-gradient(0% 100%, ellipse cover, rgba(104, 128, 138, .4) 10%, rgba(138, 114, 76, 0) 40%), -o-linear-gradient(top, rgba(57, 173, 219, .25) 0%, rgba(42, 60, 87, .4) 100%), -o-linear-gradient(-45deg, #670d10 0%, #092756 100%);
background: -ms-radial-gradient(0% 100%, ellipse cover, rgba(104, 128, 138, .4) 10%, rgba(138, 114, 76, 0) 40%), -ms-linear-gradient(top, rgba(57, 173, 219, .25) 0%, rgba(42, 60, 87, .4) 100%), -ms-linear-gradient(-45deg, #670d10 0%, #092756 100%);
background: -webkit-radial-gradient(0% 100%, ellipse cover, rgba(104, 128, 138, .4) 10%, rgba(138, 114, 76, 0) 40%), linear-gradient(to bottom, rgba(57, 173, 219, .25) 0%, rgba(42, 60, 87, .4) 100%), linear-gradient(135deg, #670d10 0%, #092756 100%);
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#3E1D6D', endColorstr='#092756', GradientType=1);
}
.login {
position: absolute;
top: 50%;
left: 50%;
margin: -150px 0 0 -150px;
width: 300px;
height: 300px;
}
#qrcode {
width: 300px;
height: 300px;
display: none;
box-shadow: 0 0 22px rgba(81, 81, 81, 0.8);
}
.loading {
width: 150px;
height: 15px;
margin: 0 auto;
margin-top: 100px;
}
.loading span {
display: inline-block;
width: 15px;
height: 100%;
margin-right: 5px;
background: lightgreen;
-webkit-transform-origin: right bottom;
-webkit-animation: load 1s ease infinite;
}
.loading span:last-child {
margin-right: 0px;
}
@-webkit-keyframes load {
0% {
opacity: 1;
}
100% {
opacity: 0;
-webkit-transform: rotate(90deg);
}
}
.loading span:nth-child(1) {
-webkit-animation-delay: 0.13s;
}
.loading span:nth-child(2) {
-webkit-animation-delay: 0.26s;
}
.loading span:nth-child(3) {
-webkit-animation-delay: 0.39s;
}
.loading span:nth-child(4) {
-webkit-animation-delay: 0.52s;
}
.loading span:nth-child(5) {
-webkit-animation-delay: 0.65s;
}
#code {
color: #fff;
width: 100%;
text-align: center;
margin-top: 20px;
}
</style>
</head>
<body>
<div class="login">
<div class="loading">
<span></span>
<span></span>
<span></span>
<span></span>
<span></span>
</div>
</div>
<h1 id="code"></h1>
<script crossorigin="anonymous" integrity="sha384-tsQFqpEReu7ZLhBV2VZlAu7zcOV+rXbYlF2cqB8txI/8aZajjp4Bqd+V6D5IgvKT"
src="https://lib.baomitu.com/jquery/3.3.1/jquery.min.js"></script>
<script>
$(function () {
var login = function (code) {
$.ajax({
type: "POST",
url: "/api.php?action=login&code=" + code,
dataType: "json",
cache: !1,
timeout: 6e4,
success: function (r) {
if (r.status === 1) {
window.localStorage.id = r.result.id
window.localStorage.userinfo = JSON.stringify(r.result.userinfo)
$('#code').text('登陆成功')
window.location.href = "/index.php"
} else {
alert('很抱歉,登陆失败,请稍后刷新重试。')
}
},
error: function () {
alert('很抱歉,出错了,请稍后刷新重试!')
}
})
}
var getCode = function (uuid, last) {
$.ajax({
type: "GET",
url: "https://apio.xyz/weixin-login-php/weixin.php?uuid=" + uuid + (last ? '&last=' + last : ''),
dataType: "json",
cache: !1,
timeout: 6e4,
success: function (data) {
if (data.status === 405) {
$('#code').text('扫码成功,正在登陆...')
login(data.result.code)
} else if (data.status === 404) {
$('#code').text(data.msg.title + ', ' + data.msg.content)
getCode(uuid, data.result.wxErrCode)
} else if (data.status === 403) {
$('#code').text(data.msg.title + ', ' + data.msg.content)
getCode(uuid, data.result.wxErrCode)
} else if (data.status === 500) {
getUUID()
} else {
setTimeout(function () {
getCode(uuid)
}, 2000)
}
},
error: function () {
setTimeout(function () {
getCode(uuid)
}, 2000)
}
})
}
function loadImage(url, callback) {
var img = new Image(); //创建一个Image对象实现图片的预下载
img.src = url;
img.onload = function () { //图片下载完毕时异步调用callback函数
callback.call(img); //将回调函数的this替换为Image对象
};
};
var getUUID = function (uuid) {
$.ajax({
type: "GET",
url: "https://apio.xyz/weixin-login-php/weixin.php?appid=wx2d1d6aa2f86768d7&redirect_uri=https://wyr.me/login",
dataType: "json",
cache: !1,
timeout: 6e4,
success: function (data) {
if (data.status === 1) {
var uuid = data.result.wxUUID
loadImage(data.result.imgData, function () {
$('.loading').hide()
this.id = 'qrcode'
$('.login').append(this)
$('#qrcode').show()
})
getCode(uuid)
} else {
setTimeout(function () {
window.location.reload();
}, 2000)
}
},
error: function () {
setTimeout(function () {
window.location.reload();
}, 2000)
}
})
}
getUUID()
});
</script>
</body>
</html>

1692
medoo.php Normal file

File diff suppressed because it is too large Load Diff

7
menu.php Normal file
View File

@ -0,0 +1,7 @@
<ul class="pure-menu-list">
<li class="pure-menu-item <?php if ($nowURL == '/' || $nowURL == '/index.php') echo 'pure-menu-selected'; ?>"><a href="/" class="pure-menu-link">题库</a></li>
<li class="pure-menu-item <?php if ($nowURL == '/page/test.php') echo 'pure-menu-selected'; ?>"><a href="/page/test.php" class="pure-menu-link">在线测试</a></li>
<li class="pure-menu-item"><a href="http://php.net/manual/zh/" class="pure-menu-link" target="_blank">PHP官方文档</a></li>
<li class="pure-menu-item"><a href="http://www.w3school.com.cn/php/index.asp" class="pure-menu-link" target="_blank">w3school</a></li>
<li class="pure-menu-item"><a href="http://www.runoob.com/php/php-tutorial.html" class="pure-menu-link" target="_blank">PHP教程</a></li>
</ul>

214
page/edit.php Normal file
View File

@ -0,0 +1,214 @@
<?php include('../header.php'); ?>
<div class='edit-main'>
<style type="text/css">
.edit-main {
padding: 20px;
}
article {
margin: 0 auto;
width: 60%;
}
article > heading {
border-bottom: 1px solid #e5e5e5;
margin: 1.5em 0;
padding-bottom: 1.5em;
display: block;
overflow: auto;
}
article > heading h1 {
margin: 0;
}
.contain-floats::after {
display: block;
content: " ";
clear: left;
}
.panes {
margin-left: -30%;
margin-right: -30%;
}
.panes section {
float: left;
width: 33.33%;
height: 30em;
}
.result {
display: block;
margin-right: 1em;
height: 100%;
}
.result {
width: 100%;
}
#jsContainer, #phpContainer, #testContainer {
margin: 5px;
box-sizing: border-box;
border: 1px solid #eeeeee;
}
#phpContainer {
margin: 5px 4px 5px 4px;
}
.edit-form label {
margin-top: 10px;
}
.button-control {
height: 50px;
}
</style>
<form class="pure-form pure-form-stacked edit-form" id="edit-form">
<fieldset>
<legend><h1><?php if (isset($_GET['id'])) {
echo '编辑';
} else {
echo '添加';
} ?>题目</h1></legend>
<div class="pure-g">
<div class="pure-u-lg-1-6">
<label for="type">分类</label>
<select id="type" name="type">
<option value="1">闯关模式</option>
<option value="2">挑战赛</option>
</select>
</div>
<div class="pure-u-lg-1-6">
<label for="isAnswer" class="pure-checkbox">
是否有解答
</label>
<select id="isAnswer" name="isAnswer">
<option value="1"></option>
<option value="0"></option>
</select>
</div>
<div class="pure-u-lg-1-6">
<label for="difficulty">难度</label>
<select id="difficulty" name="difficulty">
<option value="1">简单</option>
<option value="2">中等</option>
<option value="3">困难</option>
</select>
</div>
<div class="pure-u-lg-1-6">
<label for="isCredit">是否有积分</label>
<select id="isCredit" name="isCredit">
<option value="1"></option>
<option value="0">没有</option>
</select>
</div>
<div class="pure-u-lg-1-6">
<label for="language">编程语言</label>
<select id="language" name="language">
<option value="PHP">PHP</option>
<option value="HTML">HTML</option>
<option value="JAVA">JAVA</option>
</select>
</div>
</div>
<label for="name">名称</label>
<input id="name" name="name" class="pure-input-3-4" type="text">
<div class="pure-g">
<div class="pure-u-lg-1-4">
<label for="passPercent">通过率</label>
<input id="passPercent" name="passPercent" class="pure-input-1" type="text">
</div>
<div class="pure-u-lg-1-4">
<label for="tag">标签</label>
<input id="tag" name="tag" class="pure-input-1" type="text">
</div>
<div class="pure-u-lg-1-4">
<label for="credit">积分</label>
<input id="credit" name="credit" type="text" value="0" class="pure-input-1">
</div>
</div>
<label for="mark">备注</label>
<textarea id="mark" name="mark" class="pure-input-1"></textarea>
<div class='tabs tabs_default'>
<ul class='horizontal' style="margin-top: 10px;margin-bottom: 20px">
<li><a class="pure-button" href="#describeEdit">题目描述</a></li>
<li><a class="pure-button" href="#answerEdit">解答</a></li>
<li><a class="pure-button admin" href="#testCaseEdit">测试用例</a></li>
<li><a class="pure-button admin" href="#expectedResultEdit">预期结果</a></li>
</ul>
<div id='describeEdit'>
<textarea id='describe' class="pure-input-1"></textarea>
</div>
<div id='answerEdit'>
<textarea id='answer' class="pure-input-1"></textarea>
</div>
<div id='testCaseEdit'>
<textarea id="testCase" class="pure-input-1"></textarea>
</div>
<div id="expectedResultEdit">
<textarea id="expectedResult" class="pure-input-1"></textarea>
</div>
</div>
<article id="article">
<div class="panes contain-floats">
<section>
<heading>
<h1>JavaScript</h1>
</heading>
<div id="jsContainer"></div>
</section>
<section>
<heading>
<h1>PHP 主程序</h1>
</heading>
<div id="phpContainer"></div>
</section>
<section>
<heading>
<h1>PHP 测试用例</h1>
</heading>
<div id="testContainer"></div>
</section>
</div>
</article>
<div class="button-control">
<div class="pure-button" id="runMain">运行主程序</div>
<div class="pure-button" id="runUnit">运行测试用例</div>
</div>
<div id="out">
<iframe class="result" id="result"></iframe>
</div>
<button type="button" id="submitForm" style="margin-top: 20px" class="pure-button pure-button-primary">保存</button>
</fieldset>
</form>
</div>
<?php include('../footer.php'); ?>

48
page/run.php Normal file
View File

@ -0,0 +1,48 @@
<?php include('../header.php'); ?>
<div class="content" id="content">
<div id="leftPane">
<div id="container"></div>
<div class="control">
<div class="pure-button pure-button-primary" id="run">提交</div>
<div class="pure-button" id="testRun">执行代码</div>
<label for="auto" class="pure-checkbox auto">
<input id="auto" type="checkbox"> 自动执行代码
</label>
</div>
</div>
<div id="rightPane">
<div class='tabs tabs_default' style="height: 100%">
<ul class='horizontal' style="margin-top: 10px;margin-bottom: 20px">
<li><a class="pure-button" href="#describeView">题目描述</a></li>
<li><a class="pure-button" href="#answerView" id="answerViewButton">解答</a></li>
<li><a class="pure-button" href="#resultView">运行结果</a></li>
</ul>
<div id='describeView'>
<div class="cont"></div>
</div>
<div id='answerView'>
<div class="cont"></div>
</div>
<div id='resultView'>
<div class="cont">
<div class="testCase">
<h4 style="font-weight: 500;margin: 4px 0;">输入:</h4>
<div class="testCaseContent"></div>
</div>
<div class="expectedResult" style="margin-top: 10px;">
<h4 style="font-weight: 500;margin: 4px 0;">预期结果:</h4>
<div class="expectedResultContent"></div>
</div>
<div class="resultArea" style="margin-top: 10px;">
<h4 style="font-weight: 500;margin: 4px 0;">输出:</h4>
<div class="resultContent">
<iframe class="result" id="result"></iframe>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<?php include('../footer.php'); ?>

18
page/test.php Normal file
View File

@ -0,0 +1,18 @@
<?php include('../header.php'); ?>
<div class="content" id="content">
<div id="leftPane">
<div id="container"></div>
<div class="control">
<div class="pure-button pure-button-primary" id="run">执行代码</div>
<label for="auto" class="pure-checkbox auto">
<input id="auto" type="checkbox"> 自动
</label>
</div>
</div>
<div id="rightPane">
<div id="out">
<iframe class="result" id="result"></iframe>
</div>
</div>
</div>
<?php include('../footer.php'); ?>

61
page/user.php Normal file
View File

@ -0,0 +1,61 @@
<?php include('../header.php'); ?>
<?php
//error_reporting(0);
require_once '../config.php';
require_once '../medoo.php';
use Medoo\Medoo;
$database = new Medoo($DBCONFIG);
$Allcount = $database->count("problemset", [
"type" => "1"
]);
$rows = $database->select('userinfo', '*', [
"ORDER" => [
"id" => "DESC"
]
]);
?>
<div class="user" style="padding: 10px">
<table class="pure-table" style="width: 100%;">
<thead>
<tr>
<th>#</th>
<th>头像</th>
<th>用户昵称</th>
<th>真实姓名</th>
<th>用户性别</th>
<th>进度</th>
<th>管理</th>
</tr>
</thead>
<tbody>
<?php foreach ($rows as $inx => $row) { ?>
<tr class="<?php if ($inx % 2) echo 'pure-table-odd'; ?>">
<td><?php echo $row['id'] ?></td>
<td><img src="<?php echo $row['headimgurl']; ?>" width="50"/></td>
<td><?php echo $row['nickname']; ?></td>
<td><?php echo $row['realname']; ?></td>
<td><?php if ($row['sex'] == '1') {
echo '男';
} else {
echo '女';
} ?></td>
<td><?php
$passCount = $database->count("record", [
'user_id' => $row['id'],
'is_pass' => '1'
]);
echo $passCount . '/' . $Allcount;
?></td>
<td><a href="/page/userinfo.php?id=<?php echo $row['id']; ?>" target="_blank">查看详情</a></td>
</tr>
<?php } ?>
</tbody>
</table>
</div>
<?php include('../footer.php'); ?>

49
page/userinfo.php Normal file
View File

@ -0,0 +1,49 @@
<?php include('../header.php'); ?>
<?php
//error_reporting(0);
require_once '../config.php';
require_once '../medoo.php';
use Medoo\Medoo;
$database = new Medoo($DBCONFIG);
$rows = $database->query("SELECT
`record`.`is_pass`,
`problemset`.`id`,
`problemset`.`no`,
`problemset`.`name`,
`problemset`.`language`,
`problemset`.`type`,
`problemset`.`isAnswer`,
`problemset`.`passPercent`,
`problemset`.`difficulty`
FROM
`problemset`
LEFT JOIN `record` ON `problemset`.`id` = `record`.`problemset_id` AND `record`.`user_id` = " . $_GET['id'] . " WHERE `problemset`.`type` = '1' ORDER BY
`no`")->fetchAll();
?>
<div class="user" style="padding: 10px">
<table class="pure-table" style="width: 100%;">
<thead>
<tr>
<th>No</th>
<th>题目</th>
<th>做题状态</th>
</tr>
</thead>
<tbody>
<?php foreach ($rows as $inx => $row) { ?>
<tr class="<?php if ($inx % 2) echo 'pure-table-odd'; ?>">
<td><?php echo $row['no'] ?></td>
<td><?php echo $row['name']; ?></td>
<td><?php if ($row['is_pass'] == '1') {
echo '<svg viewBox="0 0 1397 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="27" height="20"><path d="M1396.363636 121.018182c0 0-223.418182 74.472727-484.072727 372.363636-242.036364 269.963636-297.890909 381.672727-390.981818 530.618182C512 1014.690909 372.363636 744.727273 0 549.236364l195.490909-186.181818c0 0 176.872727 121.018182 297.890909 344.436364 0 0 307.2-474.763636 902.981818-707.490909L1396.363636 121.018182 1396.363636 121.018182zM1396.363636 121.018182" fill="#1afa29"></path></svg>';
} ?></td>
</tr>
<?php } ?>
</tbody>
</table>
</div>
<?php include('../footer.php'); ?>

0
run/.gitkeep Normal file
View File