You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
educoder/public/react/src/modules/wxcode/index.js

284 lines
9.8 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

/*
* @Description: 微信端代码编辑器
* @Author: tangjiang
* @Github:
* @Date: 2020-01-15 09:56:34
* @LastEditors : tangjiang
* @LastEditTime : 2020-01-17 10:19:51
*/
import './index.scss';
import React, {useState, useEffect, useRef} from 'react';
import MonacoEditor from '@monaco-editor/react';
import { Input, Icon } from 'antd';
import { connect } from 'react-redux';
import actions from '../../redux/actions';
import cookie from 'react-cookies';
const { TextArea } = Input;
const App = (props) => {
const {
isShow,
wxCode,
path,
showLoading,
// userCode,
testCase = [],
getWXCode,
last_compile_output,
test_sets_count,
sets_error_count,
getWXCodeTestCase,
restoreWXCode,
updateWXCodeForEditor,
updateWXCodeForInterval,
evaluateWxCode,
showWXCodeTextCase,
changeWXCodeEvaluateLoading
} = props;
const {identifier} = props.match.params;
// 获取路径参数
const _params = window.location.search;
if (_params) {
let _cookie = '';
let _search = _params.split('?')[1];
if(_search.split('=')) {
_cookie = _search.split('=')[1];
cookie.save('_educoder_session', _cookie);
}
console.log(_cookie);
}
const [isActive, setIsActive] = useState(-1);
// const [isVisible, setIsVisible] = useState(false);
const editorRef = useRef(null);
let timer = null;
useEffect(() => {
// 加载代码块内容
getWXCode(identifier);
// 加载测试集
const params = {
path,
status: 0,
retry: 1
};
getWXCodeTestCase(identifier, params);
}, []);
// 关闭
const handleCloseTestCase = () => {
// setIsVisible(false);
showWXCodeTextCase(false)
}
// 测试集
const handleClickTestCase = () => {
// setIsVisible(true);
showWXCodeTextCase(true)
}
// 编辑器代码
const handleEditorChange = (origin, monaco) => {
editorRef.current = monaco; // 获取当前monaco实例
// setEditCode(origin); // 保存编辑器初始值
editorRef.current.onDidChangeModelContent(e => { // 监听编辑器内容的变化
// TODO 需要优化 节流
const val = editorRef.current.getValue();
// console.log('编辑器代码====>>>>', val);
// updateWXCodeForEditor(val);
codeChange(val);
});
};
const codeChange = (code) => {
// console.log(code);
updateWXCodeForEditor(code);
if (!timer) {
timer = setInterval(function () {
clearInterval(timer);
timer = null;
// 调用更新代码
updateWXCodeForInterval(identifier, path);
}, 10000);
}
}
// 关闭单个测试集
const handleCloseItem = (i, flag) => {
if (!flag) return;
setIsActive(isActive === i ? -1 : i);
}
// 初始化
const handleResetCode = () => {
const result = window.confirm('你在本文件中修改的内容将丢失, 是否确定重新加载初始代码?');
if (result) {
identifier && restoreWXCode(identifier, { path });
}
}
// 评测
const handleEvalateCode = () => {
changeWXCodeEvaluateLoading(true);
evaluateWxCode(identifier, path);
}
const tcclasses = isShow ? `wx-code-test-case active` : 'wx-code-test-case';
const loading = showLoading ? 'code-evaluate-loading active' : 'code-evaluate-loading';
const _val = sets_error_count === 0;
let resultTxt = (_val) ? '全部通过' : `${sets_error_count}组测试结果不匹配`;
const iclasses = _val ? 'iconfont icon-tishi1 icon success' : 'iconfont icon-tishi1 icon fail';
const tclasses = _val ? 'result-txt success' : 'result-txt fail';
const ulClasses = last_compile_output ? 'case-list hasResult' : 'case-list';
return (
<div className="wx-code-area">
<div className="wx-code-flex">
<div className="wx-code-item">
<MonacoEditor
height="100%"
width="100%"
language="python"
value={wxCode}
options={{
selectOnLineNumbers: true,
automaticLayout: true,
fontSize: `32px`
}}
theme='dark'
editorDidMount={handleEditorChange}
/>
</div>
<div className="wx-code-test">
<div className="flex-btn">
<span className="icon-btn" onClick={handleResetCode}>
<i className="iconfont icon-reset icon"></i>
<span className="icon-txt">初始化</span>
</span>
<span className="icon-btn" onClick={handleClickTestCase}>
<i className="iconfont icon-base icon"></i>
<span className="icon-txt">测试集</span>
</span>
</div>
{/* <Button type="primary" shape="circle">评测</Button> */}
<button className="wx-pt-btn" onClick={handleEvalateCode}>评测</button>
</div>
</div>
{/* 测试集 */}
<div className={tcclasses}>
<div className="text-case-list">
<div className="list-header">
<span className="header-title">{testCase.length}个测试用例</span>
<span className="header-close" onClick={handleCloseTestCase}>关闭</span>
</div>
<div className="wxcode-test-result" style={{ display: last_compile_output ? 'block' : 'none'}}>
<i className={iclasses}></i>
<span className={tclasses}>{test_sets_count - sets_error_count}/{test_sets_count}</span>
<span className={`${tclasses} result-txt-desc`}>{resultTxt}</span>
</div>
<ul className={ulClasses}>
{
testCase.map((item, i) => {
const {input, output, actual_output, is_public, result} = item;
const _classes = isActive === i ? 'case-item-desc active' : 'case-item-desc';
const iconclasses = isActive === i ? 'iconfont icon-sanjiaoxing-down icon active' : 'iconfont icon-triangle icon';
const headerClasses = is_public ? 'item-header-desc active' : 'item-header-desc';
// console.log(_classes);
return (
<li className="case-item" key={`item_${i}`}>
<div className="case-item-header" onClick={() => handleCloseItem(i, is_public)}>
<h2 className={headerClasses}>
<i className={iconclasses}></i>
测试集{i + 1}
</h2>
{
is_public
? (result
? <span className="iconfont icon-wancheng case_item_success"></span>
: <span className="iconfont icon-jinggao1 case_item_fail"></span>)
: (<span className="case-item-tips">
隐藏测试集暂不支持解锁和查看
{/* {result
? <span className="iconfont icon-wancheng case_item_success"></span>
: <span className="iconfont icon-jinggao1 case_item_fail"></span>
} */}
</span>)
}
</div>
<div className={_classes}>
<span className="desc-title">测试输入</span>
<span className="test-input">{input || '-'}</span>
<span className="desc-title">预期输出</span>
{/* <textarea rows="5">预期输出</textarea> */}
<TextArea
readOnly={true}
className="text-area-style"
value={output}
onChange={this.onChange}
placeholder="Controlled autosize"
autoSize={{ minRows: 3, maxRows: 6 }}
/>
{/* <TextArea rows={5} className="hope-result">预期输出</TextArea> */}
<span className="desc-title">实际输出</span>
<TextArea
readOnly={true}
className="text-area-style"
value={actual_output}
autoSize={{ minRows: 1, maxRows: 3 }}
/>
</div>
</li>
)
})
}
</ul>
</div>
</div>
{/* 测评中 */}
<div className={loading}>
<span className="loading-flex">
<Icon className="loading-icon" type="loading" />
<span className="loading-txt">测评中...</span>
</span>
</div>
</div>
);
}
const mapStateToProps = (state) => {
const {
path,
isShow,
wxCode,
userCode,
testCase,
showLoading,
last_compile_output,
test_sets_count,
sets_error_count
} = state.wxcodeReducer;
console.log(state);
return {
path,
isShow,
wxCode,
userCode,
testCase,
showLoading,
last_compile_output,
test_sets_count,
sets_error_count
};
}
const mapDispatchToProps = (dispatch) => ({
getWXCode: (identifier) => dispatch(actions.getWXCode(identifier)),
getWXCodeTestCase: (identifier, params) => dispatch(actions.getWXCodeTestCase(identifier, params)),
restoreWXCode: (identifier, params) => dispatch(actions.restoreWXCode(identifier, params)),
updateWXCodeForEditor: (code) => dispatch(actions.updateWXCodeForEditor(code)),
updateWXCodeForInterval: (identifier, path) => dispatch(actions.updateWXCodeForInterval(identifier, path)),
evaluateWxCode: (identifier, path) => dispatch(actions.evaluateWxCode(identifier, path)),
showWXCodeTextCase: (flag) => dispatch(actions.showWXCodeTextCase(flag)),
changeWXCodeEvaluateLoading: (flag) => dispatch(actions.changeWXCodeEvaluateLoading(flag))
});
export default connect(
mapStateToProps,
mapDispatchToProps
)(App);