Compare commits

...

3 Commits

Author SHA1 Message Date
king 86bc1a4cc0 统一文章收藏 1 year ago
king ae52d73588 品牌收藏 1 year ago
king 353e1d51e0 解决搜索代码冲突 1 year ago
  1. 4
      .env
  2. 4
      src/api/brand.ts
  3. 8
      src/api/user.ts
  4. 1
      src/app.config.ts
  5. 65
      src/components/collect/collect.module.scss
  6. 45
      src/components/collect/collect.tsx
  7. 17
      src/pages/business/videoInfo/components/catalogue.tsx
  8. 3
      src/pages/business/videoInfo/videoInfo.scss
  9. 16
      src/pages/home/components/curRecommended.tsx
  10. 3
      src/pages/index/index.tsx
  11. 27
      src/pages/preview/brand/article/article.module.scss
  12. 74
      src/pages/preview/brand/article/article.tsx
  13. 2
      src/pages/preview/brand/info/info.tsx
  14. 88
      src/pages/preview/brand/list/list.tsx
  15. 4
      src/pages/preview/illness/article/article.config.ts
  16. 81
      src/pages/preview/illness/article/article.module.scss
  17. 113
      src/pages/preview/illness/article/article.tsx
  18. 2
      src/pages/preview/illness/list/list.tsx
  19. 168
      src/pages/preview/search/search/components/list.tsx
  20. 52
      src/pages/preview/search/search/index.module.scss
  21. 159
      src/pages/preview/search/search/index.tsx
  22. BIN
      src/static/img/catalogue.png
  23. BIN
      src/static/img/omit.png
  24. 14
      types/user.d.ts

@ -1,5 +1,5 @@
#TARO_APP_API=https://yjx.dev.yaojiankang.top #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://shopfix.yaojiankang.top TARO_APP_API=https://shopfix.yaojiankang.top
#TARO_APP_API=https://playedu.yaojiankang.top #TARO_APP_API=https://playedu.yaojiankang.top
TARO_APP_LGOIN=true TARO_APP_LGOIN=true

