对接短信登录,

学习记录请求
main
king 1 year ago
parent dc1a72ce9a
commit 6201f78c93
  1. 4
      src/api/manage.ts
  2. 7
      src/api/user.ts
  3. 9
      src/pages/business/test/test.tsx
  4. 3
      src/pages/business/videoInfo/components/course.tsx
  5. 7
      src/pages/business/videoInfo/videoInfo.tsx
  6. 65
      src/pages/check/check.module.scss
  7. 72
      src/pages/check/check.tsx
  8. 9
      src/pages/manage/addCur/addCur.tsx
  9. 2
      src/pages/manage/depAdmin/depAdmin.tsx
  10. BIN
      src/static/img/tel.png
  11. BIN
      src/static/img/vCode.png

@ -105,8 +105,8 @@ export const ManageApi = {
return request<DepCurData>(`/api/v1/department/${data.id}/courses?page=${data.page}&size=${data.size}`, "GET") return request<DepCurData>(`/api/v1/department/${data.id}/courses?page=${data.page}&size=${data.size}`, "GET")
}, },
/** 未添加课程 */ /** 未添加课程 */
optionalCur(dep_id: number) { optionalCur(dep_id: number, page: number, pageSize: number) {
return request<Curriculum[]>(`/api/v1//choose/${dep_id}/index`, "GET") return request<Curriculum[]>(`/api/v1/course/choose/${dep_id}/index`, "GET", {page, pageSize})
}, },
addCur(data: AddCurProps) { addCur(data: AddCurProps) {
return request('/api/v1/course/user', "POST", data) return request('/api/v1/course/user', "POST", data)

@ -14,9 +14,9 @@ export interface LoginData {
} }
interface CheckoutBody { interface CheckoutBody {
catch_key: string
code: string code: string
phone_number: string phone_number: string
openid: string
} }
interface CheckoutData { interface CheckoutData {
@ -68,7 +68,7 @@ export const userApi = {
}, },
/** 学习记录 */ /** 学习记录 */
record() { record() {
return request<{course:HourHistory[],durations:Record<number, number>}>(`/api/v1/category/history`, "GET") return request<{ course: HourHistory[], durations: Record<number, number> }>(`/api/v1/category/history`, "GET")
}, },
courseRecord(course_id: string) { courseRecord(course_id: string) {
return request<CourseRecord>(`/api/v1/course/${course_id}/info`, "GET") return request<CourseRecord>(`/api/v1/course/${course_id}/info`, "GET")
@ -87,5 +87,8 @@ export const userApi = {
return request<{ return request<{
data: Record<number, number> data: Record<number, number>
}>(`/api/v1/statistics/statistics/${user_id}?start_time=${data.start_time}&end_time=${data.end_time}`, "GET") }>(`/api/v1/statistics/statistics/${user_id}?start_time=${data.start_time}&end_time=${data.end_time}`, "GET")
},
getCode(phone_number: number) {
return request('/api/v1/sms/send?phone_number='+phone_number, "GET")
} }
} }

@ -83,28 +83,25 @@ const Test = () => {
return ( return (
<View className={styles.content}> <View className={styles.content}>
{data?.fill.map((d, index) => <ShortAnswer {data?.fill.map((d) => <ShortAnswer
key={d.id} key={d.id}
data={d} data={d}
index={index}
onAnswer={onAnswer} onAnswer={onAnswer}
validate={validate} validate={validate}
/>)} />)}
{data?.judge.map((d, index) => <Judge {data?.judge.map((d) => <Judge
key={d.id} key={d.id}
data={d} data={d}
index={index}
onAnswer={onAnswer} onAnswer={onAnswer}
validate={validate} validate={validate}
/>)} />)}
{ {
data?.multi.map((d, index) => <Multi data?.multi.map((d) => <Multi
key={d.id} key={d.id}
data={d} data={d}
onAnswer={onAnswer} onAnswer={onAnswer}
index={index}
validate={validate}/>) validate={validate}/>)
} }

@ -16,7 +16,7 @@ interface Props {
id: number, id: number,
courseId: number courseId: number
preview?: boolean preview?: boolean
curEnd: () => void curEnd: (test?:boolean) => void
} }
@ -44,6 +44,7 @@ const Course: FC<Props> = ({id, courseId, preview, curEnd}: Props) => {
startRecording && curriculum.curEnd(courseId, id, {...startRecording, duration: data?.duration!}) //结束 startRecording && curriculum.curEnd(courseId, id, {...startRecording, duration: data?.duration!}) //结束
if (testId) { if (testId) {
Taro.navigateTo({url: `/pages/business/test/test?testId=${testId}`}) Taro.navigateTo({url: `/pages/business/test/test?testId=${testId}`})
curEnd(true)
} else { } else {
curEnd() curEnd()
} }

@ -26,9 +26,11 @@ const VideoInfo: FC = () => {
} }
}, [playing, playId]) }, [playing, playId])
const curEnd = () => { const curEnd = (test?: boolean) => {
setPlaying(false) setPlaying(false)
getData(false).then() if (!test) { // 没有考题才会请求
getData(false).then()
}
} }
function setHors(is_complete: boolean, play_id: number) { function setHors(is_complete: boolean, play_id: number) {
@ -76,6 +78,7 @@ const VideoInfo: FC = () => {
const courseHourRecordsFinish = data?.learn_hour_records.find(d => d.id === playId)?.courseHourRecordsFinish const courseHourRecordsFinish = data?.learn_hour_records.find(d => d.id === playId)?.courseHourRecordsFinish
if (typeof courseHourRecordsFinish === 'number') { if (typeof courseHourRecordsFinish === 'number') {
if (courseHourRecordsFinish === 1) { if (courseHourRecordsFinish === 1) {
console.log(playing)
if (!playing) { if (!playing) {
playNext() playNext()
} }

@ -1,39 +1,3 @@
.container {
position: relative;
}
.navbar,
.brand {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
}
.navbar {
position: relative;
line-height: 1;
font-size: 28px;
}
.brand {
width: 140px;
height: 140px;
background: #fff;
border-radius: 20px;
margin: 250px auto 145px;
image {
width: 100px;
height: 100px;
}
}
.loginTips {
margin: 24px;
text-align: center;
}
.submit { .submit {
display: flex; display: flex;
justify-content: center; justify-content: center;
@ -41,28 +5,19 @@ image {
gap: 12px; gap: 12px;
margin: 0 auto; margin: 0 auto;
a { a {
color: #fff;
color: #fff; }
}
} }
.formItem {
.errorTips {
position: fixed;
top: 10%;
left: 24px;
right: 24px;
background: red;
color: white;
padding: 24px;
border-radius: 20px;
display: flex; display: flex;
align-items: center; border-bottom: 1px solid #ededed;
gap: 12px; padding: 30px 0;
} }
.bing { .image {
height: 50vh; width: 50px;
padding: 50px 30px 0; vertical-align: top;
margin-right: 20px;
} }

@ -1,25 +1,28 @@
import {FC, useRef, useState} from "react"; import {FC, useCallback, useEffect, useRef, useState} from "react";
import {Button, Form, Image, Input, View} from "@tarojs/components"; import {Button, Form, Image, Input, View} from "@tarojs/components";
import {Profile} from "@/store"; import {Profile} from "@/store";
import {userApi} from "@/api"; import {userApi} from "@/api";
import Taro from "@tarojs/taro"; import Taro from "@tarojs/taro";
import {regexTel} from "@/utils/regu"; import {regexTel} from "@/utils/regu";
import styles from './check.module.scss' import styles from './check.module.scss'
import code from '@/static/img/vCode.png'
const uuid = () => { import tel from '@/static/img/tel.png'
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
const r = Math.random() * 16 | 0
const v = c === 'x' ? r : (r & 0x3 | 0x8)
return v.toString(16)
}).replace(/-/g, '')
}
const Bing: FC = () => { const Bing: FC = () => {
const form = useRef<HTMLFormElement | null>(null) const form = useRef<HTMLFormElement | null>(null)
const [loading, setLoading] = useState(false) const [loading, setLoading] = useState(false)
const [codeTime, setCodeTime] = useState(0)
const {setUser, setToken, setCompany} = Profile.useContainer() const {setUser, setToken, setCompany} = Profile.useContainer()
const [captchaKey, setCaptchaKey] = useState(uuid())
const openid = localStorage.getItem('openid') const openid = localStorage.getItem('openid')
const [phone_number, setPhone_number] = useState<number | undefined>(undefined)
useEffect(() => {
if (codeTime > 0) {
setTimeout(() => {
setCodeTime(codeTime - 1)
}, 1000)
}
}, [codeTime])
async function Submit(data) { async function Submit(data) {
setLoading(true) setLoading(true)
@ -32,7 +35,6 @@ const Bing: FC = () => {
try { try {
const res = await userApi.checkout({ const res = await userApi.checkout({
...value, ...value,
catch_key: captchaKey,
openid, openid,
}) })
if (res) { if (res) {
@ -42,27 +44,53 @@ const Bing: FC = () => {
Taro.switchTab({url: '/pages/index/index'}) Taro.switchTab({url: '/pages/index/index'})
} }
} catch (e) { } catch (e) {
setCaptchaKey(uuid)
} }
setLoading(false) setLoading(false)
} }
const getCode = useCallback(async () => {
if (codeTime > 0) return;
if (!phone_number || !regexTel.exec(String(phone_number))) {
Taro.showToast({title: '手机号错误', icon: 'error'})
setLoading(false)
return
}
try {
await userApi.getCode(phone_number)
Taro.showToast({title: '请注意查收', icon: "none"})
setCodeTime(60)
} catch (e) {
Taro.showToast({title: '获取短信验证码失败', icon: "error"})
}
}, [codeTime, phone_number])
return ( return (
<View className='h-10 pt-6 px-3 bg-white'> <View className='h-10 pt-6 px-3 bg-white'>
<Form className='form' onSubmit={Submit} ref={form}> <Form onSubmit={Submit} ref={form}>
<View className='item'>
<View></View> <View className={styles.formItem}>
<Input name='phone_number' placeholder={'请输入手机号'}/> <View>
<Image src={tel} className={styles.image}/>
</View>
<Input
type='number'
name='phone_number'
placeholder={'请输入手机号'}
value={String(phone_number)}
onInput={(e) => setPhone_number(Number(e.detail.value))}/>
</View> </View>
<View className='item'> <View className={styles.formItem}>
<View></View> <View>
<Image src={code} className={styles.image}/>
</View>
<View className='flex align-center flex-1'> <View className='flex align-center flex-1'>
<Input name='code' className='flex-1' placeholder={'请输入验证码'}/> <Input type='number' name='code' className='flex-1' placeholder='请输入短信验证码'/>
<Image className='w-2 ml-1' style='height:28px' <View onClick={getCode}>
src={process.env.TARO_APP_API + '/api/v1/captcha?key=' + captchaKey} {codeTime > 0 ? `${codeTime}` : '获取验证码'}
onClick={() => setCaptchaKey(uuid)}/> </View>
</View> </View>
</View> </View>

@ -1,7 +1,7 @@
import {View} from "@tarojs/components"; import {View} from "@tarojs/components";
import {getCurrentInstance} from "@tarojs/runtime"; import {getCurrentInstance} from "@tarojs/runtime";
import {ManageApi} from "@/api/manage"; import {ManageApi} from "@/api/manage";
import React, {FC, useEffect, useState} from "react"; import React, {FC, useCallback, useEffect, useState} from "react";
import Taro from "@tarojs/taro"; import Taro from "@tarojs/taro";
import VideoCover from "@/components/videoCover/videoCover"; import VideoCover from "@/components/videoCover/videoCover";
import Empty from "@/components/empty/empty"; import Empty from "@/components/empty/empty";
@ -15,18 +15,19 @@ interface AddProps {
const AddCur = () => { const AddCur = () => {
const {id} = getCurrentInstance()?.router?.params as { id: string } const {id} = getCurrentInstance()?.router?.params as { id: string }
const [data, setData] = useState<Curriculum[]>([]) const [data, setData] = useState<Curriculum[]>([])
const [page] = useState(1)
async function getData() { const getData = useCallback(async () => {
try { try {
const res = await ManageApi.optionalCur(Number(id)) const res = await ManageApi.optionalCur(Number(id), page, 10)
if (res.length) { if (res.length) {
setData(res) setData(res)
} }
} catch (e) { } catch (e) {
} }
} }, [page])
useEffect(() => { useEffect(() => {
getData() getData()

@ -119,7 +119,7 @@ const DepAdmin: FC = () => {
useEffect(() => { useEffect(() => {
getData() getData()
Taro.setNavigationBarTitle({ Taro.setNavigationBarTitle({
title: decodeURI(router.params.name!) || '部门管理' title: router.params.name ? decodeURI(router.params.name!) : '部门管理'
}) })
}, []) }, [])

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.7 KiB

Loading…
Cancel
Save