Commit 7ee954cc authored by baixian's avatar baixian

推送和多学员删除功能

parent 5bf28b13
image/wx.png

536 Bytes

......@@ -12,11 +12,11 @@
<![endif]-->
<script charset="utf-8" src="https://map.qq.com/api/js?v=2.exp&key=XSZBZ-5LHCV-5I2P7-UQHPW-6456F-JBB3B"></script>
<script src="https://cdn.img.shangjiadao.cn/qingxiao/biz/js/console-polyfill.js?20191012222" charset="utf-8"></script><script src="https://cdn.img.shangjiadao.cn/qingxiao/biz/js/es6-shim.min.js?20191012222" charset="utf-8"></script><script src="https://cdn.img.shangjiadao.cn/qingxiao/biz/js/es5-shim.js?20191012222" charset="utf-8"></script><script src="https://cdn.img.shangjiadao.cn/qingxiao/biz/js/es5-sham.min.js?20191012222" charset="utf-8"></script><script src="https://cdn.img.shangjiadao.cn/qingxiao/biz/js/json3.min.js?20191012222" charset="utf-8"></script><script src="https://cdn.img.shangjiadao.cn/qingxiao/biz/js/html5shiv.min.js?20191012222" charset="utf-8"></script><script src="https://cdn.img.shangjiadao.cn/qingxiao/biz/js/polyfill.js?20191012222" charset="utf-8"></script><script src="https://cdn.img.shangjiadao.cn/qingxiao/biz/lib/vendor.dll.js?20191012222" charset="utf-8"></script>
<script src="js/console-polyfill.js?20191012222" charset="utf-8"></script><script src="js/es6-shim.min.js?20191012222" charset="utf-8"></script><script src="js/es5-shim.js?20191012222" charset="utf-8"></script><script src="js/es5-sham.min.js?20191012222" charset="utf-8"></script><script src="js/json3.min.js?20191012222" charset="utf-8"></script><script src="js/html5shiv.min.js?20191012222" charset="utf-8"></script><script src="js/polyfill.js?20191012222" charset="utf-8"></script><script src="lib/vendor.dll.js?20191012222" charset="utf-8"></script>
</head>
</head>
<body>
<div id="root"></div>
<script src="https://cdn.img.shangjiadao.cn/qingxiao/biz/dist/main.js?1571940439010" charset="utf-8"></script>
<script src="dist/main.js?1572332208185" charset="utf-8"></script>
</body>
</html>
\ No newline at end of file
......@@ -74,6 +74,7 @@ export default {
studentsLog: `${dakaapi}member/erp/student/logs`,
studentsUnBindWx: `${dakaapi}member/erp/student/wechat/remove`,
schoolUuid: `${dakaapi}member/school_uuid`,
studentHistory: `${dakaapi}member/erp/students/status`,
},
teachers: `${dakaapi}member/erp/teachers`,
choose_teacher: `${dakaapi}member/erp/teacher/distribution`,
......@@ -90,6 +91,7 @@ export default {
changeClassStatus: `${dakaapi}member/erp/class/status`,
addClassStudents: `${dakaapi}member/erp/class/student/add`,
plansAdd: `${dakaapi}member/erp/plans`,
wxConfig: `${dakaapi}member/erp/config`,
},
teacherMgt: {
teacherInvitations: `${dakaapi}member/erp/teacher/invitations`,
......
......@@ -55,6 +55,7 @@ export default {
page: 1,
perPage: 10,
class_id: 0,
status: 1,
},
queryToAddStudentListParams: {
school_id: 0,
......@@ -1358,6 +1359,7 @@ export default {
page: 1,
perPage: 10,
class_id: 0,
status: 1,
},
queryToAddStudentListParams: {
school_id: 0,
......@@ -1372,6 +1374,7 @@ export default {
page: 1,
perPage: 10,
schedule_id: 0,
status: 1,
},
scheduleStudentTotal: 0,
scheduleStudentList: [],
......
......@@ -16,6 +16,7 @@ import * as teachersAjax from '../services/teachers';
import * as classroommgtAjax from '../services/classroommgt';
import * as commonAjax from '../services/common';
import errorcode from '../common/errorcode';
import * as studentsAjax from '../services/students';
export default {
namespace: 'classmgt',
state: {
......@@ -119,6 +120,13 @@ export default {
classInviteqrcodeShow: false,
classInviteqrcodeUrl: '',
classInviteqrcodeUrl2: '',
wxVisible: false,
wxSubmitting: false,
wxConfig: {
schedule_remind_on_off: 1,
schedule_remind_student_before: 0,
schedule_remind_teacher_before: 0,
},
},
subscriptions: {
setup({ dispatch, history }) { // eslint-disable-line
......@@ -389,6 +397,82 @@ export default {
// message.error(classAddDate.msg, 1);
}
},
* saveWxConfig({ payload }, { call, put, select }) {
const { sid } = yield select(state => state.webapp);
const {
schedule_remind,
teacher_minutes,
parent_minutes,
type,
callBack,
} = payload;
const { wxSubmitting } = yield select(state => state.classmgt);
if (wxSubmitting) {
return;
}
yield put({
type: 'updateState',
payload: {
wxSubmitting: true,
},
});
const loadmessage = message.loading('保存中...', 0);
const data = yield call(classMgtAjax.wxConfig, {
school_id: sid,
schedule_remind,
teacher_minutes,
parent_minutes,
type,
});
yield put({
type: 'updateState',
payload: {
wxSubmitting: false,
},
});
setTimeout(loadmessage);
if (data.code === 200) {
message.success('保存成功', 1);
yield put({
type: 'updateState',
payload: {
wxVisible: false,
},
});
if (callBack && (typeof callBack == 'function')) {
callBack();
}
} else {
yield put({
type: 'webapp/errorrequestresolve',
payload: {
data,
},
});
}
},
* selectWxConfig({ payload }, { call, put, select }) {
const { sid } = yield select(state => state.webapp);
const data = yield call(classMgtAjax.GetWxConfig, {
school_id: sid,
type: 1,
});
if (data.code === 200) {
yield put({
type: 'updateState',
payload: {
wxConfig: data.data,
},
});
} else {
yield put({
type: 'webapp/errorrequestresolve',
payload: {
data,
},
});
}
},
* goback({ payload }, { call, put, select }) {
yield put(routerRedux.goBack());
},
......@@ -850,6 +934,13 @@ export default {
selectedClasskey: [],
selectedClass: [],
statusChangeSubmitting: false,
wxVisible: false,
wxSubmitting: false,
wxConfig: {
schedule_remind_on_off: 1,
schedule_remind_student_before: 0,
schedule_remind_teacher_before: 0,
},
},
});
},
......
......@@ -13,7 +13,6 @@ import * as teachersAjax from '../services/teachers';
import * as courseAjax from '../services/course';
import * as classMgtAjax from '../services/classmgt';
import * as commonAjax from '../services/common';
export default {
namespace: 'students',
state: {
......@@ -78,6 +77,7 @@ export default {
extra: 'time,recently_course',
birthday_start: '',
birthday_end: '',
status: 1,
},
searchstudentListQueryParams: {
school_id: 0,
......@@ -135,6 +135,8 @@ export default {
queryRepeatStudentsLoading: false,
studentAddParams: {},
repeatStudentList: [],
deleteVisible: false,
studentsId: 0, // 学生ID
},
subscriptions: {
setup({ dispatch, history }) { // eslint-disable-line
......@@ -323,10 +325,12 @@ export default {
const { params, action } = payload;
const { studentListQueryParams, studentListTotal, searching } = yield select(state => state.students);
if (action == 'search') {
if (studentListQueryParams.status === 2) {
return;
}
if (searching) {
return;
}
yield put({
type: 'updateState',
payload: {
......@@ -982,6 +986,108 @@ export default {
message.error('小程序码生成失败', 1);
}
},
* goHistoryStudent({ payload }, { call, put, select }) {
const { stat_time_status, status, callBack } = payload;
const { sid } = yield select(state => state.webapp);
const { studentsId, historyStudentLoading } = yield select(state => state.students);
if (historyStudentLoading) {
return;
}
yield put({
type: 'updateState',
payload: {
historyStudentLoading: true,
},
});
const studentDelete = yield call(studentsAjax.studentsHistory, {
ids: studentsId,
stat_time_status,
status,
});
yield put({
type: 'updateState',
payload: {
historyStudentLoading: false,
},
});
if (studentDelete.code === 200) {
message.success(status === 1 ? '转为在读学员成功' : '转为历史在读学员成功', 1);
yield put({
type: 'studentsList',
payload: {
params: {
},
},
});
yield put({
type: 'updateState',
payload: {
deleteVisible: false,
},
});
if (callBack && (typeof callBack == 'function')) {
callBack();
}
} else {
yield put({
type: 'webapp/errorrequestresolve',
payload: {
data: studentDelete,
},
});
}
},
* goDeleteStudent({ payload }, { call, put, select }) {
const { stat_time_status, status, callBack } = payload;
const { sid } = yield select(state => state.webapp);
const { studentsId, historyStudentLoading } = yield select(state => state.students);
if (historyStudentLoading) {
return;
}
yield put({
type: 'updateState',
payload: {
historyStudentLoading: true,
},
});
const studentDelete = yield call(studentsAjax.studentsDelete, {
ids: studentsId,
stat_time_status,
});
yield put({
type: 'updateState',
payload: {
historyStudentLoading: false,
},
});
if (studentDelete.code === 200) {
message.success('删除学员成功', 1);
yield put({
type: 'studentsList',
payload: {
params: {
},
},
});
yield put({
type: 'updateState',
payload: {
deleteVisible: false,
deleteOneVisible: false,
},
});
if (callBack && (typeof callBack == 'function')) {
callBack();
}
} else {
yield put({
type: 'webapp/errorrequestresolve',
payload: {
data: studentDelete,
},
});
}
},
* pageInit({ payload }, { call, put, select }) {
yield put({
type: 'updateState',
......@@ -1047,6 +1153,7 @@ export default {
extra: 'time,recently_course',
birthday_start: '',
birthday_end: '',
status: 1,
},
searchstudentListQueryParams: {
school_id: 0,
......@@ -1101,6 +1208,10 @@ export default {
inviteCodeShow: false,
inviteCode: '',
Inviteloading: false,
deleteVisible: false,
studentsId: 0,
historyStudentLoading: false,
deleteOneVisible: false,
},
});
},
......
import { connect } from 'dva';
import React from 'react';
import PropTypes from 'prop-types';
import { message, Row, Col, Input, Select, Modal, Form, InputNumber, Checkbox } from 'antd';
import { imagify, pageIn } from '../../utils/index';
import pageStyle from './WxPushTimeModal.less';
const FormItem = Form.Item;
class WxPushTimeModal extends React.Component {
componentWillMount() {
}
componentDidUpdate() {
}
componentWillUpdate() {
}
componentDidMount() { // 挂载
pageIn('班级管理');
}
componentWillUnmount() { // 卸载
}
componentWillReceiveProps(nextProps) {
}
save = () => {
const { form, save } = this.props;
form.validateFields((err, values) => {
if (!err) {
const {
schedule_remind,
teacher_minutes,
parent_minutes,
type,
} = values;
save({
schedule_remind: schedule_remind ? 1 : 2,
teacher_minutes,
parent_minutes,
type,
callBack: () => {
form.resetFields();
},
});
}
});
}
close = () => {
const { form, close } = this.props;
form.resetFields();
close();
}
render() {
const {
visible,
wxSubmitting,
form: { getFieldDecorator, getFieldValue },
wxConfig,
} = this.props;
const formItemModalLineLayout = {
labelCol: {
xs: { span: 24 },
sm: { span: 5 },
},
wrapperCol: {
xs: { span: 24 },
sm: { span: 19 },
},
};
return (
<Modal
visible={visible}
title="微信推送设置"
okText={!wxSubmitting ? '保存' : '保存中...'}
confirmLoading={wxSubmitting}
onCancel={this.close}
onOk={this.save}
className="modifyclassModal"
maskClosable={false}
zIndex={110}
>
<Form hideRequiredMark className={pageStyle.modalform} labelAlign="left">
<FormItem>
{getFieldDecorator('schedule_remind', {
valuePropName: 'checked',
initialValue: Number(wxConfig.schedule_remind_on_off) == 1,
})(<Checkbox><span className={pageStyle.tip}>微信服务推送通知</span></Checkbox>)}
</FormItem>
{getFieldDecorator('type', { initialValue: 1 })(<Input type="hidden" />)}
<FormItem className={pageStyle.firstItem} {...formItemModalLineLayout} label="家长:上课前">
{getFieldDecorator('parent_minutes', {
initialValue: wxConfig.schedule_remind_student_before,
rules: [
{
required: true,
message: '请输入正整数',
pattern: new RegExp(/^[1-9]\d*$/, 'g'),
},
],
})(<InputNumber min={0} />)}
<span className="ant-form-text"> 分钟推送上课提醒</span>
</FormItem>
<FormItem className={pageStyle.firstItem} {...formItemModalLineLayout} label="老师:上课前">
{getFieldDecorator('teacher_minutes', {
initialValue: wxConfig.schedule_remind_teacher_before,
rules: [
{
required: true,
message: '请输入正整数',
pattern: new RegExp(/^[1-9]\d*$/, 'g'),
},
],
})(<InputNumber min={0} />)}
<span className="ant-form-text"> 分钟推送上课提醒</span>
</FormItem>
</Form>
</Modal>
);
}
}
const WxPushTime = Form.create()(WxPushTimeModal);
export default WxPushTime;
.modalform {
.tip {
font-size:14px;
font-family:PingFangSC-Medium,PingFang SC;
font-weight:500;
color:rgba(0,0,0,0.65);
display: inline-block;
margin-left: 15px;
}
.firstItem {
margin-left: 40px;
}
:global {
.ant-form-item-label > label::after {
content: '';
}
}
}
......@@ -8,7 +8,7 @@ import EditClassModal from './EditClassModal';
import ClassRoomMgt from './classRoomMgt';
import ClassStatusChangeModal from './ClassStatusChangeModal';
import ClassrRgistration from './classrRgistration';
import WxPushTimeModal from './WxPushTimeModal';
const { Option } = Select;
const { TextArea } = Input;
class ClassMgtForm extends React.Component {
......@@ -410,6 +410,34 @@ class ClassMgtForm extends React.Component {
},
});
}
wxSwitch = () => {
const { dispatch } = this.props;
dispatch({
type: 'classmgt/selectWxConfig',
});
dispatch({
type: 'classmgt/updateState',
payload: {
wxVisible: true,
},
});
}
handleWxCancel = () => {
const { dispatch } = this.props;
dispatch({
type: 'classmgt/updateState',
payload: {
wxVisible: false,
},
});
}
handleSaveWx = (value) => {
const { dispatch } = this.props;
dispatch({
type: 'classmgt/saveWxConfig',
payload: value,
});
}
render() {
const { getFieldDecorator } = this.props.form;
const {
......@@ -431,6 +459,9 @@ class ClassMgtForm extends React.Component {
classInviteqrcodeUrl,
classInviteqrcodeUrl2,
inviteClassInfo,
wxVisible,
wxSubmitting,
wxConfig,
} = this.props;
const visible = false;
const columns = [
......@@ -539,6 +570,7 @@ class ClassMgtForm extends React.Component {
<div className={pageStyle.container}>
<div className={pageStyle.headerbox}>
{hasBtnPower('sjd/classmgt', 'addClass') && <Button icon="plus" className={pageStyle.headerbtn} type="primary" onClick={this.addClass}>添加班级</Button>}
{/* <Button className={pageStyle.headerbtn} onClick={this.wxSwitch} >微信推送设置</Button> */}
{hasBtnPower('sjd/classmgt', 'allWindingUp') && <Button className={pageStyle.headerbtn} onClick={this.operateClassStatus}>批量结业</Button>}
<Button icon="download" className={pageStyle.headerbtn} onClick={() => this.exportExcel(columns)} >导出</Button>
</div>
......@@ -674,6 +706,13 @@ class ClassMgtForm extends React.Component {
inviteClassInfo={inviteClassInfo}
codeImgClose={this.codeImgClose}
/>
<WxPushTimeModal
visible={wxVisible}
close={this.handleWxCancel}
save={this.handleSaveWx}
wxSubmitting={wxSubmitting}
wxConfig={wxConfig}
/>
</div>
);
}
......@@ -709,6 +748,9 @@ function mapStateToProps(state) {
classInviteqrcodeUrl,
classInviteqrcodeUrl2,
inviteClassInfo,
wxVisible,
wxSubmitting,
wxConfig,
} = state.classmgt;
return {
classList,
......@@ -735,6 +777,9 @@ function mapStateToProps(state) {
classInviteqrcodeUrl,
classInviteqrcodeUrl2,
inviteClassInfo,
wxVisible,
wxSubmitting,
wxConfig,
};
}
export default connect(mapStateToProps)(ClassMgt);
......
......@@ -13,7 +13,7 @@ class eliminateEdit extends React.Component {
currentCourse: {
course_mode: 1,
},
expendValue: 0,
expendValue: null,
};
}
componentDidMount() { // 挂载
......@@ -42,7 +42,7 @@ class eliminateEdit extends React.Component {
currentCourse: {
surplus: 0,
},
expendValue: 0,
expendValue: null,
});
}
});
......@@ -58,6 +58,7 @@ class eliminateEdit extends React.Component {
const { close, form, dispatch } = this.props;
form.resetFields();
this.setState({
expendValue: null,
currentCourse: {
surplus: 0,
},
......@@ -186,10 +187,10 @@ class eliminateEdit extends React.Component {
}}
>
{currentCourse.course_mode == 1 &&
<span>{expendValue || 0} 课时</span>
<span>{expendValue || currentCourse.surplus } 课时</span>
}
{currentCourse.course_mode == 2 &&
<span>{expendValue || 0} </span>
<span>{expendValue || currentCourse.surplus} </span>
}
</Form.Item>
) : (
......
This diff is collapsed.
......@@ -202,3 +202,147 @@
float: left;
}
}
.tabFlex {
display: flex;
align-items: center;
margin-left: 35px;
margin-top: 20px;
.tabItem {
font-size:16px;
font-family:PingFang SC;
font-weight:400;
color:rgba(128,128,128,1);
cursor: pointer;
height: 40px;
line-height: 40px;
}
.tabActive {
font-size:16px;
font-family:PingFang SC;
font-weight:400;
color:rgba(33,148,255,1);
position: relative;
cursor: pointer;
&:after {
position: absolute;
content: '';
display: block;
width: 70%;
height: 2px;
left: 10%;
bottom: -10px;
background-color: #4DA1FF;
}
}
}
.deleteModal {
:global {
.ant-modal-close {
right: -80px;
top: -25px;
.ant-modal-close-x {
font-size: 30px;
}
}
}
}
.modalHead {
.tabItem {
display: flex;
justify-content: center;
align-items: center;
flex-direction: column;
font-size: 16px;
}
.tabTip {
font-size: 12px;
color: rgba(0,0,0,0.5);
}
.tabTip1 {
font-size: 12px;
color: rgba(0,0,0,0.5);
}
:global {
.ant-tabs {
color: #000;
}
.ant-tabs-bar {
margin: 0;
}
.ant-tabs-nav{
//margin: 0 100px 0 0;
.ant-tabs-tab:first-child {
margin-right: 100px;
}
}
.ant-tabs-tab:nth-child(2):hover {
color: #FF4242;
}
.ant-tabs-tab:nth-child(2).ant-tabs-tab-active {
color: #FF4242;
}
}
}
.modalBody {
.commonTitle {
font-size:14px;
font-family:PingFang SC;
font-weight:500;
color:rgba(0,0,0,.85);
margin: 10px 0;
span {
color: #2194FF;
display: inline-block;
margin-left: 15px;
cursor: pointer;
}
}
p {
font-size:14px;
font-family:PingFang SC;
font-weight:500;
color:rgba(0,0,0,.5);
margin-bottom: 12px;
}
.radioOption {
display: flex;
align-items: flex-start;
margin: 20px 0 30px;
}
.commonNotice {
font-size:14px;
font-family:PingFang SC;
font-weight:500;
color:rgba(0,0,0,1);
margin: 60px 0;
span {
font-size: 12px;
color: #FF4242;
display: inline-block;
width: 35px;
height: 17px;
border: 1px solid #FF4242;
background-color: rgba(255,75,105,0.1);
line-height: 17px;
border-radius: 4px;
text-align: center;
margin-right: 10px;
}
}
}
.modalFooter {
text-align: center;
.commonInput {
margin: 0 auto;
margin-bottom: 20px;
border: 1px solid #FF4242;
width: 252px;
display: block;
}
:global {
.ant-input:focus {
border-color:#FF4242;
box-shadow: 0 0 0 2px rgba(255, 66, 66, .2);
}
}
}
......@@ -872,6 +872,10 @@ class StudentMgt extends React.Component {
return <div className={pageStyle.logitem}>{item.created_at} 老师:<span className={pageStyle.logTeacherName}>{item.data.teacher_name || '-'}</span> 为学员:<span className={pageStyle.logTeacherName}>{item.data.student_name || '-'}</span> <span className={pageStyle.logAction}>消除课时</span>:{item.data.expend || '-'}{item.data.mode_type == 2 && '天'} (<span className={pageStyle.logTeacherName}>{item.data.course_title || '-'}</span> )</div>;
case 10:
return <div className={pageStyle.logitem}>{item.created_at} 老师:<span className={pageStyle.logTeacherName}>{item.data.teacher_name || '-'}</span> <span className={pageStyle.logAction}>点名学员</span><span className={pageStyle.logTeacherName}>{item.data.student_name || '-'}</span> 状态: <span className={pageStyle.logAction}>{item.data.type == 1 && '到课'}{item.data.type == 3 && '请假'}{item.data.type == 2 && '迟到'}{item.data.type == 4 && '未到'}</span> {item.data.course_mode == 1 && `扣除课时${item.data.expend}课时`}</div>;
case 11:
return <div className={pageStyle.logitem}> {item.created_at} 老师:<span className={pageStyle.logTeacherName}>{item.data.teacher_name || '-'}</span> 为学员:<span className={pageStyle.logTeacherName}>{item.data.student_name || '-'}</span>转为<span className={pageStyle.logAction}>历史在读学员</span> &nbsp;并清除<span className={pageStyle.logTeacherName}>{item.data.student_name || '-'}</span>在机构中的历史课程数据</div>;
case 12:
return <div className={pageStyle.logitem}> {item.created_at} 老师:<span className={pageStyle.logTeacherName}>{item.data.teacher_name || '-'}</span> 为学员:<span className={pageStyle.logTeacherName}>{item.data.student_name || '-'}</span>转为<span className={pageStyle.logAction}>在读学员</span></div>;
default: return null;
}
})()}
......
......@@ -111,3 +111,19 @@ export function studentAdjust(params) {
data,
});
}
export function wxConfig(params) {
const data = qs.stringify(params);
return request({
url: `${api.classMgt.wxConfig}`,
method: 'POST',
data,
});
}
export function GetWxConfig(params) {
const data = qs.stringify(params);
return request({
url: `${api.classMgt.wxConfig}?${data}`,
method: 'GET',
data,
});
}
......@@ -80,3 +80,19 @@ export function createSchoolUuid(params) {
method: 'GET',
});
}
export function studentsDelete(parmas) {
const data = qs.stringify(parmas);
return request({
url: `${api.students.studentsinfo}?${data}`,
method: 'DELETE',
data,
});
}
export function studentsHistory(parmas) {
const data = qs.stringify(parmas);
return request({
url: `${api.students.studentHistory}?${data}`,
method: 'DELETE',
data,
});
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment