登录模块调整,验证模块调整

v2
一杯沧海 1 year ago
parent 84fbd98fa9
commit 2a29617017
  1. 3
      .env
  2. 4
      project.config.json
  3. 1
      src/api/brand.ts
  4. 2
      src/api/home.ts
  5. 3
      src/api/illness.ts
  6. 10
      src/api/meeting.ts
  7. 11
      src/api/public.ts
  8. 11
      src/app.config.ts
  9. 21
      src/app.scss
  10. 128
      src/components/IconFont/icon.css
  11. 88
      src/components/IconFont/index.tsx
  12. 8
      src/components/collect/collect.module.scss
  13. 19
      src/components/collect/collect.tsx
  14. 7
      src/components/empty/empty.module.scss
  15. 16
      src/components/empty/empty.tsx
  16. 10
      src/components/image/image.tsx
  17. 15
      src/components/learningRecord/learningRecord.tsx
  18. 5
      src/components/lineChart/lineChart.module.scss
  19. 5
      src/components/lineChart/lineChart.tsx
  20. 38
      src/components/login-view/index.module.scss
  21. 28
      src/components/login-view/index.tsx
  22. 31
      src/components/loginView/index.tsx
  23. 1
      src/components/navigationBar/navigationBar.module.scss
  24. 39
      src/hooks/pubsub.ts
  25. 4
      src/pages/business/curHistory/curHistory.tsx
  26. 13
      src/pages/business/userInfo/userInfo.tsx
  27. 45
      src/pages/business/videoInfo/components/catalogue.tsx
  28. 19
      src/pages/business/videoInfo/components/hours.tsx
  29. 11
      src/pages/business/videoInfo/videoInfo.scss
  30. 18
      src/pages/business/videoInfo/videoInfo.tsx
  31. 2
      src/pages/check/check.config.ts
  32. 4
      src/pages/check/check.module.scss
  33. 26
      src/pages/check/check.tsx
  34. 17
      src/pages/home/components/curRecommended.tsx
  35. 2
      src/pages/home/components/feature.tsx
  36. 80
      src/pages/home/components/feature_recommended.tsx
  37. 7
      src/pages/home/home.tsx
  38. 8
      src/pages/index/components/videoList.tsx
  39. 24
      src/pages/index/index.module.scss
  40. 9
      src/pages/index/index.tsx
  41. 6
      src/pages/login/login.module.scss
  42. 79
      src/pages/login/login.tsx
  43. 5
      src/pages/manage/addStudent/addStudent.scss
  44. 27
      src/pages/manage/courseAdmin/components/search.tsx
  45. 5
      src/pages/manage/courseAdmin/courseAdmin.module.scss
  46. 4
      src/pages/manage/courseAdmin/courseAdmin.tsx
  47. 4
      src/pages/manage/meetings/form/form.conrfig.ts
  48. 39
      src/pages/manage/meetings/form/form.module.scss
  49. 198
      src/pages/manage/meetings/form/form.tsx
  50. 4
      src/pages/manage/meetings/list.config.ts
  51. 11
      src/pages/manage/meetings/list.module.scss
  52. 52
      src/pages/manage/meetings/meetings.module.scss
  53. 69
      src/pages/manage/meetings/meetings.tsx
  54. 18
      src/pages/manage/spotMeeting/spotMeeting.module.scss
  55. 335
      src/pages/manage/spotMeeting/spotMeeting.tsx
  56. 7
      src/pages/my/components/header/header.tsx
  57. 2
      src/pages/my/components/header/service.tsx
  58. 12
      src/pages/my/my.tsx
  59. 85
      src/pages/preview/brand/article/article.tsx
  60. 2
      src/pages/preview/brand/list/list.tsx
  61. 17
      src/pages/preview/collect/collect.tsx
  62. 4
      src/pages/preview/health/health.tsx
  63. 2
      src/pages/preview/illness/sort/sort.tsx
  64. 5
      src/pages/preview/profession/profession.tsx
  65. 10
      src/pages/preview/search/search/index.tsx
  66. 6
      src/pages/preview/videoFull/videoFull.module.scss
  67. 1
      src/pages/preview/videoFull/videoFull.tsx
  68. 2
      src/pages/preview/webView/webView.config.ts
  69. 55
      src/pages/preview/webView/webView.tsx
  70. 58
      src/pages/search/components/list.module.scss
  71. 167
      src/pages/search/components/list.tsx
  72. 3
      src/pages/search/index.config.ts
  73. 66
      src/pages/search/index.module.scss
  74. 154
      src/pages/search/index.tsx
  75. 128
      src/static/css/module.scss
  76. BIN
      src/static/img/arrow-right.png
  77. BIN
      src/static/img/beforeMeeting.png
  78. BIN
      src/static/img/cyanSearch.png
  79. BIN
      src/static/img/graySearch.png
  80. BIN
      src/static/img/meeting.png
  81. BIN
      src/static/img/meetingEnd.png
  82. 2
      src/utils/marked/components/Tablink.tsx
  83. 2
      types/home.d.ts

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