@ -11,7 +11,8 @@ export type BrandRecord = {
introductory_video_resource: any introductory_video_resource: any
article_count: number article_count: number
created_at: string created_at: string
page_view:number page_view: number
collect: boolean
} }
export type ArticleRecord = { export type ArticleRecord = {
title: string title: string
@ -19,6 +20,7 @@ export type ArticleRecord = {
created_at: string created_at: string
content: string content: string
brands: BrandRecord[] brands: BrandRecord[]
collect:boolean
} }
export const brandApi = { export const brandApi = {

@ -94,8 +94,8 @@ export const userApi = {
companyReplace(id: number) { companyReplace(id: number) {
return request(`/api/v1/company/replace/${id}`, "PATCH") return request(`/api/v1/company/replace/${id}`, "PATCH")
}, },
// /** 上传头像 */ /** 收藏 */
// putAvatar(file: string) { create(data: Create) {
// return request('/api/v1/user/avatar', "PUT", {file}) return request("/api/v1/collect/create", "POST", data)
// } }
} }

@ -91,7 +91,6 @@ export default defineAppConfig({
'videoFull/videoFull', // 资源id 视频全屏 'videoFull/videoFull', // 资源id 视频全屏
'illness/sort/sort', 'illness/sort/sort',
'illness/list/list', 'illness/list/list',
'illness/article/article',
'webView/webView', 'webView/webView',
'search/search/index', 'search/search/index',
] ]

@ -3,11 +3,68 @@
align-items: center; align-items: center;
color: #909795; color: #909795;
font-size: 24rpx; font-size: 24rpx;
padding: 0 10rpx;
}
.collectImage {
position: relative;
width: 32rpx;
height: 32rpx;
margin-right: 10rpx;
Image { Image {
width: 32rpx; width: 100%;
height: 32rpx; height: 100%;
margin-right: 10rpx; }
//vertical-align: middle; }
.zoom {
top: 0;
left: 0;
position: absolute;
content: '';
width: 32rpx;
height: 32rpx;
border-radius: 50%;
border: 1px solid #FF9E5F;
animation: Zooms 300ms ease forwards;
opacity: 1;
transform-origin: -100%, -100% 0;
}
.pulse {
animation: Pulse 300ms;
}
@keyframes Zooms {
0% {
transform: scale(1);
}
30% {
transform: scale(1.5);
left: -5%;
top: -5%;
opacity: 1;
}
100% {
transform: scale(1.5);
left: -5%;
top: -5%;
opacity: 0;
}
}
@keyframes Pulse {
0% {
transform: scale(.2);
}
60% {
transform: scale(1.2);
}
80% {
transform: scale(.8);
}
100% {
transform: scale(1);
} }
} }

@ -1,20 +1,57 @@
import {FC} from "react"; import {CSSProperties, FC, useCallback, useEffect, useState} from "react";
import star from '@/static/img/star.png' import star from '@/static/img/star.png'
import starLine from '@/static/img/starLine.png' import starLine from '@/static/img/starLine.png'
import {Image, View} from "@tarojs/components"; import {Image, View} from "@tarojs/components";
import styles from './collect.module.scss' import styles from './collect.module.scss'
import {Profile} from "@/store"
import Taro from "@tarojs/taro";
import {userApi} from "@/api";
interface Props { interface Props {
onClick?: () => void onClick?: () => void
select?: boolean select?: boolean
stylesImage?: CSSProperties
styles?: CSSProperties
owner_id: number
owner_type: CreateOwnerType
textHidden?: boolean
} }
/** 收藏 */ /** 收藏 */
const Collect: FC<Props> = (props) => { const Collect: FC<Props> = (props) => {
const {token} = Profile.useContainer()
const [loading, setLoading] = useState(false)
const [select, setSelect] = useState(props.select)
useEffect(() => {
setSelect(props.select)
}, [props])
const change = useCallback(async () => {
if (!token) {
Taro.navigateTo({url: '/pages/login/login'})
return
}
if (loading) return;
props.onClick?.()
console.log(select)
setSelect(!select)
setLoading(true)
await userApi.create({owner_id: props.owner_id, owner_type: props.owner_type})
setTimeout(() => {
setLoading(false)
}, 300)
}, [loading, token, select])
return ( return (
<View className={styles.collect}> <View className={styles.collect} onClick={change} style={props.styles}>
<Image src={props.select ? star : starLine}/> <View className={styles.collectImage} style={props.stylesImage}>
{props.select ? '已收藏' : '收藏'} <View className={`${loading && select && styles.zoom}`}/>
<Image
src={(select && token) ? star : starLine}
className={`${loading && styles.pulse}`}/>
</View>
{!props.textHidden && (select ? '已收藏' : '收藏')}
</View> </View>
) )
} }

@ -12,6 +12,8 @@ import hourRecord from "@/static/img/hourRecord.png"
import CustomPageContainer from "@/components/custom-page-container/custom-page-container"; import CustomPageContainer from "@/components/custom-page-container/custom-page-container";
import {Profile} from "@/store"; import {Profile} from "@/store";
import LoginView from "@/components/loginView"; import LoginView from "@/components/loginView";
import Collect from "@/components/collect/collect";
import omit from '@/static/img/omit.png'
interface Props { interface Props {
data: CourseDepData | null data: CourseDepData | null
@ -45,11 +47,6 @@ const Catalogue: FC<Props> = ({data, setHors, id, playId}) => {
} }
}) })
// function onPause() {
// videoEvents.setVideoState('pause')
// }
function jumCurHistory() { function jumCurHistory() {
if (playId) { if (playId) {
Taro.navigateTo({url: `/pages/business/hourHistory/hourHistory?courseId=${id}&hourId=${playId}`}) Taro.navigateTo({url: `/pages/business/hourHistory/hourHistory?courseId=${id}&hourId=${playId}`})
@ -195,7 +192,15 @@ const Catalogue: FC<Props> = ({data, setHors, id, playId}) => {
playing ? <MyButton className='flex-1'></MyButton> playing ? <MyButton className='flex-1'></MyButton>
: <MyButton className='flex-1' onClick={learning}></MyButton> : <MyButton className='flex-1' onClick={learning}></MyButton>
} }
<View className='px-3' onClick={() => setShow(true)}>...</View> <Collect
owner_id={id}
owner_type={3}
styles={{flexDirection: 'column', justifyContent: 'center', padding: '20rpx'}}
stylesImage={{margin: '0 0 8rpx 0'}}/>
<View className='px-2' onClick={() => setShow(true)}>
<Image src={omit} style={{width: '32rpx', height: '32rpx'}} mode='widthFix'/>
<View></View>
</View>
</View> </View>
} }

@ -76,6 +76,7 @@
} }
.Videobutton { .Videobutton {
align-items: center;
display: flex; display: flex;
background: #fff; background: #fff;
position: fixed; position: fixed;
@ -84,6 +85,8 @@
bottom: env(safe-area-inset-bottom); bottom: env(safe-area-inset-bottom);
box-sizing: border-box; box-sizing: border-box;
padding: 10px 20px; padding: 10px 20px;
color: #909795;
font-size: 24rpx;
} }
.more { .more {

@ -9,19 +9,9 @@ import Img from "@/components/image/image";
import {beforeTime} from "@/utils/time"; import {beforeTime} from "@/utils/time";
const toArticlePage = (d: any) => { const toArticlePage = (d: any) => {
console.log({d}) Taro.navigateTo({
switch (d.owner_type) { url: `/pages/preview/brand/article/article?id=${d.id}`
case 1: })
Taro.navigateTo({
url: `/pages/preview/brand/article/article?id=${d.id}`
})
return
case 2:
Taro.navigateTo({
url: `/pages/preview/illness/article/article?id=${d.id}`
})
return
}
} }
const CurRecommended: FC = () => { const CurRecommended: FC = () => {

@ -8,6 +8,7 @@ import NavigationBar from "@/components/navigationBar/navigationBar";
import Spin from "@/components/spinner"; import Spin from "@/components/spinner";
import Img from "@/components/image/image"; import Img from "@/components/image/image";
import {beforeTime} from "@/utils/time"; import {beforeTime} from "@/utils/time";
import {isBoolean} from "@tarojs/shared";
const category: TabList[] = [ const category: TabList[] = [
{title: "企选课程", value: 'is_required'}, {title: "企选课程", value: 'is_required'},
@ -42,7 +43,7 @@ const AuditMode: FC = () => {
const [enable, setEnable] = useState(true) const [enable, setEnable] = useState(true)
useEffect(() => { useEffect(() => {
publicApi.course({page: 1, pageSize: 10}).then(res => { publicApi.course({page: 1, pageSize: 10}).then(res => {
setAuditMode(res.audit_mode) setAuditMode(isBoolean(res.audit_mode) ? res.audit_mode : res.audit_mode === 'true')
setArticles(res.articles) setArticles(res.articles)
setEnable(false) setEnable(false)
}) })

@ -38,6 +38,26 @@
} }
} }
.botmBox {
z-index: 99;
position: fixed;
bottom: 0;
width: 690rpx;
height: 100rpx;
padding: 0 30rpx env(safe-area-inset-bottom);
display: flex;
justify-content: flex-end;
align-items: center;
background: #F5F8F7;
color: #909795;
View {
font-size: 26rpx;
padding: 0 10px;
text-align: center;
}
}
.article { .article {
font-size: 30rpx; font-size: 30rpx;
display: flex; display: flex;
@ -52,3 +72,10 @@
font-size: 40rpx; font-size: 40rpx;
margin-bottom: 50rpx; margin-bottom: 50rpx;
} }
.articleBox {
background: #fff;
min-height: calc(100vh - env(safe-area-inset-bottom) + 180rpx);
box-sizing: border-box;
padding: 30rpx 30rpx calc(env(safe-area-inset-bottom) + 150rpx) 30rpx;
}

@ -1,5 +1,5 @@
import {FC, useCallback, useEffect, useMemo, useState} from "react"; import {FC, useCallback, useEffect, useMemo, useState} from "react";
import {Image, Text, View} from "@tarojs/components"; import {Image, PageContainer, Text, View} from "@tarojs/components";
import Taro, {useRouter} from "@tarojs/taro"; import Taro, {useRouter} from "@tarojs/taro";
import {ArticleRecord, brandApi} from "@/api"; import {ArticleRecord, brandApi} from "@/api";
import styles from "./article.module.scss"; import styles from "./article.module.scss";
@ -10,6 +10,8 @@ import Empty from "@/components/empty/empty";
import Spin from "@/components/spinner"; import Spin from "@/components/spinner";
import {beforeTime} from "@/utils/time"; import {beforeTime} from "@/utils/time";
import Img from "@/components/image/image"; import Img from "@/components/image/image";
import Collect from "@/components/collect/collect";
import catalogue from "@/static/img/catalogue.png";
const article: FC = () => { const article: FC = () => {
@ -18,9 +20,12 @@ const article: FC = () => {
const {id} = useRouter().params as unknown as { id: number } const {id} = useRouter().params as unknown as { id: number }
const [articleInfo, setArticleInfo] = useState<ArticleRecord>() const [articleInfo, setArticleInfo] = useState<ArticleRecord>()
const [ultra, setUltra] = useState(true) const [ultra, setUltra] = useState(true)
const [show, setShow] = useState(false)
const globalData = Taro.getApp().globalData const globalData = Taro.getApp().globalData
const pageHeight = globalData.windowHeight - globalData.textBarHeight - globalData.statusBarHeight const pageHeight = globalData.windowHeight - globalData.textBarHeight - globalData.statusBarHeight
const {children} = useMemo(() => parse(articleInfo?.content || ''), [articleInfo]) const {children, headings} = useMemo(() => parse(articleInfo?.content || ''), [articleInfo])
const query = Taro.createSelectorQuery()
useEffect(() => { useEffect(() => {
setTimeout(() => { setTimeout(() => {
@ -34,6 +39,22 @@ const article: FC = () => {
}, 300) }, 300)
}, [children]) }, [children])
function mao(id: string) {
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.useReady(() => { Taro.useReady(() => {
getData().then() getData().then()
}) })
@ -54,12 +75,30 @@ const article: FC = () => {
function helloWorld() { function helloWorld() {
return ( return (
<> <>
<View className={styles.botmBox}>
<View>
<Collect
select={articleInfo?.collect}
styles={{flexDirection: 'column', justifyContent: 'center', padding: '20rpx'}}
stylesImage={{margin: '0 0 8rpx 0'}}
owner_id={Number(id)}
owner_type={1}/>
</View>
{
headings.length > 0 && <View onClick={() => setShow(true)}>
<Image src={catalogue} mode='widthFix' style={{width: '40rpx', height: '40rpx'}}/>
<View></View>
</View>
}
</View>
<Spin overlay enable={enable}/> <Spin overlay enable={enable}/>
<View style={{ <View
padding: '10px', className={styles.articleBox}
height: !token ? Taro.getWindowInfo().windowHeight - 60 + 'px' : 'auto', style={{
overflow: !token ? 'hidden' : 'auto' height: !token ? Taro.getWindowInfo().windowHeight - 60 + 'px' : 'auto',
}}> overflow: !token ? 'hidden' : 'auto'
}}>
<View id="childrenNode"> <View id="childrenNode">
<View className={styles.articleTitle}>{articleInfo?.title}</View> <View className={styles.articleTitle}>{articleInfo?.title}</View>
{ {
@ -67,7 +106,7 @@ const article: FC = () => {
<View> <View>
{ {
articleInfo?.brands.map(d => <View className={styles.article}> articleInfo?.brands.map(d => <View className={styles.article}>
<Img src={d.logo} width={80} height={80} className={styles.articleImag}/> <Img src={d.logo} width={80} height={80} className={styles.articleImag} errorType='avatar'/>
<View className='ml-2'> <View className='ml-2'>
<View>{d?.name}</View> <View>{d?.name}</View>
<View className='flex mt-1 text-muted font-24'> <View className='flex mt-1 text-muted font-24'>
@ -97,9 +136,26 @@ const article: FC = () => {
</View> </View>
</View> </View>
} }
<PageContainer
onClickOverlay={() => setShow(false)}
show={show}
round
overlay
overlayStyle={'background:rgba(0,0,0,0.3)'}>
<View className="px-3 py-5">
{
headings.length > 0 && headings.map((d) => <View
className="pb-3"
style={{fontSize: '28rpx', fontWeight: '500', color: '#323635'}}
onClick={() => mao(d.id)}>
{d.text}
</View>
)
}
</View>
</PageContainer>
</> </>
) )
} }
return helloWorld() return helloWorld()

@ -111,7 +111,7 @@ const BrandInfo: FC = () => {
<View className={styles['top']}> <View className={styles['top']}>
<View className='flex justify-between'> <View className='flex justify-between'>
<Text className={`${styles['title']} flex-1`}>{brandInfo?.name}</Text> <Text className={`${styles['title']} flex-1`}>{brandInfo?.name}</Text>
<Collect/> <Collect owner_type={4} owner_id={id} select={brandInfo?.collect}/>
</View> </View>
<LineEllipsis text={brandInfo?.graphic_introduction || '暂无简介'}></LineEllipsis> <LineEllipsis text={brandInfo?.graphic_introduction || '暂无简介'}></LineEllipsis>
</View> </View>

@ -19,40 +19,40 @@ const BrandItem: FC<{ data: BrandRecord; onClick: VoidFunction }> = ({data, onCl
/> />
} else if (data.brand_album) { } else if (data.brand_album) {
media = <Img media = <Img
// width={712}
height={320} height={320}
src={data.brand_album.split(",")[0]} src={data.brand_album.split(",")[0]}
mode="aspectFill" mode="aspectFill"
style={{background: '#ededed'}} style={{background: '#ededed'}}
onClick={onClick}
/> />
} }
return ( return (
<View className="bg-white flex flex-column justify-stretch mb-2_4 rounded-10 clip"> <View className="bg-white flex flex-column justify-stretch mb-2_4 rounded-10 clip">
<View className="p-3" onClick={onClick}> <View className="p-3">
<View className='mb-2 font-32 flex'> <View onClick={onClick}>
<Img <View className='mb-2 font-32 flex'>
width={76} <Img
height={76} width={76}
src={data.logo} height={76}
mode='aspectFill' src={data.logo}
errorType='avatar' mode='aspectFill'
className="rounded-10 clip" errorType='avatar'
style={{background: '#ededed'}} className="rounded-10 clip"
/> style={{background: '#ededed'}}
<View className="ml-2 flex-1"> />
<View className="text-row1 font-28">{data.name}</View> <View className="ml-2 flex-1">
<View className='font-24 mt-2 text-muted'>{beforeTime(data.created_at)}·</View> <View className="text-row1 font-28">{data.name}</View>
<View className='font-24 mt-2 text-muted'>{beforeTime(data.created_at)}·</View>
</View>
</View> </View>
</View>
<View className={styles.previewImag}> <View className={styles.previewImag}>
{media} {media}
</View> </View>
<View className="font-24 text-muted mb-4 text-row3 mt-2" style={{lineHeight: 1.4}}> <View className="font-24 text-muted mb-4 text-row3 mt-2" style={{lineHeight: 1.4}}>
{data.graphic_introduction} {data.graphic_introduction}
</View>
</View> </View>
<View className="flex gap20rpx font-24 text-muted justify-around"> <View className="flex gap20rpx font-24 text-muted justify-around">
@ -60,7 +60,7 @@ const BrandItem: FC<{ data: BrandRecord; onClick: VoidFunction }> = ({data, onCl
<Image src={articleLine}/> <Image src={articleLine}/>
{data.article_count || 0} {data.article_count || 0}
</View> </View>
<Collect/> <Collect owner_id={data.id} owner_type={4} select={data.collect}/>
</View> </View>
</View> </View>
</View> </View>
@ -78,9 +78,13 @@ const BrandList: FC = () => {
getData() getData()
}, [page]) }, [page])
const getData = useCallback(async () => { Taro.useDidShow(() => {
brands.length && getData(true)
})
const getData = useCallback(async (replace = false) => {
try { try {
const res = await brandApi.list(page, 10) const res = await brandApi.list(replace ? 1 : page, replace ? 10 * page : 10)
if (page === 1) { if (page === 1) {
if (res.list.length < 10) { if (res.list.length < 10) {
setText('暂无更多') setText('暂无更多')
@ -89,10 +93,16 @@ const BrandList: FC = () => {
} }
} }
setTotal(res.total) setTotal(res.total)
setBrands([ const data = res.list.reduce((pre, cur) => {
...brands, const index = pre.findIndex(d => d.id === cur.id)
...res.list if (index > -1) {
]) pre.splice(index, 1, cur)
} else {
pre.push(cur)
}
return pre
}, JSON.parse(JSON.stringify(brands)))
setBrands(data)
} catch (e) { } catch (e) {
} }
setLoading(false) setLoading(false)
@ -111,22 +121,18 @@ const BrandList: FC = () => {
} }
}, [total, brands])) }, [total, brands]))
let content: ReactNode
if (brands.length) {
content = (
<>
{brands.map(d => <BrandItem data={d} key={d.id} onClick={() => jumpInfo(d.id)}/>)}
<View className='text-center font-24 text-dark mt-3'>{text}</View>
</>
)
} else {
content = <Empty name='暂无品牌入驻'/>
}
return ( return (
<View className='p-2'> <View className='p-2'>
<Spinner enable={loading} overlay/> <Spinner enable={loading} overlay/>
{content} {
brands.length ?
<>
{brands.map(d => <BrandItem data={d} key={d.id} onClick={() => jumpInfo(d.id)}/>)}
<View className='text-center font-24 text-dark mt-3'>{text}</View>
</>
: <Empty name='暂无品牌入驻'/>
}
</View> </View>
) )
} }

@ -1,4 +0,0 @@
export default definePageConfig({
navigationBarTitleText: '',
onReachBottomDistance: 50
})

@ -1,81 +0,0 @@
.botmBox {
z-index: 99;
position: fixed;
bottom: 0;
width: 750rpx;
box-sizing: border-box;
height: 180rpx;
padding-bottom: 60rpx;
display: flex;
justify-content: center;
align-items: center;
background: #F5F8F7;
view {
width: 560rpx;
height: 76rpx;
background: #45D4A8;
border-radius: 38rpx 38rpx 38rpx 38rpx;
color: #fff;
font-weight: 500;
font-size: 40rpx;
text-align: center;
line-height: 76rpx;
}
}
.fixedBox {
position: fixed;
z-index: 100;
top: 0;
width: 100vw;
height: 100vh;
background: linear-gradient(to bottom, rgba(255, 255, 255, 0), rgba(255, 255, 255, 1), rgba(255, 255, 255, 1));
&-inner {
position: absolute;
width: 100vw;
top: 45vh;
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;
}
}
}
.article {
font-size: 30rpx;
display: flex;
margin-bottom: 40rpx;
}
.articleImag {
border-radius: 100rpx;
}
.articleTitle {
font-size: 40rpx;
margin-bottom: 50rpx;
}

@ -1,113 +0,0 @@
import {FC, useEffect, useMemo, useState} from "react";
import {Image, PageContainer, Text, View} from "@tarojs/components";
import Taro, {useRouter} from "@tarojs/taro";
import {ArticleRecord, brandApi} from "@/api";
import styles from './article.module.scss'
import down from '@/static/img/doubleDown.png'
import {Profile} from "@/store";
import {parse} from "@/utils/marked/marked";
import {beforeTime} from "@/utils/time";
import Img from "@/components/image/image";
const article: FC = () => {
const {token} = Profile.useContainer()
const {id} = useRouter().params as unknown as { id: number }
const [show, setShow] = useState(false)
const [articleInfo, setArticleInfo] = useState<ArticleRecord>()
const {children, headings} = useMemo(() => parse(articleInfo?.content || ''), [articleInfo])
const query = Taro.createSelectorQuery()
useEffect(() => {
getData()
}, [id])
const getData = async () => {
Taro.setNavigationBarTitle({title: '疾病文章详情'})
try {
const data = await brandApi.articleInfo(id)
Taro.setNavigationBarTitle({title: data.title})
setArticleInfo(data)
} catch (e) {
}
}
function mao(id: string) {
console.log(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
}
)
}
})
})
}
function helloWorld() {
return (
<>
<View className={styles.botmBox} style={{display: show ? 'none' : 'flex'}} onClick={() => setShow(true)}>
<View></View>
</View>
<View style={{
padding: '10px',
height: !token ? Taro.getWindowInfo().windowHeight - 60 + 'px' : 'auto',
overflow: !token ? 'hidden' : 'auto'
}}>
<View>
<View className={styles.articleTitle}>{articleInfo?.title}</View>
{
articleInfo?.brands.map(d => <View className={styles.article}>
<Img src={d.logo} width={80} height={80} className={styles.articleImag} errorType="avatar"/>
<View className='ml-2'>
<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 || 1}</View>
</View>
</View>
</View>)
}
</View>
<View></View>
{children}
</View>
{
!token &&
<View className={styles.fixedBox}>
<View className={styles['fixedBox-inner']}>
<View className={styles['fixedBox-inner-icon']}>
<Image src={down}></Image>
</View>
<View className={styles['fixedBox-inner-box']}
onClick={() => Taro.navigateTo({url: '/pages/login/login'})}>
<Text></Text>
</View>
</View>
</View>
}
<PageContainer onClickOverlay={() => {
setShow(false)
}} show={show} round={true} overlay={true} overlayStyle={'background:rgba(0,0,0,0.3)'}>
<View className="px-3 py-5">
{headings.length > 0 &&
headings.map((d) =>
<View className="pb-3" style={{fontSize: '28rpx', fontWeight: '500', color: '#323635'}} onClick={() => {
mao(d.id)
}}>{d.text}</View>
)
}
</View>
</PageContainer>
</>
)
}
return helloWorld()
}
export default article

@ -34,7 +34,7 @@ const BrandList: FC = () => {
}, [page]) }, [page])
function jump(id: number) { function jump(id: number) {
Taro.navigateTo({url: '/pages/preview/illness/article/article?id=' + id}) Taro.navigateTo({url: '/pages/preview/brand/article/article?id=' + id})
} }

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

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

@ -1,110 +1,121 @@
import {Input, View, Text, PageContainer} from "@tarojs/components"; import {Input, View, Text, PageContainer, Image} from "@tarojs/components";
import {FC, useEffect, useState} from "react"; import {FC, useEffect, useMemo, useState} from "react";
import { AtIcon } from 'taro-ui'
import styles from './index.module.scss' import styles from './index.module.scss'
import Taro from "@tarojs/taro"; import Taro from "@tarojs/taro";
import { useReady, useDidShow } from '@tarojs/taro' import {useDidShow} from '@tarojs/taro'
import SearchList from './components/list' 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 Search: FC = () => {
const globalData = Taro.getApp().globalData
const [value, setValue] = useState('') const [value, setValue] = useState('')
const [recentSearch, setRecentSearch] = useState<string[]>([]) const [recentSearch, setRecentSearch] = useState<string[]>([])
const [hotSearch,setHotSearch] = useState<any[]>([]) const [hotSearch] = useState<any[]>([])
const [show, setShow] = useState(false) const [show, setShow] = useState(false)
const [focus, setFocus] = useState(false)
useReady(()=>{
console.log('onReady')
})
useDidShow(()=>{
getRecentSearch()
})
useEffect(()=>{ useDidShow(getRecentSearch)
if(!show){
getRecentSearch()
}
},[show])
function inpFn(e){ useEffect(() => {
!show && getRecentSearch()
}, [show])
function inpFn(e) {
setValue(e.detail.value) setValue(e.detail.value)
} }
function clearSearch(){ function clearSearch() {
Taro.removeStorageSync('recentSearch') Taro.removeStorageSync('recentSearch')
getRecentSearch() getRecentSearch()
Taro.showToast({title: '删除成功'})
} }
function getRecentSearch () { function getRecentSearch() {
setRecentSearch(Taro.getStorageSync('recentSearch')) setRecentSearch(Taro.getStorageSync('recentSearch'))
} }
function getSearchItem(value) { function getSearchItem(value) {
setValue(value) setValue(value)
// Taro.navigateTo({
// url:`/pages/preview/search/list/index?name=${value}`
// })
setShow(true) setShow(true)
} }
function searchInput(){ function searchInput() {
if (value === "") return; if (value === "") return;
getSearchItem(value) getSearchItem(value)
//记录最近搜索 //记录最近搜索
let recentSearch = Taro.getStorageSync('recentSearch') || []; let recentSearch = Taro.getStorageSync('recentSearch') || [];
recentSearch.unshift(value); recentSearch.unshift(value);
Taro.setStorageSync('recentSearch', [...new Set(recentSearch)]) Taro.setStorageSync('recentSearch', [...new Set(recentSearch)])
} }
function navBack(){ function cancelSearch(){
Taro.navigateBack() setValue('')
} setShow(false)
setFocus(false)
}
const searchStyles = useMemo((): React.CSSProperties | undefined => {
if (focus || show) {
return {
transform: "translateY(-43px)",
width: "70%",
}
}
}, [focus, show])
return ( return (
<View className="flex flex-column"> <View className="flex flex-column">
<View className={styles.navBox} style={{height:`${globalData.statusBarHeight+globalData.textBarHeight}px`}}> <NavigationBar text='搜索'/>
<View style={{height:`${globalData.statusBarHeight}px`}}></View> <View className={styles.searchHeader} style={searchStyles}>
<View style={{height:`${globalData.textBarHeight}px`,display:'flex',alignItems:'center'}}>
<View className="flex justify-end" style={{width:'40px'}}>
<AtIcon value='chevron-left' size='25' color='#333' onClick={navBack}></AtIcon>
</View>
<View className="font-28 font-weight flex-1" style={{display:'flex',justifyContent:'center',paddingRight:'40px',boxSizing:'border-box'}}></View>
</View>
</View>
<View style={{paddingLeft: '30rpx'}}>
<View style={{height:`${globalData.statusBarHeight+globalData.textBarHeight}px`}}></View>
<View className={styles.searchBox}> <View className={styles.searchBox}>
<AtIcon value='search' size='20' color='#ccc'></AtIcon> <Image src={search} style={{width: '32rpx', height: '32rpx'}} mode='widthFix'/>
{ show ? <Input
<Text className={styles.input} >{value}</Text>: onFocus={() => setFocus(true)}
<Input className={styles.input} placeholder="输入关键字搜索" type={'text'} confirmType={'search'} onInput={inpFn} onConfirm={searchInput} /> onBlur={() => setFocus(false)}
} className={styles.input}
placeholder={(focus || show) ? '' : "输入关键字搜索"}
type='text'
value={value}
confirmType='search'
onInput={inpFn}
onConfirm={searchInput}/>
</View> </View>
{focus || show ? <View className='px-2 text-dark' onClick={cancelSearch}></View> : null}
</View>
{ {
recentSearch.length >= 1 && !show && recentSearch.length >= 1 && !show &&
<> <View className='px-2'>
<View className={styles.titleBox} > <View className={styles.titleBox}>
<Text className={styles.title}></Text> <Text className={styles.title}></Text>
<AtIcon onClick={clearSearch} value='trash' size='16' color='#909795'></AtIcon> <Image
src={del}
mode='widthFix'
style={{width: '16px', height: '16px', padding: '0 20rpx'}}
onClick={clearSearch}/>
</View> </View>
<View className={styles.contentBox}> <View className={styles.contentBox}>
{ {
recentSearch.length && recentSearch.length > 0 &&
recentSearch?.map(d => recentSearch?.map(d =>
<View className={styles.items}> <View className={styles.items}>
<View onClick={()=>{getSearchItem(d)}} className="font-28" >{d}</View> <View onClick={() => getSearchItem(d)} className="font-28">{d}</View>
</View>) </View>)
} }
</View> </View>
</> </View>
} }
{ {
hotSearch.length >= 1 && !show && hotSearch.length >= 1 && !show &&
<> <>
<View className={`flex justify-between ${styles.titleBox}`} > <View className={`flex justify-between ${styles.titleBox}`}>
<Text className="font-32 fwb"></Text> <Text className="font-32 fwb"></Text>
</View> </View>
@ -114,7 +125,9 @@ const Search:FC = () => {
hotSearch.length && hotSearch.length &&
hotSearch.map(d => hotSearch.map(d =>
<View className="py-1 px-2 rounded-40 mr-2 mb-2 bg-warning text-white"> <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 onClick={() => {
getSearchItem(d)
}} className="font-28">{d}</View>
</View>) </View>)
} }
</View> </View>
@ -122,11 +135,15 @@ const Search:FC = () => {
</> </>
} }
<PageContainer onBeforeLeave={() => {setShow(false)}} onClickOverlay={()=>{ setShow(false)}} show={show} round={true} overlay={true} overlayStyle={'background:rgba(0,0,0,0)'} > <PageContainer
<SearchList name={value} clear={show} /> onBeforeLeave={cancelSearch}
onClickOverlay={cancelSearch}
show={show}
round
overlay
overlayStyle={'background:rgba(0,0,0,0)'}>
<SearchList name={value} clear={show}/>
</PageContainer> </PageContainer>
</View>
</View> </View>
) )
} }

Binary file not shown.

After

Width:  |  Height:  |  Size: 424 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 324 B

14
types/user.d.ts vendored

@ -95,5 +95,19 @@ interface HourHistory extends Curriculum {
} }
} }
/**
* 1 2 3 4()
*/
type CreateOwnerType = 1 | 2 | 3 | 4
/** 收藏 */
interface Create {
/**
* id
*/
owner_id: number
owner_type: CreateOwnerType
}

Loading…
Cancel
Save