新增视频播放状态

1. 外部控制视频播放 | 暂停
main
king 1 year ago
parent 6201f78c93
commit 1e23fff664
  1. 4
      .env
  2. 2
      src/app.scss
  3. 4
      src/components/topic/judge.tsx
  4. 41
      src/components/topic/multi.tsx
  5. 7
      src/components/topic/topic.scss
  6. 33
      src/components/video/video.tsx
  7. 40
      src/hooks/videoEvents.ts
  8. 8
      src/pages/business/userInfo/userInfo.module.scss
  9. 51
      src/pages/business/videoInfo/components/catalogue.tsx
  10. 30
      src/pages/business/videoInfo/components/course.tsx
  11. 40
      src/pages/business/videoInfo/components/hours.tsx
  12. 2
      src/pages/business/videoInfo/videoInfo.scss
  13. 12
      src/pages/business/videoInfo/videoInfo.tsx
  14. 2
      src/pages/manage/spotMeeting/spotMeeting.config.ts
  15. 2
      src/pages/my/components/header/service.tsx
  16. 7
      src/static/css/module.scss

@ -1,5 +1,5 @@
TARO_APP_API=https://yjx.dev.yaojiankang.top #TARO_APP_API=https://yjx.dev.yaojiankang.top
#TARO_APP_API=https://playedu.yaojiankang.top TARO_APP_API=https://playedu.yaojiankang.top
TARO_APP_LGOIN=true TARO_APP_LGOIN=true