@ -1,8 +1,8 @@
{
"miniprogramRoot": "./dist",
"projectname": "video",
"projectname": "信桂",
"description": "",
"appid": "wx703940a70f0f1be7",
"appid": "wx7ef5cf2d16bdaea2",
"setting": {
"urlCheck": true,
"es6": false,

@ -14,6 +14,7 @@ export type BrandRecord = {
created_at: string
page_view: number
collect: boolean
last_publish_time: string
}
export type ArticleRecord = {
id: number;

@ -39,6 +39,8 @@ export interface HomeData {
illness: {
list: Illness[]
}
articles: Articles[]
courses: {data:any,total:number}
}
interface Course {

@ -1,6 +1,7 @@
import {request} from "@/api/request";
export interface Illness {
name?: any;
illness: {
name: string;
description: string;
@ -14,6 +15,8 @@ export interface Illness {
}
}
export const illnessApi = {
/** 疾病列表 */
list(id: number, page: number, page_size: number) {

@ -27,21 +27,29 @@ interface MeetingInfo {
}
export const meetingAPi = {
setMeetings(data: Meeting) {
addMeetings(data: Meeting) {
return request<{ id: number }>('/api/v1/meetings/meeting', "POST", data)
},
setMeetings(data: Meeting) {
return request<{ id: number }>(`/api/v1/meetings/meeting/${data.id}`, "PUT", data)
},
putMeeting(id: number, data: Partial<Meeting>) {
return request(`/api/v1/meetings/meeting/${id}`, "PUT", data)
},
setMeeting(id: string) {
return request<Meeting>(`/api/v1/meetings/meeting/${id}`, "GET")
},
unstopsList() {
return request<Meeting[]>(`/api/v1/meetings/unstops`, "GET")
},
setList(page: number, page_size: number) {
return request<{
data: Meeting[],
total: number
}>(`/api/v1/meetings/meeting?page=${page}&page_size=${page_size}`, "GET")
},
exists() {
return request<Meeting>('/api/v1/meetings/exists', "GET")
},

@ -14,6 +14,12 @@ export interface CoursesMode {
audit_mode: boolean
course: Courses
}
export interface NewCoursesMode {
articles: any[]
audit_mode: boolean
platform_courses: Curriculum[]
company_courses: Curriculum[]
}
export interface Courses {
/** 选秀 */
@ -34,5 +40,8 @@ export const publicApi = {
},
articlesPush(page: number, page_size: number) {
return request<{ list: Articles[], total: number }>('/home/v1/article/list', "GET", {page, page_size})
}
},
newCourse(data: { page: number, page_size: number }) {
return request<NewCoursesMode>('/home/v1/home/courses', "GET", data)
},
}

@ -6,11 +6,12 @@ export default defineAppConfig({
'pages/login/login',
'pages/check/check',
'pages/my/my',
'pages/search/index'
],
window: {
backgroundTextStyle: 'light',
navigationBarBackgroundColor: '#fff',
navigationBarTitleText: '课程',
navigationBarTitleText: '信桂',
navigationBarTextStyle: 'black'
},
tabBar: {
@ -29,6 +30,12 @@ export default defineAppConfig({
iconPath: "static/tabs/study.png",
selectedIconPath: "static/tabs/study-selected.png",
},
{
text: '搜索',
pagePath: 'pages/search/index',
iconPath: "static/img/graySearch.png",
selectedIconPath: "static/img/cyanSearch.png",
},
{
text: "我的",
pagePath: 'pages/my/my',
@ -76,6 +83,8 @@ export default defineAppConfig({
'spotMeeting/spotMeeting',
'selectDep/selectDep',
'meetings/meetings',
'meetings/list',
'meetings/form/form',
'userInfo/userInfo',
'courseAdmin/courseAdmin',
]

@ -1,6 +1,8 @@
@import "static/css/module";
//@import 'taro-ui/dist/style/index.scss';
.inlineblock { display: inline-block }
.flex {display: flex !important;flex-direction:row}
.flex-row{ flex-direction:row!important}
.flex-column{ flex-direction:column!important}
@ -20,6 +22,7 @@
.align-center{ align-items: center}
.align-stretch{ align-items: stretch}
.align-start{ align-items: flex-start}
.align-baseline{align-items: baseline}
.align-end{ align-items: flex-end}
.content-start {align-content: flex-start}
@ -37,6 +40,8 @@
.flex-shrink{flex-shrink: 0}
.gap20rpx{gap: 20rpx}
.gap30rpx{gap: 30rpx}
.gap60rpx{gap: 60rpx}
.w-1 {width: 10%;min-width: 75rpx}
.w-2 {width: 20%;min-width: 150rpx}
@ -376,6 +381,7 @@
.relative {position: relative}
.absolute {position: absolute}
.absolute-impt{position: absolute !important;}
.fixed {position: fixed}
.sticky {position: sticky}
@ -396,3 +402,18 @@
background: #000;
opacity: 0.05;
}
.z1{
z-index: 1;
}
.z2{
z-index: 2;
}
.z3{
z-index: 3;
}
.word-break{
word-break: break-all;
}

File diff suppressed because one or more lines are too long

@ -0,0 +1,88 @@
import { CSSProperties, FC } from "react"
import { Text, ITouchEvent } from "@tarojs/components"
import './icon.css'
export type IconName =
| 'arrow-clockwise'
| 'arrow-counterclockwise'
| 'backspace'
| 'bar-chart'
| 'bar-chart-line'
| 'caret-down'
| 'caret-up'
| 'caret-left'
| 'caret-right'
| 'check'
| 'check-all'
| 'chevron-double-down'
| 'chevron-double-up'
| 'chevron-double-left'
| 'chevron-double-right'
| 'chevron-down'
| 'chevron-up'
| 'chevron-left'
| 'chevron-right'
| 'circle'
| 'exclamation'
| 'gear'
| 'gender-female'
| 'gender-male'
| 'heart'
| 'info'
| 'list'
| 'lock'
| 'unlock'
| 'play-btn'
| 'play'
| 'question'
| 'shield'
| 'square'
| 'star'
| 'three-dots-vertical'
| 'three-dots'
| 'trash'
| 'x'
export type IconShape =
| 'circle'
| 'square'
| 'diamond'
| 'octagon'
| 'triangle'
export interface IconProps {
name: IconName
shape?: IconShape
color?: string
size?: string | number
fill?: boolean
className?: string
style?: CSSProperties
onClick?: (event: ITouchEvent) => void
}
const XgIcon: FC<IconProps> = (props) => {
const name = [
props.name,
props.shape,
props.fill ? 'fill' : undefined
].filter(Boolean).join('-')
const color = props.color ?? 'currentColor'
const size = typeof props.size === 'string' ? props.size : `${props.size ?? 16}px`
const fontStyle: CSSProperties = {
...(props.style ?? {}),
fontSize: size,
color,
}
return (
<Text
className={`xg-icon xg-icon-${name} ${props.className}`}
style={fontStyle}
onClick={props.onClick}
/>
)
}
export default XgIcon

@ -13,10 +13,10 @@
height: 32rpx;
margin-right: 10rpx;
Image {
width: 100%;
height: 100%;
}
//Image {
// width: 100%;
// height: 100%;
//}
}
.zoom {

@ -1,11 +1,12 @@
import {CSSProperties, FC, useCallback, useEffect, useState} from "react";
import star from '@/static/img/star.png'
import starLine from '@/static/img/starLine.png'
import {Image, View} from "@tarojs/components";
// import star from '@/static/img/star.png'
// import starLine from '@/static/img/starLine.png'
import {View} from "@tarojs/components";
import styles from './collect.module.scss'
import {Profile} from "@/store"
import Taro from "@tarojs/taro";
import {userApi} from "@/api";
import IconFont from "@/components/IconFont";
interface Props {
onClick?: () => void
@ -62,12 +63,14 @@ const Collect: FC<Props> = (props) => {
return (
<View className={styles.collect} onClick={change} style={props.styles}>
<View className={styles.collectImage} style={props.stylesImage}>
<View className={`${loading && select && styles.zoom}`}/>
<Image
src={(select && token) ? star : starLine}
className={`${loading && styles.pulse}`}/>
{/*<View className={`${loading && select && styles.zoom}`}/>*/}
<View className={`${loading ? styles.pulse : ''}`}>
<IconFont name='star' fill={!!(select && token)} color={(select && token) ? '#FF9E5F' : undefined} />
</View>
{/*<Image src={(select && token) ? star : starLine} className={`${loading && styles.pulse}`}/>*/}
</View>
{!props.textHidden && (select ? '已收藏' : '收藏')}
{/*{!props.textHidden && (select ? '已收藏' : '收藏')}*/}
{!props.textHidden && '收藏'}
</View>
)
}

@ -3,6 +3,9 @@
text-align: center;
color: #6c757d;
position: relative;
display: flex;
flex-direction: column;
align-items: center;
}
.image {
@ -14,9 +17,5 @@
.name {
font-size: 30rpx;
position: absolute;
left: 0;
right: 0;
bottom: 50rpx;
margin: auto;
}

@ -1,17 +1,29 @@
import {FC} from "react";
import {Image, View} from "@tarojs/components";
import {Button, Image, View} from "@tarojs/components";
import emptyImg from '@/static/img/empty.png'
import styles from './empty.module.scss'
import MyButton from "@/components/button/MyButton";
import Taro from "@tarojs/taro";
interface Props {
name: string
showBack?: boolean
onRefresh?:() => void
}
const Empty: FC<Props> = ({name}) => {
const Empty: FC<Props> = ({name, showBack, onRefresh}) => {
const hasBack = showBack && Taro.getCurrentPages().length > 1
const hasRefresh = onRefresh != null
return (
<View className={styles.empty}>
<Image src={emptyImg} mode='widthFix' className={styles.image} fadeIn lazyLoad/>
<View className={styles.name}>{name}</View>
{(hasBack || hasRefresh) && (
<View className='flex justify-center align-center gap60rpx mt-3'>
{hasBack && <Button type={'default'} size={'mini'} style={{padding:'0 20px'}} onClick={() => Taro.navigateBack()}></Button>}
{hasRefresh && <MyButton size={'mini'} style={{padding:'0 20px'}} onClick={onRefresh} type="primary"></MyButton>}
</View>
)}
</View>
)
}

@ -13,6 +13,8 @@ interface Props extends ImageProps {
height?: number | string
fallback?: string
errorType?: ImgErrType
loadingImage?: string
errorImage?: string
fit?: boolean // 当网络图片加载完成后高度自动
}
@ -38,6 +40,10 @@ const Img: FC<Props> = ({src, mode = 'aspectFill', width, fallback = shard, ...p
}, [src])
useEffect(() => {
if (props.errorImage) {
setErrorUrl(props.errorImage)
return
}
switch (props.errorType) {
case undefined:
case "acquiesce":
@ -78,8 +84,8 @@ const Img: FC<Props> = ({src, mode = 'aspectFill', width, fallback = shard, ...p
<View className={props?.className}
style={{
overflow: 'hidden',
width: width ? `${width}rpx` : "100%",
height: height ? `${height}rpx` : "100%",
width: width ? typeof width === 'string' ? width : `${width}rpx` : "100%",
height: height ? typeof height === 'string' ? height : `${height}rpx` : "100%",
backgroundColor: (isError || !loading) ? 'transparent' : '#F8F8F8',
}}>
{!isError &&

@ -12,10 +12,9 @@ import debounce from "@/utils/debounce";
const tabList: TabList<any>[] = [
{
title: '日',
value: {
start_time: new Date().setHours(0, 0, 0, 0),
end_time: new Date().setHours(24, 0, 0, 0)
title: '月', value: {
start_time: monthFirst(),
end_time: monthEnd()
}
},
{
@ -25,9 +24,10 @@ const tabList: TabList<any>[] = [
}
},
{
title: '月', value: {
start_time: monthFirst(),
end_time: monthEnd()
title: '日',
value: {
start_time: new Date().setHours(0, 0, 0, 0),
end_time: new Date().setHours(24, 0, 0, 0)
}
},
]
@ -59,6 +59,7 @@ const LearningRecord: FC<Props> = ({userId, style, className}) => {
}
}
// @ts-ignore
function tabChange({tab}: OnChangOpt<StatisticsParam>) {
if (!token) {
Taro.navigateTo({url: '/pages/login/login'})

@ -60,11 +60,11 @@
width: 30rpx;
background: linear-gradient(180deg, #03D9B3 0%, #05BF88 100%);
border-radius: 30rpx;
margin-bottom: 20rpx;
margin-bottom: 6rpx;
overflow: hidden;
animation: rise 300ms ease-in-out forwards;
max-height: 0;
margin-top: 10rpx;
margin-top: 6rpx;
}
.value {
@ -73,6 +73,7 @@
font-family: PingFang SC-Bold, PingFang SC;
font-weight: bold;
color: #606563;
line-height: 20rpx;
}
.time {

@ -17,6 +17,7 @@ const height = 150
const LineChart: FC<Props> = ({data}) => {
const [maxHeight, setMaxHeight] = useState<lineData>({time: '', value: 0})
const [lineChartList, setLineChartList] = useState(data)
console.log(maxHeight,lineChartList,'maxHeight')
useEffect(() => {
setLineChartList(data)
@ -31,7 +32,9 @@ const LineChart: FC<Props> = ({data}) => {
return (
<View style={{width: '100%', position: 'relative'}}>
<View className={style.records}>
<Text>{formatDateTime(new Date(maxHeight.time), 'MM月dd日')}</Text>
{/*<Text>{maxHeight.time}</Text>*/}
<Text>{maxHeight.time.split('/').join('月')}</Text>
{maxHeight.value > 0 ? `日最努力` : `期间没有学习记录`}{formatTime(maxHeight.value, 0)}
</View>
<ScrollView scrollX={!!maxHeight.value} enhanced showScrollbar={false} type='list'>

@ -0,0 +1,38 @@
.fixedBox {
position: relative;
width: 100vw;
height: 100vw;
background: linear-gradient(to bottom, rgba(255, 255, 255, 0), rgba(255, 255, 255, 1), rgba(255, 255, 255, 1));
//border: 1px solid #f40;
&-inner {
position: absolute;
width: 100vw;
bottom: 24rpx;
display: flex;
flex-direction: column;
align-items: center;
&-icon {
image {
width: 32rpx;
height: 32rpx;
}
}
&-box {
margin-top: 24rpx;
width: 680rpx;
left: 35rpx;
height: 76rpx;
background-color: #45D4A8;
color: #fff;
line-height: 76rpx;
text-align: center;
font-size: 32rpx;
font-weight: 500;
border-radius: 8rpx 8rpx 8rpx 8rpx;
}
}
}

@ -0,0 +1,28 @@
import styles from "./index.module.scss";
import { Text, View} from "@tarojs/components";
import Taro from "@tarojs/taro";
import {CSSProperties, FC} from "react";
import IconFont from "@/components/IconFont";
type Props = {
className?: string
style?: CSSProperties
}
const LoginView3: FC<Props> = ({className,style}) => {
return (
<View className={`${styles.fixedBox} ${className}`} style={style}>
<View className={styles['fixedBox-inner']}>
<View className={styles['fixedBox-inner-icon']}>
<IconFont color='#909795' name='chevron-double-down'/>
</View>
<View className={styles['fixedBox-inner-box']}
onClick={() => Taro.navigateTo({url: '/pages/login/login'})}>
<Text>1</Text>
</View>
</View>
</View>
)
}
export default LoginView3

@ -15,7 +15,7 @@ interface Props {
onSuccess?: VoidFunction
}
const LoginView: FC<Props> = (props) => {
export const LoginView: FC<Props> = (props) => {
const [isLoading, setLoading] = useState(false)
const {setUser, setToken, setCompany} = Profile.useContainer()
const sizeStyle: CSSProperties = {
@ -72,4 +72,31 @@ const LoginView: FC<Props> = (props) => {
)
}
export default LoginView
const LoginView2: FC<Props> = (props) => {
const sizeStyle: CSSProperties = {
height: `${props.height || 1000}rpx`,
paddingTop: `${props.paddingTop || 0}rpx`,
...props.style,
}
return (
<View className={styles.content} style={sizeStyle}>
{
!props.offImage && <>
<Image src={NoLogin}/>
{/*<View className={styles.title}>暂未登录</View>*/}
</>
}
<View onClick={() => {
Taro.navigateTo({
url:'/pages/login/login'
})
}} className={styles.button}></View>
</View>
)
}
export default LoginView2

@ -3,7 +3,6 @@
top: 0;
left: 0;
width: 100%;
padding-left: 20rpx;
z-index: 100;
overflow: hidden;
background: #fff;

@ -0,0 +1,39 @@
import Taro from "@tarojs/taro";
type Topic = string | symbol
type Subscriber = (...args: any[]) => void
export default function usePubsub() {
const events = new Map<Topic, Subscriber[]>()
const registers = new Map<Topic, Subscriber>()
const pub = (topic: Topic, data: any) => {
Taro.eventCenter.trigger(topic, data)
};
const sub = (topic: Topic, callback: Subscriber) => {
const cbs = events.get(topic) ?? []
events.set(topic, cbs.concat(callback))
if (!registers.has(topic)) {
console.log({topic})
const listener = (...args: any[]): void => {
events.get(topic)?.forEach((cb) => cb(...args))
}
registers.set(topic, listener)
Taro.eventCenter.on(topic, listener)
}
};
Taro.useUnload(() => {
registers.forEach((listener, topic) => {
Taro.eventCenter.off(topic, listener)
})
registers.clear()
events.clear()
})
return {
pub,
sub
}
}

@ -1,4 +1,4 @@
import {Image, Progress, View} from "@tarojs/components";
import {Image, Progress, ScrollView, View} from "@tarojs/components";
import Taro from "@tarojs/taro";
import styles from './curHistory.module.scss'
import {useState} from "react";
@ -118,6 +118,7 @@ const CurHistory = () => {
round
position='bottom'
onClickOverlay={() => setShow(false)}>
<ScrollView showScrollbar={false} scrollY={true} style={{maxHeight:'40vh',paddingBottom:'40px'}}>
<View className={styles.hourRecord}>
{hours?.length ?
hours?.map(d => <View key={d.id}>
@ -138,6 +139,7 @@ const CurHistory = () => {
</View>)
: <Empty name='暂无学习记录'/>}
</View>
</ScrollView>
</CustomPageContainer>
</View>
)

@ -61,9 +61,14 @@ const List = () => {
success(res) {
Taro.hideLoading()
if (res.statusCode === 200) {
const data: User = JSON.parse(res.data).data
setUser(data)
Taro.showToast({title: "图片上传成功"})
const resp:{msg:string,code:number,data:User} =JSON.parse(res.data)
if(resp.code === 0){
const data: User = resp.data
setUser(data)
Taro.showToast({title: "图片上传成功"})
}else{
Taro.showToast({title: resp.msg, icon: 'none',mask: true})
}
} else {
Taro.showToast({title: "图片上传失败", icon: 'error'})
}
@ -102,7 +107,7 @@ const List = () => {
return (
<>
<View className={styles.box}>
<PopPut title='头像' image={user?.avatar} no_border onClick={selectAvatar}/>
<PopPut title='头像' errorType={'avatar'} image={user?.avatar} no_border onClick={selectAvatar}/>
<PopPut title='手机号' content={user?.phone_number?.replace(user?.phone_number.slice(3, 7), "****")} chevron
no_border/>
<PopPut title='昵称' content={user?.name} isProp show={show} no_border>

@ -11,9 +11,10 @@ import curRecord from '@/static/img/curRecord.png'
import hourRecord from "@/static/img/hourRecord.png"
import CustomPageContainer from "@/components/custom-page-container/custom-page-container";
import {Profile} from "@/store";
import LoginView from "@/components/loginView";
import LoginView from "@/components/login-view";
import Collect from "@/components/collect/collect";
import omit from '@/static/img/omit.png'
// import omit from '@/static/img/omit.png'
import IconFont from "@/components/IconFont";
interface Props {
data: CourseDepData | null
@ -21,6 +22,7 @@ interface Props {
id: number //课程
playId: number | null
refresh: () => void
collectUpdate?: (v: boolean) => void
}
const tabList = [
@ -30,13 +32,12 @@ const tabList = [
]
const Catalogue: FC<Props> = ({data, setHors, id, playId, refresh}) => {
const Catalogue: FC<Props> = ({data, setHors, id, playId, collectUpdate}) => {
const [current, setCurrent] = useState(1)
const [show, setShow] = useState(false)
const [playing, setPlaying] = useState(false)
const {token} = Profile.useContainer()
videoEvents.onVideoState(({name}) => {
switch (name) {
case "pause":
@ -50,7 +51,9 @@ const Catalogue: FC<Props> = ({data, setHors, id, playId, refresh}) => {
function jumCurHistory() {
if (playId) {
Taro.navigateTo({url: `/pages/business/hourHistory/hourHistory?courseId=${id}&hourId=${playId}`})
Taro.navigateTo({
url: `/pages/business/hourHistory/hourHistory?courseId=${id}&hourId=${playId}`
})
}
}
@ -144,7 +147,6 @@ const Catalogue: FC<Props> = ({data, setHors, id, playId, refresh}) => {
}
}
return (
<>
<View className='catalogue'>
@ -154,22 +156,7 @@ const Catalogue: FC<Props> = ({data, setHors, id, playId, refresh}) => {
{current === 1 && <View>
<View className='my-2'></View>
{
!token && <LoginView
onSuccess={refresh}
offImage
style={{
position: 'absolute',
left: 0,
height: 'auto',
right: 0,
bottom: 0,
top: 0,
margin: 'auto',
paddingTop: '100rpx',
justifyContent: 'flex-end',
flexDirection: 'column-reverse',
background: 'rgba(255,255,255,.9)'
}}/>
!token && <LoginView className="absolute-impt left top" />
}
{data?.chapters.length
? Object.values(data?.chapters || {}).map((d, index) => <View key={d.id}>
@ -203,9 +190,12 @@ const Catalogue: FC<Props> = ({data, setHors, id, playId, refresh}) => {
owner_type={3}
select={data?.course.collect}
styles={{flexDirection: 'column', justifyContent: 'center'}}
stylesImage={{margin: '0 0 8rpx 0'}}/>
stylesImage={{margin: '0 0 8rpx 0'}}
onUpdate={collectUpdate}
/>
<View className='px-2 text-center' onClick={() => setShow(true)}>
<Image src={omit} style={{width: '32rpx', height: '32rpx'}} mode='widthFix'/>
{/*<Image src={omit} style={{width: '32rpx', height: '32rpx'}} mode='widthFix'/>*/}
<IconFont name='three-dots' />
<View></View>
</View>
</View>
@ -214,17 +204,18 @@ const Catalogue: FC<Props> = ({data, setHors, id, playId, refresh}) => {
<CustomPageContainer
show={show}
position='bottom'
onClickOverlay={() => setShow(false)}>
onClickOverlay={() => setShow(false)}
>
<View className='more'>
<View></View>
<View className='flex justify-around'>
<View onClick={() => Taro.navigateTo({url: '/pages/business/curHistory/curHistory?course_id=' + id})}>
<Image src={curRecord} className='image'/>
<View className='mt-2'></View>
</View>
<View onClick={jumCurHistory} className={playId ? undefined : 'filter-saturate'}>
<Image src={hourRecord} className='image'/>
<View className='mt-2'></View>
</View>
</View>
<MyButton onClick={() => setShow(false)} type='default' fillet></MyButton>

@ -1,13 +1,14 @@
import {FC} from "react";
import '../videoInfo.scss'
import {Image, Text, View} from "@tarojs/components";
import playOk from "@/static/img/play-ok.png";
import play from "@/static/img/play.png";
// import playOk from "@/static/img/play-ok.png";
// import play from "@/static/img/play.png";
import {formatMinute} from "@/utils/time";
import Taro from "@tarojs/taro";
import {curriculum} from "@/api";
import lock from '@/static/img/lock.png'
import {Profile} from "@/store";
import IconFont from "@/components/IconFont";
import '../videoInfo.scss'
interface Props {
playId: number | null
@ -71,10 +72,13 @@ const Hours: FC<Props> = ({data, click, learn_hour_records, playId}) => {
<>
{data?.map((d, index) =>
<View key={d.id}>
<View className={'hor' + ` ${complete(d.id) ? 'complete' : undefined}`}
key={index}
onClick={() => onClick(d.id, complete(d.id), d, data?.[index - 1]?.id)}>
<Image src={(complete(d.id) || playId === d.id) ? playOk : play} mode="scaleToFill" className='image'/>
<View
className={'hor' + ` ${complete(d.id) ? 'complete' : undefined}`}
key={index}
onClick={() => onClick(d.id, complete(d.id), d, data?.[index - 1]?.id)}
>
{/*<Image src={(complete(d.id) || playId === d.id) ? playOk : play} mode="scaleToFill" className='image'/>*/}
<IconFont name='play' shape='circle' size={18} color={(complete(d.id) || playId === d.id) ? undefined : '#e2e2e2'} fill />
<View className='title'>
<View className='text'>
<View style={{wordBreak: 'break-all'}}>{playId === d.id &&
@ -90,7 +94,6 @@ const Hours: FC<Props> = ({data, click, learn_hour_records, playId}) => {
</View>
</View>
</View>)}
</>
)
}

@ -7,7 +7,6 @@
height: 500rpx;
}
.header {
margin-bottom: 10px;
border-radius: 0 0 40rpx 40rpx;
@ -20,24 +19,28 @@
.catalogue {
background: #fff;
border-radius: 40rpx;
padding: 0 24rpx 24rpx;
padding: 0;
margin-top: 30rpx;
.short_desc {
padding: 0 24rpx 24rpx;
color: #606563;
line-height: 1.75;
word-break: break-word;
}
.hours {
padding: 0 24rpx 24rpx;
position: relative;
min-height: 440rpx;
min-height: 100vw;
}
}
.hor {
padding: 20rpx 0;
display: flex;
justify-content: flex-start;
align-items: baseline;
color: #323635;
.image {
@ -46,7 +49,6 @@
margin-top: 8rpx;
}
.title {
flex: 1;
width: 710rpx;
@ -67,7 +69,6 @@
margin-left: 10rpx;
margin-top: 10rpx;
}
}
}

@ -17,7 +17,6 @@ const VideoInfo: FC = () => {
const [preview, setPreview] = useState(false) // 预览
const [playing, setPlaying] = useState(false) // 学习中
const getData = useCallback(async (playing: boolean) => {
try {
const res = await curriculum.courseDep(id, depId)
@ -27,6 +26,12 @@ const VideoInfo: FC = () => {
}
}, [playing, playId])
function changeCollect(v: boolean){
let temp = data
temp!.course.collect = v
setData(temp)
}
const curEnd = (test?: boolean) => {
setPlaying(false)
if (!test) { // 没有考题才会请求
@ -103,11 +108,9 @@ const VideoInfo: FC = () => {
return (
<View className='content'>
<View className='content-video'>
{
playId
? <Course id={playId} courseId={id} curEnd={curEnd} preview={preview}/>
: <Img width={750} height={500} src={data?.course.thumb || ''} errorType='health'/>
}
{playId
? <Course id={playId} courseId={id} curEnd={curEnd} preview={preview}/>
: <Img width={750} height={500} src={data?.course.thumb || ''} errorType='health'/>}
</View>
<View className='header'>
@ -121,10 +124,9 @@ const VideoInfo: FC = () => {
<Text>{((data?.learn_hour_records.length || 0) / (data?.course.class_hour || 1) * 100).toFixed(0)}%</Text>
</View>
</View>
<Catalogue data={data} setHors={setHors} id={id} playId={playId} refresh={() => getData(false)}/>
<Catalogue data={data} setHors={setHors} id={id} playId={playId} collectUpdate={changeCollect} refresh={() => getData(false)}/>
</View>
)
}
export default VideoInfo

@ -1,3 +1,3 @@
export default definePageConfig({
navigationBarTitleText: '绑定手机号'
navigationBarTitleText: '员工验证',
})

@ -5,7 +5,6 @@
bottom: 0;
top: 0;
background: #fff;
padding: 0 20rpx;
}
.submit {
@ -13,7 +12,7 @@
justify-content: center;
align-items: center;
gap: 12px;
margin: 0 auto;
margin: 50px 24px;
a {
color: #fff;
@ -24,6 +23,7 @@
display: flex;
border-bottom: 1px solid #ededed;
padding: 30px 0;
margin: 0 24px;
}
.image {

@ -1,5 +1,5 @@
import {FC, useCallback, useEffect, useRef, useState} from "react";
import {Form, Image, Input, View} from "@tarojs/components";
import {Form, Image, Input, Text, View} from "@tarojs/components";
import {Profile} from "@/store";
import {userApi} from "@/api";
import Taro from "@tarojs/taro";
@ -8,6 +8,7 @@ import styles from './check.module.scss'
import code from '@/static/img/vCode.png'
import tel from '@/static/img/tel.png'
import MyButton from "@/components/button/MyButton";
import IconFont from "@/components/IconFont";
const Bing: FC = () => {
const form = useRef<HTMLFormElement | null>(null)
@ -76,6 +77,23 @@ const Bing: FC = () => {
return (
<View className={styles.page}>
<View className="p-3 mb-7 flex align-baseline font-30 lh1_5" style={{color:'#FF9E5F',backgroundColor:'#fff5ef'}}>
<IconFont className="mr-2" name={'exclamation'} shape={'triangle'} fill></IconFont>
<View className="flex-1">
<Text></Text>
<Text className="bold"></Text>
<Text></Text>
<Text onClick={()=>{
Taro.navigateTo({
url:`/pages/preview/webView/webView?url=${encodeURIComponent(`${process.env.TARO_APP_API}/QA/yuangongyanzheng.html`)}`
})
}} className="text-success mx-1" style={{textDecoration:'underline'}}></Text>
<Text>!</Text>
</View>
</View>
<Form onSubmit={Submit} ref={form}>
<View className={styles.formItem}>
@ -85,7 +103,7 @@ const Bing: FC = () => {
<Input
type='number'
name='phone_number'
placeholder={'请输入手机号'}
placeholder={'手机号'}
value={phone_number as unknown as string}
onInput={(e) => setPhone_number(Number(e.detail.value))}/>
</View>
@ -96,16 +114,16 @@ const Bing: FC = () => {
</View>
<View className='flex align-center flex-1'>
<Input type='number' name='code' className='flex-1' placeholder='请输入短信验证码'/>
<Input type='number' name='code' className='flex-1' placeholder='短信验证码'/>
<View onClick={getCode}>
{codeTime > 0 ? `${codeTime}` : '获取验证码'}
</View>
</View>
</View>
<MyButton
className={styles.submit}
style={{margin: '30px auto'}}
formType='submit'
disabled={loading}
>

@ -6,8 +6,8 @@ import styles from "../home.module.scss";
import VideoCover from "@/components/videoCover/videoCover";
import courseTag from '@/static/img/courseTag.png'
import ArticlesBox from "@/components/articlesBox/articlesBox";
import arrowRight from '@/static/img/arrow-right.png'
import PageScript from "@/components/pageScript/pageScript";
import IconFont from "@/components/IconFont";
const CurRecommended: FC = () => {
const [page, setPage] = useState(1)
@ -16,10 +16,11 @@ const CurRecommended: FC = () => {
const [articles, setArticles] = useState<Articles[]>([])
async function getData() {
const res = await HomeApi.course(page, 4)
const res = await HomeApi.home()
setArticles(res.articles)
setTotal(res.course.total)
const newData = res.course.data?.reduce((pre, cut) => {
setTotal(res.courses.total)
const newData = res.courses.data?.reduce((pre, cut) => {
const index = pre.findIndex(d => d.id === cut.id)
if (index === -1) {
pre.push(cut)
@ -47,14 +48,14 @@ const CurRecommended: FC = () => {
if (articles.length > 0) {
examines = (
<View className='bg-white rounded-20 clip px-3'>
<View className='mt-3 bold text-dark flex justify-between'>
<View className='mt-3 bold text-dark flex justify-between align-center mb-2'>
<Text className='font-32'></Text>
<View className='font-24 text-muted flex align-center' onClick={jumpArticles}>
<View className='font-24 text-muted flex align-center pl-2 py-2' onClick={jumpArticles}>
<Text></Text>
<Image src={arrowRight} mode='widthFix' style={{width: '20rpx', height: '20rpx'}}/>
<IconFont name={'chevron-right'} size={14} />
</View>
</View>
{articles.map(d => <ArticlesBox data={d}/>)}
{articles.map(d => <ArticlesBox key={d.id} data={d}/>)}
</View>
)
}

@ -22,7 +22,7 @@ const Feature: FC = () => {
return (
<View className='flex justify-around' style={{marginBottom: '20px'}}>
{
list.map(d => <View className='text-center' onClick={() => jump(d.url)}>
list.map(d => <View className='text-center' key={d.url} onClick={() => jump(d.url)}>
<Image src={d.image} style={{width: '48px', height: '48px', verticalAlign: 'middle'}}/>
<View className={styles.featureList}>{d.text}</View>
</View>)

@ -73,7 +73,7 @@ const FeatureRecommended: FC<Props> = (props) => {
return props.brand.map<DataContent>(d => ({
id: d.id,
title: d.name,
imageUrl: d.brand_album,
imageUrl: d.brand_album?.split(',')[0] ?? d.logo,
description: d.graphic_introduction,
path: `?id=${d.id}`,
}))
@ -117,7 +117,7 @@ const FeatureRecommended: FC<Props> = (props) => {
try {
return props.illness.map<DataContent>(d => ({
id: d.id,
imageUrl: '',
imageUrl: d.album?.split(',')[0] ?? '',
description: d.description || '暂无简介',
title: d.name,
path: `?id=${d.id}`
@ -143,36 +143,56 @@ const FeatureRecommended: FC<Props> = (props) => {
Taro.navigateTo({url})
}
return (
<View className={styles.feature}>
<Swiper nextMargin='30px' style={{height: '390rpx'}} circular autoplay>
const keys: string[] = []
const items = data.filter(d => d.data.length === 3).map(d => {
keys.push(d.url)
return (
<>
<Image
mode='heightFix'
className={styles.featureTitle}
onClick={() => jump(d.url, d)} src={d.titleUrl}/>
{
data.filter(d => d.data.length === 3).map(d => <SwiperItem key={d.url}>
<Image
mode='heightFix'
className={styles.featureTitle}
onClick={() => jump(d.url, d)} src={d.titleUrl}/>
{
d.data.length > 0 && d.data.map((c, index) => <View
className='flex'
style={{marginBottom: '16rpx'}}
key={c.id}
onClick={() => jump(d.detailsUrl + c.path, d)}>
<View style={{position: 'relative'}}>
<View className={styles.featureImage}>
<Img src={c.imageUrl} height={100} width={140} errorType={d.errorType}/>
</View>
<Image src={[first, second, third][index]} className={styles.ranking} mode='aspectFill'/>
</View>
<View className={styles.featureText}>
<View className={styles.featureTextTitle}>{c.title}</View>
<View className={styles.featureTextDescription}>{c.description}</View>
</View>
</View>)
}
</SwiperItem>)
d.data.length > 0 && d.data.map((c, index) => <View
className='flex'
style={{marginBottom: '16rpx'}}
key={c.id}
onClick={() => jump(d.detailsUrl + c.path, d)}>
<View style={{position: 'relative'}}>
<View className={styles.featureImage}>
<Img src={c.imageUrl} height={100} width={140} errorType={d.errorType}/>
</View>
<Image src={[first, second, third][index]} className={styles.ranking} mode='aspectFill'/>
</View>
<View className={styles.featureText}>
<View className={styles.featureTextTitle}>{c.title}</View>
<View className={styles.featureTextDescription}>{c.description}</View>
</View>
</View>)
}
</Swiper>
</>
)
})
// 没有top3
if (keys.length === 0) {
return null
}
// 至少2个top3
if (keys.length > 1) {
return (
<View className={styles.feature}>
<Swiper disableTouchmove={'true'} nextMargin='30px' style={{height: '390rpx'}} >
{items.map((d, i) => (<SwiperItem key={keys[i]}>{d}</SwiperItem>))}
</Swiper>
</View>
)
}
// 只有一个top3
return (
<View className={styles.feature}>
{items[0]}
</View>
)
}

@ -12,7 +12,6 @@ import {HomeApi, HomeData} from "@/api";
import logo from '@/static/img/logo.svg'
import Spin from "@/components/spinner";
import NavigationBar from "@/components/navigationBar/navigationBar";
import {Search} from "@/pages/home/components/search";
const Home: FC = () => {
const globalData = Taro.getApp().globalData
@ -51,8 +50,8 @@ const Home: FC = () => {
cancelBack
leftNode={
<>
<Image src={logo} style={{height: "70%"}} mode='heightFix'/>
<Text className='font-36 font-weight ml-2'></Text>
<Image src={logo} style={{height: "55%"}} mode='heightFix'/>
<Text className='font-36 font-weight ml-1'></Text>
</>
}
>
@ -61,7 +60,7 @@ const Home: FC = () => {
</NavigationBar>
<Spin enable={enable} overlay/>
<View className={styles.content} style={{paddingBottom: token ? 0 : '100rpx'}}>
<Search/>
{/*<Search/>*/}
<Adware data={data?.adverts || []} only_flag='routine_home_top_banner' width={710}/>
<Feature/>
<FeatureRecommended

@ -41,11 +41,11 @@ export const VideoList: FC<Props> = ({categoryKey, setCategoryKey}) => {
async function getData() {
try {
const res = await publicApi.course({page: page, pageSize: 10})
const res = await publicApi.newCourse({page: page, page_size: 10})
const old: Courses = JSON.parse(JSON.stringify(data))
setData({
is_required: screen(old.is_required, res.course.is_required || []),
is_not_required: screen(old.is_not_required, res.course.is_not_required || []),
is_required: screen(old.is_required, res.company_courses || []),
is_not_required: screen(old.is_not_required, res.platform_courses || []),
})
} catch (e) {
}
@ -114,7 +114,7 @@ export const VideoList: FC<Props> = ({categoryKey, setCategoryKey}) => {
!token && key === 'is_required'
? <LoginView onSuccess={fetchData}/> : value?.length ?
<>
<View className='py-2 flex justify-between flex-wrap'>
<View className='py-2 flex justify-between flex-wrap px-2'>
{
value?.map(c =>
<VideoCover

@ -4,23 +4,23 @@
left: 0;
right: 0;
bottom: 0;
padding: 0 20px;
min-height: 100vh;
box-sizing: border-box;
width: 750rpx;
overflow: hidden;
&:after {
position: absolute;
top: 0;
left: -10%;
width: 120%;
height: 400rpx;
content: '';
display: block;
background: linear-gradient(to bottom, #92ecc5, #f1f8f6) no-repeat;
z-index: -1;
}
//&:after {
// position: absolute;
// top: 0;
// left: -10%;
// width: 120%;
// height: 400rpx;
// content: '';
// display: block;
// background: linear-gradient(to bottom, #92ecc5, #f1f8f6) no-repeat;
// z-index: -1;
//}
}
.videoListBox {

@ -1,5 +1,5 @@
import {FC, useEffect, useState} from "react";
import {View} from "@tarojs/components";
import {View, Text} from "@tarojs/components";
import styles from './index.module.scss'
import {VideoList} from "@/pages/index/components/videoList";
import Tabs, {OnChangOpt, TabList} from "@/components/tabs/tabs";
@ -27,7 +27,6 @@ const Index: FC = () => {
<NavigationBar
cancelBack
leftNode={<Tabs tabList={category} onChange={tabChange} current={categoryKey} scrollable={false} hiddenSliding/>}
backgroundColor={'transparent'}
/>
<VideoList
categoryKey={categoryKey}
@ -38,7 +37,7 @@ const Index: FC = () => {
}
const AuditMode: FC = () => {
const [auditMode, setAuditMode] = useState(false)
const [auditMode, setAuditMode] = useState(true)
const [articles, setArticles] = useState<any[]>([])
const [enable, setEnable] = useState(true)
useEffect(() => {
@ -54,10 +53,10 @@ const AuditMode: FC = () => {
{
auditMode ?
<>
<NavigationBar text='文章列表' cancelBack/>
<NavigationBar cancelBack leftNode={<Text className="bold font-36" style={{color:'#323635'}} ></Text>} />
<View className='bg-white rounded-20 clip m-3 px-3'>
{
articles.map(d => <ArticlesBox data={d}/>)
articles.map(d => <ArticlesBox key={d.id} data={d}/>)
}
</View>
<PageScript/>

@ -25,7 +25,7 @@
.brand {
width: 140px;
margin: 250px auto 145px;
margin: 70px auto 100px;
image {
overflow: hidden;
@ -44,7 +44,7 @@
.errorTips {
position: fixed;
top: 10%;
top: 0;
left: 24px;
right: 24px;
background: red;
@ -52,7 +52,7 @@
padding: 24px;
border-radius: 20px;
display: flex;
align-items: center;
align-items: baseline;
}
.bing {

@ -1,19 +1,20 @@
import {FC, useEffect, useState} from "react";
import {Profile} from "@/store";
import {Image, Text, View} from "@tarojs/components";
import {Image, Radio, Text, View} from "@tarojs/components";
import Taro from "@tarojs/taro";
import styles from './login.module.scss'
import Icon from "@/components/icon";
import {userApi} from "@/api";
import {loginApi, LoginParams} from "@/api/login";
import MyButton from "@/components/button/MyButton";
import logo from '@/static/img/logo.svg'
import IconFont from "@/components/IconFont";
const Login: FC = () => {
const [isLoading, setLoading] = useState(false)
const [error, setError] = useState<string | null>(null)
const {setUser, setToken, setCompany, empty} = Profile.useContainer()
const [h5params, setH5Params] = useState<LoginParams | null>(null)
const [check, setCheck] = useState(false)
useEffect(() => {
empty(false)
@ -30,9 +31,21 @@ const Login: FC = () => {
}
}, [])
function setError(msg: any){
if(msg) {
Taro.showToast({
title:msg,
icon:'none'
})
}
}
function login() {
if (isLoading) return;
if (!check) {
setError('请阅读并同意《用户协议》及《隐私政策》!')
return;
}
if (h5params == null && process.env.TARO_ENV === 'h5') {
setError('页面参数错误,请刷新页面!')
return;
@ -62,7 +75,7 @@ const Login: FC = () => {
})
} else {
Taro.setStorageSync('openid', catch_key)
Taro.reLaunch({url: '/pages/check/check'})
Taro.navigateTo({url: '/pages/check/check'})
}
} catch (e) {
}
@ -85,20 +98,60 @@ const Login: FC = () => {
return (
<View className={styles.container}>
<View className={styles.brand}>
<Image mode={'scaleToFill'} src="https://playedu.yaojiankang.top/favicon.ico"/>
<View className='mt-3'></View>
<Image mode={'scaleToFill'} src={logo}/>
<View></View>
</View>
<View className={styles.loginTips}>
<Text>使</Text>
<View
className="p-3 mb-7 flex align-baseline rounded-10 font-30 lh1_5"
style={{color:'#FF9E5F',backgroundColor:'rgba(255,158,95,0.05)',border:'1px solid rgba(0,0,0,0.03)'}}
>
<IconFont className="mr-2" name={'exclamation'} shape={'triangle'} fill></IconFont>
<View className="flex-1">
<Text></Text>
<Text></Text>
<Text></Text>
<Text onClick={()=>{
Taro.navigateTo({
url:`/pages/preview/webView/webView?url=${process.env.TARO_APP_API}/QA/zhanluehezuo.html`
})
}} className="text-success" style={{textDecoration:'underline'}}></Text>
</View>
</View>
<MyButton onClick={login} loading={isLoading}></MyButton>
{error ? <View className={styles.errorTips}>
<View style={{flex: 1}}>{error}</View>
<Icon name={'close'} onClick={() => setError(null)}/>
</View> : null}
{/*<View className={styles.loginTips}>*/}
{/* <Text>请完成微信授权以继续使用!</Text>*/}
{/*</View>*/}
<MyButton onClick={login} loading={isLoading}></MyButton>
{/*{error ? <View className={styles.errorTips}>*/}
{/* <View style={{flex: 1}} className="flex align-baseline">*/}
{/* <IconFont className="mr-2" name={'exclamation'} shape={'triangle'} fill></IconFont>*/}
{/* <View className='flex-1 ml-1'>{error}</View>*/}
{/*</View>*/}
{/* <View className="p-2" onClick={() => setError(null)}>*/}
{/* <Icon name={'close'} />*/}
{/* </View>*/}
{/*</View> : null}*/}
<View className="mt-2 text-center">
<Radio style={{transform:'scale(0.8)'}} color={'#45D4A8'} checked={check} onClick={()=> setCheck(!check) }></Radio>
<Text className="ml-1"></Text>
<Text className="text-success" onClick={() => {
Taro.navigateTo({
url:`/pages/preview/webView/webView?url=${process.env.TARO_APP_API}/yonghuxieyi.html`
})
}}></Text>
<Text></Text>
<Text className="text-success" onClick={() => {
Taro.navigateTo({
url:`/pages/preview/webView/webView?url=${process.env.TARO_APP_API}/yinsizhengce.html`
})
}}></Text>
</View>
{/*{process.env.TARO_APP_LGOIN === 'true' && <MyButton onClick={TESTLOGIN}>线下登录</MyButton>}*/}
<View className="fixed left right bottom text-center text-muted mb-7 font-26" style={{opacity:'0.5'}}>ICP备20015955号-4X</View>
</View>
)
}

@ -10,7 +10,8 @@
}
.add {
position: fixed;
//position: fixed;
width: 710rpx;
margin-top: 10px;
margin-top: 30px;
border: none !important;
}

@ -1,5 +1,5 @@
import {FC, useCallback, useEffect, useState} from "react";
import {Image, Input, Radio, View} from "@tarojs/components";
import {Image, Input, Radio, Text, View} from "@tarojs/components";
import styles from "../courseAdmin.module.scss";
import Icon from "@/components/icon";
import {CourseAllParam, curriculum} from "@/api";
@ -94,18 +94,25 @@ export const Search: FC<Props> = ({param, setParam, total, setBatch}) => {
<View className='mt-3 flex justify-between font-24 text-dark align-center'>
<View className="flex">
<View onClick={() => setShow(true)} className={styles.select}>
{
param.dep_id > 0 ?
<Text style={{background: 'rgba(68,215,170,.08)', color: '#44d7aa'}}>
{deps.find(d => d.id === param.dep_id)?.name}
</Text>
:
<Text></Text>
}
<Image src={downArrow} mode='widthFix' className={styles.icon}/>
</View>
{
param.dep_id > 0
&& <View className={'ml-5' + ` ${styles.select}`}
style={{background: 'rgba(68,215,170,.08)', color: '#44d7aa'}}>
{deps.find(d => d.id === param.dep_id)?.name}
<Image src={downArrowKey} mode='widthFix' className={styles.icon}/>
</View>
}
{/*{*/}
{/* param.dep_id > 0*/}
{/* && <View className={'ml-5' + ` ${styles.select}`}*/}
{/* style={{background: 'rgba(68,215,170,.08)', color: '#44d7aa'}}>*/}
{/* {deps.find(d => d.id === param.dep_id)?.name}*/}
{/* <Image src={downArrowKey} mode='widthFix' className={styles.icon}/>*/}
{/* </View>*/}
{/*}*/}
<View>
</View>
</View>

@ -8,6 +8,8 @@ page {
position: sticky;
top: 0;
border-bottom: 1px solid #F5F8F7;
z-index: 2;
background-color: #fff;
}
.searchInput {
@ -58,12 +60,15 @@ page {
display: flex;
justify-content: space-between;
align-items: center;
z-index: 1;
}
.curTitle {
padding: 30rpx;
display: flex;
border-bottom: 1px solid #F5F8F7;
flex:1;
box-sizing: border-box;
}
.curImage {

@ -190,9 +190,9 @@ const CourseAdmin: FC = () => {
<Img src={d.thumb} width={280} height={164} errorType='course'/>
<View className={styles.classHour}>{d.class_hour}</View>
</View>
<View>
<View className="flex-1">
<View>{d.title}</View>
<View className='mt-1 text-dark font-26'>{d.short_desc}</View>
<View className='mt-1 text-dark font-26 word-break text-ellipsis-2'>{d.short_desc}</View>
</View>
</View>
<Image src={omit} mode='widthFix' style={{width: '30rpx', height: '30rpx', padding: '30rpx'}}

@ -0,0 +1,4 @@
export default definePageConfig({
navigationBarTitleText: '现场会',
onReachBottomDistance: 30
})

@ -0,0 +1,39 @@
.page {
box-sizing: border-box;
min-height: 100vh;
}
.box {
width: 100%;
box-sizing: border-box;
}
.empty{
position: absolute;
left: 0;
right: 0;
top: 0;
bottom: 0;
margin: auto;
width: 400rpx;
height: 40rpx;
text-align: center;
font-weight: bold;
}
.choice {
position: relative;
}
.button {
margin: 30rpx auto;
box-shadow: 0 0 10rpx rgba(#00d6ac, .5);
}
.buttonDel {
color: #fff;
margin: 30rpx auto;
box-shadow: 0 0 10rpx rgba(#c94f4f, .5);
}

@ -0,0 +1,198 @@
import {FC, useCallback, useEffect, useState} from "react";
import {Form, Input, Picker, View} from "@tarojs/components";
import Taro from "@tarojs/taro";
import {curriculum, Meeting, meetingAPi} from "@/api";
import {formatDate} from "@/utils/time";
import PopPut from "@/components/popPut/popPut";
import MyButton from "@/components/button/MyButton";
import styles from './form.module.scss'
import {Profile} from "@/store";
import DateTimePicker from "@/components/dateTimePicker/dateTimePicker";
const MeetingForm: FC = () => {
const params = Taro.getCurrentInstance().router?.params as { id: string | undefined }
const [manages, setManages] = useState<Manage[]>([])
const [start, setStart] = useState<string>(formatDate(new Date(new Date().getTime() + 24 * 60 * 60 * 1000), "YY-MM-dd 08:00"))
const [end, setEnd] = useState<string>(formatDate(new Date(new Date().getTime() + 24 * 60 * 60 * 1000), "YY-MM-dd 18:00"))
const [depid, setDepid] = useState<number | null>(null)
const [imgUrl, setImgUrl] = useState('')
const [name, setName] = useState('')
const [loading, setLoading] = useState(false)
const [status, setStatus] = useState(0) // 状态
const [id, setId] = useState<number | undefined>(params.id ? Number(params.id) : undefined)
const {company} = Profile.useContainer()
function setData(res: Meeting | null) {
/**
* params.id
* onShow的时候 id === res.id
*/
if (params.id || id !== res?.id) {
setImgUrl('')
setDepid(res?.dep_id || null)
setName(res?.name || '')
setStatus(res?.status || 0)
setId(res?.id || 0)
if (res) {
setEnd(formatDate(new Date(res.estimate_end_time), "YY-MM-dd hh:mm"))
setStart(formatDate(new Date(res.estimate_start_time), "YY-MM-dd hh:mm"))
}
}
setLoading(false)
}
useEffect(() => {
curriculum.department().then(res => {
setManages(res.data)
})
}, [])
Taro.useDidShow(() => {
if (params.id != undefined) {
meetingAPi.setMeeting(params.id).then(setData)
}
})
const depChange = useCallback((e) => {
setDepid(manages[Number(e.detail.value)]?.id)
}, [manages])
const change_start = useCallback((time: string) => {
const mil = new Date(time).getTime()
const endMil = new Date(end).getTime()
if (mil > endMil) {
Taro.showToast({title: '大于结束时间', icon: 'error'})
} else {
setStart(time)
}
}, [end])
const change_end = useCallback((time: string) => {
const mil = new Date(time).getTime()
const startMil = new Date(start).getTime()
if (mil < startMil) {
Taro.showToast({title: '小于开始时间', icon: 'error'})
} else {
setEnd(time)
}
}, [start])
const submit = useCallback(async (e) => {
if (loading && status === 2) return;
const values: Meeting = e.detail.value
if (!values.name) {
Taro.showToast({title: '请填写会议名称', icon: 'error'})
return
}
setLoading(true)
try {
let req = meetingAPi.setMeetings
if(!params.id){
req = meetingAPi.addMeetings
}
await req({
...values,
estimate_end_time: new Date(end).getTime(),
estimate_start_time: new Date(start).getTime(),
dep_id: depid,
company_id: company?.id!,
id: parseInt(params.id!),
})
setLoading(false)
Taro.eventCenter.trigger('updateMeetingList')
Taro.showToast({title: '操作成功', icon: 'success',mask:true})
Taro.navigateBack()
} catch (e) {
setLoading(false)
}
}, [imgUrl, depid, end, start])
return (
<View className={styles.page}>
<View className={styles.box}>
<View className={styles.choice}>
<Form onSubmit={submit}>
<PopPut
title='会议名称'
chevron
content={<Input
className='input'
name='name'
value={name}
disabled={status > 0}
maxlength={11}
placeholder='请输入会议标题'
onInput={(e) => setName(e.detail.value)}
/>}
/>
<DateTimePicker
name='estimate_start_time'
defaultValue={start}
disabled={status === 1}
onChange={(time) => change_start(time)}
>
<PopPut title='开始时间' content={start}/>
</DateTimePicker>
<DateTimePicker
name='estimate_end_time'
defaultValue={end}
disabled={status === 1}
onChange={(time) => change_end(time)}
>
<PopPut title='结束时间' content={end}/>
</DateTimePicker>
<Picker
mode='selector'
range={manages}
onChange={depChange}
disabled={status === 1}
rangeKey='name'
name='dep_id'>
<PopPut title='选择部门' content={manages?.find(x => x.id == depid)?.name}/>
</Picker>
<MyButton
formType='submit'
fillet
width={200}
className={styles.button}
loading={loading}>
{params.id ? '保存':'新建'}
</MyButton>
</Form>
</View>
</View>
</View>
)
}
export default MeetingForm

@ -0,0 +1,4 @@
export default definePageConfig({
navigationBarTitleText: '现场会',
onReachBottomDistance: 30
})

@ -0,0 +1,11 @@
.meeting {
margin-bottom: 20rpx;
border-radius: 16rpx;
padding: 30rpx 24rpx;
box-sizing: border-box;
background-color: #fff;
position: relative;
height: 138rpx;
}

@ -1,43 +1,23 @@
page{
width: 100%;
}
.meeting {
display: flex;
justify-content: space-between;
margin-bottom: 20rpx;
padding: 30rpx 24rpx;
background: #FFFFFF;
width: 710rpx;
box-sizing: border-box;
position: relative;
}
.title {
position: relative;
flex: 1;
width: 70%;
background: #fff;
padding: 20rpx;
border-radius: 10rpx;
overflow: hidden;
box-sizing: border-box;
font-size: 32rpx;
font-weight: bold;
color: #606563;
margin-bottom: 20rpx;
}
.overdue {
position: absolute;
top: 0;
bottom: 0;
right: 0;
left: 0;
text-align: center;
color: #fff;
display: flex;
justify-content: center;
align-items: center;
background: rgba(#000, .8);
.time{
font-size: 24rpx;
font-weight: 500;
color: #606563;
}
.del {
border-radius: 10rpx;
background: #FF3A2F;
display: flex;
align-items: center;
color: #fff;
width: 100rpx;
justify-content: center;
margin-left: 20rpx;
}

@ -1,19 +1,24 @@
import {FC, useCallback, useEffect, useState} from "react";
import {View} from "@tarojs/components";
import {Image, Text, View} from "@tarojs/components";
import {Meeting, meetingAPi} from "@/api";
import styles from './meetings.module.scss'
import Taro, {useReachBottom} from "@tarojs/taro";
import Empty from "@/components/empty/empty";
import {formatDate} from "@/utils/time";
import {AtList, AtSwipeAction} from "taro-ui";
import meetingEnd from "@/static/img/meetingEnd.png"
import Spin from "@/components/spinner";
const MeetingsConfig: FC = () => {
const [page, setPage] = useState(1)
const [meeting, setMeeting] = useState<Meeting[]>([])
const [total, setTotal] = useState(0)
const [curIndex, setCurIndex] = useState<Number>()
const [enable, setEnable] = useState(true)
const getData = useCallback(async () => {
try {
const res = await meetingAPi.setList(1, 10)
const res = await meetingAPi.setList(page, 10)
setTotal(res.total)
setMeeting([
...(meeting || []),
@ -21,12 +26,14 @@ const MeetingsConfig: FC = () => {
])
} catch (e) {
}
setTimeout(()=>{setEnable(false)},500)
}, [page])
function del(id: number, index: number) {
try {
Taro.showModal({
title: '确定删除',
title: `确定删除 ${meeting[index].name}`,
async success({confirm}) {
if (confirm) {
await meetingAPi.del(id)
@ -34,6 +41,9 @@ const MeetingsConfig: FC = () => {
const oldMeeting: Meeting[] = JSON.parse(JSON.stringify(meeting))
oldMeeting.splice(index, 1)
setMeeting(oldMeeting)
setCurIndex(undefined)
}else{
setCurIndex(undefined)
}
}
})
@ -41,13 +51,6 @@ const MeetingsConfig: FC = () => {
}
}
function jumpInfo(item: Meeting) {
if (Date.now() > item.estimate_end_time || item.status > 0) {
return
}
Taro.navigateTo({url: `/pages/manage/spotMeeting/spotMeeting?id=${item.id}`})
}
useReachBottom(useCallback(() => {
if (meeting?.length < total) {
setPage(page + 1)
@ -58,26 +61,48 @@ const MeetingsConfig: FC = () => {
getData()
}, [page])
async function handleClick(id : number,index: number){
await del(id,index)
}
function onOpened(index: number){
setCurIndex(index)
}
return (
<View className='p-2'>
<>
<Spin enable={enable} overlay/>
<View className='p-2' style={{boxSizing:'border-box',width:'750rpx'}}>
{
meeting.length ?
meeting.map((d, index) => <View className={styles.meeting} key={d.id}>
<View className={styles.title} onClick={() => jumpInfo(d)}>
<View className='font-weight mb-1'>{d.name}</View>
<View>{formatDate(new Date(d.estimate_start_time), "MM-dd")} {formatDate(new Date(d.estimate_start_time), "MM-dd")}</View>
{
(Date.now() > d.estimate_end_time || d.status > 1) && <View className={styles.overdue}>
{d.status > 1 ? '已结束' : "已过期"}
<AtList>
{meeting.map((d,index) => (
<AtSwipeAction
style={{width:'710rpx'}}
key={index}
onClick={()=>{handleClick(d.id,index)}}
isOpened={curIndex === index}
onOpened={() => {onOpened(index)}}
options={[{text: '删除',style: {backgroundColor: '#FF4949'},}]}
>
<View className={styles.meeting} key={d.id}>
<View className="absolute top bottom right z1 flex justify-end align-center mr-2">
<Image style={{width:'88rpx',height:'88rpx'}} src={meetingEnd}></Image>
</View>
<View className="relative z2 flex flex-column">
<Text className={styles.title}>{d.name}</Text>
<View className={styles.time}>{formatDate(new Date(d.estimate_start_time), "MM-dd")} {formatDate(new Date(d.estimate_start_time), "MM-dd")}</View>
</View>
</View>
}
</View>
<View className={styles.del} onClick={() => del(d.id, index)}></View>
</View>)
</AtSwipeAction>
))}
</AtList>
: <Empty name='无历史记录'/>
}
</View>
</>
)
}

@ -83,11 +83,25 @@
.button {
margin: 30rpx auto;
color: #fff;
box-shadow: 0 0 10rpx rgba(#00d6ac, .5);
}
.buttonDel {
background-color: rgba(255,255,255,0.1) !important;
margin: 30rpx auto;
}
.buttonEnd{
color: #fff;
margin: 30rpx auto;
box-shadow: 0 0 10rpx rgba(#c94f4f, .5);
box-shadow: 0 0 10rpx rgba(#00d6ac, .5);
}
.tips{
background-color: rgba(#00d6ac, 0.1);
margin: 0 -20rpx;
line-height: 2.5;
font-size: 26rpx;
display: flex;
justify-content: center;
align-items: center;
}

@ -1,32 +1,25 @@
import {FC, useCallback, useEffect, useState} from "react";
import {Form, Image, Input, Picker, View} from "@tarojs/components";
import {FC, useCallback, useState} from "react";
import {Image, View, Text} from "@tarojs/components";
import Taro, {getSetting, authorize} from "@tarojs/taro";
import {curriculum, Meeting, meetingAPi} from "@/api";
import { Meeting, meetingAPi} from "@/api";
import {formatDate} from "@/utils/time";
import PopPut from "@/components/popPut/popPut";
import MyButton from "@/components/button/MyButton";
import styles from './spotMeeting.module.scss'
import code from '@/static/img/code.png'
import Icon from "@/components/icon";
import failure from "@/static/img/failure.png"
import {Profile} from "@/store";
import DateTimePicker from "@/components/dateTimePicker/dateTimePicker";
import IconFont from "@/components/IconFont";
import CodeImg from "@/static/img/code.png"
import Spin from "@/components/spinner";
const SpotMeeting: FC = () => {
const path = encodeURIComponent("/pages/meeting/meeting")
const params = Taro.getCurrentInstance().router?.params as { id: string | undefined }
const [manages, setManages] = useState<Manage[]>([])
const [start, setStart] = useState<string>(formatDate(new Date(new Date().getTime() + 24 * 60 * 60 * 1000), "YY-MM-dd 08:00"))
const [end, setEnd] = useState<string>(formatDate(new Date(new Date().getTime() + 24 * 60 * 60 * 1000), "YY-MM-dd 18:00"))
const [depid, setDepid] = useState<number | null>(null)
const [imgUrl, setImgUrl] = useState('')
const [start, setStart] = useState<string>(formatDate(new Date(new Date().getTime() + 24 * 60 * 60 * 1000), "MM-dd 08:00"))
const [end, setEnd] = useState<string>(formatDate(new Date(new Date().getTime() + 24 * 60 * 60 * 1000), "MM-dd 18:00"))
const [imgUrl, setImgUrl] = useState(CodeImg)
const [name, setName] = useState('')
const [description, setDescription] = useState('')
const [loading, setLoading] = useState(false)
const [status, setStatus] = useState(0) // 状态
const [id, setId] = useState<number | undefined>(params.id ? Number(params.id) : undefined)
const pathUrl = process.env.TARO_ENV === 'h5' ? '/official/qrcode' : '/wechat/link'
const {company} = Profile.useContainer()
const [downStatus, setDownStatus] = useState<1|2|3>(1)
function setData(res: Meeting | null) {
/**
@ -35,63 +28,35 @@ const SpotMeeting: FC = () => {
*/
if (params.id || id !== res?.id) {
setImgUrl('')
setDepid(res?.dep_id || null)
setName(res?.name || '')
setDescription(res?.description || '')
setStatus(res?.status || 0)
setId(res?.id || 0)
if (res) {
downUrl(res.id, false)
setEnd(formatDate(new Date(res.estimate_end_time), "YY-MM-dd 18:00"))
setStart(formatDate(new Date(res.estimate_start_time), "YY-MM-dd 08:00"))
downUrl(res.id)
setEnd(formatDate(new Date(res.estimate_end_time), "MM-dd hh:mm"))
setStart(formatDate(new Date(res.estimate_start_time), "MM-dd hh:mm"))
}
} else {
setLoading(false)
}
}
useEffect(() => {
curriculum.department().then(res => {
setManages(res.data)
})
}, [])
Taro.useDidShow(() => {
setLoading(true)
Taro.useLoad(() => {
if (params.id != undefined) {
meetingAPi.setMeeting(params.id).then(setData)
} else {
meetingAPi.exists().then(setData)
}
})
const depChange = useCallback((e) => {
setDepid(manages[Number(e.detail.value)]?.id)
}, [manages])
const change_start = useCallback((time: string) => {
const mil = new Date(time).getTime()
const endMil = new Date(end).getTime()
if (mil > endMil) {
Taro.showToast({title: '大于结束时间', icon: 'error'})
} else {
setStart(time)
}
}, [end])
Taro.eventCenter.on('UPDATE', () => {
meetingAPi.setMeeting(params.id!).then(setData)
})
})
const change_end = useCallback((time: string) => {
const mil = new Date(time).getTime()
const startMil = new Date(start).getTime()
if (mil < startMil) {
Taro.showToast({title: '小于开始时间', icon: 'error'})
} else {
setEnd(time)
}
}, [start])
Taro.useUnload(() => {
Taro.eventCenter.off('UPDATE')
})
/** 下载二维码 */
const handleWriteFile = useCallback(() => {
console.log({imgUrl},'imgUrl')
if (imgUrl == null) {
Taro.showToast({title: '下载失败', icon: 'error'})
return
@ -101,7 +66,8 @@ const SpotMeeting: FC = () => {
success() {
Taro.showModal({title: '下载成功'})
},
fail() {
fail(err) {
console.log(err,'err')
Taro.showToast({title: '下载失败', icon: 'error'})
}
})
@ -109,6 +75,10 @@ const SpotMeeting: FC = () => {
/** 查看保存权限 */
const handleSaveCode = useCallback(() => {
if( status === 2) {
Taro.showToast({title: '会议已结束,无法下载', icon: 'none'})
return
}
if (process.env.TARO_ENV !== 'h5') {
getSetting({
success: function ({authSetting}) {
@ -135,70 +105,46 @@ const SpotMeeting: FC = () => {
}, [imgUrl]);
/** 获取二维码地址 */
const downUrl = (id: number, down = true) => {
Taro.showLoading({title: '加载二维码'})
const downUrl = (id: number,) => {
if(status === 2){
setDownStatus(2)
return
}
// Taro.showLoading({title: '加载二维码'})
const url = process.env.TARO_APP_API + pathUrl + '?meeting_id=' + id + '&path=' + path
let fileName = new Date().valueOf();
let filePath = Taro.env.USER_DATA_PATH + '/' + fileName + '.jpg'
console.log(filePath,'filePath')
if (process.env.TARO_ENV !== 'h5') {
Taro.downloadFile({
url,
filePath:filePath,
success(res) {
setImgUrl(res.tempFilePath)
if (down) {
handleSaveCode()
}
console.log(res,'res')
setImgUrl(res.filePath)
setDownStatus(3)
},
fail() {
Taro.hideLoading()
Taro.showModal({title: '二维码生成失败'})
setLoading(false)
setDownStatus(2)
// Taro.hideLoading()
// Taro.showModal({title: '二维码生成失败'})
}
})
} else {
setTimeout(() => {
setImgUrl(url)
})
if (down) {
handleSaveCode()
}
}
}
const submit = useCallback(async (e) => {
if (loading && status === 2) return;
if (imgUrl) { // 已有
handleSaveCode()
return
}
const values: Meeting = e.detail.value
if (!values.name) {
Taro.showToast({title: '请填写会议名称', icon: 'error'})
return
}
setLoading(true)
try {
const res = await meetingAPi.setMeetings({
...values,
estimate_end_time: new Date(end).getTime(),
estimate_start_time: new Date(start).getTime(),
dep_id: depid,
company_id: company?.id!
})
downUrl(res.id)
setStatus(0)
setId(res.id)
} catch (e) {
setLoading(false)
}
}, [imgUrl, depid, end, start])
function imagLoad() {
Taro.hideLoading()
setLoading(false)
}
/** 开始 */
async function onStart() {
@ -222,143 +168,98 @@ const SpotMeeting: FC = () => {
}
}
async function putMeeting() {
Taro.showLoading()
await meetingAPi.putMeeting(id!, {
name,
dep_id: depid,
company_id: company?.id!,
description,
estimate_end_time: new Date(end).getTime(),
estimate_start_time: new Date(start).getTime(),
async function onDel(){
Taro.showModal({
title:'友情提示',
content:'是否确认删除',
success: async (res) => {
if(res.confirm){
try {
Taro.showLoading()
await meetingAPi.del(id!)
Taro.showToast({title: '删除成功', icon: 'none',mask: true})
Taro.eventCenter.trigger('deleteMeeting', id)
Taro.navigateBack()
}catch (err){
Taro.showToast({title: '删除失败,稍后重试', icon: 'none',mask: true})
} finally {
Taro.hideLoading()
}
}
}
})
Taro.hideLoading()
Taro.showToast({title: '修改成功'})
}
}
return (
<View className={styles.page}>
<View className={styles.box}>
<View></View>
<View className="flex justify-between px-3">
<Text className="font-36 bold">{name}</Text>
{
status === 0 &&
<Icon name={'edit'} onClick={()=>{
Taro.navigateTo({
url:`/pages/manage/meetings/form/form?id=${id}`
})
}} />
}
</View>
{process.env.TARO_ENV === 'h5' && <View className='text-center text-muted'></View>}
<View className="hr-solid mt-3 mx-3"></View>
<View className={styles.code}>
{
imgUrl
? <Image
{/*<Img src={imgUrl} width='200px' height='200px'></Img>*/}
<Image
onLongPress={handleSaveCode}
src={imgUrl}
mode='aspectFit'
style={{width: '200px'}}
onLoad={imagLoad}
onError={imagLoad}
fadeIn/>
: <>
<View className={styles.empty}></View>
<Image src={code} mode='aspectFit' style={{width: '150px'}}/>
</>
{
downStatus < 3 &&
<View className="absolute top left bottom right flex flex-column justify-center align-center">
{downStatus === 1 && <Spin enable />}
{downStatus === 2 && <IconFont name={'exclamation'} shape={'triangle'} color={'#f00'} fill size={30} />}
</View>
}
{status === 2 && <Image src={failure} className={styles.failure}/>}
{/*:*/}
{/*<View className="flex justify-center align-center"*/}
{/* style={{width:'200px',height:'240px'}}*/}
{/*>*/}
{/* <AtLoadMore*/}
{/* status={'loading'}*/}
{/* style={{fontSize:'30rpx'}}*/}
{/* />*/}
{/*</View>*/}
{/*}*/}
</View>
<View className={styles.choice}>
<Form onSubmit={submit}>
<PopPut
title='会议名称'
chevron
content={<Input
className='input'
name='name'
value={name}
disabled={status > 0}
placeholder='请输入会议标题'
onInput={(e) => setName(e.detail.value)}
/>}
/>
<DateTimePicker
name='estimate_start_time'
defaultValue={start}
disabled={status === 1}
onChange={(time) => change_start(time)}
>
<PopPut title='开始时间' content={start}/>
</DateTimePicker>
<DateTimePicker
name='estimate_end_time'
defaultValue={end}
disabled={status === 1}
onChange={(time) => change_end(time)}
>
<PopPut title='结束时间' content={end}/>
</DateTimePicker>
<Picker
mode='selector'
range={manages}
onChange={depChange}
disabled={status === 1}
rangeKey='name'
name='dep_id'>
<PopPut title='选择部门' content={manages?.find(x => x.id == depid)?.name}/>
</Picker>
<View className='flex justify-between'>
{
id !== undefined && <>
{
status === 0 && <MyButton
fillet
type='warn'
width={150}
className={styles.buttonDel}
onClick={onStart}>
</MyButton>
}
{
status === 1 &&
<MyButton fillet type='warn' width={150} className={styles.buttonDel} onClick={onEnd}></MyButton>
}
</>
}
{
imgUrl && <MyButton
fillet
disabled={!imgUrl || status === 1}
width={150}
onClick={putMeeting}
className={styles.button}>
</MyButton>
}
</View>
<MyButton
formType='submit'
<View className="font-30 py-3">
<Text>{start}</Text>
<Text className="mx-1"></Text>
<Text>{end}</Text>
</View>
<View className={styles.tips}>
{/*<Icon name={'alert-circle'} color={'#45D4A8'}></Icon>*/}
<IconFont name={'info'} shape={'circle'} fill color={'#45D4A8'} size={14}></IconFont>
<Text className="ml-1 text-success"></Text>
</View>
<View className="mt-4">
{
status === 0 && <MyButton
fillet
width={200}
width={300}
className={styles.button}
loading={loading}>
{imgUrl ? "保存二维码" : "新建现场会"}
onClick={onStart}>
</MyButton>
</Form>
}
{status === 1 && <MyButton fillet type='warn' width={300} className={styles.buttonEnd} onClick={onEnd}></MyButton>}
</View>
{
!params.id
&& <View
className='text-center text-muted my-3'
onClick={() => Taro.navigateTo({url: '/pages/manage/meetings/meetings'})}>
<Icon name='chevron-right'/>
</View>
}
</View>
{status === 0 && <MyButton type={"default"} fillet width={320} className={styles.buttonDel} onClick={onDel}></MyButton>}
</View>
)
}

@ -5,6 +5,7 @@ import avatar from "@/static/img/avatar.png"
import blacktriang from "@/static/img/blacktriangle.png"
import {FC, useMemo} from "react";
import Img from "@/components/image/image";
import Taro from "@tarojs/taro";
interface Props {
companyList: Company[]
@ -20,8 +21,12 @@ const Header: FC<Props> = ({companyList, showCompany}) => {
return (
<View className={styles.header}>
<View className='flex'>
<View onClick={() => {
token && Taro.navigateTo({url:'/pages/business/userInfo/userInfo'})
}}>
<Img width={100} height={100} src={user?.avatar || avatar} className={`${styles.avatar} rounded-50`} errorType='avatar' onClick={token ? undefined : login} />
<View className='flex-1 flex flex-column justify-start align-start mt-1'>
</View>
<View className='flex-1 flex flex-column justify-start align-start mt-1'>
<View className='font-32' onClick={token ? undefined : login}>{token ? user?.name ?? '匿名' : '请登录'}</View>
<View className='flex align-center mt-1' onClick={token ? showCompany : login}>
<Text style={{fontSize: '24rpx', fontWeight: '500', color: '#323635'}}>{token ? company?.name : '登录解锁更多功能哦'}</Text>

@ -36,7 +36,7 @@ const Service = () => {
if ([1, 2].includes(user?.role_type || 0)) {
setList([
{title: '部门管理', src: dep, router: '/pages/manage/depAdmin/depAdmin'},
{title: '现场会', src: spotMeeting, router: '/pages/manage/spotMeeting/spotMeeting'},
{title: '现场会', src: spotMeeting, router: '/pages/manage/meetings/list'},
{title: '课程管理', src: course, router: '/pages/manage/courseAdmin/courseAdmin'},
{title: '个人中心', src: userInfo, router: '/pages/business/userInfo/userInfo'},
{title: '历史记录', src: cur, router: '/pages/business/history/history'},

@ -81,10 +81,9 @@ const My: FC = () => {
backgroundColor={`rgba(255,255,255,${Number(navbarOpacity) * .9})`}
cancelBack
leftNode={
<View className={styles.navigation}
style={{transform: `translate(0,${Number(navbarOpacity) > .5 ? "0%" : '-350%'})`}}>
<Img className="rounded-50" src={user?.avatar || avatar} mode='heightFix' width={50} height={50}
errorType='avatar'/>
<View className={styles.navigation} style={{transform: `translate(0,${Number(navbarOpacity) > .5 ? "0%" : '-350%'})`}}>
<Img className="rounded-50" src={user?.avatar || avatar} mode='heightFix' width={50} height={50}
errorType='avatar'/>
<Text className='pl-2'>{token ? user?.name : '请登录'}</Text>
</View>
}/>
@ -137,7 +136,7 @@ const My: FC = () => {
{
companyList.length >= 1 &&
companyList.map((d, idx) =>
<View className={`${styles.box} ${companyList.length - 1 === idx && styles.noBorder} `}
<View key={idx} className={`${styles.box} ${companyList.length - 1 === idx && styles.noBorder} `}
onClick={async () => {
if (company?.id === d.id) return;
Taro.showLoading({
@ -170,6 +169,9 @@ const My: FC = () => {
</View>
</PageContainer>
</View>
<View className="text-center text-muted mb-7 mt-3 font-26" style={{opacity:'0.5',width:'100%'}}>ICP备20015955号-4X</View>
</View>
)

@ -1,5 +1,5 @@
import {FC, useCallback, useEffect, useMemo, useState} from "react";
import {Image, PageContainer, Text, View} from "@tarojs/components";
import {FC, useCallback, useEffect, useMemo, useRef, useState} from "react";
import {Image, PageContainer, ScrollView, Text, View} from "@tarojs/components";
import Taro, {useRouter} from "@tarojs/taro";
import {ArticleRecord, brandApi, HomeApi} from "@/api";
import styles from "./article.module.scss";
@ -27,6 +27,24 @@ const article: FC = () => {
const query = Taro.createSelectorQuery()
const [maoId, setMaoId] = useState('')
const [timing, setTiming] = useState<NodeJS.Timeout | undefined>(undefined)
const headingTop = useRef<{ id: string; top: number }[]>([])
useEffect(() => {
if(headings.length){
if(headingTop.current?.[0]?.top){
return
}
headings.forEach(item => {
query.select(`#${item.id}`).boundingClientRect().exec((res) => {
if(res.length === headings.length && res?.[0]?.top){
headingTop.current = res
}
})
})
}
},[headings])
useEffect(() => {
@ -50,18 +68,20 @@ const article: FC = () => {
function mao(id: string) {
setMaoId(id)
setShow(false)
Taro.nextTick(() => {
query.select(`#${id}`).boundingClientRect()
query.exec((res) => {
if (res.length) {
Taro.pageScrollTo({
scrollTop: res[res.length - 1].top,
duration: 300
}
)
}
Taro.nextTick(() => {
console.log(headingTop.current,'headingTop.cur')
query.select(`#${id}`).boundingClientRect()
query.exec((res) => {
if (res.length) {
Taro.pageScrollTo({
scrollTop: headingTop.current.find(d => d.id === id)?.top ?? 0,
duration: 300
}
)
}
})
})
})
}
const onCollect = (v: boolean | undefined) => {
@ -88,7 +108,7 @@ const article: FC = () => {
})
articlesEvent.recordsAdd({id: Number(id), view: (data?.page_view || 0) + 1})
})
}, 3000))
}, 2000))
Taro.setNavigationBarTitle({title: data.title})
if (data.content.length < 200) {
@ -167,7 +187,7 @@ const article: FC = () => {
<View className={`${styles.article} flex-1`}>
<Img src={''} width={80} height={80} className={styles.articleImag} errorType='health'/>
<View className='ml-2'>
<View>{d?.name}</View>
<View>{d.name}</View>
<View className='flex mt-1 text-muted font-24'>
<View className='mr-2'>{beforeTime(articleInfo?.created_at)} . </View>
<View> {articleInfo.page_view || 0}</View>
@ -226,22 +246,25 @@ const article: FC = () => {
<View className='py-3 bold'></View>
</View>
<View className='hr-solid'/>
<View className="px-3 py-5">
{
headings.length > 0 && headings.map((d) => <View
className="pb-3"
style={{
fontSize: '28rpx',
fontWeight: '500',
color: maoId === d.id ? '#45D4A8' : '#323635',
marginLeft: 24 * (d.level - 1) + 'px',
}}
onClick={() => mao(d.id)}>
{d.text}
</View>
)
}
</View>
<ScrollView scrollY={true} style={{height:'50vh'}}>
<View className="px-3 py-5">
{
headings.length > 0 && headings.map((d) => <View
key={d.id}
className="pb-3"
style={{
fontSize: '28rpx',
fontWeight: '500',
color: maoId === d.id ? '#45D4A8' : '#323635',
marginLeft: 24 * (d.level - 1) + 'px',
}}
onClick={() => mao(d.id)}>
{d.text}
</View>
)
}
</View>
</ScrollView>
</View>
</PageContainer>
</>

@ -48,7 +48,7 @@ const BrandItem: FC<{ data: BrandRecord; onClick: VoidFunction }> = ({data, onCl
<View className="ml-2 flex-1">
<View className="text-row1 font-28">{data.name}</View>
<View className='font-24 mt-2 text-muted'>
<Text>{beforeTime(data.created_at)}</Text>
<Text>{beforeTime(data.last_publish_time)}</Text>
<Text className='ml-2'> {data.article_count || 0}</Text>
</View>
</View>

@ -28,6 +28,7 @@ const Profession = () => {
*/
async function getData(more = false) {
if (!categoryId) return;
if (!more && data.get(categoryId)) return;
const oldData = new Map<number, KillData>(data)
const categoryData = oldData.get(categoryId)
const page = more ? (categoryData?.page || 0) + 1 : categoryData?.page || 1
@ -38,7 +39,9 @@ const Profession = () => {
}
try {
setEnable(true)
const data = await userApi.collectList(categoryId!, page, 10)
setEnable(false)
// const dataList = data.list.reduce((pre, cur) => {
// const index = pre.findIndex(d => d.id === cur.id)
// if (index === -1) {
@ -73,18 +76,18 @@ const Profession = () => {
}, [data]))
useEffect(() => {
console.log(categoryId,'categoryId')
categoryId && getData()
}, [categoryId])
async function getCategory() {
try {
const res = [{name: '视频', id: 2}, {name: '文章', id: 1}, {name: '课程', id: 3}, {name: '其他', id: 4}]
const newTabs = res.map<TabList>(d => ({title: d.name, value: d.id}))
setTabs(newTabs)
setCategoryId(newTabs[0].value as number)
} catch (e) {
}
setEnable(false)
// setEnable(false)
}
function tabsChange(tab: OnChangOpt) {
@ -112,6 +115,9 @@ const Profession = () => {
Taro.useLoad(getCategory)
function KillList(data: KillData): JSX.Element {
if(enable){
return <View style={{height:'750rpx'}} className="flex justify-center align-center"><Spin enable={enable} /></View>
}
if (!data?.data?.length) {
return <Empty name='暂无数据'/>
}
@ -130,6 +136,7 @@ const Profession = () => {
<View className={styles.rightBox}>
<View className='font-weight mb-2 font-28'>{d.brand.name}</View>
<View className={styles.desc}>{d.brand.graphic_introduction || '暂无品牌简介'}</View>
{/*<View className={styles.time}>{beforeTime(d.created_at)}</View>*/}
</View>
</>
}
@ -177,7 +184,7 @@ const Profession = () => {
return (
<>
<Spin enable={enable} overlay/>
{/*<IconFont name={'check'} color={'#f40'} size={20}></IconFont>*/}
<View className='bg-white'>
<Tabs tabList={tabs} onChange={tabsChange} current={categoryId!}/>
</View>

@ -43,11 +43,11 @@ const Health: FC = () => {
{
data.length > 0 ? <>
<View className={styles.container}>
{data.map(d => <VideoList data={d} errorType='health'/>)}
{data.map(d => <VideoList key={d.id} data={d} errorType='health'/>)}
</View>
<PageScript/>
</>
: <Empty name='暂无数据'/>
: <Empty showBack onRefresh={() => getData(1)} name='暂无数据'/>
}
</View>
</>

@ -100,7 +100,7 @@ const Sort: FC = () => {
</SwiperItem>)
}
</Swiper>
: <Empty name='暂无疾病分类'/>
: <Empty showBack onRefresh={getData} name='暂无疾病分类'/>
}
</View>
)

@ -108,6 +108,11 @@ const Profession = () => {
)
}
if(!tabs.length){
return (
<Empty showBack onRefresh={getCategory} name='暂无数据'/>
)
}
return (
<>

@ -55,14 +55,15 @@ const Search: FC = () => {
setValue('')
setShow(false)
setFocus(false)
Taro.navigateBack()
}
const searchStyles = useMemo((): React.CSSProperties | undefined => {
if (focus || show) {
return {
transform: "translateY(-43px)",
width: "70%",
// transform: "translateY(-43px)",
// width: "100%",
}
}
}, [focus, show])
@ -70,7 +71,7 @@ const Search: FC = () => {
return (
<View className="flex flex-column">
<NavigationBar text='搜索'/>
<NavigationBar cancelBack={true} backgroundColor={'#F2F8F6'} text='搜索'/>
<View className={styles.searchHeader} style={searchStyles}>
<View className={styles.searchBox}>
<Image src={search} style={{width: '32rpx', height: '32rpx'}} mode='widthFix'/>
@ -86,7 +87,8 @@ const Search: FC = () => {
onConfirm={searchInput}/>
</View>
{focus || show ? <View className='px-2 text-dark' onClick={cancelSearch}></View> : null}
<View className='px-2 text-dark' onClick={cancelSearch}></View>
{/*{focus || show ? <View className='px-2 text-dark' onClick={cancelSearch}>取消</View> : null}*/}
</View>

@ -19,12 +19,12 @@ page {
position: fixed;
z-index: 20;
width: 100%;
color: #fff;
bottom: calc(env(safe-area-inset-bottom));
color: #ffffff;
bottom: calc(200rpx + env(safe-area-inset-bottom));
padding: 0 30rpx;
box-sizing: border-box;
color: #FFFFFF;
transform: translateY(-200%);
//transform: translateY(-200%);
}
.title {

@ -96,6 +96,7 @@ const VideoFull: FC = () => {
onClick={click}
controls
autoplay
showBottomProgress='false'
className={styles.video}
src={data?.resource?.url}
showCenterPlayBtn

@ -1,4 +1,4 @@
export default definePageConfig({
navigationBarTitleText: '链接',
navigationBarTitleText: '',
onReachBottomDistance: 30
})

@ -1,9 +1,54 @@
import {FC} from "react";
import {WebView} from "@tarojs/components";
import {useRouter} from "@tarojs/taro";
import {FC, useState} from "react";
import {Button, Text, View, WebView} from "@tarojs/components";
import Taro, {useRouter} from "@tarojs/taro";
import IconFont from "@/components/IconFont";
const Web:FC = () => {
const Web: FC = () => {
const [hasError, showError] = useState(false)
const {url} = useRouter().params as unknown as { url: string }
return <WebView src={url}></WebView>
const onError = () => {
showError(true)
Taro.hideNavigationBarLoading()
}
const onRefresh = () => {
showError(false)
Taro.showNavigationBarLoading()
}
Taro.useDidShow(() => {
Taro.showNavigationBarLoading()
})
if (hasError) {
return (
<View className='flex flex-column align-center fixed left right top bottom'>
<View className='flex flex-column justify-end align-center' style={{height:'40%'}}>
<View className='mb-7'></View>
</View>
<View className='flex justify-center align-center gap20rpx'>
<Button className='inlineblock' size='mini' onClick={() => Taro.navigateBack()}>
<IconFont name='chevron-left' />
<Text></Text>
</Button>
<Button className='inlineblock' size='mini' type='primary' onClick={onRefresh}>
<IconFont name='arrow-clockwise' />
<Text></Text>
</Button>
</View>
</View>
)
}
return (
<WebView
progressbarColor='#45D4A8'
src={decodeURIComponent(url)}
onLoad={() => Taro.hideNavigationBarLoading()}
onError={onError}
/>
)
}
export default Web

@ -0,0 +1,58 @@
.box {
margin-left:30rpx;
margin-bottom: 24rpx;
width:690rpx;
display: flex;
margin-bottom: 20rpx;
background-color: #fff;
border-radius: 16rpx;
padding: 24rpx;
box-sizing: border-box;
position: relative;
}
.image{
background-color: #ededed;
border-radius: 8rpx;
}
.play {
position: absolute;
z-index: 9999;
width: 50rpx !important;
height: 50rpx !important;
top: 99rpx;
left: 99rpx;
background: transparent !important;
}
.rightBox{
padding-left: 24rpx;
box-sizing: border-box;
flex: 1;
}
.articleLeftBox{
padding-right: 24rpx;
box-sizing: border-box;
flex: 1;
}
.videoRightBox{
padding-left: 24rpx;
box-sizing: border-box;
flex: 1;
}
.courseRightBox{
padding-left: 24rpx;
box-sizing: border-box;
flex: 1;
}
.desc{
font-size: 24rpx;
font-weight: 500;
color: #909795;
line-height: 34rpx;
display: -webkit-box;
word-break: break-all;
text-overflow: ellipsis;
overflow: hidden;
-webkit-box-orient:vertical;
-webkit-line-clamp:2;
}

@ -0,0 +1,167 @@
import {FC, useCallback, useEffect, useState} from "react";
import {Image, ScrollView, View} from "@tarojs/components";
import styles from './list.module.scss'
import Taro from "@tarojs/taro";
import Empty from "@/components/empty/empty";
import Img from "@/components/image/image";
import {SearchApi} from "@/api/search";
import {rfc33392time} from "@/utils/day";
import play from "@/static/img/play-back.png";
import Spin from "@/components/spinner";
type Props = {
name: string
clear: boolean
}
const SearchList: FC<Props> = ({name, clear}) => {
console.log(name, 'name')
const globalData = Taro.getApp().globalData
const [page, setPage] = useState(1)
const [brands, setBrands] = useState<any[]>([])
const [total, setTotal] = useState(0)
const [text, setText] = useState('')
const [loading, setLoading] = useState(true)
useEffect(() => {
if (!clear) {
setBrands([])
setLoading(true)
}
}, [clear])
useEffect(() => {
if (name && clear) {
getData()
}
}, [page, name, clear])
const getData = useCallback(async () => {
try {
const data = await SearchApi.list(page, 10, name)
if (page === 1) {
if (data.data.length < 10) {
setText('没有更多了~')
} else {
setText('上拉加载更多~')
}
setBrands([
...data.data
])
} else {
setBrands([
...brands,
...data.data
])
}
setTotal(data.total)
} catch (e) {
}
setLoading(false)
}, [page, name])
function jumpInfo(id: number, type: string) {
console.log(type, 'type')
let url = ''
switch (type) {
case 'brand':
url = '/pages/preview/brand/info/info';
break;
case 'article':
url = '/pages/preview/brand/article/article'
break
case 'video_records':
url = '/pages/preview/videoFull/videoFull'
break
case 'courses':
url = '/pages/business/videoInfo/videoInfo'
break
}
Taro.navigateTo({url: `${url}?id=${id}`})
}
function onScrollToLower() {
if (brands?.length < total) {
setPage(page + 1)
getData().then()
} else {
setText('没有更多了~')
}
}
return (
<ScrollView
className='scrollview'
scrollY
scrollWithAnimation
style={{height: `${globalData.windowHeight - 140}px`, backgroundColor: `#f5f5f5`, position: 'relative'}}
onScrollToLower={onScrollToLower}>
<Spin enable={loading} block overlay/>
{
brands.length >= 1 && !loading &&
<>
{brands.map((d) =>
<View onClick={() => jumpInfo(d.data.id, d.data.table)} className={styles.box} key={d.data.id}>
{
d.data.table === 'brand' &&
<>
<Img width={128} height={128} src={d.data['@data'].logo} mode='aspectFill' className={styles.image}
errorType='brand'/>
<View className={styles.rightBox}>
<View className='font-weight mb-2 font-28'>{d.data.title}</View>
<View className={styles.desc}>{d.data.content || '暂无品牌简介'}</View>
</View>
</>
}
{
d.data.table === 'article' &&
<>
<View className={styles.articleLeftBox}>
<View className='font-weight mb-2 font-28 lh-40'>{d.data['@data'].title}</View>
<View
className={styles.desc}>{rfc33392time(d.data['@data'].created_at)} {d.data['@data'].page_view}</View>
</View>
<Img width={172} height={128} src={d.data['@data'].logo} mode='aspectFill' className={styles.image}
errorType='course'/>
</>
}
{
d.data.table === 'video_records' &&
<>
<Img width={192} height={192} src={d.data['@data'].url_path} mode='aspectFill' errorType='health'
className={styles.image}/>
<Image src={play} className={styles.play} mode='aspectFit'/>
<View className={styles.videoRightBox}>
<View className='font-weight mb-2 font-28 lh-40'>{d.data['@data'].title}</View>
<View className={styles.desc}>{d.data['@data'].introduction}</View>
<View className={`${styles.desc} mt-2`}>: {d.data['@data'].video_view}</View>
</View>
</>
}
{
d.data.table === 'courses' &&
<>
<Img width={192} height={138} src={d.data['@data'].thumb} mode='aspectFill' className={styles.image}
errorType='course'/>
<View className={styles.courseRightBox}>
<View className='font-weight mb-2 font-28 lh-40'>{d.data['@data'].title}</View>
<View className={styles.desc}>:{d.data['@data'].class_hour}
{d.data['@data'].charge}</View>
</View>
</>
}
</View>
)
}
<View style={{width: '750rpx', textAlign: 'center', color: '#999'}}
className="font-28 mt-3 mb-3">{text}</View>
</>
}
{!loading && brands.length === 0 && <Empty name='空空如也'/>}
</ScrollView>
)
}
export default SearchList

@ -0,0 +1,3 @@
export default definePageConfig({
navigationStyle: 'custom'
})

@ -0,0 +1,66 @@
page {
background-color: #F2F8F6;
.searchHeader {
margin-top: 10px;
padding: 0 20rpx;
display: flex;
align-items: center;
justify-content: space-between;
transition: all 200ms;
position: sticky;
z-index: 200 ;
overflow: hidden;
}
.searchBox {
flex: 1;
height: 68rpx;
background: #FFFFFF;
border-radius: 32rpx;
box-sizing: border-box;
display: flex;
align-items: center;
padding: 0 24rpx;
.input {
font-size: 28rpx;
margin-left: 20rpx;
flex: 1;
}
}
.titleBox {
margin-top: 40rpx;
width: 100%;
display: flex;
box-sizing: border-box;
padding-right: 30rpx;
justify-content: space-between;
.title {
font-size: 30rpx;
font-weight: bold;
color: #323635;
}
}
.contentBox {
display: flex;
flex-wrap: wrap;
.items {
display: inline-block;
background: #FFFFFF;
border-radius: 32rpx;
padding: 10rpx 24rpx;
font-size: 24rpx;
font-weight: 500;
color: #323635;
line-height: 24rpx;
margin-top: 24rpx;
margin-right: 24rpx;
}
}
}

@ -0,0 +1,154 @@
import {Input, View, Text, PageContainer, Image} from "@tarojs/components";
import {FC, useEffect, useMemo, useState} from "react";
import styles from './index.module.scss'
import Taro from "@tarojs/taro";
import {useDidShow} from '@tarojs/taro'
import SearchList from './components/list'
import NavigationBar from "@/components/navigationBar/navigationBar";
import search from '@/static/img/search.png'
import del from '@/static/img/del.png'
const Search: FC = () => {
const [value, setValue] = useState('')
const [recentSearch, setRecentSearch] = useState<string[]>([])
const [hotSearch] = useState<any[]>([])
const [show, setShow] = useState(false)
const [focus, setFocus] = useState(false)
useDidShow(getRecentSearch)
useEffect(() => {
!show && getRecentSearch()
}, [show])
function inpFn(e) {
setValue(e.detail.value)
}
function clearSearch() {
Taro.removeStorageSync('recentSearch')
getRecentSearch()
Taro.showToast({title: '删除成功'})
}
function getRecentSearch() {
setRecentSearch(Taro.getStorageSync('recentSearch'))
}
function getSearchItem(value) {
setValue(value)
setShow(true)
}
function searchInput() {
if (value === "") return;
getSearchItem(value)
//记录最近搜索
let recentSearch = Taro.getStorageSync('recentSearch') || [];
recentSearch.unshift(value);
Taro.setStorageSync('recentSearch', [...new Set(recentSearch)])
}
function cancelSearch(){
setValue('')
setShow(false)
setFocus(false)
// Taro.navigateBack()
}
const searchStyles = useMemo((): React.CSSProperties | undefined => {
if (focus || show) {
return {
// transform: "translateY(-43px)",
// width: "100%",
}
}
}, [focus, show])
return (
<View className="flex flex-column">
<NavigationBar cancelBack={true} backgroundColor={'#F2F8F6'} leftNode={
<Text className="bold font-36 ml-1" style={{color:'#323635'}} ></Text>
} />
<View className={styles.searchHeader} style={searchStyles}>
<View className={styles.searchBox}>
<Image src={search} style={{width: '32rpx', height: '32rpx'}} mode='widthFix'/>
<Input
onFocus={() => setFocus(true)}
onBlur={() => setFocus(false)}
className={styles.input}
placeholder={(focus || show) ? '' : "输入关键字搜索"}
type='text'
value={value}
confirmType='search'
onInput={inpFn}
onConfirm={searchInput}/>
</View>
<View className='px-2 text-dark' onClick={cancelSearch}></View>
{/*{focus || show ? <View className='px-2 text-dark' onClick={cancelSearch}>取消</View> : null}*/}
</View>
{
recentSearch.length >= 1 && !show &&
<View className='px-2'>
<View className={styles.titleBox}>
<Text className={styles.title}></Text>
<Image
src={del}
mode='widthFix'
style={{width: '16px', height: '16px', padding: '0 20rpx'}}
onClick={clearSearch}/>
</View>
<View className={styles.contentBox}>
{
recentSearch.length > 0 &&
recentSearch?.map(d =>
<View className={styles.items}>
<View onClick={() => getSearchItem(d)} className="font-28">{d}</View>
</View>)
}
</View>
</View>
}
{
hotSearch.length >= 1 && !show &&
<>
<View className={`flex justify-between ${styles.titleBox}`}>
<Text className="font-32 fwb"></Text>
</View>
<View className="wid100 pt-3 pl-3 box-b">
<View className="wid100 flex flex-wrap">
{
hotSearch.length &&
hotSearch.map(d =>
<View className="py-1 px-2 rounded-40 mr-2 mb-2 bg-warning text-white">
<View onClick={() => {
getSearchItem(d)
}} className="font-28">{d}</View>
</View>)
}
</View>
</View>
</>
}
<PageContainer
onBeforeLeave={cancelSearch}
onClickOverlay={cancelSearch}
show={show}
round
overlay
overlayStyle={'background:rgba(0,0,0,0)'}>
{show && <SearchList name={value} clear={show}/>}
</PageContainer>
</View>
)
}
export default Search

@ -101,3 +101,131 @@ taro-button-core::after {
display: -webkit-box;
-webkit-box-orient: vertical;
}
@-webkit-keyframes loading {
0% {
-webkit-transform: rotate(0deg);
transform: rotate(0deg);
}
100% {
-webkit-transform: rotate(360deg);
transform: rotate(360deg);
}
}
@keyframes loading {
0% {
-webkit-transform: rotate(0deg);
transform: rotate(0deg);
}
100% {
-webkit-transform: rotate(360deg);
transform: rotate(360deg);
}
}
.at-loading {
display: inline-block;
position: relative;
width: 36rpx;
height: 36rpx;
}
.at-loading__ring {
-webkit-box-sizing: border-box;
box-sizing: border-box;
display: block;
position: absolute;
width: 36rpx;
height: 36rpx;
margin: 1PX;
border-width: 1PX;
border-style: solid;
border-color: #00d6ac transparent transparent transparent;
border-radius: 50%;
-webkit-animation: loading 1.2s cubic-bezier(0.5, 0, 0.5, 1) infinite;
animation: loading 1.2s cubic-bezier(0.5, 0, 0.5, 1) infinite;
}
.at-loading__ring:nth-child(1) {
-webkit-animation-delay: -0.45s;
animation-delay: -0.45s;
}
.at-loading__ring:nth-child(2) {
-webkit-animation-delay: -0.3s;
animation-delay: -0.3s;
}
.at-loading__ring:nth-child(3) {
-webkit-animation-delay: -0.15s;
animation-delay: -0.15s;
}
.at-activity-indicator__content{
font-size: 28rpx;
color: #6c757d;
}
//滑动组件样式
.at-list {
background-color: rgba(0,0,0,0) !important;
position: relative;
width: 710rpx !important;
}
.at-swipe-action {
position: relative;
overflow: hidden;
width: 710rpx !important;
border-radius: 16rpx 16rpx 16rpx 16rpx;
overflow: hidden;
margin-bottom: 20rpx;
}
.at-swipe-action__area {
height: auto;
}
.at-swipe-action__content {
position: relative;
font-size: 32rpx;
background-color: #FFF;
display: -webkit-flex;
display: -ms-flexbox;
display: flex;
height: 100%;
z-index: 2;
}
.at-swipe-action__content.animtion {
-webkit-transition: -webkit-transform 300ms cubic-bezier(0.36, 0.66, 0.04, 1);
transition: -webkit-transform 300ms cubic-bezier(0.36, 0.66, 0.04, 1);
transition: transform 300ms cubic-bezier(0.36, 0.66, 0.04, 1);
transition: transform 300ms cubic-bezier(0.36, 0.66, 0.04, 1), -webkit-transform 300ms cubic-bezier(0.36, 0.66, 0.04, 1);
}
.at-swipe-action__option {
-webkit-transition: background-color 0.3s;
transition: background-color 0.3s;
-webkit-align-items: center;
-ms-flex-align: center;
align-items: center;
-webkit-box-align: center;
display: -webkit-inline-flex;
display: -ms-inline-flexbox;
display: inline-flex;
padding: 0 32rpx;
height: 100%;
color: #FFF;
font-size: 28rpx;
width: 120rpx;
text-align: center;
background-color: #999;
}
.at-swipe-action__option:active {
background-color: #F0F0F0;
}
.at-swipe-action__options {
-webkit-align-items: center;
-ms-flex-align: center;
align-items: center;
-webkit-box-align: center;
display: -webkit-inline-flex;
display: -ms-inline-flexbox;
display: inline-flex;
position: absolute;
top: 0;
right: 0;
height: 100%;
z-index: 1;
opacity: 0;
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 828 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 803 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.7 KiB

@ -16,7 +16,7 @@ const TabLink:FC<TabLinkProps> = (props:TabLinkProps) => {
let webExp= new RegExp(/http(s)?:\/\/([\w-]+\.)+[\w-]+(\/[\w- .\/?%&=]*)?/)
if(webExp.test(props.url)){
//跳转webview
Taro.navigateTo({url:`/pages/preview/webView/webView?url=${props.url}`})
Taro.navigateTo({url:`/pages/preview/webView/webView?url=${encodeURIComponent(props.url)}`})
}else{
//跳转小程序页面
}

2
types/home.d.ts vendored

@ -15,6 +15,7 @@ interface VideList {
interface Brand {
id: number
brand_album: string
logo: string
graphic_introduction: string
name: string
resource: Resource
@ -39,4 +40,5 @@ interface Illness {
description: string
name: string
thumb:string
album: string
}

Loading…
Cancel
Save