前端页面创建
This commit is contained in:
parent
14171626c7
commit
b31b8a9b3c
|
@ -7,11 +7,12 @@
|
||||||
> 开发记录
|
> 开发记录
|
||||||
|
|
||||||
| 时间 | 更新内容 | 更新者 |
|
| 时间 | 更新内容 | 更新者 |
|
||||||
| ---------- | ------------------------------------------------------ | -------- |
|
| ---------- | ------------------------------------------------------------ | -------- |
|
||||||
| 2020-10-26 | 数据库设计,登录和注册接口,文档记录开始。 | Himit_ZH |
|
| 2020-10-26 | 数据库设计,登录和注册接口,文档记录开始。 | Himit_ZH |
|
||||||
| 2020-10-28 | 用户模块接口,题目模块接口,比赛模块接口,排行模块接口 | Himit_ZH |
|
| 2020-10-28 | 用户模块接口,题目模块接口,比赛模块接口,排行模块接口 | Himit_ZH |
|
||||||
| 2020-10-30 | 评测模块接口,判题服务系统,初始化前端vue项目 | Himit_ZH |
|
| 2020-10-30 | 评测模块接口,判题服务系统,初始化前端vue项目 | Himit_ZH |
|
||||||
| 2020-11-08 | 前端vue主页,题目列表页,登录,注册,重置密码弹窗逻辑 | Himit_ZH |
|
| 2020-11-08 | 前端vue主页,题目列表页,登录,注册,重置密码弹窗逻辑 | Himit_ZH |
|
||||||
|
| 2020-11-16 | 前端提交列表页,提交详情页,题目详情页,排行(ACM,OI)页,比赛列表页,个人主页,个人设置页 | Himit_ZH |
|
||||||
|
|
||||||
# 二、系统架构
|
# 二、系统架构
|
||||||
|
|
||||||
|
@ -301,13 +302,13 @@ jugdeCase表 评测单个样例结果表
|
||||||
contest表
|
contest表
|
||||||
|
|
||||||
| 列名 | 实体属性类型 | 键 | 备注 |
|
| 列名 | 实体属性类型 | 键 | 备注 |
|
||||||
| ------------ | ------------ | ----------- | ------------------------------------------- |
|
| ------------ | ------------ | ---- | ----------------------------------------------------- |
|
||||||
| id | long | 主键 | auto_increment 1000起步 |
|
| id | long | 主键 | auto_increment 1000起步 |
|
||||||
| uid | String | 外键 | 创建者id |
|
| uid | String | 外键 | 创建者id |
|
||||||
| title | String | | 比赛标题 |
|
| title | String | | 比赛标题 |
|
||||||
| type | int | | Acm赛制或者Rating |
|
| type | int | | Acm赛制或者Rating |
|
||||||
| source | int | | 比赛来源,原创为0,克隆赛为比赛id |
|
| source | int | | 比赛来源,原创为0,克隆赛为比赛id |
|
||||||
| auth | int | | 0为公开赛,1为私有赛(有密码),2为报名赛。 |
|
| auth | int | | 0为公开赛,1为私有赛(有密码),3为保护赛(有密码)。 |
|
||||||
| pwd | string | | 比赛密码 |
|
| pwd | string | | 比赛密码 |
|
||||||
| start_time | datetime | | 开始时间 |
|
| start_time | datetime | | 开始时间 |
|
||||||
| end_time | datetime | | 结束时间 |
|
| end_time | datetime | | 结束时间 |
|
||||||
|
|
|
@ -1243,6 +1243,15 @@
|
||||||
"@types/node": "*"
|
"@types/node": "*"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"@types/highlight.js": {
|
||||||
|
"version": "10.1.0",
|
||||||
|
"resolved": "https://registry.npm.taobao.org/@types/highlight.js/download/@types/highlight.js-10.1.0.tgz",
|
||||||
|
"integrity": "sha1-ibsMICmX16kKB70uwffQDFa7kLQ=",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"highlight.js": "*"
|
||||||
|
}
|
||||||
|
},
|
||||||
"@types/http-proxy": {
|
"@types/http-proxy": {
|
||||||
"version": "1.17.4",
|
"version": "1.17.4",
|
||||||
"resolved": "https://registry.npm.taobao.org/@types/http-proxy/download/@types/http-proxy-1.17.4.tgz?cache=0&sync_timestamp=1596839386031&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40types%2Fhttp-proxy%2Fdownload%2F%40types%2Fhttp-proxy-1.17.4.tgz",
|
"resolved": "https://registry.npm.taobao.org/@types/http-proxy/download/@types/http-proxy-1.17.4.tgz?cache=0&sync_timestamp=1596839386031&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40types%2Fhttp-proxy%2Fdownload%2F%40types%2Fhttp-proxy-1.17.4.tgz",
|
||||||
|
@ -3281,6 +3290,12 @@
|
||||||
"integrity": "sha1-lEdx/ZyByBJlxNaUGGDaBrtZR5s=",
|
"integrity": "sha1-lEdx/ZyByBJlxNaUGGDaBrtZR5s=",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"highlight.js": {
|
||||||
|
"version": "9.18.3",
|
||||||
|
"resolved": "https://registry.npm.taobao.org/highlight.js/download/highlight.js-9.18.3.tgz",
|
||||||
|
"integrity": "sha1-oaCiAo1eMUniOA+Khl7oUWcD1jQ=",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
"supports-color": {
|
"supports-color": {
|
||||||
"version": "7.2.0",
|
"version": "7.2.0",
|
||||||
"resolved": "https://registry.npm.taobao.org/supports-color/download/supports-color-7.2.0.tgz?cache=0&sync_timestamp=1598611709087&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fsupports-color%2Fdownload%2Fsupports-color-7.2.0.tgz",
|
"resolved": "https://registry.npm.taobao.org/supports-color/download/supports-color-7.2.0.tgz?cache=0&sync_timestamp=1598611709087&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fsupports-color%2Fdownload%2Fsupports-color-7.2.0.tgz",
|
||||||
|
@ -3298,6 +3313,16 @@
|
||||||
"integrity": "sha1-EnY+RyUb+VHLdcIB36WP8byy0Ec=",
|
"integrity": "sha1-EnY+RyUb+VHLdcIB36WP8byy0Ec=",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"clipboard": {
|
||||||
|
"version": "2.0.6",
|
||||||
|
"resolved": "https://registry.npm.taobao.org/clipboard/download/clipboard-2.0.6.tgz?cache=0&sync_timestamp=1599054235610&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fclipboard%2Fdownload%2Fclipboard-2.0.6.tgz",
|
||||||
|
"integrity": "sha1-UpISlu7A/fd+rRdJQhshyWhkc3Y=",
|
||||||
|
"requires": {
|
||||||
|
"good-listener": "^1.2.2",
|
||||||
|
"select": "^1.1.2",
|
||||||
|
"tiny-emitter": "^2.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"clipboardy": {
|
"clipboardy": {
|
||||||
"version": "2.3.0",
|
"version": "2.3.0",
|
||||||
"resolved": "https://registry.npm.taobao.org/clipboardy/download/clipboardy-2.3.0.tgz",
|
"resolved": "https://registry.npm.taobao.org/clipboardy/download/clipboardy-2.3.0.tgz",
|
||||||
|
@ -3367,6 +3392,11 @@
|
||||||
"q": "^1.1.2"
|
"q": "^1.1.2"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"codemirror": {
|
||||||
|
"version": "5.58.2",
|
||||||
|
"resolved": "https://registry.npm.taobao.org/codemirror/download/codemirror-5.58.2.tgz?cache=0&sync_timestamp=1603481865446&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fcodemirror%2Fdownload%2Fcodemirror-5.58.2.tgz",
|
||||||
|
"integrity": "sha1-7VSheW3hSYaIvqHN1OnusYdWXRs="
|
||||||
|
},
|
||||||
"collection-visit": {
|
"collection-visit": {
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"resolved": "https://registry.npm.taobao.org/collection-visit/download/collection-visit-1.0.0.tgz",
|
"resolved": "https://registry.npm.taobao.org/collection-visit/download/collection-visit-1.0.0.tgz",
|
||||||
|
@ -3430,8 +3460,7 @@
|
||||||
"commander": {
|
"commander": {
|
||||||
"version": "2.20.3",
|
"version": "2.20.3",
|
||||||
"resolved": "https://registry.npm.taobao.org/commander/download/commander-2.20.3.tgz?cache=0&sync_timestamp=1603599636161&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fcommander%2Fdownload%2Fcommander-2.20.3.tgz",
|
"resolved": "https://registry.npm.taobao.org/commander/download/commander-2.20.3.tgz?cache=0&sync_timestamp=1603599636161&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fcommander%2Fdownload%2Fcommander-2.20.3.tgz",
|
||||||
"integrity": "sha1-/UhehMA+tIgcIHIrpIA16FMa6zM=",
|
"integrity": "sha1-/UhehMA+tIgcIHIrpIA16FMa6zM="
|
||||||
"dev": true
|
|
||||||
},
|
},
|
||||||
"commondir": {
|
"commondir": {
|
||||||
"version": "1.0.1",
|
"version": "1.0.1",
|
||||||
|
@ -4181,6 +4210,11 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"default-passive-events": {
|
||||||
|
"version": "2.0.0",
|
||||||
|
"resolved": "https://registry.npm.taobao.org/default-passive-events/download/default-passive-events-2.0.0.tgz",
|
||||||
|
"integrity": "sha1-ebGqZ77LqrOLcYRptUgP75Ltpkk="
|
||||||
|
},
|
||||||
"defaults": {
|
"defaults": {
|
||||||
"version": "1.0.3",
|
"version": "1.0.3",
|
||||||
"resolved": "https://registry.npm.taobao.org/defaults/download/defaults-1.0.3.tgz",
|
"resolved": "https://registry.npm.taobao.org/defaults/download/defaults-1.0.3.tgz",
|
||||||
|
@ -4290,6 +4324,11 @@
|
||||||
"integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=",
|
"integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"delegate": {
|
||||||
|
"version": "3.2.0",
|
||||||
|
"resolved": "https://registry.npm.taobao.org/delegate/download/delegate-3.2.0.tgz",
|
||||||
|
"integrity": "sha1-tmtxwxWFIuirV0T3INjKDCr1kWY="
|
||||||
|
},
|
||||||
"depd": {
|
"depd": {
|
||||||
"version": "1.1.2",
|
"version": "1.1.2",
|
||||||
"resolved": "https://registry.npm.taobao.org/depd/download/depd-1.1.2.tgz",
|
"resolved": "https://registry.npm.taobao.org/depd/download/depd-1.1.2.tgz",
|
||||||
|
@ -4484,6 +4523,14 @@
|
||||||
"safer-buffer": "^2.1.0"
|
"safer-buffer": "^2.1.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"echarts": {
|
||||||
|
"version": "4.9.0",
|
||||||
|
"resolved": "https://registry.npm.taobao.org/echarts/download/echarts-4.9.0.tgz?cache=0&sync_timestamp=1605024811446&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fecharts%2Fdownload%2Fecharts-4.9.0.tgz",
|
||||||
|
"integrity": "sha1-qbm6oD8Doqcx5jQMVb77V6nhNH0=",
|
||||||
|
"requires": {
|
||||||
|
"zrender": "4.3.2"
|
||||||
|
}
|
||||||
|
},
|
||||||
"ee-first": {
|
"ee-first": {
|
||||||
"version": "1.1.1",
|
"version": "1.1.1",
|
||||||
"resolved": "https://registry.npm.taobao.org/ee-first/download/ee-first-1.1.1.tgz",
|
"resolved": "https://registry.npm.taobao.org/ee-first/download/ee-first-1.1.1.tgz",
|
||||||
|
@ -5371,6 +5418,14 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"good-listener": {
|
||||||
|
"version": "1.2.2",
|
||||||
|
"resolved": "https://registry.npm.taobao.org/good-listener/download/good-listener-1.2.2.tgz",
|
||||||
|
"integrity": "sha1-1TswzfkxPf+33JoNR3CWqm0UXFA=",
|
||||||
|
"requires": {
|
||||||
|
"delegate": "^3.1.2"
|
||||||
|
}
|
||||||
|
},
|
||||||
"graceful-fs": {
|
"graceful-fs": {
|
||||||
"version": "4.2.4",
|
"version": "4.2.4",
|
||||||
"resolved": "https://registry.npm.taobao.org/graceful-fs/download/graceful-fs-4.2.4.tgz",
|
"resolved": "https://registry.npm.taobao.org/graceful-fs/download/graceful-fs-4.2.4.tgz",
|
||||||
|
@ -5537,10 +5592,9 @@
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"highlight.js": {
|
"highlight.js": {
|
||||||
"version": "9.18.3",
|
"version": "10.3.2",
|
||||||
"resolved": "https://registry.npm.taobao.org/highlight.js/download/highlight.js-9.18.3.tgz",
|
"resolved": "https://registry.npm.taobao.org/highlight.js/download/highlight.js-10.3.2.tgz",
|
||||||
"integrity": "sha1-oaCiAo1eMUniOA+Khl7oUWcD1jQ=",
|
"integrity": "sha1-E1/TYZoAw8u4tM1tvHjVa/y8RvE="
|
||||||
"dev": true
|
|
||||||
},
|
},
|
||||||
"hmac-drbg": {
|
"hmac-drbg": {
|
||||||
"version": "1.0.1",
|
"version": "1.0.1",
|
||||||
|
@ -6408,6 +6462,14 @@
|
||||||
"verror": "1.10.0"
|
"verror": "1.10.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"katex": {
|
||||||
|
"version": "0.12.0",
|
||||||
|
"resolved": "https://registry.npm.taobao.org/katex/download/katex-0.12.0.tgz",
|
||||||
|
"integrity": "sha1-L7HGZdvSsEPtz4ofXFVfRr6qDLk=",
|
||||||
|
"requires": {
|
||||||
|
"commander": "^2.19.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"killable": {
|
"killable": {
|
||||||
"version": "1.0.1",
|
"version": "1.0.1",
|
||||||
"resolved": "https://registry.npm.taobao.org/killable/download/killable-1.0.1.tgz",
|
"resolved": "https://registry.npm.taobao.org/killable/download/killable-1.0.1.tgz",
|
||||||
|
@ -6486,8 +6548,7 @@
|
||||||
"lodash": {
|
"lodash": {
|
||||||
"version": "4.17.20",
|
"version": "4.17.20",
|
||||||
"resolved": "https://registry.npm.taobao.org/lodash/download/lodash-4.17.20.tgz?cache=0&sync_timestamp=1597335994883&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Flodash%2Fdownload%2Flodash-4.17.20.tgz",
|
"resolved": "https://registry.npm.taobao.org/lodash/download/lodash-4.17.20.tgz?cache=0&sync_timestamp=1597335994883&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Flodash%2Fdownload%2Flodash-4.17.20.tgz",
|
||||||
"integrity": "sha1-tEqbYpe8tpjxxRo1RaKzs2jVnFI=",
|
"integrity": "sha1-tEqbYpe8tpjxxRo1RaKzs2jVnFI="
|
||||||
"dev": true
|
|
||||||
},
|
},
|
||||||
"lodash.defaultsdeep": {
|
"lodash.defaultsdeep": {
|
||||||
"version": "4.6.1",
|
"version": "4.6.1",
|
||||||
|
@ -7087,6 +7148,11 @@
|
||||||
"path-key": "^2.0.0"
|
"path-key": "^2.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"nprogress": {
|
||||||
|
"version": "0.2.0",
|
||||||
|
"resolved": "https://registry.npm.taobao.org/nprogress/download/nprogress-0.2.0.tgz?cache=0&sync_timestamp=1587262530340&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fnprogress%2Fdownload%2Fnprogress-0.2.0.tgz",
|
||||||
|
"integrity": "sha1-y480xTIT2JVyP8urkH6UIq28r7E="
|
||||||
|
},
|
||||||
"nth-check": {
|
"nth-check": {
|
||||||
"version": "1.0.2",
|
"version": "1.0.2",
|
||||||
"resolved": "https://registry.npm.taobao.org/nth-check/download/nth-check-1.0.2.tgz",
|
"resolved": "https://registry.npm.taobao.org/nth-check/download/nth-check-1.0.2.tgz",
|
||||||
|
@ -8713,6 +8779,11 @@
|
||||||
"integrity": "sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8=",
|
"integrity": "sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8=",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"resize-detector": {
|
||||||
|
"version": "0.1.10",
|
||||||
|
"resolved": "https://registry.npm.taobao.org/resize-detector/download/resize-detector-0.1.10.tgz",
|
||||||
|
"integrity": "sha1-HaP5YapfkUzLz9N1LVL9Rb7raSw="
|
||||||
|
},
|
||||||
"resize-observer-polyfill": {
|
"resize-observer-polyfill": {
|
||||||
"version": "1.5.1",
|
"version": "1.5.1",
|
||||||
"resolved": "https://registry.npm.taobao.org/resize-observer-polyfill/download/resize-observer-polyfill-1.5.1.tgz",
|
"resolved": "https://registry.npm.taobao.org/resize-observer-polyfill/download/resize-observer-polyfill-1.5.1.tgz",
|
||||||
|
@ -8849,6 +8920,11 @@
|
||||||
"ajv-keywords": "^3.5.2"
|
"ajv-keywords": "^3.5.2"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"select": {
|
||||||
|
"version": "1.1.2",
|
||||||
|
"resolved": "https://registry.npm.taobao.org/select/download/select-1.1.2.tgz",
|
||||||
|
"integrity": "sha1-DnNQrN7ICxEIUoeG7B1EGNEbOW0="
|
||||||
|
},
|
||||||
"select-hose": {
|
"select-hose": {
|
||||||
"version": "2.0.0",
|
"version": "2.0.0",
|
||||||
"resolved": "https://registry.npm.taobao.org/select-hose/download/select-hose-2.0.0.tgz",
|
"resolved": "https://registry.npm.taobao.org/select-hose/download/select-hose-2.0.0.tgz",
|
||||||
|
@ -9793,6 +9869,11 @@
|
||||||
"integrity": "sha1-QFQRqOfmM5/mTbmiNN4R3DHgK9Q=",
|
"integrity": "sha1-QFQRqOfmM5/mTbmiNN4R3DHgK9Q=",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"tiny-emitter": {
|
||||||
|
"version": "2.1.0",
|
||||||
|
"resolved": "https://registry.npm.taobao.org/tiny-emitter/download/tiny-emitter-2.1.0.tgz",
|
||||||
|
"integrity": "sha1-HRpW7fxRxD6GPLtTgqcjMONVVCM="
|
||||||
|
},
|
||||||
"to-arraybuffer": {
|
"to-arraybuffer": {
|
||||||
"version": "1.0.1",
|
"version": "1.0.1",
|
||||||
"resolved": "https://registry.npm.taobao.org/to-arraybuffer/download/to-arraybuffer-1.0.1.tgz",
|
"resolved": "https://registry.npm.taobao.org/to-arraybuffer/download/to-arraybuffer-1.0.1.tgz",
|
||||||
|
@ -10272,11 +10353,37 @@
|
||||||
"resolved": "https://registry.npm.taobao.org/vue/download/vue-2.6.12.tgz",
|
"resolved": "https://registry.npm.taobao.org/vue/download/vue-2.6.12.tgz",
|
||||||
"integrity": "sha1-9evU+mvShpQD4pqJau1JBEVskSM="
|
"integrity": "sha1-9evU+mvShpQD4pqJau1JBEVskSM="
|
||||||
},
|
},
|
||||||
|
"vue-clipboard2": {
|
||||||
|
"version": "0.3.1",
|
||||||
|
"resolved": "https://registry.npm.taobao.org/vue-clipboard2/download/vue-clipboard2-0.3.1.tgz",
|
||||||
|
"integrity": "sha1-blUft704SImyiw2jsSKJ7WvKSJQ=",
|
||||||
|
"requires": {
|
||||||
|
"clipboard": "^2.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"vue-codemirror-lite": {
|
||||||
|
"version": "1.0.4",
|
||||||
|
"resolved": "https://registry.npm.taobao.org/vue-codemirror-lite/download/vue-codemirror-lite-1.0.4.tgz",
|
||||||
|
"integrity": "sha1-SKXNfRfAkUUDyM2dm1a0OOScNBA=",
|
||||||
|
"requires": {
|
||||||
|
"codemirror": "^5.22.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"vue-cropper": {
|
"vue-cropper": {
|
||||||
"version": "0.5.5",
|
"version": "0.5.5",
|
||||||
"resolved": "https://registry.npm.taobao.org/vue-cropper/download/vue-cropper-0.5.5.tgz",
|
"resolved": "https://registry.npm.taobao.org/vue-cropper/download/vue-cropper-0.5.5.tgz",
|
||||||
"integrity": "sha1-m9G6Vjx/qiaKvVL7KvTGwo0zyWI="
|
"integrity": "sha1-m9G6Vjx/qiaKvVL7KvTGwo0zyWI="
|
||||||
},
|
},
|
||||||
|
"vue-echarts": {
|
||||||
|
"version": "5.0.0-beta.0",
|
||||||
|
"resolved": "https://registry.npm.taobao.org/vue-echarts/download/vue-echarts-5.0.0-beta.0.tgz",
|
||||||
|
"integrity": "sha1-Q43UsPxczqKBcJwffGMhsFNSvfQ=",
|
||||||
|
"requires": {
|
||||||
|
"core-js": "^3.4.4",
|
||||||
|
"lodash": "^4.17.15",
|
||||||
|
"resize-detector": "^0.1.10"
|
||||||
|
}
|
||||||
|
},
|
||||||
"vue-hot-reload-api": {
|
"vue-hot-reload-api": {
|
||||||
"version": "2.3.4",
|
"version": "2.3.4",
|
||||||
"resolved": "https://registry.npm.taobao.org/vue-hot-reload-api/download/vue-hot-reload-api-2.3.4.tgz",
|
"resolved": "https://registry.npm.taobao.org/vue-hot-reload-api/download/vue-hot-reload-api-2.3.4.tgz",
|
||||||
|
@ -11258,6 +11365,11 @@
|
||||||
"dev": true
|
"dev": true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"zrender": {
|
||||||
|
"version": "4.3.2",
|
||||||
|
"resolved": "https://registry.npm.taobao.org/zrender/download/zrender-4.3.2.tgz?cache=0&sync_timestamp=1605029444182&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fzrender%2Fdownload%2Fzrender-4.3.2.tgz",
|
||||||
|
"integrity": "sha1-7HQy+UFcgsc1hLa3uMR+GwFiCcY="
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,11 +9,19 @@
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"axios": "^0.21.0",
|
"axios": "^0.21.0",
|
||||||
"core-js": "^3.6.5",
|
"core-js": "^3.6.5",
|
||||||
|
"default-passive-events": "^2.0.0",
|
||||||
|
"echarts": "^4.9.0",
|
||||||
"element-ui": "^2.14.0",
|
"element-ui": "^2.14.0",
|
||||||
"font-awesome": "^4.7.0",
|
"font-awesome": "^4.7.0",
|
||||||
|
"highlight.js": "^10.3.2",
|
||||||
|
"katex": "^0.12.0",
|
||||||
"moment": "^2.29.1",
|
"moment": "^2.29.1",
|
||||||
|
"nprogress": "^0.2.0",
|
||||||
"vue": "^2.6.11",
|
"vue": "^2.6.11",
|
||||||
|
"vue-clipboard2": "^0.3.1",
|
||||||
|
"vue-codemirror-lite": "^1.0.4",
|
||||||
"vue-cropper": "^0.5.5",
|
"vue-cropper": "^0.5.5",
|
||||||
|
"vue-echarts": "^5.0.0-beta.0",
|
||||||
"vue-m-message": "^3.0.0",
|
"vue-m-message": "^3.0.0",
|
||||||
"vue-router": "^3.2.0",
|
"vue-router": "^3.2.0",
|
||||||
"vue-template-compiler": "^2.6.12",
|
"vue-template-compiler": "^2.6.12",
|
||||||
|
@ -23,6 +31,7 @@
|
||||||
"xe-utils": "^2.8.1"
|
"xe-utils": "^2.8.1"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
"@types/highlight.js": "^10.1.0",
|
||||||
"@vue/cli-plugin-babel": "~4.5.0",
|
"@vue/cli-plugin-babel": "~4.5.0",
|
||||||
"@vue/cli-plugin-router": "~4.5.0",
|
"@vue/cli-plugin-router": "~4.5.0",
|
||||||
"@vue/cli-plugin-vuex": "~4.5.0",
|
"@vue/cli-plugin-vuex": "~4.5.0",
|
||||||
|
|
|
@ -25,17 +25,68 @@ export default {
|
||||||
-moz-box-sizing: border-box;
|
-moz-box-sizing: border-box;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
}
|
}
|
||||||
|
body{
|
||||||
|
background-color: #eee;
|
||||||
|
font-family: Helvetica Neue,Helvetica,PingFang SC,Hiragino Sans GB,Microsoft YaHei,\\5FAE\8F6F\96C5\9ED1,Arial,sans-serif;
|
||||||
|
-webkit-font-smoothing: antialiased;
|
||||||
|
color: #495060;
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
code, kbd, pre, samp {
|
||||||
|
font-family: Consolas,Menlo,Courier,monospace;
|
||||||
|
}
|
||||||
|
|
||||||
a {
|
a {
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
background-color: transparent;
|
background-color: transparent;
|
||||||
color: #495060;
|
color: #495060;
|
||||||
transition: all 0.28s ease;
|
outline: 0;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: color .2s ease;
|
||||||
}
|
}
|
||||||
a:hover{
|
a:hover{
|
||||||
color: #2196f3;
|
color: #2196f3;
|
||||||
}
|
}
|
||||||
|
.drop-menu{
|
||||||
|
padding-top: 7px;
|
||||||
|
}
|
||||||
|
.panel-title{
|
||||||
|
font-size: 21px;
|
||||||
|
font-weight: 500;
|
||||||
|
padding-top: 10px;
|
||||||
|
padding-bottom: 20px;
|
||||||
|
line-height: 30px;
|
||||||
|
}
|
||||||
|
.status-green{
|
||||||
|
background-color: #19be6b!important;
|
||||||
|
color: #fff!important;
|
||||||
|
}
|
||||||
|
.status-red{
|
||||||
|
background-color: #ed3f14!important;
|
||||||
|
color: #fff!important;
|
||||||
|
}
|
||||||
|
.status-yellow{
|
||||||
|
background-color: #f90!important;
|
||||||
|
color: #fff!important;
|
||||||
|
}
|
||||||
|
.status-blue{
|
||||||
|
background-color: #2d8cf0!important;
|
||||||
|
color: #fff!important;
|
||||||
|
}
|
||||||
|
.status-gray{
|
||||||
|
background-color:#909399!important;
|
||||||
|
color: #fff!important;
|
||||||
|
}
|
||||||
|
.own-submit-row{
|
||||||
|
background:rgb(230, 255, 223) !important;
|
||||||
|
}
|
||||||
|
.vxe-table{
|
||||||
|
color: #495060!important;
|
||||||
|
font-size: 12px!important;
|
||||||
|
}
|
||||||
|
#nprogress .bar {
|
||||||
|
background: #66B1FF !important;
|
||||||
|
}
|
||||||
@media screen and (min-width: 1200px) {
|
@media screen and (min-width: 1200px) {
|
||||||
#app {
|
#app {
|
||||||
margin-top: 80px;
|
margin-top: 80px;
|
||||||
|
@ -54,7 +105,24 @@ export default {
|
||||||
padding: 0 4%;
|
padding: 0 4%;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#problem-content .sample pre {
|
||||||
|
-ms-flex: 1 1 auto;
|
||||||
|
flex: 1 1 auto;
|
||||||
|
-ms-flex-item-align: stretch;
|
||||||
|
align-self: stretch;
|
||||||
|
border-style: solid;
|
||||||
|
background: #fafafa;
|
||||||
|
border-left: 2px solid #3498db;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-body pre {
|
||||||
|
padding: 5px 10px;
|
||||||
|
white-space: pre-wrap;
|
||||||
|
margin-top: 15px;
|
||||||
|
margin-bottom: 15px;
|
||||||
|
background: #f8f8f9;
|
||||||
|
border: 1px dashed #e9eaec;
|
||||||
|
}
|
||||||
.footer {
|
.footer {
|
||||||
margin-top: 20px;
|
margin-top: 20px;
|
||||||
margin-bottom: 10px;
|
margin-bottom: 10px;
|
||||||
|
@ -65,8 +133,10 @@ export default {
|
||||||
.fadeInUp-enter-active {
|
.fadeInUp-enter-active {
|
||||||
animation: fadeInUp .8s;
|
animation: fadeInUp .8s;
|
||||||
}
|
}
|
||||||
body{
|
.el-menu--popup {
|
||||||
background-color: #eee;
|
min-width: 120px!important;
|
||||||
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
</style>
|
</style>
|
||||||
|
|
Binary file not shown.
After Width: | Height: | Size: 13 KiB |
Binary file not shown.
After Width: | Height: | Size: 12 KiB |
|
@ -1,5 +1,10 @@
|
||||||
import axios from 'axios'
|
import axios from 'axios'
|
||||||
import mMessage from '@/common/message'
|
import mMessage from '@/common/message'
|
||||||
|
import NProgress from 'nprogress' // nprogress插件
|
||||||
|
import 'nprogress/nprogress.css' // nprogress样式
|
||||||
|
|
||||||
|
// 配置NProgress进度条选项 —— 动画效果
|
||||||
|
NProgress.configure({ ease: 'ease', speed: 1000,showSpinner: false})
|
||||||
|
|
||||||
// 环境的切换
|
// 环境的切换
|
||||||
if (process.env.NODE_ENV == 'development') {
|
if (process.env.NODE_ENV == 'development') {
|
||||||
|
@ -14,15 +19,20 @@ if (process.env.NODE_ENV == 'development') {
|
||||||
axios.defaults.timeout = 15000;
|
axios.defaults.timeout = 15000;
|
||||||
|
|
||||||
axios.interceptors.request.use(
|
axios.interceptors.request.use(
|
||||||
|
|
||||||
config => {
|
config => {
|
||||||
|
|
||||||
|
NProgress.start();
|
||||||
// 每次发送请求之前判断vuex中是否存在token
|
// 每次发送请求之前判断vuex中是否存在token
|
||||||
// 如果存在,则统一在http请求的header都加上token,这样后台根据token判断你的登录情况
|
// 如果存在,则统一在http请求的header都加上token,这样后台根据token判断你的登录情况
|
||||||
// 即使本地存在token,也有可能token是过期的,所以在响应拦截器中要对返回状态进行判断
|
// 即使本地存在token,也有可能token是过期的,所以在响应拦截器中要对返回状态进行判断
|
||||||
const token = localStorage.getItem('token')
|
const token = localStorage.getItem('token')
|
||||||
token && (config.headers.Authorization = token);
|
token && (config.headers.Authorization = token);
|
||||||
|
|
||||||
return config;
|
return config;
|
||||||
},
|
},
|
||||||
error => {
|
error => {
|
||||||
|
NProgress.done();
|
||||||
mmMessage.error(error.response.data.mMessage);
|
mmMessage.error(error.response.data.mMessage);
|
||||||
return Promise.error(error);
|
return Promise.error(error);
|
||||||
})
|
})
|
||||||
|
@ -30,6 +40,7 @@ axios.interceptors.request.use(
|
||||||
// 响应拦截器
|
// 响应拦截器
|
||||||
axios.interceptors.response.use(
|
axios.interceptors.response.use(
|
||||||
response => {
|
response => {
|
||||||
|
NProgress.done();
|
||||||
if (response.data.status === 200) {
|
if (response.data.status === 200) {
|
||||||
return Promise.resolve(response);
|
return Promise.resolve(response);
|
||||||
} else {
|
} else {
|
||||||
|
@ -39,6 +50,7 @@ axios.interceptors.response.use(
|
||||||
},
|
},
|
||||||
// 服务器状态码不是200的情况
|
// 服务器状态码不是200的情况
|
||||||
error => {
|
error => {
|
||||||
|
NProgress.done();
|
||||||
if (error.response) {
|
if (error.response) {
|
||||||
switch (error.response.status) {
|
switch (error.response.status) {
|
||||||
// 401: 未登录
|
// 401: 未登录
|
||||||
|
|
|
@ -1,93 +1,127 @@
|
||||||
export const JUDGE_STATUS = {
|
export const JUDGE_STATUS = {
|
||||||
|
'-3': {
|
||||||
|
name: 'Presentation Error',
|
||||||
|
short: 'PE',
|
||||||
|
color: 'yellow',
|
||||||
|
type: 'warning',
|
||||||
|
rgb:'#f90'
|
||||||
|
},
|
||||||
'-2': {
|
'-2': {
|
||||||
name: 'Compile Error',
|
name: 'Compile Error',
|
||||||
short: 'CE',
|
short: 'CE',
|
||||||
color: 'yellow',
|
color: 'yellow',
|
||||||
type: 'warning'
|
type: 'warning',
|
||||||
|
rgb:'#f90'
|
||||||
},
|
},
|
||||||
'-1': {
|
'-1': {
|
||||||
name: 'Wrong Answer',
|
name: 'Wrong Answer',
|
||||||
short: 'WA',
|
short: 'WA',
|
||||||
color: 'red',
|
color: 'red',
|
||||||
type: 'error'
|
type: 'error',
|
||||||
|
rgb:'#ed3f14'
|
||||||
},
|
},
|
||||||
'0': {
|
'0': {
|
||||||
name: 'Accepted',
|
name: 'Accepted',
|
||||||
short: 'AC',
|
short: 'AC',
|
||||||
color: 'green',
|
color: 'green',
|
||||||
type: 'success'
|
type: 'success',
|
||||||
|
rgb:'#19be6b'
|
||||||
},
|
},
|
||||||
'1': {
|
'1': {
|
||||||
name: 'Time Limit Exceeded',
|
name: 'Time Limit Exceeded',
|
||||||
short: 'TLE',
|
short: 'TLE',
|
||||||
color: 'red',
|
color: 'red',
|
||||||
type: 'error'
|
type: 'error',
|
||||||
|
rgb:'#ed3f14'
|
||||||
},
|
},
|
||||||
'2': {
|
'2': {
|
||||||
name: 'Time Limit Exceeded',
|
name: 'Time Limit Exceeded',
|
||||||
short: 'TLE',
|
short: 'TLE',
|
||||||
color: 'red',
|
color: 'red',
|
||||||
type: 'error'
|
type: 'error',
|
||||||
|
rgb:'#ed3f14'
|
||||||
},
|
},
|
||||||
'3': {
|
'3': {
|
||||||
name: 'Memory Limit Exceeded',
|
name: 'Memory Limit Exceeded',
|
||||||
short: 'MLE',
|
short: 'MLE',
|
||||||
color: 'red',
|
color: 'red',
|
||||||
type: 'error'
|
type: 'error',
|
||||||
|
rgb:'#ed3f14'
|
||||||
},
|
},
|
||||||
'4': {
|
'4': {
|
||||||
name: 'Runtime Error',
|
name: 'Runtime Error',
|
||||||
short: 'RE',
|
short: 'RE',
|
||||||
color: 'red',
|
color: 'red',
|
||||||
type: 'error'
|
type: 'error',
|
||||||
|
rgb:'#ed3f14'
|
||||||
},
|
},
|
||||||
'5': {
|
'5': {
|
||||||
name: 'System Error',
|
name: 'System Error',
|
||||||
short: 'SE',
|
short: 'SE',
|
||||||
color: '#909399',
|
color: 'gray',
|
||||||
type: 'error'
|
type: 'info',
|
||||||
|
rgb:'#909399'
|
||||||
},
|
},
|
||||||
'6': {
|
'6': {
|
||||||
name: 'Pending',
|
name: 'Pending',
|
||||||
color: 'yellow',
|
color: 'yellow',
|
||||||
type: 'warning'
|
type: 'warning',
|
||||||
|
rgb:'#f90'
|
||||||
},
|
},
|
||||||
'7': {
|
'7': {
|
||||||
name: 'Judging',
|
name: 'Judging',
|
||||||
color: 'blue',
|
color: 'blue',
|
||||||
type: 'info'
|
type: '',
|
||||||
|
rgb:'#2d8cf0'
|
||||||
},
|
},
|
||||||
'8': {
|
'8': {
|
||||||
name: 'Partial Accepted',
|
name: 'Partial Accepted',
|
||||||
short: 'PAC',
|
short: 'PAC',
|
||||||
color: 'blue',
|
color: 'blue',
|
||||||
type: 'info'
|
type: '',
|
||||||
|
rgb:'#2d8cf0'
|
||||||
},
|
},
|
||||||
'9': {
|
'9': {
|
||||||
name: 'Submitting',
|
name: 'Submitting',
|
||||||
color: 'yellow',
|
color: 'yellow',
|
||||||
type: 'warning'
|
type: 'warning',
|
||||||
|
rgb:'#f90'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const PROBLEM_LEVEL={
|
||||||
|
'0':{
|
||||||
|
name:'Easy',
|
||||||
|
color:'green'
|
||||||
|
},
|
||||||
|
'1':{
|
||||||
|
name:'Mid',
|
||||||
|
color:'blue'
|
||||||
|
},
|
||||||
|
'2':{
|
||||||
|
name:'Hard',
|
||||||
|
color:'red'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const CONTEST_STATUS = {
|
export const CONTEST_STATUS = {
|
||||||
'NOT_START': '1',
|
'SCHEDULED': '1',
|
||||||
'UNDERWAY': '0',
|
'RUNNING': '0',
|
||||||
'ENDED': '-1'
|
'ENDED': '-1'
|
||||||
}
|
}
|
||||||
|
|
||||||
export const CONTEST_STATUS_REVERSE = {
|
export const CONTEST_STATUS_REVERSE = {
|
||||||
'1': {
|
'1': {
|
||||||
name: 'Not Started',
|
name: 'Scheduled',
|
||||||
color: 'yellow'
|
color: '#f90'
|
||||||
},
|
},
|
||||||
'0': {
|
'0': {
|
||||||
name: 'Underway',
|
name: 'Running',
|
||||||
color: 'green'
|
color: '#19be6b'
|
||||||
},
|
},
|
||||||
'-1': {
|
'-1': {
|
||||||
name: 'Ended',
|
name: 'Ended',
|
||||||
color: 'red'
|
color: '#ed3f14'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -96,6 +130,30 @@ export const RULE_TYPE = {
|
||||||
OI: 'OI'
|
OI: 'OI'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const CONTEST_TYPE_REVERSE = {
|
||||||
|
'0': {
|
||||||
|
name:'Public',
|
||||||
|
color:'success',
|
||||||
|
tips:'公开赛,每个用户都可查看与提交',
|
||||||
|
submit:true, // 公开赛可看可提交
|
||||||
|
look:true,
|
||||||
|
},
|
||||||
|
'1':{
|
||||||
|
name:'Private',
|
||||||
|
color:'danger',
|
||||||
|
tips:'私有赛,需要密码才可查看与提交',
|
||||||
|
submit:false, // 私有赛 必须要密码才能看和提交
|
||||||
|
look:false,
|
||||||
|
},
|
||||||
|
'2':{
|
||||||
|
name:'Protect',
|
||||||
|
color:'warning',
|
||||||
|
tips:'保护赛,每个用户都可查看,提交需要密码',
|
||||||
|
submit:false, //保护赛,可以看但是不能提交,提交需要附带比赛密码
|
||||||
|
look:true,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export const CONTEST_TYPE = {
|
export const CONTEST_TYPE = {
|
||||||
PUBLIC: 'Public',
|
PUBLIC: 'Public',
|
||||||
PRIVATE: 'Password Protected'
|
PRIVATE: 'Password Protected'
|
||||||
|
@ -119,3 +177,10 @@ export const STORAGE_KEY = {
|
||||||
languages: 'languages'
|
languages: 'languages'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function buildProblemCodeKey (problemID, contestID = null) {
|
||||||
|
if (contestID) {
|
||||||
|
return `${STORAGE_KEY.PROBLEM_CODE}_${contestID}_${problemID}`
|
||||||
|
}
|
||||||
|
return `${STORAGE_KEY.PROBLEM_CODE}_NaN_${problemID}`
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,15 @@
|
||||||
|
import moment from 'moment'
|
||||||
|
import utils from './utils'
|
||||||
|
import time from './time'
|
||||||
|
|
||||||
|
// 友好显示时间
|
||||||
|
function fromNow (time) {
|
||||||
|
return moment(time * 3).fromNow()
|
||||||
|
}
|
||||||
|
|
||||||
|
export default {
|
||||||
|
submissionMemory: utils.submissionMemoryFormat,
|
||||||
|
submissionTime: utils.submissionTimeFormat,
|
||||||
|
localtime: time.utcToLocal,
|
||||||
|
fromNow: fromNow
|
||||||
|
}
|
|
@ -0,0 +1,26 @@
|
||||||
|
import hljs from 'highlight.js'
|
||||||
|
import 'highlight.js/styles/atom-one-light.css'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
install (Vue, options) {
|
||||||
|
Vue.directive('highlight', {
|
||||||
|
deep: true,
|
||||||
|
bind: function (el, binding) {
|
||||||
|
Array.from(el.querySelectorAll('code')).forEach((target) => {
|
||||||
|
if (binding.value) {
|
||||||
|
target.textContent = binding.value
|
||||||
|
}
|
||||||
|
hljs.highlightBlock(target)
|
||||||
|
})
|
||||||
|
},
|
||||||
|
componentUpdated: function (el, binding) {
|
||||||
|
Array.from(el.querySelectorAll('code')).forEach((target) => {
|
||||||
|
if (binding.value) {
|
||||||
|
target.textContent = binding.value
|
||||||
|
}
|
||||||
|
hljs.highlightBlock(target)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,35 @@
|
||||||
|
import 'katex'
|
||||||
|
import renderMathInElement from 'katex/contrib/auto-render/auto-render'
|
||||||
|
import 'katex/dist/katex.min.css'
|
||||||
|
|
||||||
|
function _ () {
|
||||||
|
}
|
||||||
|
|
||||||
|
const defaultOptions = {
|
||||||
|
errorCallback: _,
|
||||||
|
throwOnError: false,
|
||||||
|
delimiters: [
|
||||||
|
{left: '$', right: '$', display: false},
|
||||||
|
{left: '$$', right: '$$', display: true},
|
||||||
|
{left: '\\[', right: '\\]', display: true},
|
||||||
|
{left: '\\(', right: '\\)', display: false}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
function render (el, binding) {
|
||||||
|
let options = {}
|
||||||
|
if (binding.value) {
|
||||||
|
options = binding.value.options || {}
|
||||||
|
}
|
||||||
|
Object.assign(options, defaultOptions)
|
||||||
|
renderMathInElement(el, options)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default {
|
||||||
|
install: function (Vue, options) {
|
||||||
|
Vue.directive('katex', {
|
||||||
|
bind: render,
|
||||||
|
componentUpdated: render
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,35 +0,0 @@
|
||||||
import Element from 'element-ui';
|
|
||||||
|
|
||||||
//全局页面跳转是否启用loading
|
|
||||||
const routerLoading = true;
|
|
||||||
|
|
||||||
//全局api接口调用是否启用loading
|
|
||||||
const apiLoading = true;
|
|
||||||
|
|
||||||
//loading参数配置
|
|
||||||
const loadingConfig = {
|
|
||||||
lock: true,
|
|
||||||
text: 'Loading',
|
|
||||||
spinner: 'el-icon-loading',
|
|
||||||
background: 'rgba(0, 0, 0, 0.7)'
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
var loading = null ;
|
|
||||||
const loadingShow = () => {
|
|
||||||
loading = Element.Loading.service(loadingConfig);
|
|
||||||
}
|
|
||||||
|
|
||||||
const loadingHide = () => {
|
|
||||||
loading.close();
|
|
||||||
}
|
|
||||||
|
|
||||||
const loadingObj={
|
|
||||||
loadingShow,
|
|
||||||
loadingHide,
|
|
||||||
routerLoading,
|
|
||||||
apiLoading
|
|
||||||
}
|
|
||||||
|
|
||||||
export default loadingObj
|
|
|
@ -78,6 +78,39 @@ function downloadFile (url) {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getLanguages () {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
let languages = storage.get(STORAGE_KEY.languages)
|
||||||
|
if (languages) {
|
||||||
|
resolve(languages)
|
||||||
|
}else{
|
||||||
|
let langs = [
|
||||||
|
{
|
||||||
|
content_type: "text/x-csrc",
|
||||||
|
description: "GCC 5.4",
|
||||||
|
name: "C",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
content_type: "text/x-c++src",
|
||||||
|
description: "G++ 5.4",
|
||||||
|
name: "C++",
|
||||||
|
},
|
||||||
|
{ content_type: "text/x-java",
|
||||||
|
description: "OpenJDK 1.8",
|
||||||
|
name: "Java",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
content_type: "text/x-python",
|
||||||
|
description: "Python 3.7",
|
||||||
|
name: "Python3",
|
||||||
|
}
|
||||||
|
];
|
||||||
|
storage.set(STORAGE_KEY.languages,langs);
|
||||||
|
resolve(langs);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
|
@ -87,4 +120,5 @@ export default {
|
||||||
filterEmptyValue: filterEmptyValue,
|
filterEmptyValue: filterEmptyValue,
|
||||||
breakLongWords: breakLongWords,
|
breakLongWords: breakLongWords,
|
||||||
downloadFile: downloadFile,
|
downloadFile: downloadFile,
|
||||||
|
getLanguages:getLanguages
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,212 @@
|
||||||
|
<template>
|
||||||
|
<div style="margin: 0px 0px 15px 0px;font-size: 14px;">
|
||||||
|
<el-row class="header">
|
||||||
|
<el-col :xs="24" :md="16" :lg="16">
|
||||||
|
<div class="select-row">
|
||||||
|
<span>Langs:</span>
|
||||||
|
<span>
|
||||||
|
<el-select :value="this.language" @change="onLangChange" class="adjust" size="small">
|
||||||
|
<el-option v-for="item in languages" :key="item" :value="item">{{item}}
|
||||||
|
</el-option>
|
||||||
|
</el-select>
|
||||||
|
</span>
|
||||||
|
<span>
|
||||||
|
<el-tooltip content="重置代码" placement="top" style="">
|
||||||
|
<el-button icon="el-icon-refresh" @click="onResetClick" size="small"></el-button>
|
||||||
|
</el-tooltip>
|
||||||
|
</span>
|
||||||
|
<span>
|
||||||
|
<el-tooltip content="上传文件" placement="top" style="">
|
||||||
|
<el-button icon="el-icon-upload" @click="onUploadFile" size="small"></el-button>
|
||||||
|
</el-tooltip>
|
||||||
|
</span>
|
||||||
|
<span>
|
||||||
|
<input type="file" id="file-uploader" style="display: none" @change="onUploadFileDone">
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</el-col>
|
||||||
|
<el-col :xs="24" :md="8" :lg="8">
|
||||||
|
<div class="select-row fl-right">
|
||||||
|
<span>Theme:</span>
|
||||||
|
<el-select :value="this.theme" @change="onThemeChange" class="adjust" size="small">
|
||||||
|
<el-option v-for="item in themes" :key="item.label" :value="item.value">{{item.label}}
|
||||||
|
</el-option>
|
||||||
|
</el-select>
|
||||||
|
</div>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
<codemirror :value="value" :options="options" @change="onEditorCodeChange" ref="myEditor">
|
||||||
|
</codemirror>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<script>
|
||||||
|
import utils from '@/common/utils'
|
||||||
|
import { codemirror } from 'vue-codemirror-lite'
|
||||||
|
|
||||||
|
// 风格对应的样式
|
||||||
|
import 'codemirror/theme/monokai.css'
|
||||||
|
import 'codemirror/theme/solarized.css'
|
||||||
|
import 'codemirror/theme/material.css'
|
||||||
|
|
||||||
|
// mode
|
||||||
|
import 'codemirror/mode/clike/clike.js'
|
||||||
|
import 'codemirror/mode/python/python.js'
|
||||||
|
|
||||||
|
// active-line.js
|
||||||
|
import 'codemirror/addon/selection/active-line.js'
|
||||||
|
|
||||||
|
// foldGutter
|
||||||
|
import 'codemirror/addon/fold/foldgutter.css'
|
||||||
|
import 'codemirror/addon/fold/foldgutter.js'
|
||||||
|
import 'codemirror/addon/fold/brace-fold.js'
|
||||||
|
import 'codemirror/addon/fold/indent-fold.js'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'CodeMirror',
|
||||||
|
components: {
|
||||||
|
codemirror
|
||||||
|
},
|
||||||
|
props: {
|
||||||
|
value: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
languages: {
|
||||||
|
type: Array,
|
||||||
|
default: () => {
|
||||||
|
return ['C', 'C++', 'Java', 'Python3']
|
||||||
|
}
|
||||||
|
},
|
||||||
|
language: {
|
||||||
|
type: String,
|
||||||
|
default: 'C++'
|
||||||
|
},
|
||||||
|
theme: {
|
||||||
|
type: String,
|
||||||
|
default: 'monokai'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data () {
|
||||||
|
return {
|
||||||
|
options: {
|
||||||
|
// codemirror options
|
||||||
|
tabSize: 4,
|
||||||
|
mode: 'text/x-csrc',
|
||||||
|
theme: 'monokai',
|
||||||
|
// 显示行号
|
||||||
|
lineNumbers: true,
|
||||||
|
line: true,
|
||||||
|
// 代码折叠
|
||||||
|
foldGutter: true,
|
||||||
|
matchBrackets : true, //括号匹配
|
||||||
|
gutters: ['CodeMirror-linenumbers', 'CodeMirror-foldgutter'],
|
||||||
|
// 选中文本自动高亮,及高亮方式
|
||||||
|
styleSelectedText: true, //当前行高亮
|
||||||
|
lineWrapping: true,
|
||||||
|
highlightSelectionMatches: {showToken: /\w/, annotateScrollbar: true},
|
||||||
|
},
|
||||||
|
mode: {
|
||||||
|
'C++': 'text/x-csrc'
|
||||||
|
},
|
||||||
|
themes: [
|
||||||
|
{label: 'monokai', value: 'monokai'},
|
||||||
|
{label: 'solarized', value: 'solarized'},
|
||||||
|
{label: 'material', value: 'material'}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
mounted () {
|
||||||
|
utils.getLanguages().then(languages => {
|
||||||
|
let mode = {}
|
||||||
|
languages.forEach(lang => {
|
||||||
|
mode[lang.name] = lang.content_type
|
||||||
|
})
|
||||||
|
this.mode = mode
|
||||||
|
this.editor.setOption('mode', this.mode[this.language])
|
||||||
|
})
|
||||||
|
this.editor.focus()
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
onEditorCodeChange (newCode) {
|
||||||
|
this.$emit('update:value', newCode)
|
||||||
|
},
|
||||||
|
onLangChange (newVal) {
|
||||||
|
this.editor.setOption('mode', this.mode[newVal])
|
||||||
|
this.$emit('changeLang', newVal)
|
||||||
|
},
|
||||||
|
onThemeChange (newTheme) {
|
||||||
|
this.editor.setOption('theme', newTheme)
|
||||||
|
this.$emit('changeTheme', newTheme)
|
||||||
|
},
|
||||||
|
onResetClick () {
|
||||||
|
this.$emit('resetCode')
|
||||||
|
},
|
||||||
|
onUploadFile () {
|
||||||
|
document.getElementById('file-uploader').click()
|
||||||
|
},
|
||||||
|
onUploadFileDone () {
|
||||||
|
let f = document.getElementById('file-uploader').files[0]
|
||||||
|
let fileReader = new window.FileReader()
|
||||||
|
let self = this
|
||||||
|
fileReader.onload = function (e) {
|
||||||
|
var text = e.target.result
|
||||||
|
self.editor.setValue(text)
|
||||||
|
document.getElementById('file-uploader').value = ''
|
||||||
|
}
|
||||||
|
fileReader.readAsText(f, 'UTF-8')
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
editor () {
|
||||||
|
// get current editor object
|
||||||
|
return this.$refs.myEditor.editor
|
||||||
|
},
|
||||||
|
currentLanguage(){
|
||||||
|
return this.language;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
'theme' (newVal, oldVal) {
|
||||||
|
this.editor.setOption('theme', newVal)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.header {
|
||||||
|
margin-bottom: 10px;
|
||||||
|
margin-right: 5px;
|
||||||
|
margin-left: 5px;
|
||||||
|
}
|
||||||
|
.header .adjust {
|
||||||
|
width: 130px;
|
||||||
|
margin-left: 5px;
|
||||||
|
}
|
||||||
|
.select-row{
|
||||||
|
margin-top: 4px;
|
||||||
|
}
|
||||||
|
@media screen and (max-width: 768px) {
|
||||||
|
.select-row span {
|
||||||
|
margin-right: 2px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@media screen and (min-width: 768px) {
|
||||||
|
.select-row span {
|
||||||
|
margin-right: 5px;;
|
||||||
|
}
|
||||||
|
.fl-right{
|
||||||
|
float: right;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.CodeMirror {
|
||||||
|
height: auto !important;
|
||||||
|
}
|
||||||
|
.CodeMirror-scroll {
|
||||||
|
min-height: 520px;
|
||||||
|
max-height: 520px;
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -0,0 +1,40 @@
|
||||||
|
<template>
|
||||||
|
<pre v-highlight="code"><code :class="language" :style="styleObject"></code></pre>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
name: 'highlight',
|
||||||
|
data () {
|
||||||
|
return {
|
||||||
|
styleObject: {
|
||||||
|
'border-left': '3px solid '+this.borderColor
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
props: {
|
||||||
|
language: {
|
||||||
|
type: String
|
||||||
|
},
|
||||||
|
code: {
|
||||||
|
required: true,
|
||||||
|
type: String
|
||||||
|
},
|
||||||
|
borderColor: {
|
||||||
|
type: String,
|
||||||
|
default: '#19be6b'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
pre {
|
||||||
|
padding: 0;
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
code {
|
||||||
|
padding: 20px;
|
||||||
|
font-size: 1.1em;
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -4,8 +4,10 @@
|
||||||
<el-menu
|
<el-menu
|
||||||
:default-active="activeIndex"
|
:default-active="activeIndex"
|
||||||
mode="horizontal"
|
mode="horizontal"
|
||||||
:router="isRouter"
|
router
|
||||||
active-text-color="#2196f3"
|
active-text-color="#2196f3"
|
||||||
|
text-color="#495060"
|
||||||
|
|
||||||
>
|
>
|
||||||
<div class="logo">
|
<div class="logo">
|
||||||
<el-image
|
<el-image
|
||||||
|
@ -26,13 +28,16 @@
|
||||||
<el-menu-item index="/status"
|
<el-menu-item index="/status"
|
||||||
><i class="el-icon-s-marketing"></i>Status</el-menu-item
|
><i class="el-icon-s-marketing"></i>Status</el-menu-item
|
||||||
>
|
>
|
||||||
<el-menu-item index="/rank"
|
<el-submenu index="rank" >
|
||||||
><i class="el-icon-s-data"></i>Rank</el-menu-item
|
<template slot="title"><i class="el-icon-s-data"></i>Rank</template>
|
||||||
>
|
<el-menu-item index="/acm-rank">ACM Rank</el-menu-item>
|
||||||
|
<el-menu-item index="/oi-rank">OI Rank</el-menu-item>
|
||||||
|
</el-submenu>
|
||||||
|
|
||||||
<el-submenu index="about">
|
<el-submenu index="about">
|
||||||
<template slot="title"><i class="el-icon-info"></i>About</template>
|
<template slot="title"><i class="el-icon-info"></i>About</template>
|
||||||
<el-menu-item index="6-1">Introduction</el-menu-item>
|
<el-menu-item index="/introduction">Introduction</el-menu-item>
|
||||||
<el-menu-item index="6-2">Developer</el-menu-item>
|
<el-menu-item index="/developer">Developer</el-menu-item>
|
||||||
</el-submenu>
|
</el-submenu>
|
||||||
|
|
||||||
<template v-if="!isAuthenticated">
|
<template v-if="!isAuthenticated">
|
||||||
|
@ -58,7 +63,7 @@
|
||||||
|
|
||||||
>
|
>
|
||||||
<span class="el-dropdown-link">
|
<span class="el-dropdown-link">
|
||||||
{{userInfo.username}}<i class="el-icon-arrow-down el-icon--right"></i>
|
{{userInfo.username}}<i class="el-icon-caret-bottom"></i>
|
||||||
</span>
|
</span>
|
||||||
|
|
||||||
|
|
||||||
|
@ -98,12 +103,16 @@ export default {
|
||||||
ResetPwd,
|
ResetPwd,
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
this.activeIndex = this.$route.path
|
let activeName = this.$route.path.split("/")[1];
|
||||||
|
if(activeName === ''){
|
||||||
|
this.activeIndex = '/home'
|
||||||
|
}else{
|
||||||
|
this.activeIndex = '/'+activeName
|
||||||
|
}
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
activeIndex: "home",
|
activeIndex: "home",
|
||||||
isRouter:true,
|
|
||||||
centerDialogVisible: false,
|
centerDialogVisible: false,
|
||||||
imgUrl: require("@/assets/logo.png"),
|
imgUrl: require("@/assets/logo.png"),
|
||||||
};
|
};
|
||||||
|
@ -126,9 +135,6 @@ export default {
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
...mapGetters(["modalStatus", "userInfo", "isAuthenticated", "isAdminRole","token"]),
|
...mapGetters(["modalStatus", "userInfo", "isAuthenticated", "isAdminRole","token"]),
|
||||||
activeMenu() {
|
|
||||||
return "/" + this.$route.path.split("/")[1];
|
|
||||||
},
|
|
||||||
modalVisible: {
|
modalVisible: {
|
||||||
get() {
|
get() {
|
||||||
return this.modalStatus.visible;
|
return this.modalStatus.visible;
|
||||||
|
@ -202,4 +208,14 @@ export default {
|
||||||
line-height: 1em;
|
line-height: 1em;
|
||||||
color: #4e4e4e;
|
color: #4e4e4e;
|
||||||
}
|
}
|
||||||
|
.el-submenu__title i {
|
||||||
|
color: #495060!important;
|
||||||
|
}
|
||||||
|
.el-menu-item i{
|
||||||
|
color: #495060;
|
||||||
|
}
|
||||||
|
.is-active .el-submenu__title i,.is-active{
|
||||||
|
color:#2196f3!important;
|
||||||
|
}
|
||||||
|
|
||||||
</style>
|
</style>
|
|
@ -5,6 +5,7 @@ import store from './store'
|
||||||
import Element from 'element-ui'
|
import Element from 'element-ui'
|
||||||
import "element-ui/lib/theme-chalk/index.css"
|
import "element-ui/lib/theme-chalk/index.css"
|
||||||
import 'font-awesome/css/font-awesome.min.css'
|
import 'font-awesome/css/font-awesome.min.css'
|
||||||
|
import 'default-passive-events'
|
||||||
import Message from 'vue-m-message'
|
import Message from 'vue-m-message'
|
||||||
import 'vue-m-message/dist/index.css'
|
import 'vue-m-message/dist/index.css'
|
||||||
import VueCropper from 'vue-cropper'
|
import VueCropper from 'vue-cropper'
|
||||||
|
@ -14,11 +15,37 @@ import 'xe-utils'
|
||||||
import VXETable from 'vxe-table'
|
import VXETable from 'vxe-table'
|
||||||
import 'vxe-table/lib/style.css'
|
import 'vxe-table/lib/style.css'
|
||||||
|
|
||||||
Vue.use(VXETable)
|
import Katex from '@/common/katex'
|
||||||
|
|
||||||
|
import VueClipboard from 'vue-clipboard2'
|
||||||
|
import highlight from '@/common/highlight'
|
||||||
|
|
||||||
|
import filters from '@/common/filters.js'
|
||||||
|
|
||||||
|
import ECharts from 'vue-echarts/components/ECharts.vue'
|
||||||
|
import 'echarts/lib/chart/bar'
|
||||||
|
import 'echarts/lib/chart/line'
|
||||||
|
import 'echarts/lib/chart/pie'
|
||||||
|
import 'echarts/lib/component/title'
|
||||||
|
import 'echarts/lib/component/grid'
|
||||||
|
import 'echarts/lib/component/dataZoom'
|
||||||
|
import 'echarts/lib/component/legend'
|
||||||
|
import 'echarts/lib/component/tooltip'
|
||||||
|
import 'echarts/lib/component/toolbox'
|
||||||
|
import 'echarts/lib/component/markPoint'
|
||||||
|
|
||||||
|
Object.keys(filters).forEach(key => { // 注册全局过滤器
|
||||||
|
Vue.filter(key, filters[key])
|
||||||
|
})
|
||||||
|
Vue.use(Katex) // 数学公式渲染
|
||||||
|
Vue.use(VXETable) // 表格组件
|
||||||
|
Vue.use(VueClipboard) // 剪贴板
|
||||||
|
Vue.use(highlight) // 代码高亮
|
||||||
Vue.use(Element)
|
Vue.use(Element)
|
||||||
Vue.use(VueCropper)
|
Vue.use(VueCropper)
|
||||||
Vue.use(Message, { name: 'msg' }) // `Vue.prototype.$msg`
|
Vue.use(Message, { name: 'msg' }) // `Vue.prototype.$msg` 全局消息提示
|
||||||
|
|
||||||
|
Vue.component('ECharts', ECharts)
|
||||||
Vue.prototype.$axios = axios
|
Vue.prototype.$axios = axios
|
||||||
Vue.config.productionTip = false
|
Vue.config.productionTip = false
|
||||||
new Vue({
|
new Vue({
|
||||||
|
|
|
@ -4,8 +4,11 @@ import { sync } from 'vuex-router-sync'
|
||||||
import routes from '@/router/routes'
|
import routes from '@/router/routes'
|
||||||
import mMessage from '@/common/message'
|
import mMessage from '@/common/message'
|
||||||
import store from '@/store'
|
import store from '@/store'
|
||||||
import glo_loading from '@/common/loading'
|
import NProgress from 'nprogress' // nprogress插件
|
||||||
|
import 'nprogress/nprogress.css' // nprogress样式
|
||||||
|
|
||||||
|
// 配置NProgress进度条选项 —— 动画效果
|
||||||
|
NProgress.configure({ ease: 'ease', speed: 1000,showSpinner: false })
|
||||||
|
|
||||||
Vue.use(VueRouter)
|
Vue.use(VueRouter)
|
||||||
|
|
||||||
|
@ -27,17 +30,15 @@ const router = new VueRouter({
|
||||||
router.beforeEach((to, from, next) => {
|
router.beforeEach((to, from, next) => {
|
||||||
|
|
||||||
|
|
||||||
|
NProgress.start()
|
||||||
if (to.matched.some(record => record.meta.requireAuth)) { // 判断该路由是否需要登录权限
|
if (to.matched.some(record => record.meta.requireAuth)) { // 判断该路由是否需要登录权限
|
||||||
const token = localStorage.getItem('token')
|
const token = localStorage.getItem('token')
|
||||||
if (token) { // 判断当前的token是否存在 ; 登录存入的token
|
if (token) { // 判断当前的token是否存在 ; 登录存入的token
|
||||||
next()
|
next()
|
||||||
} else {
|
} else {
|
||||||
glo_loading.routerLoading ? glo_loading.loadingShow() : '' //如果全局启用页面跳转则加载loading
|
|
||||||
next({
|
next({
|
||||||
path: '/' // 无token认证的一致返回到主页
|
path: '/' // 无token认证的一致返回到主页
|
||||||
})
|
})
|
||||||
glo_loading.routerLoading ? glo_loading.loadingHide() : ''//关闭loading层
|
|
||||||
store.commit('changeModalStatus',{mode: 'Login', visible: true})
|
store.commit('changeModalStatus',{mode: 'Login', visible: true})
|
||||||
mMessage.error('请您先登录!')
|
mMessage.error('请您先登录!')
|
||||||
}
|
}
|
||||||
|
@ -47,7 +48,7 @@ router.beforeEach((to, from, next) => {
|
||||||
})
|
})
|
||||||
|
|
||||||
router.afterEach((to, from, next) => {
|
router.afterEach((to, from, next) => {
|
||||||
|
NProgress.done()
|
||||||
})
|
})
|
||||||
|
|
||||||
sync(store, router)
|
sync(store, router)
|
||||||
|
|
|
@ -5,11 +5,23 @@ import Setting from "@/views/user/Setting.vue"
|
||||||
import ProblemLIst from "@/views/problem/ProblemList.vue"
|
import ProblemLIst from "@/views/problem/ProblemList.vue"
|
||||||
import Logout from "@/views/user/Logout.vue"
|
import Logout from "@/views/user/Logout.vue"
|
||||||
import SubmissionList from "@/views/status/SubmissionList.vue"
|
import SubmissionList from "@/views/status/SubmissionList.vue"
|
||||||
|
import SubmissionDetails from "@/views/status/SubmissionDetails.vue"
|
||||||
|
import ContestList from "@/views/contest/ContestList.vue"
|
||||||
|
import Problem from "@/views/problem/Problem.vue"
|
||||||
|
import ACMRank from "@/views/rank/ACMRank.vue"
|
||||||
|
import OIRank from "@/views/rank/OIRank.vue"
|
||||||
|
import CountDown from "@/views/contest/test.vue"
|
||||||
const routes = [
|
const routes = [
|
||||||
|
{
|
||||||
|
path: '/count-down',
|
||||||
|
name: 'CountDown',
|
||||||
|
component: CountDown
|
||||||
|
},
|
||||||
{
|
{
|
||||||
path: '/',
|
path: '/',
|
||||||
|
redirect: {
|
||||||
name: 'Home',
|
name: 'Home',
|
||||||
component: Home
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '/home',
|
path: '/home',
|
||||||
|
@ -21,11 +33,36 @@ const routes = [
|
||||||
name: 'ProblemList',
|
name: 'ProblemList',
|
||||||
component: ProblemLIst
|
component: ProblemLIst
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
path: '/problem/1',
|
||||||
|
name: 'problem-details',
|
||||||
|
component: Problem
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/contest',
|
||||||
|
name: 'ContestList',
|
||||||
|
component: ContestList
|
||||||
|
},
|
||||||
{
|
{
|
||||||
path: '/status',
|
path: '/status',
|
||||||
name: 'SubmissionList',
|
name: 'SubmissionList',
|
||||||
component: SubmissionList
|
component: SubmissionList
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
path: '/submission-detail',
|
||||||
|
name: 'SubmissionDeatil',
|
||||||
|
component: SubmissionDetails
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/acm-rank',
|
||||||
|
name: 'ACM Rank',
|
||||||
|
component: ACMRank
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/oi-rank',
|
||||||
|
name: 'OI Rank',
|
||||||
|
component: OIRank
|
||||||
|
},
|
||||||
{
|
{
|
||||||
path: '/reset-password',
|
path: '/reset-password',
|
||||||
name: 'SetNewPassword',
|
name: 'SetNewPassword',
|
||||||
|
|
|
@ -0,0 +1,184 @@
|
||||||
|
import moment from 'moment'
|
||||||
|
import api from '@/common/api'
|
||||||
|
import { CONTEST_STATUS, USER_TYPE, CONTEST_TYPE } from '@/common/constants'
|
||||||
|
|
||||||
|
const state = {
|
||||||
|
now: moment(),
|
||||||
|
access: false,
|
||||||
|
rankLimit: 30,
|
||||||
|
forceUpdate: false,
|
||||||
|
contest: {
|
||||||
|
created_by: {},
|
||||||
|
contest_type: CONTEST_TYPE.PUBLIC
|
||||||
|
},
|
||||||
|
contestProblems: [],
|
||||||
|
itemVisible: {
|
||||||
|
menu: true,
|
||||||
|
chart: true,
|
||||||
|
realName: false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const getters = {
|
||||||
|
// contest 是否加载完成
|
||||||
|
contestLoaded: (state) => {
|
||||||
|
return !!state.contest.status
|
||||||
|
},
|
||||||
|
contestStatus: (state, getters) => {
|
||||||
|
if (!getters.contestLoaded) return null
|
||||||
|
let startTime = moment(state.contest.start_time)
|
||||||
|
let endTime = moment(state.contest.end_time)
|
||||||
|
let now = state.now
|
||||||
|
|
||||||
|
if (startTime > now) {
|
||||||
|
return CONTEST_STATUS.NOT_START
|
||||||
|
} else if (endTime < now) {
|
||||||
|
return CONTEST_STATUS.ENDED
|
||||||
|
} else {
|
||||||
|
return CONTEST_STATUS.UNDERWAY
|
||||||
|
}
|
||||||
|
},
|
||||||
|
contestRuleType: (state) => {
|
||||||
|
return state.contest.rule_type || null
|
||||||
|
},
|
||||||
|
isContestAdmin: (state, getters, _, rootGetters) => {
|
||||||
|
return rootGetters.isAuthenticated &&
|
||||||
|
(state.contest.created_by.id === rootGetters.user.id || rootGetters.user.admin_type === USER_TYPE.SUPER_ADMIN)
|
||||||
|
},
|
||||||
|
contestMenuDisabled: (state, getters) => {
|
||||||
|
if (getters.isContestAdmin) return false
|
||||||
|
if (state.contest.contest_type === CONTEST_TYPE.PUBLIC) {
|
||||||
|
return getters.contestStatus === CONTEST_STATUS.NOT_START
|
||||||
|
}
|
||||||
|
return !state.access
|
||||||
|
},
|
||||||
|
OIContestRealTimePermission: (state, getters, _, rootGetters) => {
|
||||||
|
if (getters.contestRuleType === 'ACM' || getters.contestStatus === CONTEST_STATUS.ENDED) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return state.contest.real_time_rank === true || getters.isContestAdmin
|
||||||
|
},
|
||||||
|
problemSubmitDisabled: (state, getters, _, rootGetters) => {
|
||||||
|
if (getters.contestStatus === CONTEST_STATUS.ENDED) {
|
||||||
|
return true
|
||||||
|
} else if (getters.contestStatus === CONTEST_STATUS.NOT_START) {
|
||||||
|
return !getters.isContestAdmin
|
||||||
|
}
|
||||||
|
return !rootGetters.isAuthenticated
|
||||||
|
},
|
||||||
|
passwordFormVisible: (state, getters) => {
|
||||||
|
return state.contest.contest_type !== CONTEST_TYPE.PUBLIC && !state.access && !getters.isContestAdmin
|
||||||
|
},
|
||||||
|
contestStartTime: (state) => {
|
||||||
|
return moment(state.contest.start_time)
|
||||||
|
},
|
||||||
|
contestEndTime: (state) => {
|
||||||
|
return moment(state.contest.end_time)
|
||||||
|
},
|
||||||
|
countdown: (state, getters) => {
|
||||||
|
if (getters.contestStatus === CONTEST_STATUS.NOT_START) {
|
||||||
|
let duration = moment.duration(getters.contestStartTime.diff(state.now, 'seconds'), 'seconds')
|
||||||
|
// time is too long
|
||||||
|
if (duration.weeks() > 0) {
|
||||||
|
return 'Start At ' + duration.humanize()
|
||||||
|
}
|
||||||
|
let texts = [Math.floor(duration.asHours()), duration.minutes(), duration.seconds()]
|
||||||
|
return '-' + texts.join(':')
|
||||||
|
} else if (getters.contestStatus === CONTEST_STATUS.UNDERWAY) {
|
||||||
|
let duration = moment.duration(getters.contestEndTime.diff(state.now, 'seconds'), 'seconds')
|
||||||
|
let texts = [Math.floor(duration.asHours()), duration.minutes(), duration.seconds()]
|
||||||
|
return '-' + texts.join(':')
|
||||||
|
} else {
|
||||||
|
return 'Ended'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const mutations = {
|
||||||
|
changeContest (state, payload) {
|
||||||
|
state.contest = payload.contest
|
||||||
|
},
|
||||||
|
changeContestItemVisible(state, payload) {
|
||||||
|
state.itemVisible = {...state.itemVisible, ...payload}
|
||||||
|
},
|
||||||
|
changeRankForceUpdate (state, payload) {
|
||||||
|
state.forceUpdate = payload.value
|
||||||
|
},
|
||||||
|
changeContestProblems(state, payload) {
|
||||||
|
state.contestProblems = payload.contestProblems
|
||||||
|
},
|
||||||
|
changeContestRankLimit(state, payload) {
|
||||||
|
state.rankLimit = payload.rankLimit
|
||||||
|
},
|
||||||
|
contestAccess(state, payload) {
|
||||||
|
state.access = payload.access
|
||||||
|
},
|
||||||
|
clearContest (state) {
|
||||||
|
state.contest = {created_by: {}}
|
||||||
|
state.contestProblems = []
|
||||||
|
state.access = false
|
||||||
|
state.itemVisible = {
|
||||||
|
menu: true,
|
||||||
|
chart: true,
|
||||||
|
realName: false
|
||||||
|
}
|
||||||
|
state.forceUpdate = false
|
||||||
|
},
|
||||||
|
now(state, payload) {
|
||||||
|
state.now = payload.now
|
||||||
|
},
|
||||||
|
nowAdd1s (state) {
|
||||||
|
state.now = moment(state.now.add(1, 's'))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const actions = {
|
||||||
|
getContest ({commit, rootState, dispatch}) {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
api.getContest(rootState.route.params.contestID).then((res) => {
|
||||||
|
resolve(res)
|
||||||
|
let contest = res.data.data
|
||||||
|
commit(types.CHANGE_CONTEST, {contest: contest})
|
||||||
|
commit(types.NOW, {now: moment(contest.now)})
|
||||||
|
if (contest.contest_type === CONTEST_TYPE.PRIVATE) {
|
||||||
|
dispatch('getContestAccess')
|
||||||
|
}
|
||||||
|
}, err => {
|
||||||
|
reject(err)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
},
|
||||||
|
getContestProblems ({commit, rootState}) {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
api.getContestProblemList(rootState.route.params.contestID).then(res => {
|
||||||
|
res.data.data.sort((a, b) => {
|
||||||
|
if (a._id === b._id) {
|
||||||
|
return 0
|
||||||
|
} else if (a._id > b._id) {
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
return -1
|
||||||
|
})
|
||||||
|
commit(types.CHANGE_CONTEST_PROBLEMS, {contestProblems: res.data.data})
|
||||||
|
resolve(res)
|
||||||
|
}, () => {
|
||||||
|
commit(types.CHANGE_CONTEST_PROBLEMS, {contestProblems: []})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
},
|
||||||
|
getContestAccess ({commit, rootState}) {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
api.getContestAccess(rootState.route.params.contestID).then(res => {
|
||||||
|
commit(types.CONTEST_ACCESS, {access: res.data.data.access})
|
||||||
|
resolve(res)
|
||||||
|
}).catch()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default {
|
||||||
|
state,
|
||||||
|
mutations,
|
||||||
|
getters,
|
||||||
|
actions
|
||||||
|
}
|
|
@ -1,6 +1,7 @@
|
||||||
import Vue from 'vue'
|
import Vue from 'vue'
|
||||||
import Vuex from 'vuex'
|
import Vuex from 'vuex'
|
||||||
import user from '@/store/user'
|
import user from '@/store/user'
|
||||||
|
import contest from "@/store/contest"
|
||||||
Vue.use(Vuex)
|
Vue.use(Vuex)
|
||||||
const rootState = {
|
const rootState = {
|
||||||
modalStatus: {
|
modalStatus: {
|
||||||
|
@ -72,12 +73,20 @@ const rootActions = {
|
||||||
},
|
},
|
||||||
startTimeOut({ commit }, payload) {
|
startTimeOut({ commit }, payload) {
|
||||||
commit('startTimeOut', payload)
|
commit('startTimeOut', payload)
|
||||||
|
},
|
||||||
|
changeDomTitle ({commit, state}, payload) {
|
||||||
|
if (payload && payload.title) {
|
||||||
|
window.document.title = state.website.website_name_shortcut + ' | ' + payload.title
|
||||||
|
} else {
|
||||||
|
window.document.title = state.website.website_name_shortcut + ' | ' + state.route.meta.title
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default new Vuex.Store({
|
export default new Vuex.Store({
|
||||||
modules: {
|
modules: {
|
||||||
user,
|
user,
|
||||||
|
contest
|
||||||
},
|
},
|
||||||
state: rootState,
|
state: rootState,
|
||||||
getters: rootGetters,
|
getters: rootGetters,
|
||||||
|
|
|
@ -9,7 +9,7 @@
|
||||||
<div class="contest-info">
|
<div class="contest-info">
|
||||||
<div class="contest-tags">
|
<div class="contest-tags">
|
||||||
<el-button type="primary" round size="mini"><i class="fa fa-calendar"></i>
|
<el-button type="primary" round size="mini"><i class="fa fa-calendar"></i>
|
||||||
{{contest.beginTime | localtime('YYYY-M-D HH:mm') }}
|
{{contest.beginTime | localtime }}
|
||||||
</el-button>
|
</el-button>
|
||||||
<el-button type="success" round size="mini"><i class="fa fa-clock-o"></i>
|
<el-button type="success" round size="mini"><i class="fa fa-clock-o"></i>
|
||||||
{{contest.duration}}
|
{{contest.duration}}
|
||||||
|
@ -88,6 +88,7 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
import time from "@/common/time";
|
||||||
export default {
|
export default {
|
||||||
name:"home",
|
name:"home",
|
||||||
data() {
|
data() {
|
||||||
|
@ -96,12 +97,12 @@ export default {
|
||||||
tableData: [{
|
tableData: [{
|
||||||
oj: 'Codeforces',
|
oj: 'Codeforces',
|
||||||
title: 'Codeforces Round #680 (Div. 1, based on VK Cup 2020-2021 - Final)',
|
title: 'Codeforces Round #680 (Div. 1, based on VK Cup 2020-2021 - Final)',
|
||||||
beginTime: '2016-05-03 12:00:00',
|
beginTime: '2020-11-08T05:00:00Z',
|
||||||
endTime:'2016-05-03 17:00:00',
|
endTime:'2020-11-08T08:00:00Z',
|
||||||
},],
|
},],
|
||||||
contests: [
|
contests: [
|
||||||
{
|
{
|
||||||
beginTime:'2020-11-11',
|
beginTime:'2020-11-08T05:00:00Z',
|
||||||
duration:'5hours',
|
duration:'5hours',
|
||||||
type:"ACM",
|
type:"ACM",
|
||||||
description:'<h1>描述</h1>',
|
description:'<h1>描述</h1>',
|
||||||
|
@ -113,7 +114,12 @@ export default {
|
||||||
goContest(){
|
goContest(){
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
|
filters: {
|
||||||
|
localtime(value) {
|
||||||
|
return time.utcToLocal(value);
|
||||||
|
},
|
||||||
|
},
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
<style scoped>
|
<style scoped>
|
||||||
|
|
|
@ -0,0 +1,363 @@
|
||||||
|
<template>
|
||||||
|
<el-row type="flex" justify="space-around">
|
||||||
|
<el-col :span="24">
|
||||||
|
<el-card shadow>
|
||||||
|
<div slot="header">
|
||||||
|
<span class="panel-title"
|
||||||
|
>{{
|
||||||
|
query.rule_type === "" ? "All" : query.rule_type
|
||||||
|
}}
|
||||||
|
Contests</span
|
||||||
|
>
|
||||||
|
<div class="filter-row">
|
||||||
|
<span>
|
||||||
|
<el-dropdown
|
||||||
|
@command="onRuleChange"
|
||||||
|
placement="bottom"
|
||||||
|
trigger="hover"
|
||||||
|
class="drop-menu"
|
||||||
|
>
|
||||||
|
<span class="el-dropdown-link">
|
||||||
|
{{ query.rule_type === "" ? "Rule" : query.rule_type }}
|
||||||
|
<i class="el-icon-caret-bottom"></i>
|
||||||
|
</span>
|
||||||
|
<el-dropdown-menu slot="dropdown">
|
||||||
|
<el-dropdown-item command="">All</el-dropdown-item>
|
||||||
|
<el-dropdown-item command="OI">OI</el-dropdown-item>
|
||||||
|
<el-dropdown-item command="ACM">ACM</el-dropdown-item>
|
||||||
|
</el-dropdown-menu>
|
||||||
|
</el-dropdown>
|
||||||
|
</span>
|
||||||
|
|
||||||
|
<span>
|
||||||
|
<el-dropdown
|
||||||
|
@on-click="onStatusChange"
|
||||||
|
placement="bottom"
|
||||||
|
trigger="hover"
|
||||||
|
class="drop-menu"
|
||||||
|
>
|
||||||
|
<span class="el-dropdown-link">
|
||||||
|
{{
|
||||||
|
query.status === ""
|
||||||
|
? "Status"
|
||||||
|
: CONTEST_STATUS_REVERSE[query.status].name
|
||||||
|
}}
|
||||||
|
<i class="el-icon-caret-bottom"></i>
|
||||||
|
</span>
|
||||||
|
<el-dropdown-menu slot="dropdown">
|
||||||
|
<el-dropdown-item command="">All</el-dropdown-item>
|
||||||
|
<el-dropdown-item command="0">Running</el-dropdown-item>
|
||||||
|
<el-dropdown-item command="1">Scheduled</el-dropdown-item>
|
||||||
|
<el-dropdown-item command="-1">Ended</el-dropdown-item>
|
||||||
|
</el-dropdown-menu>
|
||||||
|
</el-dropdown>
|
||||||
|
</span>
|
||||||
|
|
||||||
|
<span>
|
||||||
|
<vxe-input
|
||||||
|
v-model="query.keyword"
|
||||||
|
placeholder="Enter keyword"
|
||||||
|
type="search"
|
||||||
|
size="medium"
|
||||||
|
@search-click="filterByKeyword"
|
||||||
|
></vxe-input>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<p id="no-contest" v-show="contests.length == 0">暂无比赛</p>
|
||||||
|
<ol id="contest-list">
|
||||||
|
<li v-for="contest in contests" :key="contest.title" :style="getborderColor(contest)">
|
||||||
|
<el-row type="flex" justify="space-between" align="middle">
|
||||||
|
<el-col :xs="10" :md="2" :lg="2">
|
||||||
|
<img v-show="contest.rule_type == 'ACM'" class="trophy" :src="acmSrc" width="95px"/>
|
||||||
|
<img v-show="contest.rule_type == 'OI'" class="trophy" :src="oiSrc" width="95px" />
|
||||||
|
</el-col>
|
||||||
|
<el-col :xs="10" :md="20" :lg="20" class="contest-main">
|
||||||
|
<p class="title">
|
||||||
|
<a class="entry" @click.stop="toContest(contest)">
|
||||||
|
{{ contest.title }}
|
||||||
|
</a>
|
||||||
|
<template v-if="contest.auth != 0">
|
||||||
|
<i class="el-icon-lock" size="20"></i>
|
||||||
|
</template>
|
||||||
|
</p>
|
||||||
|
<ul class="detail">
|
||||||
|
<li>
|
||||||
|
<i
|
||||||
|
class="fa fa-calendar"
|
||||||
|
aria-hidden="true"
|
||||||
|
style="color: #3091f2"
|
||||||
|
></i>
|
||||||
|
{{ contest.start_time | localtime }}
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<i
|
||||||
|
class="fa fa-clock-o"
|
||||||
|
aria-hidden="true"
|
||||||
|
style="color: #3091f2"
|
||||||
|
></i>
|
||||||
|
{{ getDuration(contest.start_time, contest.end_time) }}
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<el-button
|
||||||
|
size="mini"
|
||||||
|
round
|
||||||
|
@click="onRuleChange(contest.rule_type)"
|
||||||
|
>
|
||||||
|
{{ contest.rule_type }}
|
||||||
|
</el-button>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<el-tooltip :content="CONTEST_TYPE_REVERSE[contest.auth].tips" placement="top" effect="light">
|
||||||
|
<el-tag
|
||||||
|
:type="CONTEST_TYPE_REVERSE[contest.auth].color"
|
||||||
|
effect="plain">
|
||||||
|
{{CONTEST_TYPE_REVERSE[contest.auth].name}}
|
||||||
|
</el-tag>
|
||||||
|
</el-tooltip>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</el-col>
|
||||||
|
<el-col :xs="4" :md="2" :lg="2" style="text-align: center">
|
||||||
|
<el-tag
|
||||||
|
effect="dark"
|
||||||
|
:color="CONTEST_STATUS_REVERSE[contest.status].color"
|
||||||
|
size="medium"
|
||||||
|
>
|
||||||
|
<i
|
||||||
|
class="fa fa-circle"
|
||||||
|
aria-hidden="true"
|
||||||
|
></i>
|
||||||
|
{{ CONTEST_STATUS_REVERSE[contest.status].name }}
|
||||||
|
</el-tag>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
</li>
|
||||||
|
</ol>
|
||||||
|
</el-card>
|
||||||
|
<Pagination
|
||||||
|
:total="total"
|
||||||
|
:pageSize="limit"
|
||||||
|
@on-change="getContestList"
|
||||||
|
:current.sync="page"
|
||||||
|
></Pagination>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import api from "@/common/api";
|
||||||
|
import { mapGetters } from "vuex";
|
||||||
|
import utils from "@/common/utils";
|
||||||
|
import Pagination from "@/components/common/Pagination";
|
||||||
|
import time from "@/common/time";
|
||||||
|
import { CONTEST_STATUS_REVERSE, CONTEST_TYPE,CONTEST_TYPE_REVERSE } from "@/common/constants";
|
||||||
|
|
||||||
|
const limit = 10;
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: "contest-list",
|
||||||
|
components: {
|
||||||
|
Pagination,
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
page: 1,
|
||||||
|
query: {
|
||||||
|
status: "",
|
||||||
|
keyword: "",
|
||||||
|
rule_type: "",
|
||||||
|
},
|
||||||
|
limit: limit,
|
||||||
|
total: 0,
|
||||||
|
rows: "",
|
||||||
|
contests: [
|
||||||
|
{
|
||||||
|
title: "测试比赛",
|
||||||
|
status: 0,
|
||||||
|
start_time: "2020-11-08T05:00:00Z",
|
||||||
|
end_time: "2020-11-08T08:00:00Z",
|
||||||
|
rule_type: "ACM",
|
||||||
|
auth: 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "测试比赛",
|
||||||
|
status: 0,
|
||||||
|
start_time: "2020-11-08T05:00:00Z",
|
||||||
|
end_time: "2020-11-08T08:00:00Z",
|
||||||
|
rule_type: "ACM",
|
||||||
|
auth: 2,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "测试比赛",
|
||||||
|
status: -1,
|
||||||
|
start_time: "2020-11-08T05:00:00Z",
|
||||||
|
end_time: "2020-11-08T08:00:00Z",
|
||||||
|
rule_type: "ACM",
|
||||||
|
auth: 0,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "测试比赛",
|
||||||
|
status: 1,
|
||||||
|
start_time: "2020-11-08T05:00:00Z",
|
||||||
|
end_time: "2020-11-08T08:00:00Z",
|
||||||
|
rule_type: "ACM",
|
||||||
|
auth: 0,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "测试比赛",
|
||||||
|
status: 0,
|
||||||
|
start_time: "2020-11-08T05:00:00Z",
|
||||||
|
end_time: "2020-11-08T08:00:00Z",
|
||||||
|
rule_type: "OI",
|
||||||
|
auth: 0,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
CONTEST_STATUS_REVERSE: CONTEST_STATUS_REVERSE,
|
||||||
|
// for password modal use
|
||||||
|
cur_contest_id: "",
|
||||||
|
CONTEST_TYPE_REVERSE:CONTEST_TYPE_REVERSE,
|
||||||
|
acmSrc: require("../../assets/acm.jpg"),
|
||||||
|
oiSrc: require("../../assets/oi.jpg"),
|
||||||
|
};
|
||||||
|
},
|
||||||
|
// beforeRouteEnter(to, from, next) {
|
||||||
|
// // api.getContestList(0, limit).then(
|
||||||
|
// // (res) => {
|
||||||
|
// // next((vm) => {
|
||||||
|
// // vm.contests = res.data.data.results;
|
||||||
|
// // vm.total = res.data.data.total;
|
||||||
|
// // });
|
||||||
|
// // },
|
||||||
|
// // (res) => {
|
||||||
|
// // next();
|
||||||
|
// // }
|
||||||
|
// // );
|
||||||
|
// },
|
||||||
|
methods: {
|
||||||
|
init() {
|
||||||
|
let route = this.$route.query;
|
||||||
|
this.query.status = route.status || "";
|
||||||
|
this.query.rule_type = route.rule_type || "";
|
||||||
|
this.query.keyword = route.keyword || "";
|
||||||
|
this.page = parseInt(route.page) || 1;
|
||||||
|
this.getContestList();
|
||||||
|
},
|
||||||
|
getContestList(page = 1) {
|
||||||
|
let offset = (page - 1) * this.limit;
|
||||||
|
api.getContestList(offset, this.limit, this.query).then((res) => {
|
||||||
|
this.contests = res.data.data.results;
|
||||||
|
this.total = res.data.data.total;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
filterByKeyword() {
|
||||||
|
let query = Object.assign({}, this.query);
|
||||||
|
query.page = this.page;
|
||||||
|
this.$router.push({
|
||||||
|
name: "contest-list",
|
||||||
|
query: utils.filterEmptyValue(query),
|
||||||
|
});
|
||||||
|
},
|
||||||
|
onRuleChange(rule) {
|
||||||
|
this.query.rule_type = rule;
|
||||||
|
this.page = 1;
|
||||||
|
this.changeRoute();
|
||||||
|
},
|
||||||
|
onStatusChange(status) {
|
||||||
|
this.query.status = status;
|
||||||
|
this.page = 1;
|
||||||
|
this.changeRoute();
|
||||||
|
},
|
||||||
|
toContest(contest) {
|
||||||
|
this.cur_contest_id = contest.id;
|
||||||
|
if (
|
||||||
|
contest.contest_type !== CONTEST_TYPE.PUBLIC &&
|
||||||
|
!this.isAuthenticated
|
||||||
|
) {
|
||||||
|
this.$error("请先登录");
|
||||||
|
this.$store.dispatch("changeModalStatus", { visible: true });
|
||||||
|
} else {
|
||||||
|
this.$router.push({
|
||||||
|
name: "contest-details",
|
||||||
|
params: { contestID: contest.id },
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
getDuration(startTime, endTime) {
|
||||||
|
return time.duration(startTime, endTime);
|
||||||
|
},
|
||||||
|
getborderColor(contest){
|
||||||
|
return "border-left: 4px solid "+CONTEST_STATUS_REVERSE[contest.status].color;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
...mapGetters(["isAuthenticated", "user"]),
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
$route(newVal, oldVal) {
|
||||||
|
if (newVal !== oldVal) {
|
||||||
|
this.init();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
<style scoped>
|
||||||
|
#no-contest {
|
||||||
|
text-align: center;
|
||||||
|
font-size: 16px;
|
||||||
|
padding: 20px;
|
||||||
|
}
|
||||||
|
.filter-row {
|
||||||
|
float: right;
|
||||||
|
}
|
||||||
|
.el-tag--dark{
|
||||||
|
border-color: #FFF;
|
||||||
|
}
|
||||||
|
@media screen and (max-width: 768px) {
|
||||||
|
.filter-row span {
|
||||||
|
margin-right: 2px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@media screen and (min-width: 768px) {
|
||||||
|
.filter-row span {
|
||||||
|
margin-right: 20px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#contest-list > li {
|
||||||
|
padding: 5px;
|
||||||
|
margin-left: -20px;
|
||||||
|
margin-top: 10px;
|
||||||
|
width: 100%;
|
||||||
|
border-bottom: 1px solid rgba(187, 187, 187, 0.5);
|
||||||
|
list-style: none;
|
||||||
|
}
|
||||||
|
#contest-list .trophy {
|
||||||
|
height: 70px;
|
||||||
|
margin-left: 10px;
|
||||||
|
margin-right: -20px;
|
||||||
|
}
|
||||||
|
#contest-list .contest-main {
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
#contest-list .contest-main .title {
|
||||||
|
font-size: 18px;
|
||||||
|
padding-left: 8px;
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
#contest-list .contest-main .title a.entry {
|
||||||
|
color: #495060;
|
||||||
|
}
|
||||||
|
#contest-list .contest-main .title a:hover {
|
||||||
|
color: #2d8cf0;
|
||||||
|
border-bottom: 1px solid #2d8cf0;
|
||||||
|
}
|
||||||
|
#contest-list .contest-main .detail {
|
||||||
|
padding-left: 0;
|
||||||
|
padding-bottom: 10px;
|
||||||
|
}
|
||||||
|
#contest-list .contest-main li {
|
||||||
|
display: inline-block;
|
||||||
|
padding: 10px 0 0 10px;
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -0,0 +1,83 @@
|
||||||
|
<template>
|
||||||
|
<span>
|
||||||
|
<slot>{{content}}</slot>
|
||||||
|
</span>
|
||||||
|
</template>
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
name: "CountDown",
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
timer: null,
|
||||||
|
date: null,
|
||||||
|
savedtime: 0, //时间
|
||||||
|
hour: null,
|
||||||
|
min: null,
|
||||||
|
sec: null,
|
||||||
|
content: this.endText //显示
|
||||||
|
};
|
||||||
|
},
|
||||||
|
props: {
|
||||||
|
// 倒计时时间 (分钟)
|
||||||
|
endTime: {
|
||||||
|
type: Number,
|
||||||
|
default: ""
|
||||||
|
},
|
||||||
|
endText: {
|
||||||
|
type: String,
|
||||||
|
default: "0:00:00"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
// 时间换成毫秒传递
|
||||||
|
this.timeStart(this.endTime * 60000);
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
// 起始时间
|
||||||
|
timeStart(endTime) {
|
||||||
|
this.date = new Date();
|
||||||
|
var date1 = new Date().getTime(); // 获取当前时间戳
|
||||||
|
// 当前时间戳+3600s(一小时,其他时间通过计算时间戳进行相应加减),重新设置 Date 对象
|
||||||
|
this.date.setTime(date1 + endTime);
|
||||||
|
this.date = this.date.getTime();
|
||||||
|
// 传递结束时的时间戳
|
||||||
|
this.countdowm(this.date);
|
||||||
|
},
|
||||||
|
// 继续倒计时
|
||||||
|
timeresume() {
|
||||||
|
this.timeStart(this.savedtime);
|
||||||
|
},
|
||||||
|
// 暂停时间
|
||||||
|
timepause() {
|
||||||
|
clearInterval(this.timer);
|
||||||
|
this.savedtime =
|
||||||
|
this.hour * 60 * 60 * 1000 + this.min * 60 * 1000 + this.sec * 1000;
|
||||||
|
},
|
||||||
|
// 开始倒计时
|
||||||
|
countdowm(timestamp) {
|
||||||
|
let self = this;
|
||||||
|
self.timer = setInterval(function() {
|
||||||
|
let nowTime = new Date();
|
||||||
|
let endTime = new Date(timestamp * 1);
|
||||||
|
let t = endTime.getTime() - nowTime.getTime();
|
||||||
|
// 判断剩余时间是否 >0
|
||||||
|
if (t > 0) {
|
||||||
|
self.hour = Math.floor((t / 3600000) % 24);
|
||||||
|
self.min = Math.floor((t / 60000) % 60);
|
||||||
|
self.sec = Math.floor((t / 1000) % 60);
|
||||||
|
self.$emit("callBack", 1 + self.min + self.hour * 60); // 每减少一分钟父页面滑块的值就减 1
|
||||||
|
let min = self.min < 10 ? "0" + self.min : self.min;
|
||||||
|
let sec = self.sec < 10 ? "0" + self.sec : self.sec;
|
||||||
|
let format = `${self.hour}:${min}:${sec}`;
|
||||||
|
self.content = format;
|
||||||
|
} else {
|
||||||
|
// 倒计时结束
|
||||||
|
self.$emit("callBack", 0);
|
||||||
|
clearInterval(self.timer);
|
||||||
|
self.content = "0:00:00";
|
||||||
|
}
|
||||||
|
}, 1000);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
|
@ -0,0 +1,82 @@
|
||||||
|
<template>
|
||||||
|
|
||||||
|
<div class="item">
|
||||||
|
<div class="open_con">
|
||||||
|
<el-button
|
||||||
|
icon="el-icon-switch-button"
|
||||||
|
circle
|
||||||
|
:plain="plain"
|
||||||
|
type="primary"
|
||||||
|
@click="OPens"
|
||||||
|
></el-button>
|
||||||
|
</div>
|
||||||
|
<div class="slider">
|
||||||
|
<el-slider v-model="value" :format-tooltip="formatTooltip"></el-slider>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<script>
|
||||||
|
import countDown from "./count"; //引入倒计时组件
|
||||||
|
export default {
|
||||||
|
name: "Caeds",
|
||||||
|
components: { countDown },
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
value: 0,
|
||||||
|
plain: true, // 开关按钮 true 是关闭,false是打开
|
||||||
|
stop: 0,
|
||||||
|
time: "0:00:00"
|
||||||
|
};
|
||||||
|
},
|
||||||
|
mounted() {},
|
||||||
|
methods: {
|
||||||
|
formatTooltip(val) {
|
||||||
|
if (val < 60) {
|
||||||
|
if (val < 10) {
|
||||||
|
this.time = "0:0" + val + ":00";
|
||||||
|
return "0:0" + val + ":00";
|
||||||
|
} else {
|
||||||
|
this.time = "0:" + val + ":00";
|
||||||
|
return "0:" + val + ":00";
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (val < 70) {
|
||||||
|
this.time = "1:0" + (val - 60) + ":00";
|
||||||
|
return "1:0" + (val - 60) + ":00";
|
||||||
|
} else {
|
||||||
|
this.time = "1:" + (val - 60) + ":00";
|
||||||
|
return "1:" + (val - 60) + ":00";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
//
|
||||||
|
callBack(val) {
|
||||||
|
console.log(val);
|
||||||
|
this.value = val;
|
||||||
|
// 倒计时结束 关闭按钮
|
||||||
|
if (val == 0) {
|
||||||
|
this.stop = 0;
|
||||||
|
this.plain = true;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
OPens() {
|
||||||
|
if (this.value != 0) {
|
||||||
|
if (!this.plain && this.stop == 1) {
|
||||||
|
this.stop = 2;
|
||||||
|
console.log("stop");
|
||||||
|
this.$refs.countdown.timepause();
|
||||||
|
}
|
||||||
|
if (this.plain && this.stop == 2) {
|
||||||
|
this.stop = 1;
|
||||||
|
console.log("open");
|
||||||
|
this.$refs.countdown.timeresume();
|
||||||
|
}
|
||||||
|
if (this.stop == 0) {
|
||||||
|
this.stop = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.plain = !this.plain;
|
||||||
|
},
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
|
@ -0,0 +1,714 @@
|
||||||
|
<template>
|
||||||
|
<div class="flex-container">
|
||||||
|
<div id="problem-main">
|
||||||
|
<!--problem main-->
|
||||||
|
<el-row >
|
||||||
|
<el-col :sm="24" :md="12" :lg="12" class="problem-detail">
|
||||||
|
<el-card :padding="10" shadow="always">
|
||||||
|
<div slot="header" class="panel-title">
|
||||||
|
<span>{{ problem.title }}</span><br>
|
||||||
|
<span><el-tag v-for="tag in problem.tags" :key="tag" effect="plain" size="small" style="margin-right:10px;">{{ tag }}</el-tag></span>
|
||||||
|
<div class="problem-menu">
|
||||||
|
<span v-if="this.contestID"> <el-link type="primary" :underline="false"><i class="fa fa-home" aria-hidden="true"></i> Contest</el-link></span>
|
||||||
|
<span> <el-link type="primary" :underline="false" @click="graphVisible = !graphVisible"><i class="fa fa-pie-chart" aria-hidden="true"></i> Statistic</el-link></span>
|
||||||
|
<span> <el-link type="primary" :underline="false"><i class="fa fa-bars" aria-hidden="true"></i> Submissions</el-link></span>
|
||||||
|
</div>
|
||||||
|
<div class="question-intr">
|
||||||
|
<span>Time Limit:{{problem.time_limit}}</span><br>
|
||||||
|
<span>Memory Limit:{{problem.memory_limit}}</span><br>
|
||||||
|
<span>Level:{{problem.difficulty}}</span><span style="margin-left: 10px;">Score:{{problem.score}}</span><br>
|
||||||
|
<span v-show="problem.author">Create By:{{problem.author}}</span><br>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="problem-content" class="markdown-body" v-katex>
|
||||||
|
<p class="title">Description</p>
|
||||||
|
<p class="content" v-html="problem.description"></p>
|
||||||
|
<!-- {{$t('m.music')}} -->
|
||||||
|
<p class="title">Input</p>
|
||||||
|
<p class="content" v-html="problem.input_description"></p>
|
||||||
|
|
||||||
|
<p class="title">Output</p>
|
||||||
|
<p class="content" v-html="problem.output_description"></p>
|
||||||
|
|
||||||
|
<div v-for="(sample, index) of problem.samples" :key="index">
|
||||||
|
<div class="flex-container sample">
|
||||||
|
<div class="sample-input">
|
||||||
|
<p class="title">
|
||||||
|
Sample Input {{ index + 1 }}
|
||||||
|
<a
|
||||||
|
class="copy"
|
||||||
|
v-clipboard:copy="sample.input"
|
||||||
|
v-clipboard:success="onCopy"
|
||||||
|
v-clipboard:error="onCopyError"
|
||||||
|
>
|
||||||
|
<i class="el-icon-document-copy"></i>
|
||||||
|
</a>
|
||||||
|
</p>
|
||||||
|
<pre>{{ sample.input }}</pre>
|
||||||
|
</div>
|
||||||
|
<div class="sample-output">
|
||||||
|
<p class="title">Sample Output {{ index + 1 }}
|
||||||
|
<a
|
||||||
|
class="copy"
|
||||||
|
v-clipboard:copy="sample.output"
|
||||||
|
v-clipboard:success="onCopy"
|
||||||
|
v-clipboard:error="onCopyError"
|
||||||
|
>
|
||||||
|
<i class="el-icon-document-copy"></i>
|
||||||
|
</a>
|
||||||
|
|
||||||
|
</p>
|
||||||
|
<pre>{{ sample.output }}</pre>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div v-if="problem.hint">
|
||||||
|
<p class="title">Hint</p>
|
||||||
|
<el-card dis-hover>
|
||||||
|
<div class="content" v-html="problem.hint"></div>
|
||||||
|
</el-card>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div v-if="problem.source">
|
||||||
|
<p class="title">Source</p>
|
||||||
|
<p class="content">{{ problem.source }}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</el-card>
|
||||||
|
</el-col>
|
||||||
|
<el-col :sm="24" :md="12" :lg="12" class="submit-detail">
|
||||||
|
<!--problem main end-->
|
||||||
|
<el-card :padding="20" id="submit-code" shadow="always">
|
||||||
|
<CodeMirror
|
||||||
|
:value.sync="code"
|
||||||
|
:languages="problem.languages"
|
||||||
|
:language="language"
|
||||||
|
:theme="theme"
|
||||||
|
@resetCode="onResetToTemplate"
|
||||||
|
@changeTheme="onChangeTheme"
|
||||||
|
@changeLang="onChangeLang"
|
||||||
|
></CodeMirror>
|
||||||
|
<el-row>
|
||||||
|
<el-col :sm="24" :md="10" :lg="10" style="margin-top:4px;">
|
||||||
|
<div class="status" v-if="statusVisible">
|
||||||
|
<template
|
||||||
|
v-if="
|
||||||
|
!this.contestID ||
|
||||||
|
(this.contestID && OIContestRealTimePermission)
|
||||||
|
"
|
||||||
|
>
|
||||||
|
<span>Status</span>
|
||||||
|
<el-tag
|
||||||
|
type="dot"
|
||||||
|
:color="submissionStatus.color"
|
||||||
|
@click.native="handleRoute('/status/' + submissionId)"
|
||||||
|
>
|
||||||
|
{{ submissionStatus.text.replace(/ /g, "_") }}
|
||||||
|
</el-tag>
|
||||||
|
</template>
|
||||||
|
<template
|
||||||
|
v-else-if="this.contestID && !OIContestRealTimePermission"
|
||||||
|
>
|
||||||
|
<el-alert type="success" show-icon effect="dark" :closable="false"
|
||||||
|
>Submitted successfully</el-alert
|
||||||
|
>
|
||||||
|
</template>
|
||||||
|
</div>
|
||||||
|
<div v-else-if="problem.my_status === 0">
|
||||||
|
<el-alert type="success" show-icon effect="dark" :closable="false"
|
||||||
|
>You have solved the problem</el-alert
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
v-else-if="
|
||||||
|
this.contestID &&
|
||||||
|
!OIContestRealTimePermission &&
|
||||||
|
submissionExists
|
||||||
|
"
|
||||||
|
>
|
||||||
|
<el-alert type="success" show-icon effect="dark" :closable="false"
|
||||||
|
>You have submitted a solution</el-alert
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
<div v-if="contestEnded">
|
||||||
|
<el-alert type="warning" show-icon effect="dark" :closable="false"
|
||||||
|
>Contest has ended</el-alert
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
</el-col>
|
||||||
|
|
||||||
|
<el-col :sm="24" :md="14" :lg="14" style="margin-top:4px;">
|
||||||
|
<template v-if="captchaRequired">
|
||||||
|
<div class="captcha-container">
|
||||||
|
<el-tooltip
|
||||||
|
v-if="captchaRequired"
|
||||||
|
content="Click to refresh"
|
||||||
|
placement="top"
|
||||||
|
>
|
||||||
|
<img :src="captchaSrc" @click="getCaptchaSrc" />
|
||||||
|
</el-tooltip>
|
||||||
|
<el-input v-model="captchaCode" class="captcha-code" />
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<el-button
|
||||||
|
type="primary"
|
||||||
|
icon="el-icon-edit-outline"
|
||||||
|
:loading="submitting"
|
||||||
|
@click="submitCode"
|
||||||
|
:disabled="problemSubmitDisabled || submitted"
|
||||||
|
class="fl-right"
|
||||||
|
>
|
||||||
|
<span v-if="submitting">Submitting</span>
|
||||||
|
<span v-else>Submit</span>
|
||||||
|
</el-button>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
</el-card>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- <div id="right-column">
|
||||||
|
<VerticalMenu @on-click="handleRoute">
|
||||||
|
<template v-if="this.contestID">
|
||||||
|
<VerticalMenu-item :route="{name: 'contest-problem-list', params: {contestID: contestID}}">
|
||||||
|
<Icon type="ios-photos"></Icon>
|
||||||
|
{{$t('m.Problems')}}
|
||||||
|
</VerticalMenu-item>
|
||||||
|
|
||||||
|
<VerticalMenu-item :route="{name: 'contest-announcement-list', params: {contestID: contestID}}">
|
||||||
|
<Icon type="chatbubble-working"></Icon>
|
||||||
|
{{$t('m.Announcements')}}
|
||||||
|
</VerticalMenu-item>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<VerticalMenu-item v-if="!this.contestID || OIContestRealTimePermission" :route="submissionRoute">
|
||||||
|
<Icon type="navicon-round"></Icon>
|
||||||
|
{{$t('m.Submissions')}}
|
||||||
|
</VerticalMenu-item>
|
||||||
|
|
||||||
|
<template v-if="this.contestID">
|
||||||
|
<VerticalMenu-item v-if="!this.contestID || OIContestRealTimePermission"
|
||||||
|
:route="{name: 'contest-rank', params: {contestID: contestID}}">
|
||||||
|
<Icon type="stats-bars"></Icon>
|
||||||
|
{{$t('m.Rankings')}}
|
||||||
|
</VerticalMenu-item>
|
||||||
|
<VerticalMenu-item :route="{name: 'contest-details', params: {contestID: contestID}}">
|
||||||
|
<Icon type="home"></Icon>
|
||||||
|
{{$t('m.View_Contest')}}
|
||||||
|
</VerticalMenu-item>
|
||||||
|
</template>
|
||||||
|
</VerticalMenu> -->
|
||||||
|
|
||||||
|
|
||||||
|
<el-dialog :visible.sync="graphVisible" width="400px">
|
||||||
|
<div id="pieChart-detail">
|
||||||
|
<ECharts :options="largePie" :initOptions="largePieInitOpts"></ECharts>
|
||||||
|
</div>
|
||||||
|
<div slot="footer">
|
||||||
|
<el-button type="ghost" @click="graphVisible=false" size="small">Close</el-button>
|
||||||
|
</div>
|
||||||
|
</el-dialog>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { mapGetters, mapActions } from "vuex";
|
||||||
|
import CodeMirror from "@/components/common/CodeMirror.vue";
|
||||||
|
import storage from "@/common/storage";
|
||||||
|
import {
|
||||||
|
JUDGE_STATUS,
|
||||||
|
CONTEST_STATUS,
|
||||||
|
buildProblemCodeKey,
|
||||||
|
} from "@/common/constants";
|
||||||
|
import {pie, largePie} from './chartData'
|
||||||
|
import api from "@/common/api";
|
||||||
|
import mMessage from '@/common/message'
|
||||||
|
|
||||||
|
// 只显示这些状态的图形占用
|
||||||
|
const filtedStatus = ["-1", "-2", "0", "1", "2", "3", "4", "8"];
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: "Problem",
|
||||||
|
components: {
|
||||||
|
CodeMirror,
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
statusVisible: false,
|
||||||
|
captchaRequired: false,
|
||||||
|
graphVisible: false,
|
||||||
|
submissionExists: false,
|
||||||
|
captchaCode: "",
|
||||||
|
captchaSrc: "",
|
||||||
|
contestID: "",
|
||||||
|
problemID: 1000,
|
||||||
|
submitting: false,
|
||||||
|
code: "",
|
||||||
|
language: "C++",
|
||||||
|
theme: "monokai",
|
||||||
|
submissionId: "",
|
||||||
|
submitted: false,
|
||||||
|
result: {
|
||||||
|
result: 9,
|
||||||
|
},
|
||||||
|
problem: {
|
||||||
|
title: "A + B Problem",
|
||||||
|
description:
|
||||||
|
"<p>请计算两个整数的和并输出结果。</p><p>注意不要有不必要的输出,比如"请输入 a 和 b 的值: ",示例代码见隐藏部分。</p>",
|
||||||
|
hint:
|
||||||
|
'<p>C \u8bed\u8a00\u5b9e\u73b0:</p><pre><code class="lang-c++">#include <stdio.h> \nint main(){\n int a, b;\n scanf("%d%d", &a, &b);\n printf("%d\\n", a+b);\n return 0;\n}</code></pre><p>Java \u5b9e\u73b0:</p><pre><code class="lang-java">import java.util.Scanner;\npublic class Main{\n public static void main(String[] args){\n Scanner in=new Scanner(System.in);\n int a=in.nextInt();\n int b=in.nextInt();\n System.out.println((a+b)); \n }\n}</code></pre>',
|
||||||
|
input_description:
|
||||||
|
"<p>\u4e24\u4e2a\u7528\u7a7a\u683c\u5206\u5f00\u7684\u6574\u6570.</p>",
|
||||||
|
output_description: "<p>\u4e24\u6570\u4e4b\u548c</p>",
|
||||||
|
my_status: 0,
|
||||||
|
time_limit:'1000MS',
|
||||||
|
memory_limit:'32MB',
|
||||||
|
score:100,
|
||||||
|
template: {},
|
||||||
|
languages: ["C++", "Python3","C"],
|
||||||
|
author:'Himit_ZH',
|
||||||
|
rule_type: "OI",
|
||||||
|
difficulty: "Mid",
|
||||||
|
source: "\u7ecf\u5178\u9898\u76ee",
|
||||||
|
samples: [
|
||||||
|
{
|
||||||
|
input: "1 1",
|
||||||
|
output: "2",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
input: "2 3",
|
||||||
|
output: "5",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
tags: ['简单题','模拟题'],
|
||||||
|
io_mode: { io_mode: "Standard IO" },
|
||||||
|
},
|
||||||
|
pie: pie,
|
||||||
|
largePie: largePie,
|
||||||
|
// echarts 无法获取隐藏dom的大小,需手动指定
|
||||||
|
largePieInitOpts: {
|
||||||
|
width: '380',
|
||||||
|
height: '380'
|
||||||
|
}
|
||||||
|
};
|
||||||
|
},
|
||||||
|
// beforeRouteEnter (to, from, next) {
|
||||||
|
// let problemCode = storage.get(buildProblemCodeKey(to.params.problemID, to.params.contestID))
|
||||||
|
// if (problemCode) {
|
||||||
|
// next(vm => {
|
||||||
|
// vm.language = problemCode.language
|
||||||
|
// vm.code = problemCode.code
|
||||||
|
// vm.theme = problemCode.theme
|
||||||
|
// })
|
||||||
|
// } else {
|
||||||
|
// next()
|
||||||
|
// }
|
||||||
|
// },
|
||||||
|
mounted() {
|
||||||
|
this.$store.commit("changeContestItemVisible", { menu: false });
|
||||||
|
this.init();
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
...mapActions(["changeDomTitle"]),
|
||||||
|
init() {
|
||||||
|
// this.$Loading.start()
|
||||||
|
this.contestID = this.$route.params.contestID;
|
||||||
|
this.problemID = this.$route.params.problemID;
|
||||||
|
let func =
|
||||||
|
this.$route.name === "problem-details"
|
||||||
|
? "getProblem"
|
||||||
|
: "getContestProblem";
|
||||||
|
api[func](this.problemID, this.contestID).then(
|
||||||
|
(res) => {
|
||||||
|
this.$Loading.finish();
|
||||||
|
let problem = res.data.data;
|
||||||
|
this.changeDomTitle({ title: problem.title });
|
||||||
|
api.submissionExists(problem.id).then((res) => {
|
||||||
|
this.submissionExists = res.data.data;
|
||||||
|
});
|
||||||
|
problem.languages = problem.languages.sort();
|
||||||
|
this.problem = problem;
|
||||||
|
this.changePie(problem);
|
||||||
|
|
||||||
|
// 在beforeRouteEnter中修改了, 说明本地有code,无需加载template
|
||||||
|
if (this.code !== "") {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// try to load problem template
|
||||||
|
this.language = this.problem.languages[0];
|
||||||
|
let template = this.problem.template;
|
||||||
|
if (template && template[this.language]) {
|
||||||
|
this.code = template[this.language];
|
||||||
|
}
|
||||||
|
},
|
||||||
|
() => {
|
||||||
|
this.$Loading.error();
|
||||||
|
}
|
||||||
|
);
|
||||||
|
},
|
||||||
|
// changePie (problemData) {
|
||||||
|
// // 只显示特定的一些状态
|
||||||
|
// for (let k in problemData.statistic_info) {
|
||||||
|
// if (filtedStatus.indexOf(k) === -1) {
|
||||||
|
// delete problemData.statistic_info[k]
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// let acNum = problemData.accepted_number
|
||||||
|
// let data = [
|
||||||
|
// {name: 'WA', value: problemData.submission_number - acNum},
|
||||||
|
// {name: 'AC', value: acNum}
|
||||||
|
// ]
|
||||||
|
// this.pie.series[0].data = data
|
||||||
|
// // 只把大图的AC selected下,这里需要做一下deepcopy
|
||||||
|
// let data2 = JSON.parse(JSON.stringify(data))
|
||||||
|
// data2[1].selected = true
|
||||||
|
// this.largePie.series[1].data = data2
|
||||||
|
|
||||||
|
// // 根据结果设置legend,没有提交过的legend不显示
|
||||||
|
// let legend = Object.keys(problemData.statistic_info).map(ele => JUDGE_STATUS[ele].short)
|
||||||
|
// if (legend.length === 0) {
|
||||||
|
// legend.push('AC', 'WA')
|
||||||
|
// }
|
||||||
|
// this.largePie.legend.data = legend
|
||||||
|
|
||||||
|
// // 把ac的数据提取出来放在最后
|
||||||
|
// let acCount = problemData.statistic_info['0']
|
||||||
|
// delete problemData.statistic_info['0']
|
||||||
|
|
||||||
|
// let largePieData = []
|
||||||
|
// Object.keys(problemData.statistic_info).forEach(ele => {
|
||||||
|
// largePieData.push({name: JUDGE_STATUS[ele].short, value: problemData.statistic_info[ele]})
|
||||||
|
// })
|
||||||
|
// largePieData.push({name: 'AC', value: acCount})
|
||||||
|
// this.largePie.series[0].data = largePieData
|
||||||
|
// },
|
||||||
|
handleRoute(route) {
|
||||||
|
this.$router.push(route);
|
||||||
|
},
|
||||||
|
onChangeLang(newLang) {
|
||||||
|
if (this.problem.template[newLang]) {
|
||||||
|
if (this.code.trim() === "") {
|
||||||
|
this.code = this.problem.template[newLang];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.language = newLang;
|
||||||
|
},
|
||||||
|
onChangeTheme(newTheme) {
|
||||||
|
this.theme = newTheme;
|
||||||
|
},
|
||||||
|
onResetToTemplate() {
|
||||||
|
this.$confirm("你是否确定要重置你的代码?", "提示", {
|
||||||
|
cancelButtonText: "取消",
|
||||||
|
confirmButtonText: "确定",
|
||||||
|
type: "warning",
|
||||||
|
})
|
||||||
|
.then(() => {
|
||||||
|
let template = this.problem.template;
|
||||||
|
if (template && template[this.language]) {
|
||||||
|
this.code = template[this.language];
|
||||||
|
} else {
|
||||||
|
this.code = "";
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(() => {});
|
||||||
|
},
|
||||||
|
checkSubmissionStatus() {
|
||||||
|
// 使用setTimeout避免一些问题
|
||||||
|
if (this.refreshStatus) {
|
||||||
|
// 如果之前的提交状态检查还没有停止,则停止,否则将会失去timeout的引用造成无限请求
|
||||||
|
clearTimeout(this.refreshStatus);
|
||||||
|
}
|
||||||
|
const checkStatus = () => {
|
||||||
|
let id = this.submissionId;
|
||||||
|
api.getSubmission(id).then(
|
||||||
|
(res) => {
|
||||||
|
this.result = res.data.data;
|
||||||
|
if (Object.keys(res.data.data.statistic_info).length !== 0) {
|
||||||
|
this.submitting = false;
|
||||||
|
this.submitted = false;
|
||||||
|
clearTimeout(this.refreshStatus);
|
||||||
|
this.init();
|
||||||
|
} else {
|
||||||
|
this.refreshStatus = setTimeout(checkStatus, 2000);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
(res) => {
|
||||||
|
this.submitting = false;
|
||||||
|
clearTimeout(this.refreshStatus);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
};
|
||||||
|
this.refreshStatus = setTimeout(checkStatus, 2000);
|
||||||
|
},
|
||||||
|
submitCode() {
|
||||||
|
if (this.code.trim() === "") {
|
||||||
|
this.$error("m.Code_can_not_be_empty");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.submissionId = "";
|
||||||
|
this.result = { result: 9 };
|
||||||
|
this.submitting = true;
|
||||||
|
let data = {
|
||||||
|
problem_id: this.problem.id,
|
||||||
|
language: this.language,
|
||||||
|
code: this.code,
|
||||||
|
contest_id: this.contestID,
|
||||||
|
};
|
||||||
|
if (this.captchaRequired) {
|
||||||
|
data.captcha = this.captchaCode;
|
||||||
|
}
|
||||||
|
const submitFunc = (data, detailsVisible) => {
|
||||||
|
this.statusVisible = true;
|
||||||
|
api.submitCode(data).then(
|
||||||
|
(res) => {
|
||||||
|
this.submissionId = res.data.data && res.data.data.submission_id;
|
||||||
|
// 定时检查状态
|
||||||
|
this.submitting = false;
|
||||||
|
this.submissionExists = true;
|
||||||
|
if (!detailsVisible) {
|
||||||
|
this.$Modal.success({
|
||||||
|
title: "Success",
|
||||||
|
content: "Submit_code_successfully",
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.submitted = true;
|
||||||
|
this.checkSubmissionStatus();
|
||||||
|
},
|
||||||
|
(res) => {
|
||||||
|
this.getCaptchaSrc();
|
||||||
|
if (res.data.data.startsWith("Captcha is required")) {
|
||||||
|
this.captchaRequired = true;
|
||||||
|
}
|
||||||
|
this.submitting = false;
|
||||||
|
this.statusVisible = false;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
if (this.contestRuleType === "OI" && !this.OIContestRealTimePermission) {
|
||||||
|
if (this.submissionExists) {
|
||||||
|
this.$Modal.confirm({
|
||||||
|
title: "",
|
||||||
|
content:
|
||||||
|
"<h3>" +
|
||||||
|
"You_have_submission_in_this_problem_sure_to_cover_it" +
|
||||||
|
"<h3>",
|
||||||
|
onOk: () => {
|
||||||
|
// 暂时解决对话框与后面提示对话框冲突的问题(否则一闪而过)
|
||||||
|
setTimeout(() => {
|
||||||
|
submitFunc(data, false);
|
||||||
|
}, 1000);
|
||||||
|
},
|
||||||
|
onCancel: () => {
|
||||||
|
this.submitting = false;
|
||||||
|
},
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
submitFunc(data, false);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
submitFunc(data, true);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onCopy(event) {
|
||||||
|
mMessage.success('Sample copied successfully');
|
||||||
|
},
|
||||||
|
onCopyError(e) {
|
||||||
|
mMessage.success('Sample copy failed');
|
||||||
|
},
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
...mapGetters([
|
||||||
|
"problemSubmitDisabled",
|
||||||
|
"contestRuleType",
|
||||||
|
"OIContestRealTimePermission",
|
||||||
|
"contestStatus",
|
||||||
|
]),
|
||||||
|
contest() {
|
||||||
|
return this.$store.state.contest.contest;
|
||||||
|
},
|
||||||
|
contestEnded() {
|
||||||
|
return this.contestStatus === CONTEST_STATUS.ENDED;
|
||||||
|
},
|
||||||
|
submissionStatus() {
|
||||||
|
return {
|
||||||
|
text: JUDGE_STATUS[this.result.result]["name"],
|
||||||
|
color: JUDGE_STATUS[this.result.result]["color"],
|
||||||
|
};
|
||||||
|
},
|
||||||
|
submissionRoute() {
|
||||||
|
if (this.contestID) {
|
||||||
|
return {
|
||||||
|
name: "contest-submission-list",
|
||||||
|
query: { problemID: this.problemID },
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
return {
|
||||||
|
name: "submission-list",
|
||||||
|
query: { problemID: this.problemID },
|
||||||
|
};
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
beforeRouteLeave(to, from, next) {
|
||||||
|
// 防止切换组件后仍然不断请求
|
||||||
|
clearInterval(this.refreshStatus);
|
||||||
|
|
||||||
|
this.$store.commit("changeContestItemVisible", { menu: true });
|
||||||
|
storage.set(buildProblemCodeKey(this.problem._id, from.params.contestID), {
|
||||||
|
code: this.code,
|
||||||
|
language: this.language,
|
||||||
|
theme: this.theme,
|
||||||
|
});
|
||||||
|
next();
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
$route() {
|
||||||
|
this.init();
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
#problem-main {
|
||||||
|
flex: auto;
|
||||||
|
}
|
||||||
|
.problem-menu{
|
||||||
|
float: right;
|
||||||
|
}
|
||||||
|
|
||||||
|
.problem-menu span{
|
||||||
|
margin-left: 10px;
|
||||||
|
}
|
||||||
|
.el-link{
|
||||||
|
font-size: 16px!important;
|
||||||
|
}
|
||||||
|
.question-intr {
|
||||||
|
margin-top: 30px;
|
||||||
|
border-radius: 4px;
|
||||||
|
border: 1px solid #ddd;
|
||||||
|
border-left: 2px solid #3498db;
|
||||||
|
background: #fafafa;
|
||||||
|
padding: 10px;
|
||||||
|
line-height: 1.8;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
@media screen and (min-width: 768px) {
|
||||||
|
.problem-detail {
|
||||||
|
height: 672px;
|
||||||
|
overflow-y: auto;
|
||||||
|
}
|
||||||
|
.problem-menu span{
|
||||||
|
margin-left: 20px;
|
||||||
|
}
|
||||||
|
.question-intr{
|
||||||
|
margin-top: 5px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.submit-detail{
|
||||||
|
height:100%
|
||||||
|
}
|
||||||
|
/deep/ .el-card__header {
|
||||||
|
border-bottom: 0px;
|
||||||
|
padding-bottom: 0px;
|
||||||
|
}
|
||||||
|
#right-column {
|
||||||
|
flex: none;
|
||||||
|
width: 220px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#problem-content {
|
||||||
|
margin-top: -50px;
|
||||||
|
}
|
||||||
|
#problem-content .title {
|
||||||
|
font-size: 20px;
|
||||||
|
font-weight: 400;
|
||||||
|
margin: 25px 0 8px 0;
|
||||||
|
color: #3091f2;
|
||||||
|
}
|
||||||
|
#problem-content .copy {
|
||||||
|
padding-left: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
p.content {
|
||||||
|
margin-left: 25px;
|
||||||
|
margin-right: 20px;
|
||||||
|
font-size: 15px;
|
||||||
|
}
|
||||||
|
.flex-container {
|
||||||
|
display: flex;
|
||||||
|
width: 100%;
|
||||||
|
max-width: 100%;
|
||||||
|
justify-content: space-around;
|
||||||
|
align-items: flex-start;
|
||||||
|
flex-flow: row nowrap;
|
||||||
|
}
|
||||||
|
.sample {
|
||||||
|
align-items: stretch;
|
||||||
|
}
|
||||||
|
.sample-input,
|
||||||
|
.sample-output {
|
||||||
|
width: 50%;
|
||||||
|
flex: 1 1 auto;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
margin-right: 5%;
|
||||||
|
}
|
||||||
|
.sample pre {
|
||||||
|
flex: 1 1 auto;
|
||||||
|
align-self: stretch;
|
||||||
|
border-style: solid;
|
||||||
|
background: transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* #submit-code {
|
||||||
|
margin-top: 20px;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
} */
|
||||||
|
#submit-code .status {
|
||||||
|
float: left;
|
||||||
|
}
|
||||||
|
#submit-code .status span {
|
||||||
|
margin-right: 10px;
|
||||||
|
margin-left: 10px;
|
||||||
|
}
|
||||||
|
.captcha-container {
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
.captcha-container .captcha-code {
|
||||||
|
width: auto;
|
||||||
|
margin-top: -20px;
|
||||||
|
margin-left: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fl-right {
|
||||||
|
float: right;
|
||||||
|
}
|
||||||
|
/deep/.el-dialog__body {
|
||||||
|
padding: 10px 10px!important;
|
||||||
|
}
|
||||||
|
#pieChart .echarts {
|
||||||
|
height: 250px;
|
||||||
|
width: 210px;
|
||||||
|
}
|
||||||
|
#pieChart #detail {
|
||||||
|
position: absolute;
|
||||||
|
right: 10px;
|
||||||
|
top: 10px;
|
||||||
|
}
|
||||||
|
/deep/.echarts {
|
||||||
|
width: 350px;
|
||||||
|
height: 350px;
|
||||||
|
}
|
||||||
|
#pieChart-detail {
|
||||||
|
/* margin-top: 20px; */
|
||||||
|
height: 350px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
|
@ -16,7 +16,7 @@
|
||||||
>
|
>
|
||||||
<span class="el-dropdown-link">
|
<span class="el-dropdown-link">
|
||||||
{{query.difficulty === '' ? 'Difficulty' : query.difficulty}}
|
{{query.difficulty === '' ? 'Difficulty' : query.difficulty}}
|
||||||
<i class="el-icon-arrow-down el-icon--right"></i>
|
<i class="el-icon-caret-bottom"></i>
|
||||||
</span>
|
</span>
|
||||||
<el-dropdown-menu slot="dropdown">
|
<el-dropdown-menu slot="dropdown">
|
||||||
<el-dropdown-item command="All">All</el-dropdown-item>
|
<el-dropdown-item command="All">All</el-dropdown-item>
|
||||||
|
@ -37,9 +37,24 @@
|
||||||
@cell-mouseenter="cellHover"
|
@cell-mouseenter="cellHover"
|
||||||
:data="problemList">
|
:data="problemList">
|
||||||
<vxe-table-column field="pid" title="Problem ID" width="100"></vxe-table-column>
|
<vxe-table-column field="pid" title="Problem ID" width="100"></vxe-table-column>
|
||||||
<vxe-table-column field="title" title="Title" width="300" type="html"></vxe-table-column>
|
|
||||||
<vxe-table-column field="level" title="Level" width="150" type="html"></vxe-table-column>
|
<vxe-table-column field="title" title="Title" width="300">
|
||||||
<vxe-table-column field="tag" title="Tag" width="250" type="html"></vxe-table-column>
|
<template v-slot="{ row }">
|
||||||
|
<a :href="getProblemUri(row.pid)" style="color:rgb(87, 163, 243);">{{row.title}}</a>
|
||||||
|
</template>
|
||||||
|
</vxe-table-column>
|
||||||
|
|
||||||
|
<vxe-table-column field="level" title="Level" width="150">
|
||||||
|
<template v-slot="{ row }">
|
||||||
|
<span :class="getLevelColor(row.level)">{{PROBLEM_LEVEL[row.level].name}}</span>
|
||||||
|
</template>
|
||||||
|
</vxe-table-column>
|
||||||
|
|
||||||
|
<vxe-table-column field="tag" title="Tag" width="250" type="html">
|
||||||
|
<template v-slot="{ row }">
|
||||||
|
<span class="el-tag el-tag--medium el-tag--light is-hit" style="margin-right: 7px;" v-for="tag in row.tags" :key="tag">{{tag}}</span>
|
||||||
|
</template>
|
||||||
|
</vxe-table-column>
|
||||||
<vxe-table-column field="total" title="Total" width="100"></vxe-table-column>
|
<vxe-table-column field="total" title="Total" width="100"></vxe-table-column>
|
||||||
<vxe-table-column field="ACRate" title="AC Rate" width="100"></vxe-table-column>
|
<vxe-table-column field="ACRate" title="AC Rate" width="100"></vxe-table-column>
|
||||||
</vxe-table>
|
</vxe-table>
|
||||||
|
@ -51,68 +66,12 @@
|
||||||
<el-col :sm="24" :md="6" :lg="6">
|
<el-col :sm="24" :md="6" :lg="6">
|
||||||
<el-card style="text-align:center">
|
<el-card style="text-align:center">
|
||||||
<span class="panel-title" >题目</span>
|
<span class="panel-title" >题目</span>
|
||||||
<el-row>
|
<el-row v-for="record in problemRecord" :key="record">
|
||||||
<el-col :xs="5" :sm="4" :md="6" :lg="4" style="margin-top: 10px;">
|
<el-col :xs="5" :sm="4" :md="6" :lg="4" style="margin-top: 10px;">
|
||||||
<el-tag type="success" effect="dark" size="small">AC</el-tag>
|
<el-tag effect="dark" size="small" :color="JUDGE_STATUS[record.status].rgb">{{JUDGE_STATUS[record.status].short}}</el-tag>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :xs="19" :sm="20" :md="18" :lg="20" >
|
<el-col :xs="19" :sm="20" :md="18" :lg="20" >
|
||||||
<el-progress :text-inside="true" :stroke-width="20" :percentage="70" status="success"></el-progress>
|
<el-progress :text-inside="true" :stroke-width="20" :percentage="record.count" :color="JUDGE_STATUS[record.status].rgb"></el-progress>
|
||||||
</el-col>
|
|
||||||
</el-row>
|
|
||||||
<el-row>
|
|
||||||
<el-col :xs="5" :sm="4" :md="6" :lg="4" style="margin-top: 10px;">
|
|
||||||
<el-tag type="danger" effect="dark" size="small">WA</el-tag>
|
|
||||||
</el-col>
|
|
||||||
<el-col :xs="19" :sm="20" :md="18" :lg="20" >
|
|
||||||
<el-progress :text-inside="true" :stroke-width="20" :percentage="70" status="exception"></el-progress>
|
|
||||||
</el-col>
|
|
||||||
</el-row>
|
|
||||||
<el-row>
|
|
||||||
<el-col :xs="5" :sm="4" :md="6" :lg="4" style="margin-top: 10px;">
|
|
||||||
<el-tag type="danger" effect="dark" size="small">MLE</el-tag>
|
|
||||||
</el-col>
|
|
||||||
<el-col :xs="19" :sm="20" :md="18" :lg="20" >
|
|
||||||
<el-progress :text-inside="true" :stroke-width="20" :percentage="70" status="exception"></el-progress>
|
|
||||||
</el-col>
|
|
||||||
</el-row>
|
|
||||||
<el-row>
|
|
||||||
<el-col :xs="5" :sm="4" :md="6" :lg="4" style="margin-top: 10px;">
|
|
||||||
<el-tag type="danger" effect="dark" size="small">TLE</el-tag>
|
|
||||||
</el-col>
|
|
||||||
<el-col :xs="19" :sm="20" :md="18" :lg="20" >
|
|
||||||
<el-progress :text-inside="true" :stroke-width="20" :percentage="70" status="exception"></el-progress>
|
|
||||||
</el-col>
|
|
||||||
</el-row>
|
|
||||||
<el-row>
|
|
||||||
<el-col :xs="5" :sm="4" :md="6" :lg="4" style="margin-top: 10px;">
|
|
||||||
<el-tag type="danger" effect="dark" size="small">RTE</el-tag>
|
|
||||||
</el-col>
|
|
||||||
<el-col :xs="19" :sm="20" :md="18" :lg="20" >
|
|
||||||
<el-progress :text-inside="true" :stroke-width="20" :percentage="70" status="exception"></el-progress>
|
|
||||||
</el-col>
|
|
||||||
</el-row>
|
|
||||||
<el-row>
|
|
||||||
<el-col :xs="5" :sm="4" :md="6" :lg="4" style="margin-top: 10px;">
|
|
||||||
<el-tag type="warning" effect="dark" size="small">PE</el-tag>
|
|
||||||
</el-col>
|
|
||||||
<el-col :xs="19" :sm="20" :md="18" :lg="20" >
|
|
||||||
<el-progress :text-inside="true" :stroke-width="20" :percentage="70" status="warning"></el-progress>
|
|
||||||
</el-col>
|
|
||||||
</el-row>
|
|
||||||
<el-row>
|
|
||||||
<el-col :xs="5" :sm="4" :md="6" :lg="4" style="margin-top: 10px;">
|
|
||||||
<el-tag type="warning" effect="dark" size="small">CE</el-tag>
|
|
||||||
</el-col>
|
|
||||||
<el-col :xs="19" :sm="20" :md="18" :lg="20" >
|
|
||||||
<el-progress :text-inside="true" :stroke-width="20" :percentage="70" status="warning"></el-progress>
|
|
||||||
</el-col>
|
|
||||||
</el-row>
|
|
||||||
<el-row>
|
|
||||||
<el-col :xs="5" :sm="4" :md="6" :lg="4" style="margin-top: 10px;">
|
|
||||||
<el-tag type="info" effect="dark" size="small">SE</el-tag>
|
|
||||||
</el-col>
|
|
||||||
<el-col :xs="19" :sm="20" :md="18" :lg="20" >
|
|
||||||
<el-progress :text-inside="true" :stroke-width="20" :percentage="70" :color="SEcolor"></el-progress>
|
|
||||||
</el-col>
|
</el-col>
|
||||||
</el-row>
|
</el-row>
|
||||||
</el-card>
|
</el-card>
|
||||||
|
@ -140,6 +99,7 @@
|
||||||
import { mapGetters } from 'vuex'
|
import { mapGetters } from 'vuex'
|
||||||
import api from '@/common/api'
|
import api from '@/common/api'
|
||||||
import utils from '@/common/utils'
|
import utils from '@/common/utils'
|
||||||
|
import { PROBLEM_LEVEL,JUDGE_STATUS } from '@/common/constants'
|
||||||
import Pagination from '@/components/common/Pagination'
|
import Pagination from '@/components/common/Pagination'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
|
@ -150,41 +110,33 @@
|
||||||
data () {
|
data () {
|
||||||
return {
|
return {
|
||||||
SEcolor:'#909399',
|
SEcolor:'#909399',
|
||||||
|
PROBLEM_LEVEL:'',
|
||||||
|
JUDGE_STATUS:'',
|
||||||
tagList: [{
|
tagList: [{
|
||||||
id:'12',
|
id:'12',
|
||||||
name:'模拟题'
|
name:'模拟题'
|
||||||
},
|
}],
|
||||||
{
|
problemRecord:[
|
||||||
id:'13',
|
{status:'0',count:'70'},
|
||||||
name:'模拟题'
|
{status:'-1',count:'70'},
|
||||||
},
|
{status:'3',count:'70'},
|
||||||
{
|
{status:'1',count:'70'},
|
||||||
id:'14',
|
{status:'4',count:'70'},
|
||||||
name:'模拟题'
|
{status:'-3',count:'70'},
|
||||||
},
|
{status:'-2',count:'70'},
|
||||||
{
|
{status:'5',count:'70'},
|
||||||
id:'15',
|
],
|
||||||
name:'模拟题'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id:'16',
|
|
||||||
name:'模拟题'
|
|
||||||
},],
|
|
||||||
problemList: [
|
problemList: [
|
||||||
{pid:'1000',title:'<a href="https://github.com/x-extends/vxe-table" class="title-link">测试标题</a>',level:'<span class="el-tag el-tag--dark el-tag--small">Easy</span>',
|
{pid:'1000',title:'测试标题',level:0,
|
||||||
tag:'<span class="el-tag el-tag--medium el-tag--light is-hit" style="margin-right: 7px;">简单题</span><span class="el-tag el-tag--medium el-tag--light is-hit" style="margin-right: 7px;">简单题</span>',
|
tags:['简单题','模拟题'],
|
||||||
total:'10000',ACRate:'59.12%'
|
total:'10000',ACRate:'59.12%'
|
||||||
},
|
},
|
||||||
{pid:'1000',title:'<a href="https://github.com/x-extends/vxe-table" class="title-link">测试标题</a>',level:'<span class="el-tag el-tag--dark el-tag--small">Easy</span>',
|
{pid:'1000',title:'测试标题',level:1,
|
||||||
tag:'<span class="el-tag el-tag--medium el-tag--light is-hit" style="margin-right: 7px;">简单题</span><span class="el-tag el-tag--medium el-tag--light is-hit" style="margin-right: 7px;">简单题</span>',
|
tags:['简单题','模拟题'],
|
||||||
total:'10000',ACRate:'59.12%'
|
total:'10000',ACRate:'59.12%'
|
||||||
},
|
},
|
||||||
{pid:'1000',title:'<a href="https://github.com/x-extends/vxe-table" class="title-link">测试标题</a>',level:'<span class="el-tag el-tag--dark el-tag--small">Easy</span>',
|
{pid:'1000',title:'测试标题',level:2,
|
||||||
tag:'<span class="el-tag el-tag--medium el-tag--light is-hit" style="margin-right: 7px;">简单题</span><span class="el-tag el-tag--medium el-tag--light is-hit" style="margin-right: 7px;">简单题</span>',
|
tags:['简单题','模拟题'],
|
||||||
total:'10000',ACRate:'59.12%'
|
|
||||||
},
|
|
||||||
{pid:'1000',title:'<a href="https://github.com/x-extends/vxe-table" class="title-link">测试标题</a>',level:'<span class="el-tag el-tag--dark el-tag--small">Easy</span>',
|
|
||||||
tag:'<span class="el-tag el-tag--medium el-tag--light is-hit" style="margin-right: 7px;">简单题</span><span class="el-tag el-tag--medium el-tag--light is-hit" style="margin-right: 7px;">简单题</span>',
|
|
||||||
total:'10000',ACRate:'59.12%'
|
total:'10000',ACRate:'59.12%'
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
@ -210,7 +162,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
mounted () {
|
mounted () {
|
||||||
this.init()
|
this.init();
|
||||||
|
this.PROBLEM_LEVEL = Object.assign({}, PROBLEM_LEVEL);
|
||||||
|
this.JUDGE_STATUS = Object.assign({}, JUDGE_STATUS)
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
init (simulate = false) {
|
init (simulate = false) {
|
||||||
|
@ -279,6 +233,12 @@
|
||||||
this.$success('Good Luck')
|
this.$success('Good Luck')
|
||||||
this.$router.push({name: 'problem-details', params: {problemID: res.data.data}})
|
this.$router.push({name: 'problem-details', params: {problemID: res.data.data}})
|
||||||
})
|
})
|
||||||
|
},
|
||||||
|
getProblemUri(pid){
|
||||||
|
return '/problem/'+pid;
|
||||||
|
},
|
||||||
|
getLevelColor(level){
|
||||||
|
return 'el-tag el-tag--small status-'+PROBLEM_LEVEL[level].color;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
|
@ -305,7 +265,9 @@
|
||||||
font-size: 21px;
|
font-size: 21px;
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
}
|
}
|
||||||
|
/deep/.el-tag--dark {
|
||||||
|
border-color: #d9ecff;
|
||||||
|
}
|
||||||
/deep/.tag-btn {
|
/deep/.tag-btn {
|
||||||
margin-left: 4px!important;
|
margin-left: 4px!important;
|
||||||
margin-top: 4px;
|
margin-top: 4px;
|
||||||
|
@ -327,13 +289,6 @@
|
||||||
margin-top:5px;
|
margin-top:5px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.panel-title{
|
|
||||||
font-size: 21px;
|
|
||||||
font-weight: 500;
|
|
||||||
padding-top: 10px;
|
|
||||||
padding-bottom: 20px;
|
|
||||||
line-height: 30px;
|
|
||||||
}
|
|
||||||
ul{
|
ul{
|
||||||
float: right;
|
float: right;
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,120 @@
|
||||||
|
const pieColorMap = {
|
||||||
|
'AC': {color: '#19be6b'},
|
||||||
|
'WA': {color: '#ed3f14'},
|
||||||
|
'TLE': {color: '#ff9300'},
|
||||||
|
'MLE': {color: '#f7de00'},
|
||||||
|
'RE': {color: '#ff6104'},
|
||||||
|
'CE': {color: '#80848f'},
|
||||||
|
'PAC': {color: '#2d8cf0'}
|
||||||
|
}
|
||||||
|
|
||||||
|
function getItemColor (obj) {
|
||||||
|
return pieColorMap[obj.name].color
|
||||||
|
}
|
||||||
|
|
||||||
|
const pie = {
|
||||||
|
tooltip: {
|
||||||
|
trigger: 'item',
|
||||||
|
formatter: '{a} <br/>{b}: {c} ({d}%)'
|
||||||
|
},
|
||||||
|
legend: {
|
||||||
|
left: 'center',
|
||||||
|
top: '10',
|
||||||
|
orient: 'horizontal',
|
||||||
|
data: ['AC', 'WA']
|
||||||
|
},
|
||||||
|
series: [
|
||||||
|
{
|
||||||
|
name: 'Summary',
|
||||||
|
type: 'pie',
|
||||||
|
radius: '60%',
|
||||||
|
center: ['53%', '55%'],
|
||||||
|
itemStyle: {
|
||||||
|
normal: {color: getItemColor}
|
||||||
|
},
|
||||||
|
data: [
|
||||||
|
{value: 0, name: 'WA'},
|
||||||
|
{value: 0, name: 'AC'}
|
||||||
|
],
|
||||||
|
label: {
|
||||||
|
normal: {
|
||||||
|
position: 'inner',
|
||||||
|
show: true,
|
||||||
|
formatter: '{b}: {c}\n {d}%',
|
||||||
|
textStyle: {
|
||||||
|
fontWeight: 'bold'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
const largePie = {
|
||||||
|
tooltip: {
|
||||||
|
trigger: 'item',
|
||||||
|
formatter: '{a} <br/>{b}: {c} ({d}%)'
|
||||||
|
},
|
||||||
|
legend: {
|
||||||
|
left: 'center',
|
||||||
|
top:0,
|
||||||
|
orient:
|
||||||
|
'horizontal',
|
||||||
|
itemGap:
|
||||||
|
10,
|
||||||
|
data:
|
||||||
|
['AC', 'RE', 'WA', 'TLE', 'PAC', 'MLE']
|
||||||
|
},
|
||||||
|
series: [
|
||||||
|
{
|
||||||
|
name: 'Detail',
|
||||||
|
type: 'pie',
|
||||||
|
radius: ['50%', '65%'],
|
||||||
|
center: ['50%', '55%'],
|
||||||
|
itemStyle: {
|
||||||
|
normal: {color: getItemColor}
|
||||||
|
},
|
||||||
|
data: [
|
||||||
|
{value: 0, name: 'RE'},
|
||||||
|
{value: 0, name: 'WA'},
|
||||||
|
{value: 0, name: 'TLE'},
|
||||||
|
{value: 0, name: 'AC'},
|
||||||
|
{value: 0, name: 'MLE'},
|
||||||
|
{value: 0, name: 'PAC'}
|
||||||
|
],
|
||||||
|
label: {
|
||||||
|
normal: {
|
||||||
|
formatter: '{b}: \n{d}%\n {c}',
|
||||||
|
textStyle:{
|
||||||
|
fontSize:10,
|
||||||
|
fontWeight: 'bold'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
labelLine: {
|
||||||
|
normal: {}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Summary',
|
||||||
|
type: 'pie',
|
||||||
|
radius: '35%',
|
||||||
|
center: ['52%', '55%'],
|
||||||
|
itemStyle: {
|
||||||
|
normal: {color: getItemColor}
|
||||||
|
},
|
||||||
|
data: [
|
||||||
|
{value: 0, name: 'WA'},
|
||||||
|
{value: 0, name: 'AC', selected: true}
|
||||||
|
],
|
||||||
|
label: {
|
||||||
|
normal: {
|
||||||
|
position: 'inner',
|
||||||
|
formatter: '{b}: {c}\n {d}%'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
export { pie, largePie }
|
|
@ -0,0 +1,167 @@
|
||||||
|
<template>
|
||||||
|
<el-row type="flex" justify="space-around">
|
||||||
|
<el-col :span="22">
|
||||||
|
<el-card :padding="10">
|
||||||
|
<div slot="header"><span class="panel-title">ACM Ranklist</span></div>
|
||||||
|
<div class="echarts">
|
||||||
|
<ECharts :options="options" ref="chart" auto-resize></ECharts>
|
||||||
|
</div>
|
||||||
|
</el-card>
|
||||||
|
<vxe-table :data="dataRank" :loading="loadingTable" align="center" highlight-hover-row style="font-weight: 500;">
|
||||||
|
<vxe-table-column type="seq" width="100"></vxe-table-column>
|
||||||
|
<vxe-table-column field="username" title="User" width="197">
|
||||||
|
<template v-slot="{ row }">
|
||||||
|
<a :href="getInfoByUsername(row.username)" style="color:rgb(87, 163, 243);">{{row.username}}</a>
|
||||||
|
</template>
|
||||||
|
</vxe-table-column>
|
||||||
|
<vxe-table-column field="nickname" title="Nickname" width="197"></vxe-table-column>
|
||||||
|
<vxe-table-column field="signature" title="Mood" width="197"></vxe-table-column>
|
||||||
|
<vxe-table-column field="ac" title="AC" width="197"></vxe-table-column>
|
||||||
|
<vxe-table-column field="total" title="Total" width="197"></vxe-table-column>
|
||||||
|
<vxe-table-column field="rating" title="Rating" width="197"></vxe-table-column>
|
||||||
|
</vxe-table>
|
||||||
|
|
||||||
|
<Pagination :total="total" :page-size.sync="limit" :current.sync="page"
|
||||||
|
@on-change="getRankData" show-sizer
|
||||||
|
@on-page-size-change="getRankData(1)"></Pagination>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import api from '@/common/api'
|
||||||
|
import Pagination from '@/components/common/Pagination'
|
||||||
|
import utils from '@/common/utils'
|
||||||
|
import { RULE_TYPE } from '@/common/constants'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'acm-rank',
|
||||||
|
components: {
|
||||||
|
Pagination
|
||||||
|
},
|
||||||
|
data () {
|
||||||
|
return {
|
||||||
|
page: 1,
|
||||||
|
limit: 30,
|
||||||
|
total: 0,
|
||||||
|
loadingTable: false,
|
||||||
|
dataRank: [
|
||||||
|
{username:'root',nickname:'Himit_ZH',signature:'Show me your code',ac:100,total:100,rating:'100%'},
|
||||||
|
{username:'root',nickname:'Himit_ZH',signature:'Show me your code',ac:100,total:100,rating:'100%'},
|
||||||
|
{username:'root',nickname:'Himit_ZH',signature:'Show me your code',ac:100,total:100,rating:'100%'},
|
||||||
|
|
||||||
|
],
|
||||||
|
options: {
|
||||||
|
tooltip: {
|
||||||
|
trigger: 'axis'
|
||||||
|
},
|
||||||
|
legend: {
|
||||||
|
data: ['AC', 'Total']
|
||||||
|
},
|
||||||
|
grid: {
|
||||||
|
x: '3%',
|
||||||
|
x2: '3%'
|
||||||
|
},
|
||||||
|
toolbox: {
|
||||||
|
show: true,
|
||||||
|
feature: {
|
||||||
|
dataView: {show: true, readOnly: true},
|
||||||
|
magicType: {show: true, type: ['line', 'bar', 'stack']},
|
||||||
|
saveAsImage: {show: true}
|
||||||
|
},
|
||||||
|
right: '5%',
|
||||||
|
top:'5%'
|
||||||
|
},
|
||||||
|
calculable: true,
|
||||||
|
xAxis: [
|
||||||
|
{
|
||||||
|
type: 'category',
|
||||||
|
data: ['root'],
|
||||||
|
axisLabel: {
|
||||||
|
interval: 0,
|
||||||
|
showMinLabel: true,
|
||||||
|
showMaxLabel: true,
|
||||||
|
align: 'center',
|
||||||
|
formatter: (value, index) => {
|
||||||
|
return utils.breakLongWords(value, 10)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
yAxis: [
|
||||||
|
{
|
||||||
|
type: 'value'
|
||||||
|
}
|
||||||
|
],
|
||||||
|
series: [
|
||||||
|
{
|
||||||
|
name: 'AC',
|
||||||
|
type: 'bar',
|
||||||
|
data: [0],
|
||||||
|
markPoint: {
|
||||||
|
data: [
|
||||||
|
{type: 'max', name: 'max'}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Total',
|
||||||
|
type: 'bar',
|
||||||
|
data: [0],
|
||||||
|
markPoint: {
|
||||||
|
data: [
|
||||||
|
{type: 'max', name: 'max'}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
mounted () {
|
||||||
|
// this.getRankData(1)
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
getRankData (page) {
|
||||||
|
let offset = (page - 1) * this.limit
|
||||||
|
let bar = this.$refs.chart
|
||||||
|
bar.showLoading({maskColor: 'rgba(250, 250, 250, 0.8)'})
|
||||||
|
this.loadingTable = true
|
||||||
|
api.getUserRank(offset, this.limit, RULE_TYPE.ACM).then(res => {
|
||||||
|
this.loadingTable = false
|
||||||
|
if (page === 1) {
|
||||||
|
this.changeCharts(res.data.data.results.slice(0, 10))
|
||||||
|
}
|
||||||
|
this.total = res.data.data.total
|
||||||
|
this.dataRank = res.data.data.results
|
||||||
|
bar.hideLoading()
|
||||||
|
}).catch(() => {
|
||||||
|
this.loadingTable = false
|
||||||
|
bar.hideLoading()
|
||||||
|
})
|
||||||
|
},
|
||||||
|
changeCharts (rankData) {
|
||||||
|
let [usernames, acData, totalData] = [[], [], []]
|
||||||
|
rankData.forEach(ele => {
|
||||||
|
usernames.push(ele.user.username)
|
||||||
|
acData.push(ele.accepted_number)
|
||||||
|
totalData.push(ele.submission_number)
|
||||||
|
})
|
||||||
|
this.options.xAxis[0].data = usernames
|
||||||
|
this.options.series[0].data = acData
|
||||||
|
this.options.series[1].data = totalData
|
||||||
|
},
|
||||||
|
getInfoByUsername(username){
|
||||||
|
return '/user-home/'+username;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.echarts {
|
||||||
|
margin: 0 auto;
|
||||||
|
width: 95%;
|
||||||
|
height: 400px;
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -0,0 +1,153 @@
|
||||||
|
<template>
|
||||||
|
<el-row type="flex" justify="space-around">
|
||||||
|
<el-col :span="22">
|
||||||
|
<el-card :padding="10">
|
||||||
|
<div slot="header"><span class="panel-title">OI Ranklist</span></div>
|
||||||
|
<div class="echarts">
|
||||||
|
<ECharts :options="options" ref="chart" auto-resize></ECharts>
|
||||||
|
</div>
|
||||||
|
</el-card>
|
||||||
|
<vxe-table :data="dataRank" :loading="loadingTable" align="center" highlight-hover-row style="font-weight: 500;">
|
||||||
|
<vxe-table-column type="seq" width="100"></vxe-table-column>
|
||||||
|
<vxe-table-column field="username" title="User" width="168">
|
||||||
|
<template v-slot="{ row }">
|
||||||
|
<a :href="getInfoByUsername(row.username)" style="color:rgb(87, 163, 243);">{{row.username}}</a>
|
||||||
|
</template>
|
||||||
|
</vxe-table-column>
|
||||||
|
<vxe-table-column field="nickname" title="Nickname" width="168"></vxe-table-column>
|
||||||
|
<vxe-table-column field="signature" title="Mood" width="173"></vxe-table-column>
|
||||||
|
<vxe-table-column field="score" title="Score" width="168"></vxe-table-column>
|
||||||
|
<vxe-table-column field="ac" title="AC" width="168"></vxe-table-column>
|
||||||
|
<vxe-table-column field="total" title="Total" width="168"></vxe-table-column>
|
||||||
|
<vxe-table-column field="rating" title="Rating" width="168"></vxe-table-column>
|
||||||
|
</vxe-table>
|
||||||
|
<Pagination :total="total" :page-size.sync="limit" :current.sync="page"
|
||||||
|
@on-change="getRankData"
|
||||||
|
show-sizer @on-page-size-change="getRankData(1)"></Pagination>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import api from '@/common/api'
|
||||||
|
import Pagination from '@/components/common/Pagination'
|
||||||
|
import utils from '@/common/utils'
|
||||||
|
import { RULE_TYPE } from '@/common/constants'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'acm-rank',
|
||||||
|
components: {
|
||||||
|
Pagination
|
||||||
|
},
|
||||||
|
data () {
|
||||||
|
return {
|
||||||
|
page: 1,
|
||||||
|
limit: 30,
|
||||||
|
total: 0,
|
||||||
|
dataRank: [
|
||||||
|
{username:'root',nickname:'Himit_ZH',signature:'Show me your code',score:10000,ac:100,total:100,rating:'100%'},
|
||||||
|
{username:'root',nickname:'Himit_ZH',signature:'Show me your code',score:10000,ac:100,total:100,rating:'100%'},
|
||||||
|
{username:'root',nickname:'Himit_ZH',signature:'Show me your code',score:10000,ac:100,total:100,rating:'100%'},
|
||||||
|
],
|
||||||
|
options: {
|
||||||
|
tooltip: {
|
||||||
|
trigger: 'axis'
|
||||||
|
},
|
||||||
|
legend: {
|
||||||
|
data: ['Score']
|
||||||
|
},
|
||||||
|
grid: {
|
||||||
|
x: '3%',
|
||||||
|
x2: '3%'
|
||||||
|
},
|
||||||
|
toolbox: {
|
||||||
|
show: true,
|
||||||
|
feature: {
|
||||||
|
dataView: {show: true, readOnly: true},
|
||||||
|
magicType: {show: true, type: ['line', 'bar']},
|
||||||
|
saveAsImage: {show: true}
|
||||||
|
},
|
||||||
|
right: '5%',
|
||||||
|
top:'5%'
|
||||||
|
},
|
||||||
|
calculable: true,
|
||||||
|
xAxis: [
|
||||||
|
{
|
||||||
|
type: 'category',
|
||||||
|
data: ['root'],
|
||||||
|
boundaryGap: true,
|
||||||
|
axisLabel: {
|
||||||
|
interval: 0,
|
||||||
|
showMinLabel: true,
|
||||||
|
showMaxLabel: true,
|
||||||
|
align: 'center',
|
||||||
|
formatter: (value, index) => {
|
||||||
|
return utils.breakLongWords(value, 14)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
axisTick: {
|
||||||
|
alignWithLabel: true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
yAxis: [
|
||||||
|
{
|
||||||
|
type: 'value'
|
||||||
|
}
|
||||||
|
],
|
||||||
|
series: [
|
||||||
|
{
|
||||||
|
name: 'Score',
|
||||||
|
type: 'bar',
|
||||||
|
data: [0],
|
||||||
|
barMaxWidth: '80',
|
||||||
|
markPoint: {
|
||||||
|
data: [
|
||||||
|
{type: 'max', name: 'max'}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
mounted () {
|
||||||
|
// this.getRankData(1)
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
getRankData (page) {
|
||||||
|
let offset = (page - 1) * this.limit
|
||||||
|
let bar = this.$refs.chart
|
||||||
|
bar.showLoading({maskColor: 'rgba(250, 250, 250, 0.8)'})
|
||||||
|
api.getUserRank(offset, this.limit, RULE_TYPE.OI).then(res => {
|
||||||
|
if (page === 1) {
|
||||||
|
this.changeCharts(res.data.data.results.slice(0, 10))
|
||||||
|
}
|
||||||
|
this.total = res.data.data.total
|
||||||
|
this.dataRank = res.data.data.results
|
||||||
|
bar.hideLoading()
|
||||||
|
})
|
||||||
|
},
|
||||||
|
changeCharts (rankData) {
|
||||||
|
let [usernames, scores] = [[], []]
|
||||||
|
rankData.forEach(ele => {
|
||||||
|
usernames.push(ele.user.username)
|
||||||
|
scores.push(ele.total_score)
|
||||||
|
})
|
||||||
|
this.options.xAxis[0].data = usernames
|
||||||
|
this.options.series[0].data = scores
|
||||||
|
},
|
||||||
|
getInfoByUsername(username){
|
||||||
|
return '/user-home/'+username;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.echarts {
|
||||||
|
margin: 0 auto;
|
||||||
|
width: 95%;
|
||||||
|
height: 400px;
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -0,0 +1,267 @@
|
||||||
|
<template>
|
||||||
|
<el-row type="flex" justify="space-around">
|
||||||
|
<el-col :span="22" id="status">
|
||||||
|
<el-alert :type="status.type" show-icon :closable="false" effect="dark" :class="getbackgroudColor(submission.data[0].status)"
|
||||||
|
style="padding: 18px;">
|
||||||
|
<template slot="title">
|
||||||
|
<span class="title">{{ status.statusName }}</span>
|
||||||
|
</template>
|
||||||
|
<template slot>
|
||||||
|
<div v-if="isCE" class="content">
|
||||||
|
<pre>{{ submission.data[0].err_info }}</pre>
|
||||||
|
</div>
|
||||||
|
<div v-else class="content">
|
||||||
|
<span class="span-row">Time: {{ submission.data[0].time }}</span>
|
||||||
|
<span class="span-row">Memory: {{ submission.data[0].memory }}</span>
|
||||||
|
<span class="span-row">Language: {{ submission.data[0].language }}</span>
|
||||||
|
<span class="span-row">Author: {{ submission.data[0].author }}</span>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</el-alert>
|
||||||
|
</el-col>
|
||||||
|
|
||||||
|
<el-col v-if="submission.data && !isCE" :span="22">
|
||||||
|
<vxe-table align="center" :data="submission.data" stripe style="padding-top: 13px;">
|
||||||
|
<vxe-table-column field="sid" title="ID" width="213"></vxe-table-column>
|
||||||
|
<vxe-table-column
|
||||||
|
field="stime"
|
||||||
|
title="Submit time"
|
||||||
|
width="213"
|
||||||
|
></vxe-table-column>
|
||||||
|
<vxe-table-column field="pid" title="Problem ID" width="213">
|
||||||
|
<template v-slot="{ row }">
|
||||||
|
<a
|
||||||
|
:href="getProblemUri(row.pid)"
|
||||||
|
style="color: rgb(87, 163, 243)"
|
||||||
|
>{{ row.pid }}</a
|
||||||
|
>
|
||||||
|
</template>
|
||||||
|
</vxe-table-column>
|
||||||
|
<vxe-table-column field="status" title="Status" width="213">
|
||||||
|
<template v-slot="{ row }">
|
||||||
|
<span :class="getStatusColor(row.status)">{{
|
||||||
|
JUDGE_STATUS[row.status].name
|
||||||
|
}}</span>
|
||||||
|
</template>
|
||||||
|
</vxe-table-column>
|
||||||
|
<vxe-table-column
|
||||||
|
field="time"
|
||||||
|
title="Time"
|
||||||
|
width="213"
|
||||||
|
></vxe-table-column>
|
||||||
|
<vxe-table-column
|
||||||
|
field="memory"
|
||||||
|
title="Memory"
|
||||||
|
width="213"
|
||||||
|
></vxe-table-column>
|
||||||
|
</vxe-table>
|
||||||
|
</el-col>
|
||||||
|
|
||||||
|
<el-col :span="22">
|
||||||
|
<Highlight
|
||||||
|
:code="submission.code"
|
||||||
|
:language="submission.language"
|
||||||
|
:border-color="status.color"
|
||||||
|
></Highlight>
|
||||||
|
</el-col>
|
||||||
|
<el-col v-if="submission.can_unshare" :span="22">
|
||||||
|
<div id="share-btn">
|
||||||
|
<el-button type="primary" icon="el-icon-document-copy" size="large" @click="doCopy">Copy</el-button>
|
||||||
|
<el-button
|
||||||
|
v-if="submission.shared"
|
||||||
|
type="warning"
|
||||||
|
size="large"
|
||||||
|
icon="el-icon-circle-close"
|
||||||
|
@click="shareSubmission(false)"
|
||||||
|
>
|
||||||
|
Unshared
|
||||||
|
</el-button>
|
||||||
|
<el-button
|
||||||
|
v-else
|
||||||
|
type="primary"
|
||||||
|
size="large"
|
||||||
|
icon="el-icon-share"
|
||||||
|
@click="shareSubmission(true)"
|
||||||
|
>
|
||||||
|
Shared
|
||||||
|
</el-button>
|
||||||
|
</div>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import api from "@/common/api";
|
||||||
|
import { JUDGE_STATUS } from "@/common/constants";
|
||||||
|
import utils from "@/common/utils";
|
||||||
|
import Highlight from "@/components/common/Highlight";
|
||||||
|
import mMessage from '@/common/message'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: "submissionDetails",
|
||||||
|
components: {
|
||||||
|
Highlight,
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
submission: {
|
||||||
|
code:
|
||||||
|
"import java.util.Scanner;\n\
|
||||||
|
public class Main{\n\
|
||||||
|
public static void main(String[] args){\n\
|
||||||
|
Scanner in=new Scanner(System.in);\n\
|
||||||
|
int a=in.nextInt();\n\
|
||||||
|
int b=in.nextInt();\n\
|
||||||
|
System.out.println((a+b)); \n\
|
||||||
|
}\n\
|
||||||
|
}",
|
||||||
|
data: [{
|
||||||
|
sid: 1000,
|
||||||
|
stime: "2020-08-08 16:00:00",
|
||||||
|
pid: "1001",
|
||||||
|
status: 0,
|
||||||
|
time: "4ms",
|
||||||
|
memory: "3MB",
|
||||||
|
language:'Java',
|
||||||
|
author: "Himit_ZH",
|
||||||
|
err_info:'CE错误',
|
||||||
|
}],
|
||||||
|
can_unshare:true,
|
||||||
|
shared:true
|
||||||
|
},
|
||||||
|
isConcat: false,
|
||||||
|
loading: false,
|
||||||
|
JUDGE_STATUS:'',
|
||||||
|
};
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
this.getSubmission();
|
||||||
|
this.JUDGE_STATUS = Object.assign({}, JUDGE_STATUS);
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
doCopy() {
|
||||||
|
this.$copyText(this.submission.code).then(function (e) {
|
||||||
|
mMessage.success('Code copied successfully');
|
||||||
|
}, function (e) {
|
||||||
|
mMessage.success('Code copy failed');
|
||||||
|
})
|
||||||
|
},
|
||||||
|
getProblemUri(pid) {
|
||||||
|
return "/problem/" + pid;
|
||||||
|
},
|
||||||
|
getStatusColor(status) {
|
||||||
|
return "el-tag el-tag--medium status-" + JUDGE_STATUS[status].color;
|
||||||
|
},
|
||||||
|
getbackgroudColor(status){
|
||||||
|
return "status-" + JUDGE_STATUS[status].color;
|
||||||
|
},
|
||||||
|
getSubmission() {
|
||||||
|
this.loading = true;
|
||||||
|
api.getSubmission(this.$route.params.id).then(
|
||||||
|
(res) => {
|
||||||
|
this.loading = false;
|
||||||
|
let data = res.data.data;
|
||||||
|
if (data.info && data.info.data && !this.isConcat) {
|
||||||
|
// score exist means the submission is OI problem submission
|
||||||
|
if (data.info.data[0].score !== undefined) {
|
||||||
|
this.isConcat = true;
|
||||||
|
const scoreColumn = {
|
||||||
|
title: this.$i18n.t("m.Score"),
|
||||||
|
align: "center",
|
||||||
|
key: "score",
|
||||||
|
};
|
||||||
|
this.columns.push(scoreColumn);
|
||||||
|
this.loadingTable = false;
|
||||||
|
}
|
||||||
|
if (this.isAdminRole) {
|
||||||
|
this.isConcat = true;
|
||||||
|
const adminColumn = [
|
||||||
|
{
|
||||||
|
title: this.$i18n.t("m.Real_Time"),
|
||||||
|
align: "center",
|
||||||
|
render: (h, params) => {
|
||||||
|
return h(
|
||||||
|
"span",
|
||||||
|
utils.submissionTimeFormat(params.row.real_time)
|
||||||
|
);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: this.$i18n.t("m.Signal"),
|
||||||
|
align: "center",
|
||||||
|
key: "signal",
|
||||||
|
},
|
||||||
|
];
|
||||||
|
this.columns = this.columns.concat(adminColumn);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.submission = data;
|
||||||
|
},
|
||||||
|
() => {
|
||||||
|
this.loading = false;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
},
|
||||||
|
shareSubmission(shared) {
|
||||||
|
let data = { id: this.submission.data[0].sid, shared: shared };
|
||||||
|
api.updateSubmission(data).then(
|
||||||
|
(res) => {
|
||||||
|
this.getSubmission();
|
||||||
|
this.$success(this.$i18n.t("m.Succeeded"));
|
||||||
|
},
|
||||||
|
() => {}
|
||||||
|
);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
status() {
|
||||||
|
return {
|
||||||
|
type: JUDGE_STATUS[this.submission.data[0].status].type,
|
||||||
|
statusName: JUDGE_STATUS[this.submission.data[0].status].name,
|
||||||
|
color: JUDGE_STATUS[this.submission.data[0].status].rgb,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
isCE() {
|
||||||
|
return this.submission.data[0].status === -2;
|
||||||
|
},
|
||||||
|
isAdminRole() {
|
||||||
|
return this.$store.getters.isAdminRole;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
#status .title {
|
||||||
|
font-size: 20px;
|
||||||
|
}
|
||||||
|
#status .content {
|
||||||
|
margin-top: 10px;
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
#status .content span {
|
||||||
|
margin-right: 10px;
|
||||||
|
}
|
||||||
|
#status .span-row{
|
||||||
|
display:block;
|
||||||
|
float:left
|
||||||
|
}
|
||||||
|
#status .content pre {
|
||||||
|
white-space: pre-wrap;
|
||||||
|
word-wrap: break-word;
|
||||||
|
word-break: break-all;
|
||||||
|
}
|
||||||
|
|
||||||
|
#share-btn {
|
||||||
|
float: right;
|
||||||
|
margin-top: 5px;
|
||||||
|
margin-right: 10px;
|
||||||
|
}
|
||||||
|
.el-row--flex {
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
pre {
|
||||||
|
border: none;
|
||||||
|
background: none;
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -4,9 +4,21 @@
|
||||||
<el-card shadow>
|
<el-card shadow>
|
||||||
<div slot="header">
|
<div slot="header">
|
||||||
<el-row :gutter="18">
|
<el-row :gutter="18">
|
||||||
<el-col :md="15" :lg="15">
|
<el-col :md="2" :lg="2">
|
||||||
<span class="panel-title hidden-xs-only" >Problem List</span>
|
<span class="panel-title hidden-xs-only" >Status</span>
|
||||||
</el-col>
|
</el-col>
|
||||||
|
|
||||||
|
<el-col :xs="16" :md="10" :lg="10">
|
||||||
|
<el-switch
|
||||||
|
style="display: block"
|
||||||
|
v-model="formFilter.myself"
|
||||||
|
active-color="#ff4949"
|
||||||
|
active-text="Mine"
|
||||||
|
:width="40"
|
||||||
|
inactive-text="All">
|
||||||
|
</el-switch>
|
||||||
|
</el-col>
|
||||||
|
|
||||||
<el-col :xs="8" :md="4" :lg="4">
|
<el-col :xs="8" :md="4" :lg="4">
|
||||||
<el-dropdown
|
<el-dropdown
|
||||||
class="drop-menu"
|
class="drop-menu"
|
||||||
|
@ -16,7 +28,7 @@
|
||||||
>
|
>
|
||||||
<span class="el-dropdown-link">
|
<span class="el-dropdown-link">
|
||||||
{{formFilter.status === '' ? 'Status' : formFilter.status}}
|
{{formFilter.status === '' ? 'Status' : formFilter.status}}
|
||||||
<i class="el-icon-arrow-down el-icon--right"></i>
|
<i class="el-icon-caret-bottom"></i>
|
||||||
</span>
|
</span>
|
||||||
<el-dropdown-menu slot="dropdown">
|
<el-dropdown-menu slot="dropdown">
|
||||||
<el-dropdown-item command="All">All</el-dropdown-item>
|
<el-dropdown-item command="All">All</el-dropdown-item>
|
||||||
|
@ -26,24 +38,46 @@
|
||||||
</el-dropdown-menu>
|
</el-dropdown-menu>
|
||||||
</el-dropdown>
|
</el-dropdown>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :xs="16" :md="5" :lg="5">
|
|
||||||
<vxe-input v-model="formFilter.pid" placeholder="Enter keyword" type="search" size="medium" @search-click="filterByKeyword"></vxe-input>
|
<el-col :xs="24" :md="4" :lg="4" class="search">
|
||||||
|
<vxe-input v-model="formFilter.pid" placeholder="Enter Problem ID" type="search" size="medium" @search-click="filterByKeyword"></vxe-input>
|
||||||
|
</el-col>
|
||||||
|
<el-col :xs="24" :md="4" :lg="4" class="search">
|
||||||
|
<vxe-input v-model="formFilter.pid" placeholder="Enter Author" type="search" size="medium" @search-click="filterByKeyword"></vxe-input>
|
||||||
</el-col>
|
</el-col>
|
||||||
</el-row>
|
</el-row>
|
||||||
</div>
|
</div>
|
||||||
<vxe-table
|
<vxe-table
|
||||||
border="inner"
|
border="inner"
|
||||||
stripe
|
stripe
|
||||||
|
highlight-current-row
|
||||||
|
highlight-hover-row
|
||||||
|
align="center"
|
||||||
|
:row-class-name="tableRowClassName"
|
||||||
:data="submissions">
|
:data="submissions">
|
||||||
<vxe-table-column field="sid" title="ID" width="100"></vxe-table-column>
|
<vxe-table-column field="sid" title="ID" width="150"></vxe-table-column>
|
||||||
<vxe-table-column field="stime" title="Submit time" width="300" type="html"></vxe-table-column>
|
<vxe-table-column field="stime" title="Submit time" width="150"></vxe-table-column>
|
||||||
<vxe-table-column field="pid" title="Problem ID" width="150" type="html"></vxe-table-column>
|
<vxe-table-column field="pid" title="Problem ID" width="150">
|
||||||
<vxe-table-column field="status" title="Status" width="250" type="html"></vxe-table-column>
|
<template v-slot="{ row }">
|
||||||
<vxe-table-column field="time" title="Time" width="100"></vxe-table-column>
|
<a :href="getProblemUri(row.pid)" style="color:rgb(87, 163, 243);">{{row.pid}}</a>
|
||||||
<vxe-table-column field="memory" title="Memory" width="100"></vxe-table-column>
|
</template>
|
||||||
<vxe-table-column field="language" title="Language" width="100"></vxe-table-column>
|
</vxe-table-column>
|
||||||
<vxe-table-column field="judger" title="Judger" width="100"></vxe-table-column>
|
<vxe-table-column field="status" title="Status" width="150">
|
||||||
<vxe-table-column field="author" title="Author" width="100"></vxe-table-column>
|
<template v-slot="{ row }">
|
||||||
|
<span :class="getStatusColor(row.status)">{{JUDGE_STATUS[row.status].name}}</span>
|
||||||
|
</template>
|
||||||
|
</vxe-table-column>
|
||||||
|
<vxe-table-column field="time" title="Time" width="150"></vxe-table-column>
|
||||||
|
<vxe-table-column field="memory" title="Memory" width="150"></vxe-table-column>
|
||||||
|
<vxe-table-column field="language" title="Language" width="150">
|
||||||
|
<template v-slot="{ row }">
|
||||||
|
<el-tooltip class="item" effect="dark" content="查看提交详情" placement="top">
|
||||||
|
<el-button type="text" @click="showSubmitDetail(row)">{{ row.language }}</el-button>
|
||||||
|
</el-tooltip>
|
||||||
|
</template>
|
||||||
|
</vxe-table-column>
|
||||||
|
<vxe-table-column field="judger" title="Judger" width="150"></vxe-table-column>
|
||||||
|
<vxe-table-column field="author" title="Author" width="150"></vxe-table-column>
|
||||||
</vxe-table>
|
</vxe-table>
|
||||||
</el-card>
|
</el-card>
|
||||||
<Pagination :total="total" :page-size="limit" @on-change="changeRoute" :current.sync="page"></Pagination>
|
<Pagination :total="total" :page-size="limit" @on-change="changeRoute" :current.sync="page"></Pagination>
|
||||||
|
@ -58,11 +92,10 @@
|
||||||
import utils from '@/common/utils'
|
import utils from '@/common/utils'
|
||||||
import time from '@/common/time'
|
import time from '@/common/time'
|
||||||
import Pagination from '@/components/common/Pagination'
|
import Pagination from '@/components/common/Pagination'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'submissionList',
|
name: 'submissionList',
|
||||||
components: {
|
components: {
|
||||||
Pagination
|
Pagination,
|
||||||
},
|
},
|
||||||
data () {
|
data () {
|
||||||
return {
|
return {
|
||||||
|
@ -73,7 +106,42 @@
|
||||||
pid:''
|
pid:''
|
||||||
},
|
},
|
||||||
loadingTable: false,
|
loadingTable: false,
|
||||||
submissions: [],
|
submissions: [
|
||||||
|
{
|
||||||
|
sid:1000,
|
||||||
|
stime:'2020-08-08 16:00:00',
|
||||||
|
pid:'1001',
|
||||||
|
status:0,
|
||||||
|
time:'4ms',
|
||||||
|
memory:'3MB',
|
||||||
|
language:'C++',
|
||||||
|
judger:'192.168.1.1',
|
||||||
|
author:'Himit_ZH'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
sid:1001,
|
||||||
|
stime:'2020-08-08 16:00:00',
|
||||||
|
pid:'1001',
|
||||||
|
status:0,
|
||||||
|
time:'4ms',
|
||||||
|
memory:'3MB',
|
||||||
|
language:'C++',
|
||||||
|
judger:'192.168.1.1',
|
||||||
|
author:'Himit_Z'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
sid:1000,
|
||||||
|
stime:'2020-08-08 16:00:00',
|
||||||
|
pid:'1001',
|
||||||
|
status:0,
|
||||||
|
time:'4ms',
|
||||||
|
memory:'3MB',
|
||||||
|
language:'C++',
|
||||||
|
judger:'192.168.1.1',
|
||||||
|
author:'Himit_H'
|
||||||
|
}
|
||||||
|
|
||||||
|
],
|
||||||
total: 30,
|
total: 30,
|
||||||
limit: 15,
|
limit: 15,
|
||||||
page: 1,
|
page: 1,
|
||||||
|
@ -193,6 +261,21 @@
|
||||||
}, () => {
|
}, () => {
|
||||||
this.submissions[index].loading = false
|
this.submissions[index].loading = false
|
||||||
})
|
})
|
||||||
|
},
|
||||||
|
showSubmitDetail (row) {
|
||||||
|
this.selectSubmitRow = row;
|
||||||
|
this.showDetails = true;
|
||||||
|
},
|
||||||
|
getProblemUri(pid){
|
||||||
|
return '/problem/'+pid;
|
||||||
|
},
|
||||||
|
getStatusColor(status){
|
||||||
|
return 'el-tag el-tag--medium status-'+JUDGE_STATUS[status].color;
|
||||||
|
},
|
||||||
|
tableRowClassName({row, rowIndex}){
|
||||||
|
if(row.author =='Himit_ZH'){
|
||||||
|
return 'own-submit-row';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
|
@ -230,8 +313,11 @@
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped >
|
<style scoped >
|
||||||
.ivu-btn-text {
|
|
||||||
color: #57a3f3;
|
@media only screen and (max-width: 767px){
|
||||||
|
.search{
|
||||||
|
margin-top: 20px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.flex-container #main {
|
.flex-container #main {
|
||||||
|
@ -245,4 +331,19 @@
|
||||||
flex: none;
|
flex: none;
|
||||||
width: 210px;
|
width: 210px;
|
||||||
}
|
}
|
||||||
|
/deep/ .el-card__header {
|
||||||
|
border-bottom: 0px;
|
||||||
|
padding-bottom: 0px;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
/deep/ .el-button{
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
/deep/ .el-dialog {
|
||||||
|
border-radius: 6px !important;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
/deep/ .el-switch{
|
||||||
|
padding-top: 6px;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
Loading…
Reference in New Issue