Merge branch 'dev_aliyun' of https://bdgit.educoder.net/Hjqreturn/educoder into dev_aliyun
commit
c449018d85
@ -0,0 +1,44 @@
|
||||
class HelpsController < ApplicationController
|
||||
before_action :require_login, only: [:feedback]
|
||||
|
||||
helper_method :current_help
|
||||
|
||||
def about
|
||||
render_ok(content: current_help&.about_us)
|
||||
end
|
||||
|
||||
def contact
|
||||
@cooperations = Cooperation.all.group(:user_type)
|
||||
end
|
||||
|
||||
def cooperatives
|
||||
@data = { 'alliance_coop' => [], 'com_coop' => [], 'edu_coop' => [] }
|
||||
@data = @data.merge CooImg.all.group_by(&:img_type)
|
||||
end
|
||||
|
||||
def agreement
|
||||
render_ok(content: current_help&.agreement)
|
||||
end
|
||||
|
||||
def help_center
|
||||
render_ok(content: current_help&.help_center)
|
||||
end
|
||||
|
||||
def feedback
|
||||
content = "<p>[#{params[:question_kind]}]</p><p>问题页面网址:#{params[:url]}</p>#{params[:description]}"
|
||||
|
||||
ActiveRecord::Base.transaction do
|
||||
attr = { sender_id: User.current.id, receiver_id: 1, content: content, send_time: Time.now }
|
||||
PrivateMessage.create!(attr.merge(user_id: User.current.id, target_id: 1, status: 1))
|
||||
PrivateMessage.create!(attr.merge(user_id: 1, target_id: User.current.id, status: 0))
|
||||
end
|
||||
|
||||
render_ok
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def current_help
|
||||
@_current_help ||= Help.first
|
||||
end
|
||||
end
|
@ -0,0 +1,8 @@
|
||||
json.contacts do
|
||||
json.array! @cooperations.each do |item|
|
||||
json.extract! item, :name, :qq, :mail
|
||||
json.type item.user_type_text
|
||||
end
|
||||
end
|
||||
|
||||
json.address current_help.status
|
@ -0,0 +1,11 @@
|
||||
json.data do
|
||||
json.array! @data.each do |type, objs|
|
||||
json.name I18n.t("enumerize.coo_img.img_type.#{type}")
|
||||
json.values do
|
||||
json.array! objs.sort_by(&:position).each do |obj|
|
||||
json.img obj.url_states || (Util::FileManage.exist?('CooImg', obj.id) ? Util::FileManage.disk_file_url('CooImg', obj.id) : '')
|
||||
json.url obj.src_states
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,5 @@
|
||||
class AddVncEvaluateForShixuns < ActiveRecord::Migration[5.2]
|
||||
def change
|
||||
add_column :shixuns, :vnc_evaluate, :boolean, default: false
|
||||
end
|
||||
end
|
Before Width: | Height: | Size: 661 KiB After Width: | Height: | Size: 155 KiB |
File diff suppressed because one or more lines are too long
@ -0,0 +1,12 @@
|
||||
import Loadable from 'react-loadable';
|
||||
|
||||
import Loading from "./Loading";
|
||||
|
||||
const CustomLoadable = (loader, loading = Loading) => {
|
||||
return Loadable({
|
||||
loader,
|
||||
loading
|
||||
})
|
||||
}
|
||||
|
||||
export default CustomLoadable
|
@ -0,0 +1,53 @@
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { Card } from "antd";
|
||||
import axios from 'axios';
|
||||
|
||||
import { MarkdownToHtml } from 'educoder';
|
||||
|
||||
class AboutUs extends React.Component {
|
||||
constructor (props) {
|
||||
super(props);
|
||||
|
||||
this.state = {
|
||||
loading: true,
|
||||
content: null
|
||||
}
|
||||
}
|
||||
|
||||
componentDidMount(){
|
||||
this.getContent();
|
||||
}
|
||||
|
||||
getContent(){
|
||||
axios.get("/helps/about.json").then((result) => {
|
||||
if(result){
|
||||
this.setState({
|
||||
content: result.data.content,
|
||||
loading: false
|
||||
})
|
||||
}
|
||||
}).catch((error) => {
|
||||
console.log(error);
|
||||
this.setState({ loading: false });
|
||||
})
|
||||
}
|
||||
|
||||
render() {
|
||||
let { loading, content } = this.state;
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div className="about-us-container">
|
||||
<Card title="关于我们" bordered={false} loading={loading} style={{ minHeight: 600 }}>
|
||||
<div className="about-us-content">
|
||||
{ content && <MarkdownToHtml content={content} selector="work_content" className=""></MarkdownToHtml> }
|
||||
</div>
|
||||
</Card>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export default AboutUs;
|
@ -0,0 +1,53 @@
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { Card } from "antd";
|
||||
import axios from 'axios';
|
||||
|
||||
import { MarkdownToHtml } from 'educoder';
|
||||
|
||||
class Agreement extends React.Component {
|
||||
constructor (props) {
|
||||
super(props);
|
||||
|
||||
this.state = {
|
||||
loading: true,
|
||||
content: null
|
||||
}
|
||||
}
|
||||
|
||||
componentDidMount(){
|
||||
this.getContent();
|
||||
}
|
||||
|
||||
getContent(){
|
||||
axios.get("/helps/agreement.json").then((result) => {
|
||||
if(result){
|
||||
this.setState({
|
||||
content: result.data.content,
|
||||
loading: false
|
||||
})
|
||||
}
|
||||
}).catch((error) => {
|
||||
console.log(error);
|
||||
this.setState({ loading: false });
|
||||
})
|
||||
}
|
||||
|
||||
render() {
|
||||
let { loading, content } = this.state;
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div className="agreement-container">
|
||||
<Card title="服务协议" bordered={false} loading={loading} style={{ minHeight: 600 }}>
|
||||
<div className="agreement-content">
|
||||
{ content && <MarkdownToHtml content={content} selector="work_content" className=""></MarkdownToHtml> }
|
||||
</div>
|
||||
</Card>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export default Agreement;
|
@ -0,0 +1,24 @@
|
||||
.contact-us-container {
|
||||
|
||||
}
|
||||
.contact-us-container .contact-item {
|
||||
padding: 20px 15px;
|
||||
border-bottom: 1px solid #EEEEEE;
|
||||
}
|
||||
.contact-us-container .contact-item:first-child {
|
||||
padding-top: 0;
|
||||
}
|
||||
.contact-us-container .contact-item:last-child {
|
||||
border-bottom: unset;
|
||||
}
|
||||
|
||||
.contact-us-container .contact-item-label {
|
||||
font-size: 16px;
|
||||
padding-bottom: 10px;
|
||||
}
|
||||
.contact-us-container .contact-item-content {
|
||||
margin-left: 10px;
|
||||
}
|
||||
.contact-us-container .contact-item-content .ant-row {
|
||||
margin-top: 10px;
|
||||
}
|
@ -0,0 +1,17 @@
|
||||
.cooperatives-container {
|
||||
|
||||
}
|
||||
|
||||
.cooperatives-container .cooperative-item-title {
|
||||
margin-bottom: 20px;
|
||||
font-size: 16px;
|
||||
}
|
||||
.cooperatives-container .cooperative-item-list-item {
|
||||
padding: 10px 0;
|
||||
height: 60px;
|
||||
border: 1px solid #eee;
|
||||
}
|
||||
.cooperatives-container .cooperative-item-list-item img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
@ -0,0 +1,81 @@
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { List, Card } from "antd";
|
||||
import axios from 'axios';
|
||||
import { getImageUrl } from 'educoder';
|
||||
|
||||
import './Cooperatives.css';
|
||||
|
||||
class Cooperatives extends React.Component {
|
||||
constructor (props) {
|
||||
super(props);
|
||||
|
||||
this.state = {
|
||||
loading: true,
|
||||
data: [
|
||||
{ name: "产学联盟" },
|
||||
{ name: "知名企业" },
|
||||
{ name: "各类院校" }
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
componentDidMount(){
|
||||
this.getCooperatives();
|
||||
}
|
||||
|
||||
getCooperatives(){
|
||||
axios.get("/helps/cooperatives.json").then((result) => {
|
||||
if(result){
|
||||
this.setState({
|
||||
data: result.data.data,
|
||||
loading: false
|
||||
})
|
||||
}
|
||||
}).catch((error) => {
|
||||
console.log(error);
|
||||
this.setState({ loading: false });
|
||||
})
|
||||
}
|
||||
|
||||
render() {
|
||||
let { loading, data } = this.state;
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div className="cooperatives-container">
|
||||
<Card title="合作伙伴" bordered={false} loading={loading} style={{ minHeight: 600 }}>
|
||||
<div className="cooperatives-content">
|
||||
{
|
||||
data && data.length > 0 && data.map((item, _key) => {
|
||||
return (
|
||||
<div className="cooperative-item">
|
||||
<div className="cooperative-item-title">{ item.name }</div>
|
||||
<div className="cooperative-item-list">
|
||||
<List
|
||||
grid={{ gutter: 16, column: 4 }}
|
||||
dataSource={item.values}
|
||||
renderItem={obj => (
|
||||
<List.Item>
|
||||
<div className="cooperative-item-list-item">
|
||||
<a href={obj.url || 'javascript:void(0)'} target={obj.url && '_blank'}>
|
||||
<img className="" height="90" src={getImageUrl(obj.img.substr(1))} />
|
||||
</a>
|
||||
</div>
|
||||
</List.Item>
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
})
|
||||
}
|
||||
</div>
|
||||
</Card>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export default Cooperatives;
|
@ -0,0 +1,7 @@
|
||||
.feedback-container {
|
||||
|
||||
}
|
||||
.feedback-container .feedback-message {
|
||||
line-height: 26px;
|
||||
color: #999999;
|
||||
}
|
@ -0,0 +1,87 @@
|
||||
import React from 'react';
|
||||
import { Form, Input, Radio, Button } from "antd";
|
||||
import axios from 'axios';
|
||||
|
||||
const { TextArea } = Input;
|
||||
|
||||
class FeedbackForm extends React.Component {
|
||||
constructor (props) {
|
||||
super(props);
|
||||
}
|
||||
|
||||
handleSubmit = e => {
|
||||
e.preventDefault();
|
||||
|
||||
this.props.form.validateFields((err, fieldsValue) => {
|
||||
if(err){ return }
|
||||
|
||||
axios.post("/helps/feedback.json", fieldsValue)
|
||||
.then((result) => {
|
||||
if (result.status === 200 && result.data.status === 0) {
|
||||
this.props.history.push(`/messages/${this.props.current_user.login}/message_detail?target_ids=1`);
|
||||
}
|
||||
}).catch((error) => {
|
||||
console.log(error)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
render() {
|
||||
const { getFieldDecorator } = this.props.form;
|
||||
|
||||
return (
|
||||
<div className="feedback-form">
|
||||
<Form onSubmit={this.handleSubmit}>
|
||||
<Form.Item label="问题分类">
|
||||
{getFieldDecorator('question_kind', {
|
||||
initialValue: "登录注册",
|
||||
rules: [
|
||||
{
|
||||
required: true,
|
||||
message: '不能为空',
|
||||
},
|
||||
],
|
||||
})(
|
||||
<Radio.Group>
|
||||
<Radio value="登录注册">登录注册</Radio>
|
||||
<Radio value="信息认证">信息认证</Radio>
|
||||
<Radio value="实训编程">实训编程</Radio>
|
||||
<Radio value="实训课程">实训课程</Radio>
|
||||
<Radio value="课堂">课堂</Radio>
|
||||
<Radio value="其它">其它</Radio>
|
||||
</Radio.Group>
|
||||
)}
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item label="问题页面网址">
|
||||
{getFieldDecorator('url', {
|
||||
rules: [
|
||||
{
|
||||
required: true,
|
||||
message: '不能为空',
|
||||
},
|
||||
],
|
||||
})(<Input placeholder="反馈平台问题,请同时填写对应的问题页面链接,以便平台能够及时跟踪解决,谢谢" />)}
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item label="问题描述">
|
||||
{getFieldDecorator('description', {
|
||||
rules: [
|
||||
{
|
||||
required: true,
|
||||
message: '不能为空',
|
||||
},
|
||||
],
|
||||
})(<TextArea rows={4} placeholder="反馈平台问题,请同时填写对应的问题页面链接,以便平台能够及时跟踪解决,谢谢" />)}
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item>
|
||||
<Button type="primary" htmlType="submit">提交</Button>
|
||||
</Form.Item>
|
||||
</Form>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export default FeedbackForm;
|
@ -0,0 +1,9 @@
|
||||
.help-container {
|
||||
margin-top: 30px;
|
||||
}
|
||||
.help-container .help-menu {
|
||||
text-align: center;
|
||||
}
|
||||
.help-container .help-content {
|
||||
margin-bottom: 40px;
|
||||
}
|
@ -0,0 +1,77 @@
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { Switch, Route, Link } from 'react-router-dom';
|
||||
import { Affix, Menu, Row, Col } from "antd";
|
||||
import { SnackbarHOC } from 'educoder';
|
||||
|
||||
import './Help.css';
|
||||
|
||||
import CustomLoadable from "../../CustomLoadable";
|
||||
import {TPMIndexHOC} from "../tpm/TPMIndexHOC";
|
||||
|
||||
const AboutUs = CustomLoadable(() => import('./AboutUs'));
|
||||
const ContactUs = CustomLoadable(() => import('./ContactUs'));
|
||||
const Cooperatives = CustomLoadable(() => import('./Cooperatives'));
|
||||
const Agreement = CustomLoadable(() => import('./Agreement'));
|
||||
const HelpCenter = CustomLoadable(() => import('./HelpCenter'));
|
||||
const Feedback = CustomLoadable(() => import('./Feedback'));
|
||||
|
||||
class Help extends React.Component {
|
||||
constructor (props) {
|
||||
super(props);
|
||||
|
||||
this.state = {
|
||||
type: props.match.params.type || 'about_us'
|
||||
}
|
||||
}
|
||||
|
||||
componentDidUpdate(prevProps) {
|
||||
console.log('update', prevProps, this.props);
|
||||
if(prevProps.match.params.type !== this.props.match.params.type){
|
||||
this.setState({ type: this.props.match.params.type });
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<div className="newMain clearfix">
|
||||
<div className="educontent help-container">
|
||||
<Row gutter={{ xs: 8, sm: 16, md: 24, lg: 32 }}>
|
||||
<Col span={4}>
|
||||
<Affix offsetTop={20}>
|
||||
<div className="help-menu">
|
||||
<Menu
|
||||
mode="inline"
|
||||
selectedKeys={[this.state.type]}>
|
||||
|
||||
<Menu.Item key="about_us"><Link to="/help/about_us">关于我们</Link></Menu.Item>
|
||||
<Menu.Item key="contact_us"><Link to="/help/contact_us">联系我们</Link></Menu.Item>
|
||||
<Menu.Item key="cooperatives"><Link to="/help/cooperatives">合作伙伴</Link></Menu.Item>
|
||||
<Menu.Item key="agreement"><Link to="/help/agreement">服务协议</Link></Menu.Item>
|
||||
<Menu.Item key="help_center"><Link to="/help/help_center">帮助中心</Link></Menu.Item>
|
||||
<Menu.Item key="feedback"><Link to="/help/feedback">意见反馈</Link></Menu.Item>
|
||||
</Menu>
|
||||
</div>
|
||||
</Affix>
|
||||
</Col>
|
||||
<Col span={20}>
|
||||
<div className="help-content">
|
||||
<Switch>
|
||||
<Route path='/help/about_us' component={AboutUs}></Route>
|
||||
<Route path='/help/contact_us' component={ContactUs}></Route>
|
||||
<Route path='/help/cooperatives' component={Cooperatives}></Route>
|
||||
<Route path='/help/agreement' component={Agreement}></Route>
|
||||
<Route path='/help/help_center' component={HelpCenter}></Route>
|
||||
<Route path='/help/feedback' render={ (props)=>(<Feedback {...this.props} {...props} {...this.state}></Feedback>) }></Route>
|
||||
<Route component={AboutUs}/>
|
||||
</Switch>
|
||||
</div>
|
||||
</Col>
|
||||
</Row>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export default SnackbarHOC() (TPMIndexHOC ( Help ));
|
@ -0,0 +1,53 @@
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { Card } from "antd";
|
||||
import axios from 'axios';
|
||||
|
||||
import { MarkdownToHtml } from 'educoder';
|
||||
|
||||
class HelpCenter extends React.Component {
|
||||
constructor (props) {
|
||||
super(props);
|
||||
|
||||
this.state = {
|
||||
loading: true,
|
||||
content: null
|
||||
}
|
||||
}
|
||||
|
||||
componentDidMount(){
|
||||
this.getContent();
|
||||
}
|
||||
|
||||
getContent(){
|
||||
axios.get("/helps/help_center.json").then((result) => {
|
||||
if(result){
|
||||
this.setState({
|
||||
content: result.data.content,
|
||||
loading: false
|
||||
})
|
||||
}
|
||||
}).catch((error) => {
|
||||
console.log(error);
|
||||
this.setState({ loading: false });
|
||||
})
|
||||
}
|
||||
|
||||
render() {
|
||||
let { loading, content } = this.state;
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div className="help-center-container">
|
||||
<Card title="帮助中心" bordered={false} loading={loading} style={{ minHeight: 600 }}>
|
||||
<div className="help-center-content">
|
||||
{ content && <MarkdownToHtml content={content} selector="work_content" className=""></MarkdownToHtml> }
|
||||
</div>
|
||||
</Card>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export default HelpCenter;
|
Loading…
Reference in new issue