Commit 3dff18a8 by guomingpang

Merge branch 'dev' of…

Merge branch 'dev' of ssh://xmgit.ixm5.cn:10022/xiaomai-cloud-class/xiaomai-cloud-class-web into dev
parents d9ac3788 3ef3f08f
......@@ -613,10 +613,11 @@ module.exports = function (webpackEnv) {
silent: true,
// The formatter is invoked directly in WebpackDevServerUtils during development
formatter: isEnvProduction ? typescriptFormatter : undefined
}),
new vConsolePlugin({
enable: (process.env.DEPLOY_ENV === 'prod' || process.env.DEPLOY_ENV === 'beta') ? false : true
})
// new vConsolePlugin({
// enable: (process.env.DEPLOY_ENV === 'prod' || process.env.DEPLOY_ENV === 'beta') ? false : true
// })
].filter(Boolean),
// Some libraries import Node modules but don't use them in the browser.
// Tell webpack to provide empty mocks for them so importing them works.
......
......@@ -4,7 +4,7 @@
* @Author: 吴文洁
* @Date: 2020-06-05 14:59:14
* @LastEditors: 吴文洁
* @LastEditTime: 2020-08-04 19:28:08
* @LastEditTime: 2020-10-09 15:30:45
* @Description:
* @Copyrigh: © 2020 杭州杰竞科技有限公司 版权所有
*/
......
......@@ -2,8 +2,8 @@
/*
* @Author: 吴文洁
* @Date: 2020-06-05 09:38:03
* @LastEditors: 吴文洁
* @LastEditTime: 2020-09-02 15:45:50
* @LastEditors: louzhedong
* @LastEditTime: 2020-12-26 16:08:19
* @Description:
* @Copyrigh: © 2020 杭州杰竞科技有限公司 版权所有
*/
......@@ -14,7 +14,7 @@ const execSync = require('child_process').execSync;
const branchName = execSync('git rev-parse --abbrev-ref HEAD').toString().trim();
// 校验分支名是否合法
const firstPattern = new RegExp('dev|rc|gray|master');
const secondPattern = new RegExp('(feature|hotfix)/[a-z]{4,}/[0-9]{8,}/[a-zA-Z-]{4,}');
const secondPattern = new RegExp('(feature|hotfix)/[a-z]{4,}/[0-9]{8,}/[0-9a-zA-Z-]{3,}');
const firstMatch = firstPattern.test(branchName);
const secondMatch = secondPattern.test(branchName);
......@@ -27,10 +27,11 @@ if (!firstMatch && !secondMatch) {
// 获取缓存区内容
// 通过diff指令获得所有改动过(不包括删除)的js文件路径
const fileNameStr = execSync('git diff --diff-filter=AM --cached HEAD --name-only').toString();
const fileNameList = fileNameStr.split('\n').filter(item => !!item);
// 过滤掉空格
const fileNameList = fileNameStr.split('\n').filter((item) => !!item);
// 获取需要检测的文件
const detectedFileList = fileNameList.filter(file => {
const detectedFileList = fileNameList.filter((file) => {
// 过滤掉空的和hooks文件夹下所有的文件
return file && file.indexOf('hooks') < 0;
});
......@@ -39,7 +40,7 @@ const detectedFileList = fileNameList.filter(file => {
let errorFileList = [];
detectedFileList.forEach((file) => {
const results = execSync(`git diff --cached ${file}`);
const pattern = /^http:\/\/{1,}/;
const pattern = /^http\:\/\/.{1,}/;
if (pattern.test(results.toString())) {
errorFileList.push(file);
}
......@@ -60,7 +61,7 @@ fileNameList.forEach((file) => {
if (conflictPattern.test(results)) {
conflictFileList.push(file);
}
})
});
if (conflictFileList.length > 0) {
const conflictFileStr = JSON.stringify(conflictFileList);
// eslint-disable-next-line no-console
......
......@@ -22,7 +22,7 @@
"@typescript-eslint/eslint-plugin": "^2.10.0",
"@typescript-eslint/parser": "^2.10.0",
"ali-oss": "^6.12.0",
"antd": "^4.16.3",
"antd": "4.16.5",
"array-move": "^3.0.1",
"axios": "^0.20.0",
"babel-eslint": "10.1.0",
......@@ -55,7 +55,7 @@
"fs-extra": "^8.1.0",
"html-webpack-plugin": "4.0.0-beta.11",
"html2canvas": "^1.0.0-rc.7",
"husky": "^4.2.5",
"husky": "^4.3.0",
"identity-obj-proxy": "3.0.0",
"jest": "24.9.0",
"jest-environment-jsdom-fourteen": "1.0.1",
......@@ -110,7 +110,7 @@
"start:dev1": "cross-env DEPLOY_ENV=dev node scripts/start.js",
"start:rc": "cross-env DEPLOY_ENV=rc node scripts/start.js",
"start:gray": "cross-env DEPLOY_ENV=gray node scripts/start.js",
"build:dev": "cross-env DEPLOY_ENV=dev node scripts/build.js",
"build:dev": "cross-env DEPLOY_ENV=dev node --max_old_space_size=4096 scripts/build.js",
"build:dev1": "cross-env DEPLOY_ENV=dev node scripts/build.js",
"build:rc": "cross-env DEPLOY_ENV=rc node scripts/build.js",
"build:gray": "cross-env DEPLOY_ENV=gray node scripts/build.js",
......@@ -144,6 +144,13 @@
"@types/jquery": "^3.5.4",
"ali-oss": "^6.12.0",
"react-sortable-hoc": "^1.11.0",
"vconsole-webpack-plugin": "^1.5.2"
"vconsole-webpack-plugin": "^1.6.1"
},
"husky": {
"hooks": {
"pre-commit": "node hooks/pre-commit.js",
"commit-msg": "node hooks/commit-msg.js",
"pre-push": "node hooks/pre-commit.js"
}
}
}
......@@ -44,6 +44,10 @@ const FileVerifyMap = {
type: "word",
maxSize: 100
},
"application/wps-writer": {
type: "word",
maxSize: 100,
},
"application/vnd.openxmlformats-officedocument.wordprocessingml.document": {
type: "word",
maxSize: 100
......
......@@ -2,7 +2,7 @@
* @Author: 吴文洁
* @Date: 2020-08-31 09:34:31
* @LastEditors: yuananting
* @LastEditTime: 2021-07-12 17:40:26
* @LastEditTime: 2021-07-14 10:49:14
* @Description:
* @Copyright: 杭州杰竞科技有限公司 版权所有
*/
......
......@@ -2,7 +2,7 @@
* @Author: 吴文洁
* @Date: 2020-08-31 09:34:25
* @LastEditors: Please set LastEditors
* @LastEditTime: 2021-06-23 16:08:50
* @LastEditTime: 2021-06-23 16:14:11
* @Description:
* @Copyright: 杭州杰竞科技有限公司 版权所有
*/
......
/*
* @Author: wufan
* @Date: 2021-05-11 10:21:37
* @LastEditors: fusanqiasng
* @LastEditTime: 2021-06-22 16:52:48
* @Description: 企业微信api
* @@Copyrigh: © 2020 杭州杰竞科技有限公司 版权所有
*/
import User from '@/common/js/user';
import Service from '@/common/js/service';
import Platform from '@/core/platform';
export default class WechatApi {
static async initConfig(params = { isAgentConfig: false, url: '' }) {
return Service.Hades('anon/hades/getWxCorpJSAPISignature', {
storeId: User.getStoreId(),
url: params.url,
}).then((result) => {
const res = result.result;
this.config({
beta: true, // 必须这么写,否则wx.invoke调用形式的jsapi会有问题
debug: false, // 开启调试模式,调用的所有api的返回值会在客户端alert出来,若要查看传入的参数,可以在pc端打开,参数信息会通过log打出,仅在pc端时才会打印。
appId: res.appId, // 必填,企业微信的corpID
timestamp: res.timestamp, // 必填,生成签名的时间戳
nonceStr: res.nonceStr, // 必填,生成签名的随机串
signature: res.signature, // 必填,签名,见 附录-JS-SDK使用权限签名算法
jsApiList: ['chooseImage', 'shareToExternalContact', 'selectExternalContact', 'selectEnterpriseContact'],
}).then(() => {
console.log('微信config设置完毕')
if (params.isAgentConfig) {
return new Promise(async (resolve, reject) => {
Service.Hades('anon/hades/getWxWorkJSAPISignature', {
storeId: User.getStoreId(),
url: params.url,
}).then((result2) => {
const res2 = result2.result;
this.agentConfig({
corpid: res2.corpid, // 必填,企业微信的corpid,必须与当前登录的企业一致
agentid: res2.agentid, // 必填,企业微信的应用id (e.g. 1000247)
timestamp: res2.timestamp, // 必填,生成签名的时间戳
nonceStr: res2.nonceStr, // 必填,生成签名的随机串
signature: res2.signature, // 必填,签名,见附录-JS-SDK使用权限签名算法
jsApiList: ['selectExternalContact', 'getCurExternalContact', 'getContext', 'shareToExternalContact', 'sendChatMessage', 'shareToExternalChat'],
success: (res) => {
console.log(res, 'res-agentconfig');
console.info('window.WWOpenData', window.WWOpenData);
resolve(res);
},
fail: (err) => {
console.log(1213545344545)
console.log(err, 'err-agentconfig');
reject(err);
},
});
});
});
}
})
});
}
static async config(config) {
return new Promise((resolve, reject) => {
console.info('wx.config', config);
wx.config(config);
wx.ready(resolve);
wx.error(reject);
}).then(
() => {
console.info('wx.ready');
},
(error) => {
console.error('wx.error', error);
throw error;
}
);
}
static async agentConfig(config) {
return new Promise((success, fail) => {
console.info('wx.agentConfig', config);
wx.agentConfig({ ...config, success, fail });
}).then(
(res) => {
console.info('wx.agentConfig success', res);
return res;
},
(error) => {
console.error('wx.agentConfig fail', error);
throw error;
}
);
}
static getCurExternalContact() {
return new Promise((resolve, reject) => {
wx.ready(() => {
wx.invoke('getCurExternalContact', {}, function (res) {
if (res.err_msg == 'getCurExternalContact:ok') {
resolve(res.userId); //返回当前外部联系人userId
} else {
reject(res.err_msg); //错误处理
}
});
});
});
}
static getContext() {
return new Promise((resolve, reject) => {
wx.ready(() => {
wx.invoke('getContext', {}, function (res) {
if (res.err_msg == 'getContext:ok') {
resolve(res.entry); //返回进入H5页面的入口类型,目前有normal、contact_profile、single_chat_tools、group_chat_tools、chat_attachment
} else {
reject(res.err_msg); //错误处理
}
});
});
});
}
}
import React, { useRef, useLayoutEffect } from 'react'
export default function WWOpenDataCom({ type, openid }) {
const ref = useRef(null)
useLayoutEffect(() => {
console.log(WWOpenData)
WWOpenData && WWOpenData.bind(ref.current)
})
return <ww-open-data ref={ref} type={type} openid={openid} />
}
\ No newline at end of file
......@@ -1699,3 +1699,23 @@ input:focus {
.ant-tag-blue{
background: transparent !important;
}
.createQWCourse{
.footer {
position: fixed;
bottom: 0;
height: 58px;
width: 100%;
display: flex;
align-items: center;
justify-content: flex-end;
padding-right: 252px;
background: #fff;
border-top: 1px solid #E8E8E8;
z-index: 999;
.ant-btn {
margin-left: 10px;
}
}
}
\ No newline at end of file
module.exports = {
isWeiXin() {
const ua = navigator.userAgent.toLowerCase();
return ua.indexOf('micromessenger') > 0;
},
isWorkWx (){
return /wxwork/i.test(navigator.userAgent)
},
isAlipay() {
const ua = navigator.userAgent.toLowerCase();
return ua.indexOf('aliapp') > 0 || ua.indexOf('alipay') > 0;
},
isXiaoMaiApp() {
const ua = navigator.userAgent.toLowerCase();
return ua.match(/xiaomai_ios/i) === 'xiaomai_ios' || ua.match(/xiaomai_android/i) === 'xiaomai_android';
},
isXiaoMaiIOSApp() {
const ua = navigator.userAgent.toLowerCase();
return ua.match(/xiaomai_ios/i) === 'xiaomai_ios';
},
isXiaoMaiAndroidApp() {
const ua = navigator.userAgent.toLowerCase();
return ua.match(/xiaomai_android/i) === 'xiaomai_android';
},
isAndroid() {
const ua = navigator.userAgent.toLowerCase();
return /android/i.test(ua);
},
isIOS() {
const ua = navigator.userAgent.toLowerCase();
return /iphone|ipad|ipod/i.test(ua);
},
isMeiKe() {
const ua = navigator.userAgent.toLowerCase();
return /xmappc/i.test(ua);
},
};
\ No newline at end of file
import Platform from './platform';
import Service from "@/common/js/service";
import User from '@/common/js/user';
export default class WechatApi {
static initShareConfig() {
// if (Platform.isWeiXin()) {
const data = { url: window.location.href.split('#')[0], storeId: User.getStoreId(), }
Service.Hades('anon/hades/getWxWorkJSAPISignature', data).then((result) => {
const res = result.result;
const conf ={
corpid: res.corpid, // 必填,企业微信的corpid,必须与当前登录的企业一致
agentid: res.agentid, // 必填,企业微信的应用id (e.g. 1000247)
timestamp: res.timestamp, // 必填,生成签名的时间戳
nonceStr: res.nonceStr,// 必填,生成签名的随机串
signature: res.signature,
jsApiList: ['startLiving','downloadLivingReplay'],
success: function(res) {
console.log('agentConfig注册成功')
console.log(res,'agentConfig')
},
fail: function(res) {
console.log(res,' agentConfig1 错误')
if(res.errMsg.indexOf('function not exist') > -1){
alert('版本过低请升级')
}
},
complete:(res)=>{
console.log(res,' agentConfig2 错误')
}
}
console.log(conf)
wx.agentConfig(conf);
});
// }
}
}
\ No newline at end of file
......@@ -52,7 +52,6 @@ export function getWXWorkLoginNoCheck(params: object) {
export function getLesseeVersionMsg() {
return Service.Hades("public/customerHades/getLesseeVersionMsg",{enterpriseId:User.getEnterpriseId()})
}
export function getYoZoSign(params: object) {
return Service.Apollo('public/apollo/getYoZoSign', params);
}
......
......@@ -61,7 +61,7 @@ export default class StoreService {
}
static getYoZoSign(params:any){
return new Promise((resolve) => {
getYoZoSign(params).then(res => {
getYoZoSign(params).then((res:any) => {
const { result = [] } = res;
resolve(result)
});
......
/*
* @Author: 吴文洁
* @Date: 2020-08-20 09:21:40
* @LastEditors: zhangleyuan
* @LastEditTime: 2021-03-04 17:16:30
* @LastEditors: yuananting
* @LastEditTime: 2021-07-15 11:48:58
* @Description:
* @Copyright: 杭州杰竞科技有限公司 版权所有
*/
......@@ -77,6 +77,10 @@ const FILR_VERIFY_MAP = {
type: "word",
maxSize: 100
},
"application/wps-writer": {
type: "word",
maxSize: 100,
},
"application/vnd.openxmlformats-officedocument.wordprocessingml.document": {
type: "word",
maxSize: 100
......
......@@ -47,6 +47,8 @@
<script type="text/javascript" src="https://image.xiaomaiketang.com/xm/PhotoClip.js"></script>
<script type="text/javascript" charset="utf-8" src="//g.alicdn.com/sd/ncpc/nc.js?t=2015052012"></script>
<script type="text/javascript" src="https://xiaomai-js.oss-cn-hangzhou.aliyuncs.com/loghub-xm-0.0.1-beta.js"></script>
<script type="text/javascript" src="//res.wx.qq.com/open/js/jweixin-1.2.0.js"></script>
<script type="text/javascript" src="//open.work.weixin.qq.com/wwopen/js/jwxwork-1.0.0.js"></script>
</head>
<body>
<noscript>You need to enable JavaScript to run this app.</noscript>
......
......@@ -111,7 +111,7 @@ class CollegeInfoPage extends React.Component {
} = this.state;
return (
<div className="page college-info-page">
<div className="content-header">学院基本信息</div>
<div className="content-header">学院信息</div>
<div className="box">
<div className="college-info-page-form">
......
......@@ -15,6 +15,8 @@ import college from '@/common/lottie/college.json';
import StoreService from "@/domains/store-domain/storeService";
import EmployeeAddOrEditModal from "../store-manage/EmployeeAddOrEditModal";
import User from "@/common/js/user";
import WechatApi from '@/common/js/wechatApi';
import WWOpenDataCom from '@/components/WWOpenDataCom';
import LimitTip from "./LimitTip";
import "./EmployeeManage.less";
......@@ -106,8 +108,11 @@ function EmployeeManage() {
useEffect(() => {
getListInfo();
}, [storeId]);
async function getListInfo() {
await getStoreRole();
}
......@@ -152,7 +157,11 @@ function EmployeeManage() {
/>
)}
<span className="title">{val}</span>
{/* <span className="title">{val}</span> */}
<span className="title">
<WWOpenDataCom type="userName" openid={val} />
</span>
</div>
);
},
......@@ -188,7 +197,7 @@ function EmployeeManage() {
<span className="divider-line">{" | "}</span>
<span
className="delete"
onClick={() =>{
onClick={() => {
handleDeleteWorkWechatEmployeeConfirm(record)
}}
>
......@@ -237,7 +246,7 @@ function EmployeeManage() {
role: [],
avatar: "",
storeUserId: "",
weChatAccount:""
weChatAccount: ""
});
}}
isWorkWechat={isWorkWechat}
......@@ -268,7 +277,7 @@ function EmployeeManage() {
function handleDeleteEmployee(storeUserId: string) {
StoreService.deleteEmployee({ storeUserId }).then((res: any) => {
const msg = isWorkWechat ? "员工已删除":"讲师已删除";
const msg = isWorkWechat ? "员工已删除" : "讲师已删除";
message.success(msg);
getEmployeeList();
});
......@@ -375,7 +384,7 @@ function EmployeeManage() {
</Button>
}
</div>
<LimitTip type="员工" total={realTotal} tip={()=>{return (<div>数据为当前学院的员工数,若员工存在多个学院,企业人数只统计为1人</div>)}}/>
<LimitTip type="员工" total={realTotal} tip={() => { return (<div>数据为当前学院的员工数,若员工存在多个学院,企业人数只统计为1人</div>) }} />
<div className="box-body">
<XMTable
renderEmpty={{
......
......@@ -15,10 +15,9 @@ import { Input, DatePicker, Select, Button, message } from "antd";
import StoreService from "@/domains/store-domain/storeService";
import User from "@/common/js/user";
import ChooseMembersModal from "./modal/ChooseMembersModal";
import LimitTip from "./LimitTip"
import { XMTable } from '@/components';
import college from '@/common/lottie/college.json';
import LimitTip from "./LimitTip"
import "./UserManagePage.less";
import moment from "moment";
......
......@@ -14,6 +14,8 @@ import SetEmployeeModal from "./SetEmployeeModal";
import search from '../../lottie/search/data.json';
import './ChooseMembersModal.less';
import _ from 'underscore';
import WechatApi from '@/common/js/wechatApi';
import WWOpenDataCom from '@/components/WWOpenDataCom';
const { Search } = Input;
......@@ -42,8 +44,48 @@ class ChooseMembersModal extends React.Component {
componentDidMount() {
this.getUserAuthority();
this.initWechatConfig();
}
initWechatConfig = async () => {
WechatApi.initConfig({ isAgentConfig: true, url: window.location.href.split('#')[0] }).then(()=>{
console.info('window.WWOpenData', window.WWOpenData);
// if (WWOpenData.checkSession) {
// WWOpenData.checkSession({
// success() {
// console.info('open-data 登录态校验成功')
// },
// fail() {
// console.error('open-data 登录态过期')
// },
// })
// }
// if (WWOpenData.on) {
// /**
// * ww-open-data 元素数据发生变更时触发
// */
// WWOpenData.on('update', event => {
// const openid = event.detail.element.getAttribute('openid')
// console.info('渲染数据发生变更', openid, event.detail.hasData)
// })
// /**
// * ww-open-data 获取数据失败时触发
// */
// WWOpenData.on('error', () => {
// console.error('获取数据失败')
// })
// }
// WWOpenData.bindAll(document.querySelectorAll('ww-open-data'))
})
.catch(error=>{
console.log("error-----",error);
})
}
// 获取对应文件相关成员
getUserAuthority = (searchKey='') => {
const { query } = this.state;
......@@ -219,6 +261,7 @@ class ChooseMembersModal extends React.Component {
<span className="icon iconfont avatar-icon">&#xe84a;</span>
<Tooltip title={name}>
<span className='userImg'>{name}</span>
{/* <WWOpenDataCom type="userName" openid={name}/> */}
</Tooltip>
</div>
)
......
import React, { useState, useRef, useEffect, useContext } from 'react'
import { Route, withRouter } from 'react-router-dom';
import Breadcrumbs from "@/components/Breadcrumbs";
import moment from 'moment'
import { LIVE_SHARE } from "@/domains/course-domain/constants";
import { Form, Alert, Input, Button, InputNumber, DatePicker, Select, Radio, message, Modal } from 'antd';
import Service from "@/common/js/service";
import User from "@/common/js/user";
import qrcode from "@/libs/qrcode/qrcode.js";
declare var wx: any;
const { Option } = Select;
const courseType = {
0: '通用直播',
1: '小班课',
2: '大班课',
3: '企业培训',
4: '活动直播'
}
function CerateQWCourse(props: any) {
const [courseName, setCourseName] = useState('');
const [liveDuration, setLiveDuration] = useState(60);
const [liveStart, setLiveStart] = useState(0);
const [type, setType] = useState('0');
const [livingId, setLivingId] = useState(0);
function handleSave() {
const param = {
courseName,
description: '直播的简介,最多支持300个字节直播的简介,最多支持300个字节直播的简介,最多支持300个字节直播的简介,最多支持300个字节直播的简介,最多支持300个字节直播的简介,最多支持300个字节',
liveDuration: liveDuration * 60 * 100,
liveStart,
remindTime: 1000 * 60 * 10,
storeId: User.getStoreId(),
storeUserId: User.getStoreUserId(),
type: parseInt(type)
}
Service.Hades('anon/hades/wxWorkCreateLiveDemo', param).then((res) => {
console.log(22)
handleConvertShortUrl(res.result)
setLivingId(res.result)
wx.invoke('startLiving', {
"livingId": res.result,
}, function (res: any) {
console.log(122, res)
if (res.err_msg == "startLiving:ok") {
// livingId = res.livingId;
}
});
})
}
function handleConvertShortUrl(id: any) {
const longUrl = `${LIVE_SHARE}qw/live/${id}?id=${User.getStoreId()}`
console.log(longUrl)
// 发请求
Service.Sales('public/businessShow/convertShortUrls', {
urls: [longUrl]
}).then((res) => {
const { result = [] } = res;
const qrcodeWrapDom: any = document.querySelector('.qrcode');
qrcodeWrapDom.innerHTML = ''
const qrcodeNode = new qrcode({
text: result[0].shortUrl,
size: 100,
});
(qrcodeWrapDom as any).appendChild(qrcodeNode);
})
}
function downloadLivingReplay(){
wx.invoke('downloadLivingReplay', {
livingId
}, function(res:any) {
console.log(res,'tyuuioythbn')
if (res.err_msg != "downloadLivingReplay:ok") {
// 错误处理
}
});
}
return <div className="page createQWCourse ">
<Breadcrumbs navList={props.type === 'edit' ? "编辑考试" : "新建直播课"} goBack={props.history.goBack} />
<div className="box">
<div className="form">
<div className="title">直播信息</div>
<Form
labelCol={{ span: 3 }}
wrapperCol={{ span: 14 }}
layout="horizontal"
>
<Form.Item label="课程名称"
required>
<Input value={courseName} onChange={(e) => { setCourseName(e.target.value) }} style={{ width: 200 }} ></Input>
</Form.Item>
<Form.Item label="持续时长"
required>
<InputNumber value={liveDuration} max={1440} min={1} onChange={(value: any) => { setLiveDuration(parseInt(value) as any) }} style={{ width: 100 }} />
</Form.Item>
<Form.Item label="开始时间"
required>
<DatePicker
format="YYYY/MM/DD HH:mm"
value={liveStart ? moment(Number(liveStart)) : null}
style={{ width: 200 }}
placeholder="开始时间"
showTime
onChange={(date: any) => { setLiveStart(date ? date.valueOf() : 0) }}
/>
</Form.Item>
<Form.Item label="直播的类型"
required>
<Select value={type} placeholder="请选直播的类型" style={{ width: 200 }} onChange={(val) => {
setType(val)
}} >
{
Object.keys(courseType).map((key: any) => {
return <Option value={key}>{(courseType as any)[key]}</Option>
})
}
</Select>
</Form.Item>
</Form>
</div>
</div>
<div style={{marginTop:100}} className="qrBox">
<div style={{width:100,margin:'0 auto'}} className="qrcode"></div>
</div>
<div className="footer">
<Button onClick={downloadLivingReplay}>下载直播回放</Button>
<Button onClick={props.history.goBack}>取消</Button>
<Button type="primary" onClick={handleSave}>保存</Button>
</div>
</div>
}
export default withRouter(CerateQWCourse);
\ No newline at end of file
......@@ -312,7 +312,7 @@ class LiveCourseList extends React.Component {
return (
<div className='related-task'>
<Choose>
<When condition={record.relatedPlanLis}>
<When condition={record.relatedPlanList}>
<Tooltip title={this.handlePlanName(record.relatedPlanList)} placement='top' arrowPointAtCenter>
{record.relatedPlanList.map((item, index) => {
return (
......
......@@ -9,8 +9,10 @@
import React from 'react';
import { Button, Modal, message } from 'antd';
import Service from '@/common/js/service';
import { withRouter ,Route} from "react-router-dom";
import './liveCourseOpt.less';
import BaseService from "@/domains/basic-domain/baseService";
import CerateQWCourse from './CerateQWCourse'
import User from '@/common/js/user'
class LiveCourseOpt extends React.Component {
constructor(props) {
......@@ -25,6 +27,13 @@ class LiveCourseOpt extends React.Component {
pathname: '/create-live-course?type=add',
})
}
handleCreateQWCouese=()=>{
const { match } = this.props;
this.props.history.push(`${match.url}/createqwcourse`)
}
// 下载直播客户端
handleDownloadClient = () => {
const { isMac } = this.state;
......@@ -47,6 +56,7 @@ class LiveCourseOpt extends React.Component {
}
render() {
const userRole = User.getUserRole();
const { match } = this.props;
return (
<div className="live-course-opt">
<div className="opt__left">
......@@ -55,9 +65,10 @@ class LiveCourseOpt extends React.Component {
}
<Button onClick={this.handleDownloadClient}>下载直播客户端</Button>
</div>
<Route path={`${match.url}/createqwcourse`} component={CerateQWCourse} />
</div>
)
}
}
export default LiveCourseOpt;
\ No newline at end of file
export default withRouter(LiveCourseOpt);
\ No newline at end of file
......@@ -313,7 +313,7 @@ class ManageCoursewareModal extends React.Component {
const { failObject } = this.state;
const uploadFail = failObject[item.id];
// 上课前45分钟/上课中/已结束的情况下都不可操作
// 上课前30分钟/上课中/已结束的情况下都不可操作
if (this.props.data.startTime < Date.now() + 1800000 || item.progress || uploadFail) {
return <span>-</span>;
}
......
/*
* @Author: 吴文洁
* @Date: 2020-07-23 14:54:16
* @LastEditors: yuananting
* @LastEditTime: 2021-07-12 11:39:35
* @LastEditors: Please set LastEditors
* @LastEditTime: 2021-07-14 18:19:22
* @Description: 大班直播课预览弹窗
* @Copyright: 杭州杰竞科技有限公司 版权所有
*/
......@@ -166,12 +166,7 @@ class PreviewCourseModal extends React.Component {
<div className='container__header'>
<Choose>
<When condition={type === 'videoCourse'}>
<video
controls
src={courseChapterList.length && courseChapterList[0].mediaUrl || scheduleVideoUrl }
poster={coverUrl ? coverUrl : `https://image.xiaomaiketang.com/xm/TwtGPQGE4K.png`}
className='course-url'
/>
<img src={coverUrl ? coverUrl : `https://image.xiaomaiketang.com/xm/TwtGPQGE4K.png`} className='course-cover' alt='' />
</When>
<Otherwise>
<img src={coverUrl} className='course-cover' alt='' />
......
......@@ -2,7 +2,7 @@
* @Author: 吴文洁
* @Date: 2020-08-05 10:07:47
* @LastEditors: Please set LastEditors
* @LastEditTime: 2021-07-06 14:47:23
* @LastEditTime: 2021-07-14 11:44:14
* @Description: 线下课新增/编辑页
* @Copyright: 杭州杰竞科技有限公司 版权所有
*/
......@@ -340,9 +340,10 @@ class AddOfflineCourse extends React.Component {
handleSelectCover = (file) => {
this.setState({
visible: true,
imageFile: file,
imageFile: file
});
};
}
//获取resourceId
getSignature = (blob, fileName) => {
......@@ -653,6 +654,11 @@ class AddOfflineCourse extends React.Component {
};
whetherVisitorsJoinChange = () => {
const {whetherSetApply,whetherVisitorsJoin} =this.state;
if(whetherSetApply =='NO'){
message.warning('关闭报名无法获取手机号!')
return
}
if (this.state.whetherVisitorsJoin === 'NO') {
this.setState({ whetherVisitorsJoin: 'YES' });
} else {
......@@ -847,13 +853,7 @@ class AddOfflineCourse extends React.Component {
})}
</Select>
</div>
<div className='allow-tourist-join'>
<span className='label'>观看设置:</span>
<div className='content'>
<Switch checked={whetherVisitorsJoin === 'NO' ? true : false} onChange={this.whetherVisitorsJoinChange} />
<div className='desc'>{whetherVisitorsJoin === 'NO' ? '已开启,学员需绑定手机号才可观看' : '已关闭,学员无需绑定手机号即可观看'}</div>
</div>
</div>
<div className='introduce'>
<span className='label'>课程简介:</span>
<div className='content'>
......@@ -957,6 +957,7 @@ class AddOfflineCourse extends React.Component {
startTimeApply: undefined,
endTimeApply: undefined,
quota: null,
whetherVisitorsJoin: whetherSetApply !== 'YES' ? whetherVisitorsJoin : false
});
}}
/>
......@@ -1068,6 +1069,13 @@ class AddOfflineCourse extends React.Component {
)}
</div>
</div>
<div className='allow-tourist-join'>
<span className='label'>观看设置:</span>
<div className='content'>
<Switch checked={whetherVisitorsJoin === 'NO' ? true : false} onChange={this.whetherVisitorsJoinChange} />
<div className='desc'>{whetherVisitorsJoin === 'NO' ? '已开启,仅限绑定了手机号的学员报名线下课' : '已关闭,允许未绑定手机号的学员报名线下课'}</div>
</div>
</div>
<div className='course-catalog'>
<span className='label'>考勤签到:</span>
<div className='switch-box'>
......
/*
* @Author: 吴文洁
* @Date: 2020-08-05 10:07:47
* @LastEditors: Please set LastEditors
* @LastEditTime: 2021-07-13 15:25:32
* @LastEditors: yuananting
* @LastEditTime: 2021-07-14 16:41:36
* @Description: 线上课新增/编辑页
* @Copyright: 杭州杰竞科技有限公司 版权所有
*/
......@@ -343,13 +343,19 @@ class AddVideoCourse extends React.Component {
})
}
}else{
let _mediaName = folderName;
if(folderFormat === 'PDF'){
_mediaName = folderName.replace('.pdf','')
}else{
_mediaName = folderName.replace('.doc','') && folderName.replace('.docx','')
}
const suffix = _.last(folderName.split('.')).toUpperCase();
_courseChapterList.push({
mediaContent: resourceId,
contentType: 'SCHEDULE',
mediaType: suffix,
mediaName: folderName,
id: resourceId,
mediaName: _mediaName,
resourceId,
mediaUrl: ossUrl,
sort: _courseChapterList.length
})
......@@ -478,7 +484,7 @@ class AddVideoCourse extends React.Component {
return false
}
if (!courseChapterList.length) {
message.warning('请上传视频')
message.warning('请上传课节')
resolve(false)
return false
}
......@@ -915,7 +921,7 @@ class AddVideoCourse extends React.Component {
queryTypeEnum={'ONLINE'}
confirm={{
title: '文件过大,无法上传',
content: '为保障学员的观看体验,上传的视频大小不能超过2G'
content: '上传的视频大小不能超过2G,文件大小不能超过100M'
}}
tooltip={''}
isOpen={showSelectFileModal}
......
......@@ -192,7 +192,7 @@
&__name {
color: #333;
width: 356px;
width: 353px;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
......
......@@ -22,8 +22,6 @@
display: flex;
flex-direction: column;
.info__title {
width: 680px;
height: 28px;
font-size: 20px;
font-family: PingFangSC-Medium, PingFang SC;
font-weight: 500;
......
......@@ -171,7 +171,7 @@ function VideoCourseDetail(){
</div>
<div className="course-detail__info">
<div className="info__title">{courseName}</div>
<div className="info__category">{`分类:${categoryName}`}</div>
<div className="info__category">{`课程分类:${categoryName}`}</div>
<div className="info__chapterNum">{`课节数量:${courseChapterList.length}`}</div>
</div>
</div>
......
......@@ -57,7 +57,7 @@ class LearningDetailModal extends React.Component {
<div className="course-wrap">
<div className="course-ware" key={index}>
<div className="course-ware__index">{`${
index > 9 ? index + 1 : `0${index + 1}`
index < 9 ? `0${index + 1}` : index + 1
} `}</div>
<img className='course-ware__img' src={FileTypeIcon[item.mediaType]} alt='' />
<div className="course-ware__name">{item.courseChapterName && item.courseChapterName.replace('.MP4','')}</div>
......
......@@ -126,8 +126,8 @@ class VideoCourseList extends React.Component {
width: 100,
align: 'right',
render: (val, item) => {
return <div onClick={() => this.handleLinkToCourseDetail(item.id)}>{val || 1}</div>;
},
return <div onClick={() => this.handleLinkToCourseDetail(item.id)}>{val || 1}</div>
}
},
{
title: (
......@@ -364,8 +364,8 @@ class VideoCourseList extends React.Component {
// 显示分享弹窗
handleShowShareModal = (record, needStr = false) => {
const { type } = this.props;
const { id, scheduleVideoUrl } = record;
const htmlUrl = `${LIVE_SHARE}video_detail/${id}?id=${User.getStoreId()}`;
const { id, scheduleVideoUrl, chapterNum } = record;
const htmlUrl = chapterNum > 1 ? `${LIVE_SHARE}course_detail/${id}?id=${User.getStoreId()}` : `${LIVE_SHARE}video_detail/${id}?id=${User.getStoreId()}`;
const longUrl = htmlUrl;
const { coverUrl, courseName } = record;
const shareData = {
......
......@@ -2,8 +2,8 @@
* @Description:
* @Author: zangsuyun
* @Date: 2021-03-13 09:54:26
* @LastEditors: yuananting
* @LastEditTime: 2021-06-10 19:55:24
* @LastEditors: Please set LastEditors
* @LastEditTime: 2021-06-28 15:42:48
* @Copyright: © 2020 杭州杰竞科技有限公司 版权所有
*/
......
......@@ -2,7 +2,7 @@
* @Author: zhangleyuan
* @Date: 2021-02-20 16:46:46
* @LastEditors: fusanqiasng
* @LastEditTime: 2021-06-01 11:45:34
* @LastEditTime: 2021-06-15 14:37:20
* @Description: 描述一下
* @@Copyrigh: © 2020 杭州杰竞科技有限公司 版权所有
*/
......
/*
* @Author: yuananting
* @Date: 2021-07-05 10:50:30
* @LastEditors: Please set LastEditors
* @LastEditTime: 2021-07-09 17:36:15
* @LastEditors: yuananting
* @LastEditTime: 2021-07-14 14:32:55
* @Description: 描述一下咯
* @Copyrigh: © 2020 杭州杰竞科技有限公司 版权所有
* @@Copyrigh: © 2020 杭州杰竞科技有限公司 版权所有
......@@ -194,10 +194,10 @@ class UserLearnDetailModal extends React.Component {
return (
<div className='chapter-record'>
<span>
{chapterIndex + 1}.{index + 1}&nbsp;
{index < 9 ? `0${index + 1} ` : index + 1}
</span>
<img className='chapter-img' src={FileTypeIcon[record.mediaType]} />
<span>{record.name}</span>
<span className='chapter-name'>{record.name}</span>
</div>
);
},
......
......@@ -65,6 +65,12 @@
height: 18px;
margin: 0 10px;
}
.chapter-name {
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
width: 400px;
}
}
.record-name {
display: flex;
......
......@@ -2,7 +2,7 @@
* @Author: yuananting
* @Date: 2021-07-05 10:50:10
* @LastEditors: yuananting
* @LastEditTime: 2021-07-09 15:19:31
* @LastEditTime: 2021-07-13 19:55:29
* @Description: 描述一下咯
* @Copyrigh: © 2020 杭州杰竞科技有限公司 版权所有
* @@Copyrigh: © 2020 杭州杰竞科技有限公司 版权所有
......@@ -102,7 +102,7 @@ class SelectOperatorModal extends React.Component {
selectPicture: [], //弹窗内已选择的线上课程
currentPictureCourseListData: [], //页面中已关联的线上课程
activeKey: 'video',
activeKey: 'live',
currentTaskCourseData: this.props.data[this.props.selectedTaskIndex].courseList || [],
};
}
......
......@@ -34,7 +34,7 @@ class ScanFileModal extends React.Component {
style={{ width: 632, objectFit: "cover" }}
/>
)}
{fileType === "MP4" && (
{fileType === "VIDEO" && (
<div>
<Player
src={item.mediaUrl || item.ossAddress || item.ossUrl}
......
......@@ -10,4 +10,7 @@
height: 60px;
}
}
.video-react .video-react-play-progress:after {
width: max-content;
}
}
......@@ -15,6 +15,7 @@ import zhCN from 'antd/es/locale/zh_CN'
import User from '@/common/js/user';
import BaseService from "@/domains/basic-domain/baseService";
import moment from 'moment';
import WechatApi from '@/common/js/wechatApi';
import { VersionContext, VersionInfo, XMContext } from '@/store/context';
import { setStoreGroupPermission, setStorePermission, setStoreGroupList, setStoreList } from '@/store/actions/index';
import Service from "@/common/js/service";
......@@ -28,7 +29,7 @@ declare var window: any;
const App: React.FC = (props: any) => {
const [storeUserId, setStoreUserId] = useState('')
const ctx: any = useContext(XMContext);
const [versionInfo, setVersionInfo] = useState<VersionInfo|null>(null)
const [versionInfo, setVersionInfo] = useState<VersionInfo | null>(null)
const userId = User.getUserId();
const [menuType, setMenuType] = useState(true);
const enterpriseId = User.getEnterpriseId();
......@@ -36,6 +37,7 @@ const App: React.FC = (props: any) => {
useEffect(() => {
initWechatConfig();
getStoreAndUserInfo();
getVersion();
if (window.location.hash === "#/") {
......@@ -45,6 +47,10 @@ const App: React.FC = (props: any) => {
}
}, [])
async function initWechatConfig() {
WechatApi.initConfig({ isAgentConfig: true, url: window.location.href.split('#')[0] })
}
useEffect(() => {
getStorePermission();
}, [window.location.hash])
......@@ -66,7 +72,7 @@ const App: React.FC = (props: any) => {
let version = res.result;
User.setVersion(version);
User.setExpirationTime(res.result.validEndTime)
let versioninfo:VersionInfo = {
let versioninfo: VersionInfo = {
dayTime: version.dayTime,
stateEnum: version.stateEnum,
userNum: version.userNum === -1 ? '不限人数' : version.userNum,
......@@ -87,28 +93,28 @@ const App: React.FC = (props: any) => {
}
function getStoreInfo() {
console.log("currentStoreUserInfo",window.currentStoreUserInfo);
console.log("currentStoreUserInfo", window.currentStoreUserInfo);
const params = {
storeId: User.getStoreId(),
userId: User.getUserId(),
};
Service.Hades('public/customerHades/getStoreAndUserMsg', params).then((res) => {
if(res.success){
if (res.success) {
const { id, storeUserId, storeName, userRole, storeType } = res.result;
User.setStoreId(id);
User.setStoreUserId(storeUserId);
User.setStoreName(storeName);
Bus.trigger('storeNameChange',storeName);
Bus.trigger('storeNameChange', storeName);
User.setUserRole(userRole);
User.setStoreType(storeType);
setCurrentStoreUserInfo(id,storeUserId)
setCurrentStoreUserInfo(id, storeUserId)
setStoreUserId(storeUserId);
getUserPermission();
}
})
}
function setCurrentStoreUserInfo(storeId:any,storeUserId:any){
function setCurrentStoreUserInfo(storeId: any, storeUserId: any) {
window.currentStoreUserInfo.storeId = storeId;
window.currentStoreUserInfo.storeUserId = storeUserId;
window.currentStoreUserInfo.userId = User.getUserId();
......@@ -134,7 +140,7 @@ const App: React.FC = (props: any) => {
Bus.trigger('storeNameChange', storeName);
User.setUserRole(userRole);
User.setStoreType(storeType);
setCurrentStoreUserInfo(id,storeUserId);
setCurrentStoreUserInfo(id, storeUserId);
ctx.dispatch(setStoreGroupList(storeGroupVOS))
ctx.dispatch(setStoreList(storeVOS));
setStoreUserId(storeUserId)
......
......@@ -6,8 +6,8 @@ import CheckBeforeSendCode from '../../components/CheckBeforeSendCode';
import User from '@/common/js/user';
import WechatLogin from './WechatLogin';
import BaseService from '@/domains/basic-domain/baseService';
import axios from 'axios';
import storage from '@/common/js/storage';
import axios from 'axios';
import _ from 'underscore';
import user from '@/common/js/user';
const { TabPane } = Tabs;
......@@ -44,14 +44,14 @@ function Login(props) {
userId,
};
BaseService.getWXWorkLoginNoCheck(params).then((res) => {
User.setUserId(res.result.loginInfo.userId)
User.setToken(res.result.loginInfo.xmToken)
User.setEnterpriseId(res.result.enterpriseId)
window.currentStoreUserInfo = {}
User.setUserId(res.result.loginInfo.userId);
User.setToken(res.result.loginInfo.xmToken);
User.setEnterpriseId(res.result.enterpriseId);
window.currentStoreUserInfo = {};
window.currentStoreUserInfo.userId = res.result.loginInfo.userId;
window.currentStoreUserInfo.token = res.result.loginInfo.xmToken;
window.currentStoreUserInfo.enterpriseId = res.result.enterpriseId;
User.setIdentifier(res.result.identifier)
User.setIdentifier(res.result.identifier);
window.RCHistory.push({
pathname: `/switch-route`,
});
......
......@@ -5,7 +5,6 @@
@import '../../core/filter.less';
@top-height: 60px;
.right-container {
position: absolute;
left: @xm-left-width;
......
......@@ -97,7 +97,7 @@
margin: 6px 8px;
width: calc(100% - 15px);
&:hover {
background: #f3f6fa;
background: rgba(41, 102, 255, .05);
border-radius: 2px;
color: #333;
}
......@@ -109,6 +109,7 @@
&.single-menu {
background: rgba(41, 102, 255, .1) !important;
color: @active-color;
font-weight:500;
}
}
.ant-menu-submenu {
......@@ -118,6 +119,9 @@
}
.ant-menu-item {
padding-left: 46px !important;
&:hover {
color: @active-color!important;
}
}
}
......@@ -126,10 +130,15 @@
.ant-menu-item-selected {
color: @active-color;
font-weight: 500;
.listType {
background: @active-color;
}
}
.ant-menu-submenu-arrow {
right: 22px;
color: @active-color;
}
}
.ant-menu-submenu-arrow {
right: 22px;
......@@ -268,8 +277,22 @@
left: 74px;
}
}
.ant-menu-submenu-open.ant-menu-submenu-inline > .ant-menu-submenu-title > .ant-menu-submenu-arrow {
color: #2966FF;
.ant-menu-submenu:hover {
// background: rgba(41, 102, 255, .05) !important;
&.ant-menu-submenu-title:hover {
color: #333333!important;
}
.ant-menu-submenu-title > .ant-menu-submenu-arrow {
color: #5e606a!important;
}
&.icon-img-box {
background-color: rgba(41, 102, 255, .05)!important;
}
}
.ant-menu-light .ant-menu-submenu-title:hover {
color: #333!important;
background: rgba(41, 102, 255, .05) !important;
}
.ant-menu:not(.ant-menu-horizontal) .ant-menu-item-selected {
background: rgba(41, 102, 255, .1) !important;
......
......@@ -25,21 +25,21 @@ function VersionPanel(props: any) {
const versionInfo = useContext(VersionContext);
function onVersionEnter() {
setShowVersionPopover(true)
setShowVersionPopover(true);
}
function onVersionLeave() {
setShowVersionPopover(false)
setShowRenewPopover(false)
setShowVersionPopover(false);
setShowRenewPopover(false);
}
function onRenewClick() {
setShowRenewPopover(true)
setShowVersionPopover(false)
setShowRenewPopover(true);
setShowVersionPopover(false);
}
const versionPopoverClass = classNames({
'popover':true,
'popover-show':showVersionPopover
})
popover: true,
'popover-show': showVersionPopover,
});
return (
<div className='version-info' onMouseEnter={onVersionEnter} onMouseLeave={onVersionLeave}>
......@@ -56,18 +56,18 @@ function VersionPanel(props: any) {
</div>
<div className='expiration-time'>
有效期至{versionInfo?.validEndTime}
{versionInfo?.stateEnum === "NO" ? '(已过期)' : ''}
{versionInfo?.stateEnum === 'NO' ? '(已过期)' : ''}
</div>
<div className={versionPopoverClass}>
<div className='title'>版本信息</div>
{versionInfo?.stateEnum === "NO" ? <div className='expiration-tag'>已过期</div> : ''}
{versionInfo?.stateEnum === 'NO' ? <div className='expiration-tag'>已过期</div> : ''}
<div className='content'>
<div className='widget' style={{ marginRight: '26px', marginBottom: '16px', width: '70px' }}>
<div className='lable'>剩余天数</div>
<div className='lable-text'>{versionInfo?.surplusDayTime}</div>
</div>
<div className='widget' style={{ marginBottom: '16px', width:"212px"}}>
<div className='widget' style={{ marginBottom: '16px', width: '212px' }}>
<div className='lable'>有效起止日期</div>
<div className='lable-text'>
{versionInfo?.validStartTimeST === versionInfo?.validEndTimeST ? "-" : `${versionInfo?.validStartTime}~${versionInfo?.validEndTime}`}
......@@ -109,10 +109,9 @@ function VersionPanel(props: any) {
</div>
</div>
</div>
)
);
}
function Aside(props: any) {
const { menuType, handleMenuType } = props;
const ctx: any = useContext(XMContext);
......@@ -167,7 +166,6 @@ function Aside(props: any) {
}
function toggleMenu(item: any, selectKey: any) {
console.log('item', item, selectKey);
setSelectKeyParent(selectKey);
window.RCHistory.push(item.link);
if (!menuType) {
......@@ -221,7 +219,6 @@ function Aside(props: any) {
<div className='left'>
<div className='nav'>
<Menu
{...openKeysConstrol}
style={menuType ? { minHeight: '100%', background: '#0E1935' } : { minHeight: '100%', background: '#0E1935', width: '56px' }}
selectedKeys={selectKey}
onOpenChange={onOpenChange}
......@@ -242,7 +239,7 @@ function Aside(props: any) {
<img src={item.img} className='icon-img' />
</div>
) : (
<div className='icon-img-box' style={{ backgroundColor: '#fff', width: '40px', height: '40px', display: 'inline-block' }}>
<div className='icon-img-box' style={{ width: '40px', height: '40px', display: 'inline-block' }}>
<img src={item.img} className='icon-img' />
</div>
)
......
......@@ -7,7 +7,6 @@ import './WechatLogin.less';
const Logo = require('@/common/images/logo.png');
declare var location: any;
declare var window: any;
export default function WechatLogin(props: any) {
const freshTime = 60;
const init: any = null;
......@@ -72,6 +71,10 @@ export default function WechatLogin(props: any) {
User.setUserId(_res.result.loginInfo.userId);
User.setToken(_res.result.loginInfo.xmToken);
User.setEnterpriseId(_res.result.enterpriseId);
window.currentStoreUserInfo = {}
window.currentStoreUserInfo.userId = _res.result.loginInfo.userId;
window.currentStoreUserInfo.token = _res.result.loginInfo.xmToken;
window.currentStoreUserInfo.enterpriseId = _res.result.enterpriseId;
User.setIdentifier(_res.result.identifier);
window.currentStoreUserInfo = {}
window.currentStoreUserInfo.userId = _res.result.loginInfo.userId;
......
/*
* @Author: wufan
* @Date: 2020-11-27 16:21:49
* @LastEditors: zhangleyuan
* @LastEditTime: 2021-03-09 14:21:35
* @LastEditors: wufan
* @LastEditTime: 2021-05-11 10:58:58
* @Description: Description
* @@Copyrigh: © 2020 杭州杰竞科技有限公司 版权所有
*/
......
......@@ -15,6 +15,8 @@ import { QuestionCircleOutlined } from "@ant-design/icons";
import StoreService from "@/domains/store-domain/storeService";
import EmployeeAddOrEditModal from "./EmployeeAddOrEditModal";
import User from "@/common/js/user";
import WechatApi from '@/common/js/wechatApi';
import WWOpenDataCom from '@/components/WWOpenDataCom';
import "./EmployeesManagePage.less";
import Item from "antd/lib/list/Item";
......@@ -86,12 +88,22 @@ function EmployeesManagePage() {
useEffect(() => {
getEmployeeList();
initWechatConfig();
}, [query]);
useEffect(() => {
getListInfo();
}, [storeId]);
async function initWechatConfig() {
WechatApi.initConfig({ isAgentConfig: true, url: window.location.href.split('#')[0] }).then(()=>{
console.info('window.WWOpenData', window.WWOpenData);
})
.catch(error=>{
console.log("error-----",error);
})
}
async function getListInfo() {
await getStoreRole();
}
......@@ -137,6 +149,9 @@ function EmployeesManagePage() {
)}
<span className="title">{val}</span>
{/* <span className="title">
<WWOpenDataCom type="userName" openid={val}/>
</span> */}
</div>
);
},
......
/*
* @Author: yuananting
* @Date: 2021-02-23 18:28:50
* @LastEditors: wufan
* @LastEditTime: 2021-06-24 13:39:30
* @LastEditors: fusanqiasng
* @LastEditTime: 2021-06-25 14:35:20
* @Description: 助学工具-课程分类
* @Copyrigh: © 2020 杭州杰竞科技有限公司 版权所有
*/
......@@ -545,9 +545,9 @@ class CourseCategoryManage extends Component {
)}
<div className='box'>
<div className='search-condition'>
<span className='search-label'>搜索分类名称:</span>
<span className='search-label'>搜索名称:</span>
<Search
placeholder='请输入名称'
placeholder='搜索分类名称'
style={{ width: '300px' }}
onSearch={(value) => this.queryCategoryTree('init', value)}
className='search-input'
......@@ -571,7 +571,7 @@ class CourseCategoryManage extends Component {
<div className='course-category-tree'>
{
<Choose>
<When condition={(treeData.length !== 0)}>
<When condition={treeData.length !== 0}>
<DirectoryTree
expandedKeys={expandedKeys}
autoExpandParent={autoExpandParent}
......@@ -584,11 +584,7 @@ class CourseCategoryManage extends Component {
treeData={treeData}></DirectoryTree>
</When>
<Otherwise>
<LottieIcon
title={<span className="desc">搜索无结果</span>}
type="search"
size={150}
/>
<LottieIcon title={<span className='desc'>搜索无结果</span>} type='search' size={150} />
</Otherwise>
</Choose>
}
......
/*
* @Author: 吴文洁
* @Date: 2020-03-18 10:01:28
* @LastEditors: yuananting
* @LastEditTime: 2021-03-27 14:44:31
* @LastEditors: fusanqiasng
* @LastEditTime: 2021-06-22 17:01:05
* @Description: 录音组件
*/
import React, { Component } from "react";
import { Button, Modal } from "antd";
import React, { Component } from 'react';
import { Button, Modal } from 'antd';
import UploadOss from "@/core/upload";
import { RECORD_ERROR } from "@/common/constants/academic";
import AudioRecorder from "../components/audioRecord";
import UploadOss from '@/core/upload';
import { RECORD_ERROR } from '@/common/constants/academic';
import AudioRecorder from '../components/audioRecord';
import "./XMRecord.less";
import './XMRecord.less';
class XMRecord extends Component {
constructor(props) {
......@@ -49,15 +49,10 @@ class XMRecord extends Component {
if (navigator.mediaDevices.getUserMedia === undefined) {
navigator.mediaDevices.getUserMedia = function (constraints) {
// 首先,如果有getUserMedia的话,就获得它
var getUserMedia =
navigator.getUserMedia ||
navigator.webkitGetUserMedia ||
navigator.mozGetUserMedia;
var getUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia;
// 一些浏览器根本没实现它 - 那么就返回一个error到promise的reject来保持一个统一的接口
if (!getUserMedia) {
return Promise.reject(
new Error("getUserMedia is not implemented in this browser")
);
return Promise.reject(new Error('getUserMedia is not implemented in this browser'));
}
// 否则,为老的navigator.getUserMedia方法包裹一个Promise
......@@ -69,12 +64,11 @@ class XMRecord extends Component {
};
openDeviceFailure = (reason) => {
const { title = "麦克风调用错误", content = "请检查麦克风是否可用" } =
RECORD_ERROR[reason.name] || {};
const { title = '麦克风调用错误', content = '请检查麦克风是否可用' } = RECORD_ERROR[reason.name] || {};
Modal.info({
title,
content,
okText: "我知道了",
okText: '我知道了',
});
};
......@@ -122,8 +116,7 @@ class XMRecord extends Component {
this.mMediaRecorder.stop();
}
const blob = this.mMediaRecorder.upload();
UploadOss.uploadBlobToOSS(blob, window.random_string(16) + ".wav").then(
(mp3URL) => {
UploadOss.uploadBlobToOSS(blob, window.random_string(16) + '.wav').then((mp3URL) => {
const { recordTime } = this.state;
this.props.onFinish(mp3URL, recordTime * 1000);
this.setState({
......@@ -131,8 +124,7 @@ class XMRecord extends Component {
isFinished: true,
});
window.clearInterval(this.timer);
}
);
});
};
// 格式化当前录音时长
......@@ -166,36 +158,27 @@ class XMRecord extends Component {
const { isFinished, recordTime } = this.state;
const { visible, maxTime = 180 } = this.props;
return (
<div className={`xm-record ${visible ? "visible" : "hidden"}`}>
<div className="record-left">
<div className="text">
<div className={`xm-record ${visible ? 'visible' : 'hidden'}`}>
<div className='record-left'>
<div className='text'>
{isFinished ? (
<img
style={{ width: 14, height: 14 }}
src="https://image.xiaomaiketang.com/xm/xCahGm2Q2J.png"
/>
<img style={{ width: 14, height: 14 }} src='https://image.xiaomaiketang.com/xm/xCahGm2Q2J.png' />
) : (
<img src="https://xiaomai-image.oss-cn-hangzhou.aliyuncs.com/1584607726775.png" />
<img src='https://xiaomai-image.oss-cn-hangzhou.aliyuncs.com/1584607726775.png' />
)}
{isFinished ? <span>录音</span> : <span>录音中...</span>}
</div>
<div className="time">{`${this.formatRecordTime(
recordTime
)}/${this.formatRecordTime(maxTime)}`}</div>
<div className='time'>{`${this.formatRecordTime(recordTime)}/${this.formatRecordTime(maxTime)}`}</div>
</div>
<div className="btn-wrapper">
<div className='btn-wrapper'>
<Button onClick={this.handleCancel}>取消</Button>
{isFinished ? (
<Button type="primary" onClick={this.handleStartRecord}>
<Button type='primary' onClick={this.handleStartRecord}>
开始
</Button>
) : (
<Button
type="primary"
className="finish"
onClick={this.handleFinishRecord}
>
<Button type='primary' className='finish' onClick={this.handleFinishRecord}>
完成
</Button>
)}
......
import React from 'react';
import { Modal, message } from 'antd';
import { Modal, message,Button} from 'antd';
import html2canvas from 'html2canvas';
import User from "../../../common/js/user";
import QRCode from '../../../libs/qrcode/qrcode';
......@@ -126,6 +126,18 @@ class ExamShareModal extends React.Component {
<div className="sub-title">学员可通过微信扫描海报二维码,查看考试</div>
<div className="content" onClick={this.handleDownloadPoster}>下载海报</div>
</div>
<div className="share-url right__item" style={{ marginTop: 40 }}>
<div className="title">② 链接分享</div>
<div className="sub-title">用户可通过微信或浏览器打开以下链接,查看考试(建议使用谷歌浏览器)</div>
<div className="content">
<div className="share-url" id="shareUrl">{shareUrl}</div>
<Button
type="primary"
onClick={this.handleCopy}
>复制</Button>
</div>
</div>
</div>
</Modal>
)
......
......@@ -2,7 +2,7 @@
* @Author: yuananting
* @Date: 2021-02-25 14:34:29
* @LastEditors: yuananting
* @LastEditTime: 2021-06-09 12:00:12
* @LastEditTime: 2021-06-09 12:02:55
* @Description: 助学工具-题库-操作题目Tab
* @Copyrigh: © 2020 杭州杰竞科技有限公司 版权所有
*/
......
/*
* @Author: yuananting
* @Date: 2021-02-25 11:23:47
* @LastEditors: yuananting
* @LastEditTime: 2021-06-03 17:12:01
* @LastEditors: fusanqiasng
* @LastEditTime: 2021-06-15 14:41:18
* @Description: 助学工具-题库-题目列表数据
* @Copyrigh: © 2020 杭州杰竞科技有限公司 版权所有
*/
......
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