@ -255,7 +255,7 @@
.text-hover-primary { color: #0056b3;} .text-hover-primary { color: #0056b3;}
.text-secondary {color: #6c757d;} .text-secondary {color: #6c757d;}
.text-hover-secondary { color: #494f54;} .text-hover-secondary { color: #494f54;}
.text-success {color: #28a745;} .text-success {color: #45D4A8;}
.text-hover-success{color: #19692c;} .text-hover-success{color: #19692c;}
.text-info { color: #17a2b8;} .text-info { color: #17a2b8;}
.text-hover-info {color: #0f6674;} .text-hover-info {color: #0f6674;}

@ -43,14 +43,14 @@ const Judge: FC<Props> = ({data, onAnswer, validate, frequency}) => {
color={validate ? 'correct' !== rightKey ? 'red' : '#45d4a8' : '#45d4a8'} color={validate ? 'correct' !== rightKey ? 'red' : '#45d4a8' : '#45d4a8'}
disabled={validate ? 'correct' !== rightAnswer : false} disabled={validate ? 'correct' !== rightAnswer : false}
> >
<Text></Text>
</Radio> </Radio>
<Radio <Radio
value={'error'} value={'error'}
color={validate ? 'error' !== rightKey ? 'red' : '#45d4a8' : '#45d4a8'} color={validate ? 'error' !== rightKey ? 'red' : '#45d4a8' : '#45d4a8'}
disabled={validate ? 'error' !== rightAnswer : false} disabled={validate ? 'error' !== rightAnswer : false}
className='option'> className='option'>
<Text></Text>
</Radio> </Radio>
</RadioGroup> </RadioGroup>

@ -1,4 +1,4 @@
import {FC, useEffect, useState} from "react"; import {FC, useCallback, useEffect, useState} from "react";
import {Checkbox, CheckboxGroup, Radio, RadioGroup, Text, View} from "@tarojs/components"; import {Checkbox, CheckboxGroup, Radio, RadioGroup, Text, View} from "@tarojs/components";
import './topic.scss' import './topic.scss'
@ -22,20 +22,37 @@ const Multi: FC<Props> = ({data, onAnswer, validate, frequency}) => {
{value: "D", title: data.answerD}, {value: "D", title: data.answerD},
] ]
function onChange(e) { function RadioChange(e) {
const value = e.detail.value const value = e.detail.value
if (data.type) { setRightAnswer([value])
setRightAnswer(value) }
const changeCheckbox = useCallback((value: string) => {
const index = rightAnswer.indexOf(value)
if (index === -1) {
setRightAnswer([...rightAnswer, value])
} else { } else {
setRightAnswer([value]) const oldRightAnswer: string[] = JSON.parse(JSON.stringify(rightAnswer))
oldRightAnswer.splice(index, 1)
setRightAnswer(oldRightAnswer)
} }
} }, [rightAnswer])
useEffect(() => { useEffect(() => {
if (validate) { if (validate) {
const isAnswer = rightKey.toString() === rightAnswer.toString() if (rightAnswer.length !== rightKey.length) {
onAnswer(isAnswer) onAnswer(false)
setError(!isAnswer) setError(false)
} else {
const isAnswer = rightAnswer.reduce((pre, cut) => {
if (!pre) {
return false
}
return rightKey.indexOf(cut) !== -1
}, true)
onAnswer(isAnswer)
setError(!isAnswer)
}
} }
}, [validate]) }, [validate])
@ -47,17 +64,19 @@ const Multi: FC<Props> = ({data, onAnswer, validate, frequency}) => {
</View> </View>
<View> <View>
{data.type ? <CheckboxGroup onChange={onChange}> {data.type ? <CheckboxGroup>
{answers.map(d => <Checkbox {answers.map(d => <Checkbox
onClick={() => changeCheckbox(d.value)}
key={d.value} key={d.value}
value={d.value} value={d.value}
className='option' className='option'
disabled={validate} disabled={validate}
checked={rightAnswer.includes(d.value)}
> >
<Text className='title'>{d.value}{d.title}</Text> <Text className='title'>{d.value}{d.title}</Text>
</Checkbox>)} </Checkbox>)}
</CheckboxGroup> </CheckboxGroup>
: <RadioGroup onChange={onChange}> : <RadioGroup onChange={RadioChange}>
{answers.map(d => <Radio {answers.map(d => <Radio
key={d.value} key={d.value}
value={d.value} value={d.value}

@ -16,7 +16,8 @@
.option, .option,
.weui-cells_checkbox { .weui-cells_checkbox {
display: block; display: flex;
align-items: center;
margin-bottom: 10px; margin-bottom: 10px;
line-height: 2; line-height: 2;
@ -26,6 +27,10 @@
} }
} }
.taro-checkbox_checked {
top: 0 !important;
}
.statistics { .statistics {
border-top: 1px solid #F5F8F7; border-top: 1px solid #F5F8F7;
height: 60rpx; height: 60rpx;

@ -3,9 +3,9 @@ import {HVideoOptions} from "@/components/video/type";
import Taro from "@tarojs/taro"; import Taro from "@tarojs/taro";
import {FC, useState} from "react"; import {FC, useState} from "react";
import unique_ident from "@/hooks/unique_ident"; import unique_ident from "@/hooks/unique_ident";
import videoEvents from "@/hooks/videoEvents";
const deviation: number = 1 const deviation: number = 1
const HVideo: FC<HVideoOptions> = (opt: HVideoOptions) => { const HVideo: FC<HVideoOptions> = (opt: HVideoOptions) => {
let video: Taro.VideoContext let video: Taro.VideoContext
@ -13,8 +13,17 @@ const HVideo: FC<HVideoOptions> = (opt: HVideoOptions) => {
try { try {
video = Taro.createVideoContext('myVideo') video = Taro.createVideoContext('myVideo')
} catch (e) { videoEvents.onSetVideoState(({name}) => {
} switch (name) {
case "pause":
video?.pause()
break
case "play":
video?.play()
break
}
})
} catch (e) {}
function onTimeUpdate(event: BaseEventOrig<VideoProps.onTimeUpdateEventDetail>) { function onTimeUpdate(event: BaseEventOrig<VideoProps.onTimeUpdateEventDetail>) {
// if (opt.preview) return; // if (opt.preview) return;
@ -38,8 +47,10 @@ const HVideo: FC<HVideoOptions> = (opt: HVideoOptions) => {
}) })
} }
opt.setTime((time: number) => { opt.setTime((time?: number) => {
video?.seek(time) if (typeof time === 'number') {
video?.seek(time)
}
video?.play() video?.play()
}) })
@ -53,11 +64,20 @@ const HVideo: FC<HVideoOptions> = (opt: HVideoOptions) => {
} }
} }
function onPlay() {
videoEvents.videoState('play')
}
function onPause() {
videoEvents.videoState('pause')
}
Taro.useDidHide(() => { Taro.useDidHide(() => {
video?.pause() video?.pause()
unique_ident.put(Number(currentTime.toFixed(2)), Date.now()) unique_ident.put(Number(currentTime.toFixed(2)), Date.now())
}) })
Taro.useDidShow(() => { Taro.useDidShow(() => {
if (!video) { if (!video) {
video = Taro.createVideoContext('myVideo') video = Taro.createVideoContext('myVideo')
@ -67,6 +87,7 @@ const HVideo: FC<HVideoOptions> = (opt: HVideoOptions) => {
} }
}) })
return ( return (
<Video <Video
id={'myVideo'} id={'myVideo'}
@ -78,6 +99,8 @@ const HVideo: FC<HVideoOptions> = (opt: HVideoOptions) => {
direction={90} direction={90}
onTimeUpdate={onTimeUpdate} onTimeUpdate={onTimeUpdate}
onEnded={onEnded} onEnded={onEnded}
onPlay={onPlay}
onPause={onPause}
/> />
) )
} }

@ -0,0 +1,40 @@
import Taro from "@tarojs/taro";
const KEY = "VIDEO_EVENT"
const SET_KEY = 'SET_VIDEO_EVENT'
type StateChangeName = 'play' | 'pause'
/** 视频状态播改变播放 */
function videoState(name: StateChangeName) {
Taro.eventCenter.trigger(KEY, {name})
}
/** 接受状态播放改变 */
function onVideoState(fn: ({name: StateChangeName}) => void) {
Taro.eventCenter.once(KEY, fn)
}
/** 设置视频状态 */
function setVideoState(name: StateChangeName) {
Taro.eventCenter.trigger(SET_KEY, {name})
}
/** 接受状态改变 */
function onSetVideoState(fn: (data: { name: StateChangeName }) => void) {
Taro.eventCenter.on(SET_KEY, fn)
}
function videoOff() {
Taro.eventCenter.off(KEY)
Taro.eventCenter.off(SET_KEY)
}
export default {
videoState,
onVideoState,
onSetVideoState,
setVideoState,
videoOff
}

@ -1,17 +1,17 @@
.box { .box {
width: 690rpx; width: 690rpx;
height: 412rpx; background: #fff;
background: #FFF;
border-radius: 20rpx; border-radius: 20rpx;
margin: auto; margin: auto;
overflow: hidden; overflow: hidden;
margin-top: 20px; margin-top: 20px;
padding: 10px 0; padding: 20px 0;
} }
.buttonFixed { .buttonFixed {
position: fixed; position: fixed;
bottom: 100px; bottom: env(safe-area-inset-bottom);
margin-bottom: 30rpx;
left: 0; left: 0;
width: 100%; width: 100%;
padding: 0 30rpx; padding: 0 30rpx;

@ -9,6 +9,7 @@ import CustomPageContainer from "@/components/custom-page-container/custom-page-
import MyButton from "@/components/button/MyButton"; import MyButton from "@/components/button/MyButton";
import curRecord from '@/static/img/curRecord.png' import curRecord from '@/static/img/curRecord.png'
import hourRecord from '@/static/img/hourRecord.png' import hourRecord from '@/static/img/hourRecord.png'
import videoEvents from "@/hooks/videoEvents";
interface Props { interface Props {
data: CourseDepData | null data: CourseDepData | null
@ -24,9 +25,27 @@ const tabList = [
] ]
const Catalogue: FC<Props> = ({data, setHors, id, playId}) => { const Catalogue: FC<Props> = ({data, setHors, id, playId,}) => {
const [current, setCurrent] = useState(1) const [current, setCurrent] = useState(1)
const [show, setShow] = useState(false) const [show, setShow] = useState(false)
const [playing, setPlaying] = useState(false)
videoEvents.onVideoState(({name}) => {
switch (name) {
case "pause":
setPlaying(false)
break
case 'play':
setPlaying(true)
break
}
})
function onPause() {
videoEvents.setVideoState('pause')
}
function jumCurHistory() { function jumCurHistory() {
if (playId) { if (playId) {
@ -76,19 +95,27 @@ const Catalogue: FC<Props> = ({data, setHors, id, playId}) => {
function learning() { function learning() {
const flats: Hour[] = Object.values(data?.hours || {}).flat(Infinity) as Hour[] const flats: Hour[] = Object.values(data?.hours || {}).flat(Infinity) as Hour[]
if ((data?.learn_hour_records?.length || undefined) == data?.learn_record?.hour_count && flats.length) { if ((data?.learn_hour_records?.length || undefined) == data?.learn_record?.hour_count && flats.length) {
setHors(true, flats[0].id) if (flats[0].id === playId) {
videoEvents.setVideoState('play')
} else {
setHors(true, flats[0].id)
}
return return
} }
if (data?.learn_hour_records.length) { if (data?.learn_hour_records.length) {
const lastTimeId = data.learn_hour_records[data.learn_hour_records.length - 1].id const lastTimeId = data.learn_hour_records[data.learn_hour_records.length - 1].id
for (const [index, flat] of flats.entries()) { for (const [index, flat] of flats.entries()) {
if (flat.id === lastTimeId) { if (flat.id === lastTimeId) {
const next = flats[index + 1] const next = flats[index + 1]
if (next) { if (next) {
setHors(true, next.id) if (next.id === playId) {
videoEvents.setVideoState('play')
} else {
setHors(true, next.id)
}
} }
} }
} }
@ -106,23 +133,33 @@ const Catalogue: FC<Props> = ({data, setHors, id, playId}) => {
{current === 0 && <View className='short_desc'>{data?.course.short_desc || data?.course.title}</View>} {current === 0 && <View className='short_desc'>{data?.course.short_desc || data?.course.title}</View>}
{current === 1 && <View> {current === 1 && <View>
<View className='my-2'></View> <View className='my-2'></View>
{data?.chapters.length ? Object.values(data?.chapters || {}).map((d, index) => <View> {data?.chapters.length
? Object.values(data?.chapters || {}).map((d, index) => <View>
<Collapse title={`${index + 1}.${d.name}`}> <Collapse title={`${index + 1}.${d.name}`}>
<Hours <Hours
playId={playId}
click={(is_complete, id) => upChaptersOver(is_complete, id, index)} click={(is_complete, id) => upChaptersOver(is_complete, id, index)}
learn_hour_records={data.learn_hour_records} learn_hour_records={data.learn_hour_records}
data={getHors(d.id)} data={getHors(d.id)}
/> />
</Collapse> </Collapse>
</View>) </View>)
: <Hours data={data?.hours?.[0]} click={setHors} learn_hour_records={data?.learn_hour_records}/>} : <Hours
playId={playId}
data={data?.hours?.[0]}
click={setHors}
learn_hour_records={data?.learn_hour_records}/>}
</View>} </View>}
{current === 2 && <View className='text-center'></View>} {current === 2 && <View className='text-center'></View>}
</View> </View>
</View> </View>
<View className='Videobutton'> <View className='Videobutton'>
<MyButton onClick={learning}></MyButton> {
playing ? <MyButton onClick={onPause}></MyButton>
: <MyButton onClick={learning}></MyButton>
}
<View className='px-3' onClick={() => setShow(true)}>...</View> <View className='px-3' onClick={() => setShow(true)}>...</View>
</View> </View>

@ -16,7 +16,7 @@ interface Props {
id: number, id: number,
courseId: number courseId: number
preview?: boolean preview?: boolean
curEnd: (test?:boolean) => void curEnd: (test?: boolean) => void
} }
@ -243,29 +243,31 @@ const Course: FC<Props> = ({id, courseId, preview, curEnd}: Props) => {
)} )}
</Swiper> </Swiper>
<View> <View>
<View className='statistics'>
<View>{frequency}</View>
{
(index + 1) === examAll?.[time]?.length && <View>
{!validate && <MyButton width={150} fillet onClick={() => setValidate(true)}></MyButton>}
{frequency > 0 && validate && <MyButton width={150} fillet onClick={onceMore}></MyButton>}
{frequency === 0 && validate && <MyButton width={150} fillet onClick={again}></MyButton>}
</View>
}
</View>
<View className='upAndDown'> <View className='upAndDown'>
<View> <View>
{index !== 0 && <MyButton size='mini' width={150} onClick={() => setIndex(index - 1)}></MyButton>} {index !== 0 && <MyButton type='default' size='mini' width={150}
onClick={() => setIndex(index - 1)}></MyButton>}
</View> </View>
<View> <View>
{ {
(index + 1) !== examAll?.[time]?.length (index + 1) !== examAll?.[time]?.length
&& <MyButton size='mini' width={150} onClick={() => setIndex(index + 1)}></MyButton> &&
<MyButton size='mini' width={150} type='default' onClick={() => setIndex(index + 1)}></MyButton>
} }
</View> </View>
</View> </View>
<View className='statistics'>
<View>{frequency}</View>
{
(index + 1) === examAll?.[time]?.length && <View>
{!validate && <MyButton width={150} fillet onClick={() => setValidate(true)}></MyButton>}
{frequency > 0 && validate && <MyButton width={150} fillet onClick={onceMore}></MyButton>}
{frequency === 0 && validate && <MyButton width={150} fillet onClick={again}></MyButton>}
</View>
}
</View>
</View> </View>
</CustomPageContainer> </CustomPageContainer>
</View> </View>

@ -1,6 +1,6 @@
import {FC} from "react"; import {FC} from "react";
import '../videoInfo.scss' import '../videoInfo.scss'
import {Image, View} from "@tarojs/components"; import {Image, Text, View} from "@tarojs/components";
import playOk from "@/static/img/play-ok.png"; import playOk from "@/static/img/play-ok.png";
import play from "@/static/img/play.png"; import play from "@/static/img/play.png";
import {formatMinute} from "@/utils/time"; import {formatMinute} from "@/utils/time";
@ -9,6 +9,7 @@ import {curriculum} from "@/api";
import lock from '@/static/img/lock.png' import lock from '@/static/img/lock.png'
interface Props { interface Props {
playId: number | null
data?: Hour[] | null data?: Hour[] | null
learn_hour_records?: LearnHourRecords[] learn_hour_records?: LearnHourRecords[]
click: (is_complete: boolean, id: number) => void click: (is_complete: boolean, id: number) => void
@ -21,7 +22,7 @@ async function jumTest(hour: Hour) {
}) })
} }
const Hours: FC<Props> = ({data, click, learn_hour_records}) => { const Hours: FC<Props> = ({data, click, learn_hour_records, playId}) => {
const complete = (id: number): number | undefined => { const complete = (id: number): number | undefined => {
const find = learn_hour_records?.find(d => d.id === id) const find = learn_hour_records?.find(d => d.id === id)
if (find) { if (find) {
@ -53,7 +54,7 @@ const Hours: FC<Props> = ({data, click, learn_hour_records}) => {
} }
if (upId && complete(upId) !== 1) { if (upId && complete(upId) !== 1) {
Taro.showToast({title: '禁止播放', icon: 'none'}) Taro.showToast({title: '锁定中', icon: 'none'})
return return
} }
@ -63,23 +64,26 @@ const Hours: FC<Props> = ({data, click, learn_hour_records}) => {
return ( return (
<> <>
{data?.map((d, index) => {data?.map((d, index) =>
<View className={'hor' + ` ${complete(d.id) ? 'complete' : undefined}`} <>
key={index} <View className={'hor' + ` ${complete(d.id) ? 'complete' : undefined}`}
onClick={() => onClick(d.id, complete(d.id), d, data?.[index - 1]?.id)}> key={index}
<Image src={complete(d.id) ? playOk : play} mode="scaleToFill" className='image'/> onClick={() => onClick(d.id, complete(d.id), d, data?.[index - 1]?.id)}>
<View className='title'> <Image src={(complete(d.id) || playId === d.id) ? playOk : play} mode="scaleToFill" className='image'/>
<View className='text'> <View className='title'>
<View>{index + 1}.{d.title}</View> <View className='text'>
<View className='font-26 text-muted'>{formatMinute(d.duration)}</View> <View style={{wordBreak: 'break-all'}}>{playId === d.id && <Text className='text-center text-success'></Text>}{index + 1}. {d.title}</View>
{complete(d.id) === 0 && <View className='font-26 text-danger'></View>} <View className='font-26 text-muted mt-1'>{formatMinute(d.duration)}</View>
{complete(d.id) === 0 && <View className='font-26 text-danger'></View>}
</View>
{
complete(data?.[index - 1]?.id) == null
&& index !== 0
&& <Image className='lock' src={lock} mode='aspectFit'/>
}
</View> </View>
{
complete(data?.[index - 1]?.id) == null
&& index !== 0
&& <Image className='lock' src={lock} mode='aspectFit'/>
}
</View> </View>
</View>)} </>)}
</> </>
) )
} }

@ -43,7 +43,7 @@
.image { .image {
width: 40rpx; width: 40rpx;
height: 40rpx; height: 40rpx;
margin-top: 10rpx; margin-top: 8rpx;
} }

@ -8,13 +8,14 @@ import Taro from "@tarojs/taro";
import eventsIndex from "@/hooks/eventsIndex"; import eventsIndex from "@/hooks/eventsIndex";
import {formatMinute} from "@/utils/time"; import {formatMinute} from "@/utils/time";
import unique_ident from "@/hooks/unique_ident"; import unique_ident from "@/hooks/unique_ident";
import videoEvents from "@/hooks/videoEvents";
const VideoInfo: FC = () => { const VideoInfo: FC = () => {
const {id, depId} = Taro.getCurrentInstance()?.router?.params as any const {id, depId} = Taro.getCurrentInstance()?.router?.params as any
const [data, setData] = useState<CourseDepData | null>(null) const [data, setData] = useState<CourseDepData | null>(null)
const [playId, setPlayId] = useState<number | null>(null) const [playId, setPlayId] = useState<number | null>(null)
const [preview, setPreview] = useState(false) const [preview, setPreview] = useState(false) // 预览
const [playing, setPlaying] = useState(false) const [playing, setPlaying] = useState(false) // 学习中
const getData = useCallback(async (playing: boolean) => { const getData = useCallback(async (playing: boolean) => {
const res = await curriculum.courseDep(id, depId) const res = await curriculum.courseDep(id, depId)
@ -102,6 +103,7 @@ const VideoInfo: FC = () => {
Taro.useUnload(() => { Taro.useUnload(() => {
unique_ident.del() unique_ident.del()
videoEvents.videoOff()
}) })
return ( return (
<> <>
@ -123,7 +125,11 @@ const VideoInfo: FC = () => {
<Text>{((data?.learn_hour_records.length || 0) / (data?.course.class_hour || 1) * 100).toFixed(0)}%</Text> <Text>{((data?.learn_hour_records.length || 0) / (data?.course.class_hour || 1) * 100).toFixed(0)}%</Text>
</View> </View>
</View> </View>
<Catalogue data={data} setHors={setHors} id={id} playId={playId}/> <Catalogue
data={data}
setHors={setHors}
id={id}
playId={playId}/>
</View> </View>
</> </>
) )

@ -1,4 +1,4 @@
export default definePageConfig({ export default definePageConfig({
navigationBarTitleText: '见面会', navigationBarTitleText: '现场会',
enableShareAppMessage: true enableShareAppMessage: true
}) })

@ -27,7 +27,7 @@ const Service = () => {
if ([1, 2].includes(user?.role_type || 0)) { if ([1, 2].includes(user?.role_type || 0)) {
oldList.unshift(...[ oldList.unshift(...[
{title: '部门管理', src: dep, router: '/pages/manage/depAdmin/depAdmin'}, {title: '部门管理', src: dep, router: '/pages/manage/depAdmin/depAdmin'},
{title: '课程市场', src: buy, router: '/pages/manage/curriculum/curriculum'}, // {title: '课程市场', src: buy, router: '/pages/manage/curriculum/curriculum'},
{title: '现场会', src: buy, router: '/pages/manage/spotMeeting/spotMeeting'}, {title: '现场会', src: buy, router: '/pages/manage/spotMeeting/spotMeeting'},
]) ])
setList(oldList) setList(oldList)

@ -5,7 +5,6 @@ page,
-webkit-overflow-scrolling: touch; -webkit-overflow-scrolling: touch;
box-sizing: border-box; box-sizing: border-box;
padding-bottom: env(safe-area-inset-bottom); padding-bottom: env(safe-area-inset-bottom);
//min-height: 100vh;
} }
body { body {
@ -13,7 +12,7 @@ body {
} }
.weui-cells_checkbox .weui-check:checked + .weui-icon-checked:before, .weui-cells_checkbox .weui-check:checked + .weui-icon-checked:before,
.taro-checkbox_checked{ .taro-checkbox_checked {
color: #45D4A8 !important; color: #45D4A8 !important;
} }
@ -45,16 +44,14 @@ taro-button-core::after {
.card { .card {
height: 100px;
background: #fff; background: #fff;
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: space-between; justify-content: space-between;
border-bottom: 1px solid #F5F8F7; border-bottom: 1px solid #F5F8F7;
padding: 0 20rpx; padding: 10px 20rpx;
font-size: 30rpx; font-size: 30rpx;
&-content { &-content {
font-size: 27rpx; font-size: 27rpx;
color: #8c8c8c; color: #8c8c8c;

Loading…
Cancel
Save