mirror of
https://github.com/QingdaoU/OnlineJudgeFE.git
synced 2025-01-01 09:31:42 +00:00
add login view; fix bugs in add contest problem.
This commit is contained in:
parent
06e007801a
commit
2b11b7117b
@ -7,7 +7,7 @@ module.exports = {
|
||||
index: path.resolve(__dirname, '../dist/index.html'),
|
||||
assetsRoot: path.resolve(__dirname, '../dist'),
|
||||
assetsSubDirectory: 'static',
|
||||
assetsPublicPath: '/admin',
|
||||
assetsPublicPath: '/admin/',
|
||||
productionSourceMap: true,
|
||||
// Gzip off by default as many popular static hosts such as
|
||||
// Surge or Netlify already gzip all static assets for you.
|
||||
|
@ -11,6 +11,7 @@
|
||||
"lint": "eslint --ext .js,.vue src"
|
||||
},
|
||||
"dependencies": {
|
||||
"axios": "^0.17.0",
|
||||
"element-ui": "^1.3.7",
|
||||
"font-awesome": "^4.7.0",
|
||||
"moment": "^2.18.1",
|
||||
@ -19,7 +20,6 @@
|
||||
"vue": "^2.3.3",
|
||||
"vue-codemirror": "^3.1.0",
|
||||
"vue-i18n": "^7.0.5",
|
||||
"vue-resource": "^1.3.4",
|
||||
"vue-router": "^2.6.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
@ -1,80 +1,31 @@
|
||||
<template>
|
||||
<div>
|
||||
<div>
|
||||
<SideMenu></SideMenu>
|
||||
</div>
|
||||
<div class="content-app">
|
||||
<router-view></router-view>
|
||||
<div class="footer">
|
||||
Build Version: {{ version }}
|
||||
</div>
|
||||
</div>
|
||||
<div id="app">
|
||||
<router-view></router-view>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import 'font-awesome/css/font-awesome.min.css'
|
||||
import SideMenu from './components/SideMenu.vue'
|
||||
import api from './api.js'
|
||||
|
||||
export default {
|
||||
name: 'app',
|
||||
data () {
|
||||
return {
|
||||
version: process.env.VERSION
|
||||
}
|
||||
},
|
||||
components: {
|
||||
SideMenu
|
||||
},
|
||||
methods: {},
|
||||
mounted () {
|
||||
api.login('root', 'rootroot').then(res => {})
|
||||
}
|
||||
components: {}
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<style lang="less">
|
||||
body {
|
||||
margin: 0;
|
||||
background-color: rgb(236, 242, 247)!important;
|
||||
}
|
||||
|
||||
a {
|
||||
background-color: transparent;
|
||||
-webkit-text-decoration-skip: objects
|
||||
}
|
||||
|
||||
a:active, a:hover {
|
||||
outline-width: 0
|
||||
}
|
||||
|
||||
img {
|
||||
border-style: none
|
||||
}
|
||||
|
||||
body {
|
||||
padding: 0;
|
||||
font-family: Helvetica Neue, Helvetica, PingFang SC, Hiragino Sans GB, Microsoft YaHei, SimSun, sans-serif;
|
||||
overflow: auto;
|
||||
font-weight: 400;
|
||||
font-size: 14px;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
background-color: #EDECEC;
|
||||
overflow-y: scroll;
|
||||
background-color: #324157;
|
||||
}
|
||||
|
||||
* {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.content-app {
|
||||
padding-top: 20px;
|
||||
padding-right:10px;
|
||||
padding-left: 210px;
|
||||
}
|
||||
|
||||
.footer {
|
||||
margin: 15px;
|
||||
text-align: center;
|
||||
font-size: small;
|
||||
#app {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
width: 100%;
|
||||
}
|
||||
</style>
|
||||
|
223
admin/src/api.js
223
admin/src/api.js
@ -1,65 +1,50 @@
|
||||
import Vue from 'vue'
|
||||
import VueResource from 'vue-resource'
|
||||
import router from './router'
|
||||
import axios from 'axios'
|
||||
|
||||
Vue.use(VueResource)
|
||||
Vue.http.options.root = '/api'
|
||||
Vue.http.options.emulateJSON = false
|
||||
|
||||
function getCookie (name) {
|
||||
let allCookies = document.cookie.split('; ')
|
||||
for (let i = 0; i < allCookies.length; i++) {
|
||||
let cookie = allCookies[i].split('=')
|
||||
if (cookie[0] === name) {
|
||||
return cookie[1]
|
||||
} else {
|
||||
return ''
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Vue.http.interceptors.push((request, next) => {
|
||||
request.headers.set('X-CSRFToken', getCookie('csrftoken'))
|
||||
next()
|
||||
})
|
||||
Vue.prototype.$http = axios
|
||||
axios.defaults.baseURL = '/api'
|
||||
axios.defaults.xsrfHeaderName = 'X-CSRFToken'
|
||||
axios.defaults.xsrfCookieName = 'csrftoken'
|
||||
|
||||
export default {
|
||||
// 登录
|
||||
login (username, password) {
|
||||
return ajax('login', 'get', {
|
||||
options: {
|
||||
params: {
|
||||
username,
|
||||
password
|
||||
}
|
||||
return ajax('login', 'post', {
|
||||
data: {
|
||||
username,
|
||||
password
|
||||
}
|
||||
})
|
||||
},
|
||||
logout () {
|
||||
return ajax('logout', 'get')
|
||||
},
|
||||
getProfile () {
|
||||
return ajax('profile', 'get')
|
||||
},
|
||||
// 获取公告列表
|
||||
getAnnouncementList (offset, limit) {
|
||||
return ajax('admin/announcement', 'get', {
|
||||
options: {
|
||||
params: {
|
||||
paging: true,
|
||||
offset,
|
||||
limit
|
||||
}
|
||||
params: {
|
||||
paging: true,
|
||||
offset,
|
||||
limit
|
||||
}
|
||||
})
|
||||
},
|
||||
// 删除公告
|
||||
deleteAnnouncement (id) {
|
||||
return ajax('admin/announcement', 'delete', {
|
||||
options: {
|
||||
params: {
|
||||
id
|
||||
}
|
||||
params: {
|
||||
id
|
||||
}
|
||||
})
|
||||
},
|
||||
// 修改公告
|
||||
modifyAnnouncement (id, title, content, visible) {
|
||||
return ajax('admin/announcement', 'put', {
|
||||
body: {
|
||||
data: {
|
||||
id,
|
||||
title,
|
||||
content,
|
||||
@ -70,7 +55,7 @@ export default {
|
||||
// 添加公告
|
||||
createAnnouncement (title, content, visible) {
|
||||
return ajax('admin/announcement', 'post', {
|
||||
body: {
|
||||
data: {
|
||||
title,
|
||||
content,
|
||||
visible
|
||||
@ -92,17 +77,15 @@ export default {
|
||||
// 获取单个用户信息
|
||||
getUser (id) {
|
||||
return ajax('admin/user', 'get', {
|
||||
options: {
|
||||
params: {
|
||||
id
|
||||
}
|
||||
params: {
|
||||
id
|
||||
}
|
||||
})
|
||||
},
|
||||
// 编辑用户
|
||||
editUser (body) {
|
||||
editUser (data) {
|
||||
return ajax('admin/user', 'put', {
|
||||
body
|
||||
data
|
||||
})
|
||||
},
|
||||
getLanguages () {
|
||||
@ -111,22 +94,22 @@ export default {
|
||||
getSMTPConfig () {
|
||||
return ajax('admin/smtp', 'get')
|
||||
},
|
||||
createSMTPConfig (body) {
|
||||
createSMTPConfig (data) {
|
||||
return ajax('admin/smtp', 'post', {
|
||||
body
|
||||
data
|
||||
})
|
||||
},
|
||||
editSMTPConfig (body) {
|
||||
editSMTPConfig (data) {
|
||||
return ajax('admin/smtp', 'put', {
|
||||
body
|
||||
data
|
||||
})
|
||||
},
|
||||
getWebsiteConfig () {
|
||||
return ajax('admin/website', 'get')
|
||||
},
|
||||
editWebsiteConfig (config) {
|
||||
editWebsiteConfig (data) {
|
||||
return ajax('admin/website', 'post', {
|
||||
body: config
|
||||
data
|
||||
})
|
||||
},
|
||||
getJudgeServer () {
|
||||
@ -134,30 +117,26 @@ export default {
|
||||
},
|
||||
deleteJudgeServer (hostname) {
|
||||
return ajax('admin/judge_server', 'delete', {
|
||||
options: {
|
||||
params: {
|
||||
hostname: hostname
|
||||
}
|
||||
params: {
|
||||
hostname: hostname
|
||||
}
|
||||
})
|
||||
},
|
||||
createContest (body) {
|
||||
createContest (data) {
|
||||
return ajax('admin/contest', 'post', {
|
||||
body: body
|
||||
data
|
||||
})
|
||||
},
|
||||
getContest (id) {
|
||||
return ajax('admin/contest', 'get', {
|
||||
options: {
|
||||
params: {
|
||||
id
|
||||
}
|
||||
params: {
|
||||
id
|
||||
}
|
||||
})
|
||||
},
|
||||
editContest (body) {
|
||||
editContest (data) {
|
||||
return ajax('admin/contest', 'put', {
|
||||
body
|
||||
data
|
||||
})
|
||||
},
|
||||
getContestList (offset, limit, keyword) {
|
||||
@ -166,53 +145,45 @@ export default {
|
||||
params.keyword = keyword
|
||||
}
|
||||
return ajax('admin/contest', 'get', {
|
||||
options: {
|
||||
params: params
|
||||
}
|
||||
params: params
|
||||
})
|
||||
},
|
||||
getContestAnnouncementList (contestId) {
|
||||
return ajax('admin/contest/announcement', 'get', {
|
||||
options: {
|
||||
params: {
|
||||
contest_id: contestId
|
||||
}
|
||||
params: {
|
||||
contest_id: contestId
|
||||
}
|
||||
})
|
||||
},
|
||||
createContestAnnouncement (body) {
|
||||
createContestAnnouncement (data) {
|
||||
return ajax('admin/contest/announcement', 'post', {
|
||||
body
|
||||
data
|
||||
})
|
||||
},
|
||||
deleteContestAnnouncement (id) {
|
||||
return ajax('admin/contest/announcement', 'delete', {
|
||||
options: {
|
||||
params: {
|
||||
id
|
||||
}
|
||||
params: {
|
||||
id
|
||||
}
|
||||
})
|
||||
},
|
||||
getProblemTagList () {
|
||||
return ajax('problem/tags', 'get')
|
||||
},
|
||||
createProblem (body) {
|
||||
createProblem (data) {
|
||||
return ajax('admin/problem', 'post', {
|
||||
body
|
||||
data
|
||||
})
|
||||
},
|
||||
editProblem (body) {
|
||||
editProblem (data) {
|
||||
return ajax('admin/problem', 'put', {
|
||||
body
|
||||
data
|
||||
})
|
||||
},
|
||||
getProblem (id) {
|
||||
return ajax('admin/problem', 'get', {
|
||||
options: {
|
||||
params: {
|
||||
id
|
||||
}
|
||||
params: {
|
||||
id
|
||||
}
|
||||
})
|
||||
},
|
||||
@ -222,9 +193,7 @@ export default {
|
||||
params.keyword = keyword
|
||||
}
|
||||
return ajax('admin/problem', 'get', {
|
||||
options: {
|
||||
params: params
|
||||
}
|
||||
params
|
||||
})
|
||||
},
|
||||
getContestProblemList (offset, limit, keyword, contestId) {
|
||||
@ -233,76 +202,66 @@ export default {
|
||||
params.keyword = keyword
|
||||
}
|
||||
return ajax('admin/contest/problem', 'get', {
|
||||
options: {
|
||||
params: params
|
||||
}
|
||||
params
|
||||
})
|
||||
},
|
||||
getContestProblem (id) {
|
||||
return ajax('admin/contest/problem', 'get', {
|
||||
options: {
|
||||
params: {
|
||||
id
|
||||
}
|
||||
params: {
|
||||
id
|
||||
}
|
||||
})
|
||||
},
|
||||
createContestProblem (body) {
|
||||
createContestProblem (data) {
|
||||
return ajax('admin/contest/problem', 'post', {
|
||||
body
|
||||
data
|
||||
})
|
||||
},
|
||||
editContestProblem (body) {
|
||||
editContestProblem (data) {
|
||||
return ajax('admin/contest/problem', 'put', {
|
||||
body
|
||||
data
|
||||
})
|
||||
}
|
||||
}
|
||||
/**
|
||||
ajax 请求
|
||||
@param url
|
||||
@param type get|post|put|jsonp ....
|
||||
@param options options = {
|
||||
body: request body
|
||||
options: ..,
|
||||
succCallBack: Function
|
||||
errCallBack: Function
|
||||
}
|
||||
@return Promise
|
||||
*/
|
||||
|
||||
function ajax (url, type, options) {
|
||||
return new Promise(function (resolve, reject) {
|
||||
options = options || {}
|
||||
if (options.body === undefined) {
|
||||
options.body = options.options
|
||||
options.options = undefined
|
||||
}
|
||||
Vue.http[type](url, options.body, options.options).then(res => {
|
||||
// 出错了
|
||||
/**
|
||||
* @param url
|
||||
* @param method get|post|put|delete...
|
||||
* @param params like queryString. if a url is index?a=1&b=2, params = {a: '1', b: '2'}
|
||||
* @param data post data, use for method put|post
|
||||
* @returns {Promise}
|
||||
*/
|
||||
function ajax (url, method, options) {
|
||||
if (options !== undefined) {
|
||||
var {params = {}, data = {}} = options
|
||||
} else {
|
||||
params = data = {}
|
||||
}
|
||||
return new Promise((resolve, reject) => {
|
||||
axios({
|
||||
url,
|
||||
method,
|
||||
params,
|
||||
data
|
||||
}).then(res => {
|
||||
// API正常返回(status=20x), 是否错误通过有无error判断
|
||||
if (res.data.error !== null) {
|
||||
Vue.prototype.$error(res.data.data)
|
||||
reject(res)
|
||||
if (options.errCallBack !== undefined) {
|
||||
options.errCallBack(res)
|
||||
// // 若后端返回为登录,则为session失效,应退出当前登录用户
|
||||
if (res.data.data.startsWith('Please login')) {
|
||||
router.push({name: 'login'})
|
||||
}
|
||||
} else {
|
||||
// 请求成功
|
||||
resolve(res)
|
||||
if (options.succCallBack !== undefined) {
|
||||
options.succCallBack(res)
|
||||
} else if (type !== 'get') {
|
||||
Vue.prototype.$success()
|
||||
if (method !== 'get') {
|
||||
Vue.prototype.$success('Succeeded')
|
||||
}
|
||||
}
|
||||
}, res => {
|
||||
// 请求失败
|
||||
// API请求异常,一般为Server error 或 network error
|
||||
reject(res)
|
||||
if (options.errCallBack !== undefined) {
|
||||
options.errCallBack(res)
|
||||
} else {
|
||||
Vue.prototype.$error('Network Error')
|
||||
}
|
||||
Vue.prototype.$error(res.data.data)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
@ -42,6 +42,7 @@ export default{
|
||||
width: 200px;
|
||||
height: 100%;
|
||||
position: fixed!important;
|
||||
z-index: 100;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
|
@ -2,10 +2,10 @@ import Vue from 'vue'
|
||||
import App from './App'
|
||||
import Element from 'element-ui'
|
||||
import 'element-ui/lib/theme-default/index.css'
|
||||
import VueRouter from 'vue-router'
|
||||
import locale from 'element-ui/lib/locale/lang/en'
|
||||
|
||||
import filters from './filters.js'
|
||||
import filters from './utils/filters.js'
|
||||
import router from './router'
|
||||
|
||||
import Panel from './components/Panel.vue'
|
||||
import IconBtn from './components/btn/IconBtn.vue'
|
||||
@ -17,98 +17,13 @@ Object.keys(filters).forEach(key => {
|
||||
Vue.filter(key, filters[key])
|
||||
})
|
||||
|
||||
Vue.use(Element, { locale })
|
||||
Vue.use(VueRouter)
|
||||
Vue.use(Element, {locale})
|
||||
// Vue.use(VueI18n)
|
||||
Vue.component(IconBtn.name, IconBtn)
|
||||
Vue.component(Panel.name, Panel)
|
||||
Vue.component(Save.name, Save)
|
||||
Vue.component(Cancel.name, Cancel)
|
||||
|
||||
// 引入 view 组件
|
||||
import { Announcement, User, Conf, JudgeServer, Problem, Contest, ContestList,
|
||||
ContestAnnouncement, ProblemList } from './views'
|
||||
|
||||
const router = new VueRouter({
|
||||
mode: 'history',
|
||||
scrollBehavior: () => ({ y: 0 }),
|
||||
routes: [
|
||||
{
|
||||
path: '/announcement',
|
||||
name: 'announcement',
|
||||
component: Announcement
|
||||
},
|
||||
{
|
||||
path: '/user',
|
||||
name: 'user',
|
||||
component: User
|
||||
},
|
||||
{
|
||||
path: '/conf',
|
||||
name: 'conf',
|
||||
component: Conf
|
||||
},
|
||||
{
|
||||
path: '/judge-server',
|
||||
name: 'judge-server',
|
||||
component: JudgeServer
|
||||
},
|
||||
{
|
||||
path: '/problems',
|
||||
name: 'problem-list',
|
||||
component: ProblemList
|
||||
},
|
||||
{
|
||||
path: '/problem/create',
|
||||
name: 'create-problem',
|
||||
component: Problem
|
||||
},
|
||||
{
|
||||
path: '/problem/edit/:problemId',
|
||||
name: 'edit-problem',
|
||||
component: Problem
|
||||
},
|
||||
{
|
||||
path: '/contest/create',
|
||||
name: 'create-contest',
|
||||
component: Contest
|
||||
},
|
||||
{
|
||||
path: '/contest',
|
||||
name: 'contest-list',
|
||||
component: ContestList
|
||||
},
|
||||
{
|
||||
path: '/contest/:contestId/edit',
|
||||
name: 'edit-contest',
|
||||
component: Contest
|
||||
},
|
||||
{
|
||||
path: '/contest/:contestId/announcement',
|
||||
name: 'contest-announcement',
|
||||
component: ContestAnnouncement
|
||||
},
|
||||
{
|
||||
path: '/contest/:contestId/problems',
|
||||
name: 'contest-problem-list',
|
||||
component: ProblemList
|
||||
},
|
||||
{
|
||||
path: '/contest/:contestId/problem/create',
|
||||
name: 'create-contest-problem',
|
||||
component: Problem
|
||||
},
|
||||
{
|
||||
path: '/contest/:contestId/problem/:problemId/edit',
|
||||
name: 'edit-contest-problem',
|
||||
component: Problem
|
||||
},
|
||||
{
|
||||
path: '*', redirect: '/announcement'
|
||||
}
|
||||
]
|
||||
})
|
||||
|
||||
Vue.prototype.$error = (msg) => {
|
||||
Vue.prototype.$message({'message': msg, 'type': 'error'})
|
||||
}
|
||||
@ -125,4 +40,4 @@ Vue.prototype.$success = (msg) => {
|
||||
}
|
||||
}
|
||||
|
||||
new Vue(Vue.util.extend({ router }, App)).$mount('#app')
|
||||
new Vue(Vue.util.extend({router}, App)).$mount('#app')
|
||||
|
113
admin/src/router.js
Normal file
113
admin/src/router.js
Normal file
@ -0,0 +1,113 @@
|
||||
import Vue from 'vue'
|
||||
import VueRouter from 'vue-router'
|
||||
// 引入 view 组件
|
||||
import {
|
||||
Announcement,
|
||||
Conf,
|
||||
Contest,
|
||||
ContestAnnouncement,
|
||||
ContestList,
|
||||
Home,
|
||||
JudgeServer,
|
||||
Login,
|
||||
Problem,
|
||||
ProblemList,
|
||||
User
|
||||
} from './views'
|
||||
|
||||
Vue.use(VueRouter)
|
||||
|
||||
export default new VueRouter({
|
||||
mode: 'history',
|
||||
base: '/admin/',
|
||||
scrollBehavior: () => ({y: 0}),
|
||||
routes: [
|
||||
{
|
||||
path: '/login',
|
||||
name: 'login',
|
||||
component: Login
|
||||
},
|
||||
{
|
||||
path: '/',
|
||||
component: Home,
|
||||
children: [
|
||||
{
|
||||
path: '',
|
||||
component: Announcement
|
||||
},
|
||||
{
|
||||
path: '/announcement',
|
||||
name: 'announcement',
|
||||
component: Announcement
|
||||
},
|
||||
{
|
||||
path: '/user',
|
||||
name: 'user',
|
||||
component: User
|
||||
},
|
||||
{
|
||||
path: '/conf',
|
||||
name: 'conf',
|
||||
component: Conf
|
||||
},
|
||||
{
|
||||
path: '/judge-server',
|
||||
name: 'judge-server',
|
||||
component: JudgeServer
|
||||
},
|
||||
{
|
||||
path: '/problems',
|
||||
name: 'problem-list',
|
||||
component: ProblemList
|
||||
},
|
||||
{
|
||||
path: '/problem/create',
|
||||
name: 'create-problem',
|
||||
component: Problem
|
||||
},
|
||||
{
|
||||
path: '/problem/edit/:problemId',
|
||||
name: 'edit-problem',
|
||||
component: Problem
|
||||
},
|
||||
{
|
||||
path: '/contest/create',
|
||||
name: 'create-contest',
|
||||
component: Contest
|
||||
},
|
||||
{
|
||||
path: '/contest',
|
||||
name: 'contest-list',
|
||||
component: ContestList
|
||||
},
|
||||
{
|
||||
path: '/contest/:contestId/edit',
|
||||
name: 'edit-contest',
|
||||
component: Contest
|
||||
},
|
||||
{
|
||||
path: '/contest/:contestId/announcement',
|
||||
name: 'contest-announcement',
|
||||
component: ContestAnnouncement
|
||||
},
|
||||
{
|
||||
path: '/contest/:contestId/problems',
|
||||
name: 'contest-problem-list',
|
||||
component: ProblemList
|
||||
},
|
||||
{
|
||||
path: '/contest/:contestId/problem/create',
|
||||
name: 'create-contest-problem',
|
||||
component: Problem
|
||||
},
|
||||
{
|
||||
path: '/contest/:contestId/problem/:problemId/edit',
|
||||
name: 'edit-contest-problem',
|
||||
component: Problem
|
||||
},
|
||||
{
|
||||
path: '*', redirect: '/problem-list'
|
||||
}
|
||||
]
|
||||
}]
|
||||
})
|
5
admin/src/utils/constants.js
Normal file
5
admin/src/utils/constants.js
Normal file
@ -0,0 +1,5 @@
|
||||
export const CONTEST_STATUS_REVERSE = {
|
||||
'-1': 'Ended',
|
||||
'0': 'Underway',
|
||||
'1': 'Not Started'
|
||||
}
|
111
admin/src/views/Home.vue
Normal file
111
admin/src/views/Home.vue
Normal file
@ -0,0 +1,111 @@
|
||||
<template>
|
||||
<div class="container">
|
||||
<div>
|
||||
<SideMenu></SideMenu>
|
||||
</div>
|
||||
<div id="header">
|
||||
<el-dropdown @command="handleCommand">
|
||||
<span>{{profile.user.username}}<i class="el-icon-caret-bottom el-icon--right"></i></span>
|
||||
<el-dropdown-menu slot="dropdown">
|
||||
<el-dropdown-item command="logout" >Logout</el-dropdown-item>
|
||||
</el-dropdown-menu>
|
||||
</el-dropdown>
|
||||
</div>
|
||||
<div class="content-app">
|
||||
<router-view></router-view>
|
||||
<div class="footer">
|
||||
Build Version: {{ version }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import 'font-awesome/css/font-awesome.min.css'
|
||||
import SideMenu from '../components/SideMenu.vue'
|
||||
import api from '../api'
|
||||
|
||||
export default {
|
||||
name: 'app',
|
||||
data () {
|
||||
return {
|
||||
version: process.env.VERSION,
|
||||
profile: {
|
||||
user: {}
|
||||
}
|
||||
}
|
||||
},
|
||||
components: {
|
||||
SideMenu
|
||||
},
|
||||
beforeRouteEnter (to, from, next) {
|
||||
api.getProfile().then(res => {
|
||||
if (!res.data.data) {
|
||||
// not login
|
||||
next({name: 'login'})
|
||||
} else {
|
||||
next(vm => {
|
||||
vm.profile = res.data.data
|
||||
})
|
||||
}
|
||||
})
|
||||
},
|
||||
methods: {
|
||||
handleCommand (command) {
|
||||
if (command === 'logout') {
|
||||
api.logout().then(() => {
|
||||
this.$router.push({name: 'login'})
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less">
|
||||
a {
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
a:active, a:hover {
|
||||
outline-width: 0
|
||||
}
|
||||
|
||||
img {
|
||||
border-style: none
|
||||
}
|
||||
|
||||
.container {
|
||||
overflow: auto;
|
||||
font-weight: 400;
|
||||
height: 100%;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
background-color: #EDECEC;
|
||||
overflow-y: scroll;
|
||||
}
|
||||
|
||||
* {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
#header {
|
||||
text-align: right;
|
||||
padding-left: 210px;
|
||||
padding-right: 30px;
|
||||
line-height: 50px;
|
||||
height: 50px;
|
||||
background: #F9FAFC;
|
||||
}
|
||||
|
||||
.content-app {
|
||||
padding-top: 20px;
|
||||
padding-right: 10px;
|
||||
padding-left: 210px;
|
||||
}
|
||||
|
||||
.footer {
|
||||
margin: 15px;
|
||||
text-align: center;
|
||||
font-size: small;
|
||||
}
|
||||
</style>
|
@ -15,7 +15,7 @@
|
||||
:data="contestList"
|
||||
style="width: 100%">
|
||||
<el-table-column type="expand">
|
||||
<template scope="props">
|
||||
<template slot-scope="props">
|
||||
<div>
|
||||
<el-tag :type="props.row.visible ? 'success' : 'danger'">{{props.row.visible ? 'Visible' : 'Invisible'}}
|
||||
</el-tag>
|
||||
@ -23,8 +23,8 @@
|
||||
{{ props.row.contest_type}}
|
||||
</el-tag>
|
||||
<el-tag
|
||||
:type="props.row.status === 'Ended' ? 'gray' : props.row.status === 'Underway' ? 'success' : 'primary'">
|
||||
{{ props.row.status }}
|
||||
:type="props.row.status === '-1' ? 'gray' : props.row.status === '0' ? 'success' : 'primary'">
|
||||
{{ props.row.status | contestStatus}}
|
||||
</el-tag>
|
||||
</div>
|
||||
<p>
|
||||
@ -43,14 +43,14 @@
|
||||
<el-table-column
|
||||
prop="start_time"
|
||||
label="Start Time">
|
||||
<template scope="scope">
|
||||
<template slot-scope="scope">
|
||||
{{scope.row.start_time | localtime }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
prop="end_time"
|
||||
label="End Time">
|
||||
<template scope="scope">
|
||||
<template slot-scope="scope">
|
||||
{{scope.row.end_time | localtime }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
@ -85,6 +85,7 @@
|
||||
|
||||
<script>
|
||||
import api from '../../api.js'
|
||||
import {CONTEST_STATUS_REVERSE} from '../../utils/constants'
|
||||
|
||||
export default {
|
||||
name: 'ContestList',
|
||||
@ -101,6 +102,11 @@
|
||||
mounted () {
|
||||
this.getContestList(this.currentPage)
|
||||
},
|
||||
filters: {
|
||||
contestStatus (value) {
|
||||
return CONTEST_STATUS_REVERSE[value]
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
// 切换页码回调
|
||||
currentChange (page) {
|
||||
|
@ -19,14 +19,14 @@
|
||||
<el-table-column
|
||||
prop="create_time"
|
||||
label="CreateTime">
|
||||
<template scope="scope">
|
||||
<template slot-scope="scope">
|
||||
{{ scope.row.create_time | localtime }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
prop="last_update_time"
|
||||
label="LastUpdateTime">
|
||||
<template scope="scope">
|
||||
<template slot-scope="scope">
|
||||
{{scope.row.last_update_time | localtime }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
@ -10,7 +10,7 @@
|
||||
border>
|
||||
<el-table-column
|
||||
type="expand">
|
||||
<template scope="props">
|
||||
<template slot-scope="props">
|
||||
<p>IP:
|
||||
<el-tag type="success">{{ props.row.ip }}</el-tag>
|
||||
Judger Version:
|
||||
@ -25,7 +25,7 @@
|
||||
<el-table-column
|
||||
prop="status"
|
||||
label="Status">
|
||||
<template scope="scope">
|
||||
<template slot-scope="scope">
|
||||
<el-tag
|
||||
:type="scope.row.status === 'normal' ? 'success' : 'danger'">
|
||||
{{ scope.row.status === 'normal' ? 'Normal' : 'Abnormal' }}
|
||||
@ -47,17 +47,17 @@
|
||||
<el-table-column
|
||||
prop="cpu_usage"
|
||||
label="CPU Usage">
|
||||
<template scope="scope">{{ scope.row.cpu_usage }}%</template>
|
||||
<template slot-scope="scope">{{ scope.row.cpu_usage }}%</template>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
prop="memory_usage"
|
||||
label="Memory Usage">
|
||||
<template scope="scope">{{ scope.row.memory_usage }}%</template>
|
||||
<template slot-scope="scope">{{ scope.row.memory_usage }}%</template>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
fixed="right"
|
||||
label="option">
|
||||
<template scope="scope">
|
||||
<template slot-scope="scope">
|
||||
<icon-btn name="Delete" icon="trash" @click.native="deleteJudgeServer(scope.row.hostname)"></icon-btn>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
@ -17,19 +17,19 @@
|
||||
<el-table-column prop="id" label="ID"></el-table-column>
|
||||
<el-table-column prop="username" label="Userame"></el-table-column>
|
||||
<el-table-column prop="create_time" label="Create Time">
|
||||
<template scope="scope">
|
||||
<template slot-scope="scope">
|
||||
{{scope.row.create_time | localtime }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="last_login" label="Last Login">
|
||||
<template scope="scope">
|
||||
<template slot-scope="scope">
|
||||
{{scope.row.last_login | localtime }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="real_name" label="Real Name"></el-table-column>
|
||||
<el-table-column prop="email" label="Email"></el-table-column>
|
||||
<el-table-column prop="admin_type" label="User Type">
|
||||
<template scope="scope">
|
||||
<template slot-scope="scope">
|
||||
{{ scope.row.admin_type }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
83
admin/src/views/general/login.vue
Normal file
83
admin/src/views/general/login.vue
Normal file
@ -0,0 +1,83 @@
|
||||
<template>
|
||||
<el-form :model="ruleForm2" :rules="rules2" ref="ruleForm2" label-position="left" label-width="0px"
|
||||
class="demo-ruleForm login-container">
|
||||
<h3 class="title">Welcome to Login</h3>
|
||||
<el-form-item prop="account">
|
||||
<el-input type="text" v-model="ruleForm2.account" auto-complete="off" placeholder="username"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item prop="password">
|
||||
<el-input type="password" v-model="ruleForm2.password" auto-complete="off" placeholder="password"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item style="width:100%;">
|
||||
<el-button type="primary" style="width:100%;" @click.native.prevent="handleLogin" :loading="logining">GO
|
||||
</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import api from '../../api'
|
||||
|
||||
export default {
|
||||
data () {
|
||||
return {
|
||||
logining: false,
|
||||
ruleForm2: {
|
||||
account: 'root',
|
||||
password: 'rootroot'
|
||||
},
|
||||
rules2: {
|
||||
account: [
|
||||
{required: true, trigger: 'blur'}
|
||||
],
|
||||
password: [
|
||||
{required: true, trigger: 'blur'}
|
||||
]
|
||||
},
|
||||
checked: true
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
handleLogin (ev) {
|
||||
this.$refs.ruleForm2.validate((valid) => {
|
||||
if (valid) {
|
||||
this.logining = true
|
||||
api.login(this.ruleForm2.account, this.ruleForm2.password).then(data => {
|
||||
this.logining = false
|
||||
this.$router.push({name: 'problem-list'})
|
||||
}, () => {
|
||||
this.logining = false
|
||||
})
|
||||
} else {
|
||||
this.$error('Please check the error fields')
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.login-container {
|
||||
/*box-shadow: 0 0px 8px 0 rgba(0, 0, 0, 0.06), 0 1px 0px 0 rgba(0, 0, 0, 0.02);*/
|
||||
-webkit-border-radius: 5px;
|
||||
border-radius: 5px;
|
||||
-moz-border-radius: 5px;
|
||||
background-clip: padding-box;
|
||||
margin: 180px auto;
|
||||
width: 350px;
|
||||
padding: 35px 35px 15px 35px;
|
||||
background: #fff;
|
||||
border: 1px solid #eaeaea;
|
||||
box-shadow: 0 0 25px #cac6c6;
|
||||
.title {
|
||||
margin: 0px auto 40px auto;
|
||||
text-align: center;
|
||||
color: #505458;
|
||||
}
|
||||
.remember {
|
||||
margin: 0px 0px 35px 0px;
|
||||
}
|
||||
}
|
||||
</style>
|
@ -7,8 +7,10 @@ import ProblemList from './problem/ProblemList.vue'
|
||||
import ContestList from './contest/ContestList.vue'
|
||||
import Contest from './contest/Contest.vue'
|
||||
import ContestAnnouncement from './contest/Announcement.vue'
|
||||
import Login from './general/login.vue'
|
||||
import Home from './Home.vue'
|
||||
|
||||
export {
|
||||
Announcement, User, Conf, JudgeServer, Problem, ProblemList, Contest,
|
||||
ContestList, ContestAnnouncement
|
||||
ContestList, ContestAnnouncement, Login, Home
|
||||
}
|
||||
|
@ -15,7 +15,8 @@
|
||||
<el-form ref="form" :model="problem" :rules="rules" label-position="top" label-width="70px">
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="6">
|
||||
<el-form-item prop="_id" label="Display ID" :required="this.routeName === 'create-contest-problem' || this.routeName === 'edit-contet-problem'">
|
||||
<el-form-item prop="_id" label="Display ID"
|
||||
:required="this.routeName === 'create-contest-problem' || this.routeName === 'edit-contet-problem'">
|
||||
<el-input placeholder="Display ID" v-model="problem._id"></el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
@ -113,7 +114,8 @@
|
||||
<el-col :span="8">
|
||||
<el-form-item label="Languages" :error="error.languages" required>
|
||||
<el-checkbox-group v-model="problem.languages">
|
||||
<el-tooltip class="spj-radio" v-for="lang in allLanguage.languages" :key="'spj'+lang.name" effect="dark" :content="lang.description" placement="top-start">
|
||||
<el-tooltip class="spj-radio" v-for="lang in allLanguage.languages" :key="'spj'+lang.name" effect="dark"
|
||||
:content="lang.description" placement="top-start">
|
||||
<el-checkbox :label="lang.name"></el-checkbox>
|
||||
</el-tooltip>
|
||||
</el-checkbox-group>
|
||||
@ -121,36 +123,38 @@
|
||||
</el-col>
|
||||
</el-row>
|
||||
<div>
|
||||
<el-form-item v-for="(sample, index) in problem.samples" :key="'sample'+index">
|
||||
<Accordion :title="'Sample' + (index + 1)">
|
||||
<el-button type="warning" size="small" icon="delete" slot="header" @click="deleteSample(index)">Delete</el-button>
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="12">
|
||||
<el-form-item label="Input Samples" required>
|
||||
<el-input
|
||||
:rows="5"
|
||||
type="textarea"
|
||||
placeholder="Input Samples"
|
||||
v-model="sample.input">
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="Output Samples" required>
|
||||
<el-input
|
||||
:rows="5"
|
||||
type="textarea"
|
||||
placeholder="Output Samples"
|
||||
v-model="sample.output">
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</Accordion>
|
||||
</el-form-item>
|
||||
<el-form-item v-for="(sample, index) in problem.samples" :key="'sample'+index">
|
||||
<Accordion :title="'Sample' + (index + 1)">
|
||||
<el-button type="warning" size="small" icon="delete" slot="header" @click="deleteSample(index)">Delete
|
||||
</el-button>
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="12">
|
||||
<el-form-item label="Input Samples" required>
|
||||
<el-input
|
||||
:rows="5"
|
||||
type="textarea"
|
||||
placeholder="Input Samples"
|
||||
v-model="sample.input">
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="Output Samples" required>
|
||||
<el-input
|
||||
:rows="5"
|
||||
type="textarea"
|
||||
placeholder="Output Samples"
|
||||
v-model="sample.output">
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</Accordion>
|
||||
</el-form-item>
|
||||
</div>
|
||||
<div class="add-sample-btn">
|
||||
<button type="button" class="add-samples" @click="addSample()"><i class="el-icon-plus"></i>Add Samples</button>
|
||||
<button type="button" class="add-samples" @click="addSample()"><i class="el-icon-plus"></i>Add Samples
|
||||
</button>
|
||||
</div>
|
||||
<el-form-item label="Code Template">
|
||||
<el-row>
|
||||
@ -172,7 +176,8 @@
|
||||
<el-col v-if="problem.spj" :span="12">
|
||||
<el-form-item label="Special Judge Language">
|
||||
<el-radio-group v-model="problem.spj_language">
|
||||
<el-tooltip class="spj-radio" v-for="lang in allLanguage.spj_languages" :key="lang.name" effect="dark" :content="lang.description" placement="top-start">
|
||||
<el-tooltip class="spj-radio" v-for="lang in allLanguage.spj_languages" :key="lang.name" effect="dark"
|
||||
:content="lang.description" placement="top-start">
|
||||
<el-radio :label="lang.name">{{ lang.name }}</el-radio>
|
||||
</el-tooltip>
|
||||
</el-radio-group>
|
||||
@ -220,7 +225,7 @@
|
||||
<el-table-column
|
||||
prop="score"
|
||||
label="Score">
|
||||
<template scope="scope">
|
||||
<template slot-scope="scope">
|
||||
<el-input
|
||||
size="small"
|
||||
placeholder="Score"
|
||||
@ -249,7 +254,8 @@
|
||||
import Accordion from '../../components/Accordion'
|
||||
import CodeMirror from '../../components/CodeMirror'
|
||||
import api from '../../api'
|
||||
export default{
|
||||
|
||||
export default {
|
||||
name: 'Problem',
|
||||
components: {
|
||||
Simditor,
|
||||
@ -259,9 +265,9 @@
|
||||
data () {
|
||||
return {
|
||||
rules: {
|
||||
title: { required: true, message: 'Title is required', trigger: 'blur' },
|
||||
input_description: { required: true, message: 'Input Description is required', trigger: 'blur' },
|
||||
output_description: { required: true, message: 'Output Description is required', trigger: 'blur' }
|
||||
title: {required: true, message: 'Title is required', trigger: 'blur'},
|
||||
input_description: {required: true, message: 'Input Description is required', trigger: 'blur'},
|
||||
output_description: {required: true, message: 'Output Description is required', trigger: 'blur'}
|
||||
},
|
||||
mode: '',
|
||||
problem: {
|
||||
@ -318,6 +324,14 @@
|
||||
hint: '',
|
||||
source: ''
|
||||
}
|
||||
let contestID = this.$route.params.contestId
|
||||
if (contestID) {
|
||||
this.problem.contest_id = contestID
|
||||
this.disableRuleType = true
|
||||
api.getContest(contestID).then(res => {
|
||||
this.problem.rule_type = this.reProblem.rule_type = res.data.data.rule_type
|
||||
})
|
||||
}
|
||||
|
||||
this.problem.spj_language = 'C'
|
||||
|
||||
@ -326,8 +340,8 @@
|
||||
|
||||
// get problem after getting languages list to avoid find undefined value in `watch problem.languages`
|
||||
if (this.mode === 'edit') {
|
||||
let funcName = {'edit-problem': 'getProblem', 'edit-contest-problem': 'getContestProblem'}[this.routeName]
|
||||
this.title = 'Edit Problem'
|
||||
let funcName = {'edit-problem': 'getProblem', 'edit-contest-problem': 'getContestProblem'}[this.routeName]
|
||||
api[funcName](this.$route.params.problemId).then(problemRes => {
|
||||
let data = problemRes.data.data
|
||||
if (!data.spj_code) {
|
||||
@ -336,21 +350,12 @@
|
||||
data.spj_language = data.spj_language || 'C'
|
||||
this.problem = data
|
||||
this.testCaseUploaded = true
|
||||
|
||||
if (this.routeName === 'edit-contest-problem') {
|
||||
this.problem.contest_id = this.$route.params.contestId
|
||||
this.disableRuleType = true
|
||||
}
|
||||
})
|
||||
} else {
|
||||
this.title = 'Add Problem'
|
||||
for (let item of allLanguage.languages) {
|
||||
this.problem.languages.push(item.name)
|
||||
}
|
||||
if (this.routeName === 'create-contest-problem') {
|
||||
this.problem.contest_id = this.$route.params.contestId
|
||||
this.disableRuleType = true
|
||||
}
|
||||
}
|
||||
})
|
||||
},
|
||||
@ -393,7 +398,8 @@
|
||||
}).then(() => {
|
||||
this.problem.spj = !this.problem.spj
|
||||
this.resetTestCase()
|
||||
}).catch(() => {})
|
||||
}).catch(() => {
|
||||
})
|
||||
} else {
|
||||
this.problem.spj = !this.problem.spj
|
||||
}
|
||||
@ -405,7 +411,8 @@
|
||||
tagList.push({value: tag.name})
|
||||
}
|
||||
cb(tagList)
|
||||
}).catch(() => {})
|
||||
}).catch(() => {
|
||||
})
|
||||
},
|
||||
resetTestCase () {
|
||||
this.testCaseUploaded = false
|
||||
@ -498,7 +505,8 @@
|
||||
this.problem.template[k] = this.template[k].code
|
||||
}
|
||||
}
|
||||
let funcName = {'create-problem': 'createProblem',
|
||||
let funcName = {
|
||||
'create-problem': 'createProblem',
|
||||
'edit-problem': 'editProblem',
|
||||
'create-contest-problem': 'createContestProblem',
|
||||
'edit-contest-problem': 'editContestProblem'
|
||||
@ -509,56 +517,57 @@
|
||||
} else {
|
||||
this.$router.push({name: 'problem-list'})
|
||||
}
|
||||
}).catch(() => {})
|
||||
}).catch(() => {
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.problem{
|
||||
.difficulty-select{
|
||||
width: 120px;
|
||||
}
|
||||
.spj-radio{
|
||||
margin-right: 15px;
|
||||
}
|
||||
.input-new-tag{
|
||||
width: 78px;
|
||||
}
|
||||
.button-new-tag{
|
||||
height: 24px;
|
||||
line-height: 22px;
|
||||
padding-top: 0;
|
||||
padding-bottom: 0;
|
||||
}
|
||||
.tags{
|
||||
.el-tag{
|
||||
margin-right: 10px;
|
||||
.problem {
|
||||
.difficulty-select {
|
||||
width: 120px;
|
||||
}
|
||||
.spj-radio {
|
||||
margin-right: 15px;
|
||||
}
|
||||
.input-new-tag {
|
||||
width: 78px;
|
||||
}
|
||||
.button-new-tag {
|
||||
height: 24px;
|
||||
line-height: 22px;
|
||||
padding-top: 0;
|
||||
padding-bottom: 0;
|
||||
}
|
||||
.tags {
|
||||
.el-tag {
|
||||
margin-right: 10px;
|
||||
}
|
||||
}
|
||||
.accordion {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
.add-samples {
|
||||
width: 100%;
|
||||
background-color: #fff;
|
||||
border: 1px dashed #aaa;
|
||||
outline: none;
|
||||
cursor: pointer;
|
||||
color: #666;
|
||||
height: 35px;
|
||||
font-size: 14px;
|
||||
&:hover {
|
||||
background-color: #f9fafc;
|
||||
}
|
||||
i {
|
||||
margin-right: 10px;
|
||||
}
|
||||
}
|
||||
.add-sample-btn {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
}
|
||||
.accordion{
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
.add-samples{
|
||||
width: 100%;
|
||||
background-color: #fff;
|
||||
border: 1px dashed #aaa;
|
||||
outline: none;
|
||||
cursor: pointer;
|
||||
color: #666;
|
||||
height: 35px;
|
||||
font-size: 14px;
|
||||
&:hover {
|
||||
background-color: #f9fafc;
|
||||
}
|
||||
i{
|
||||
margin-right: 10px;
|
||||
}
|
||||
}
|
||||
.add-sample-btn {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
|
@ -33,13 +33,13 @@
|
||||
<el-table-column
|
||||
prop="create_time"
|
||||
label="Create Time">
|
||||
<template scope="scope">
|
||||
<template slot-scope="scope">
|
||||
{{scope.row.create_time | localtime }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
label="Status">
|
||||
<template scope="props">
|
||||
<template slot-scope="props">
|
||||
<el-tag :type="props.row.visible ? 'success' : 'danger'">{{props.row.visible ? 'Visible' : 'Invisible'}}
|
||||
</el-tag>
|
||||
</template>
|
||||
@ -52,7 +52,6 @@
|
||||
width="180">
|
||||
<div>
|
||||
<icon-btn name="Edit" icon="edit" @click.native="goEdit(row.id)"></icon-btn>
|
||||
<icon-btn name="Submission" icon="code"></icon-btn>
|
||||
</div>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
|
@ -94,7 +94,7 @@ http {
|
||||
listen 80 default_server;
|
||||
server_name _;
|
||||
|
||||
location /static/avatar {
|
||||
location ^~ (/admin)?/static/avatar {
|
||||
expires max;
|
||||
alias /data/avatar;
|
||||
}
|
||||
|
@ -10,12 +10,12 @@ run_build() {
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "Build success, dist files in $1/dist\n"
|
||||
echo -e "Build success, dist files in $1/dist\n"
|
||||
}
|
||||
|
||||
sleep 3
|
||||
|
||||
run_build /OJ_FE/oj
|
||||
# run_build /OJ_FE/oj
|
||||
run_build /OJ_FE/admin
|
||||
echo -e "\n\n Congratulations, All have done without error."
|
||||
echo -e "you can check the onlinejudge with http://IP:80 \n"
|
||||
|
||||
exec nginx -c /OJ_FE/deploy/nginx.conf
|
@ -27,7 +27,7 @@ router.beforeEach((to, from, next) => {
|
||||
if (!storage.get(STORAGE_KEY.AUTHED)) {
|
||||
Vue.prototype.$error('please login first')
|
||||
next({
|
||||
name: 'test'
|
||||
name: 'home'
|
||||
})
|
||||
} else {
|
||||
next()
|
||||
|
Loading…
Reference in New Issue
Block a user