品牌收藏

v2
king 1 year ago
parent 353e1d51e0
commit ae52d73588
  1. 4
      .env
  2. 3
      src/api/brand.ts
  3. 8
      src/api/user.ts
  4. 65
      src/components/collect/collect.module.scss
  5. 45
      src/components/collect/collect.tsx
  6. 17
      src/pages/business/videoInfo/components/catalogue.tsx
  7. 3
      src/pages/business/videoInfo/videoInfo.scss
  8. 3
      src/pages/index/index.tsx
  9. 2
      src/pages/preview/brand/article/article.tsx
  10. 2
      src/pages/preview/brand/info/info.tsx
  11. 89
      src/pages/preview/brand/list/list.tsx
  12. 23
      src/pages/preview/illness/article/article.module.scss
  13. 51
      src/pages/preview/illness/article/article.tsx
  14. BIN
      src/static/img/catalogue.png
  15. BIN
      src/static/img/omit.png
  16. 14
      types/user.d.ts

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

@ -11,7 +11,8 @@ export type BrandRecord = {
introductory_video_resource: any
article_count: number
created_at: string
page_view:number
page_view: number
collect: boolean
}
export type ArticleRecord = {
title: string

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

@ -3,11 +3,68 @@
align-items: center;
color: #909795;
font-size: 24rpx;
padding: 0 10rpx;
}
.collectImage {
position: relative;
width: 32rpx;
height: 32rpx;
margin-right: 10rpx;
Image {
width: 32rpx;
height: 32rpx;
margin-right: 10rpx;
//vertical-align: middle;
width: 100%;
height: 100%;
}
}
.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 starLine from '@/static/img/starLine.png'
import {Image, View} from "@tarojs/components";
import styles from './collect.module.scss'
import {Profile} from "@/store"
import Taro from "@tarojs/taro";
import {userApi} from "@/api";
interface Props {
onClick?: () => void
select?: boolean
stylesImage?: CSSProperties
styles?: CSSProperties
owner_id: number
owner_type: CreateOwnerType
textHidden?: boolean
}
/** 收藏 */
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 (
<View className={styles.collect}>
<Image src={props.select ? star : starLine}/>
{props.select ? '已收藏' : '收藏'}
<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>
{!props.textHidden && (select ? '已收藏' : '收藏')}
</View>
)
}

@ -12,6 +12,8 @@ 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 Collect from "@/components/collect/collect";
import omit from '@/static/img/omit.png'
interface Props {
data: CourseDepData | null
@ -45,11 +47,6 @@ const Catalogue: FC<Props> = ({data, setHors, id, playId}) => {
}
})
// function onPause() {
// videoEvents.setVideoState('pause')
// }
function jumCurHistory() {
if (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>
: <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>
}

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

@ -8,6 +8,7 @@ import NavigationBar from "@/components/navigationBar/navigationBar";
import Spin from "@/components/spinner";
import Img from "@/components/image/image";
import {beforeTime} from "@/utils/time";
import {isBoolean} from "@tarojs/shared";
const category: TabList[] = [
{title: "企选课程", value: 'is_required'},
@ -42,7 +43,7 @@ const AuditMode: FC = () => {
const [enable, setEnable] = useState(true)
useEffect(() => {
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)
setEnable(false)
})

@ -20,7 +20,7 @@ const article: FC = () => {
const [ultra, setUltra] = useState(true)
const globalData = Taro.getApp().globalData
const pageHeight = globalData.windowHeight - globalData.textBarHeight - globalData.statusBarHeight
const {children} = useMemo(() => parse(articleInfo?.content || ''), [articleInfo])
const {children, headings} = useMemo(() => parse(articleInfo?.content || ''), [articleInfo])
useEffect(() => {
setTimeout(() => {

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

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

@ -4,26 +4,25 @@
bottom: 0;
width: 750rpx;
box-sizing: border-box;
height: 180rpx;
padding-bottom: 60rpx;
height: 150rpx;
padding-bottom: env(safe-area-inset-bottom);
display: flex;
justify-content: center;
justify-content: flex-end;
align-items: center;
background: #F5F8F7;
color: #909795;
font-size: 26rpx;
view {
width: 560rpx;
height: 76rpx;
background: #45D4A8;
border-radius: 38rpx 38rpx 38rpx 38rpx;
color: #fff;
font-weight: 500;
font-size: 40rpx;
View {
padding: 0 10px;
text-align: center;
line-height: 76rpx;
}
}
.articleBox {
padding: 30rpx 30rpx calc(env(safe-area-inset-bottom) + 150rpx) 30rpx;
}
.fixedBox {
position: fixed;
z-index: 100;

@ -8,6 +8,8 @@ import {Profile} from "@/store";
import {parse} from "@/utils/marked/marked";
import {beforeTime} from "@/utils/time";
import Img from "@/components/image/image";
import catalogue from '@/static/img/catalogue.png'
import Collect from "@/components/collect/collect";
const article: FC = () => {
const {token} = Profile.useContainer()
@ -32,7 +34,6 @@ const article: FC = () => {
}
function mao(id: string) {
console.log(id)
setShow(false)
Taro.nextTick(() => {
query.select(`#${id}`).boundingClientRect()
@ -52,13 +53,24 @@ const article: FC = () => {
return (
<>
<View className={styles.botmBox} style={{display: show ? 'none' : 'flex'}} onClick={() => setShow(true)}>
<View></View>
<View>
<Collect
styles={{flexDirection: 'column', justifyContent: 'center', padding: '20rpx'}}
stylesImage={{margin: '0 0 8rpx 0'}}
owner_id={id}
owner_type={1}/>
</View>
<View>
<Image src={catalogue} mode='widthFix' style={{width: '40rpx', height: '40rpx'}}/>
<View></View>
</View>
</View>
<View style={{
padding: '10px',
height: !token ? Taro.getWindowInfo().windowHeight - 60 + 'px' : 'auto',
overflow: !token ? 'hidden' : 'auto'
}}>
<View
className={styles.articleBox}
style={{
height: !token ? Taro.getWindowInfo().windowHeight - 60 + 'px' : 'auto',
overflow: !token ? 'hidden' : 'auto'
}}>
<View>
<View className={styles.articleTitle}>{articleInfo?.title}</View>
{
@ -74,7 +86,6 @@ const article: FC = () => {
</View>)
}
</View>
<View></View>
{children}
</View>
{
@ -92,22 +103,26 @@ const article: FC = () => {
</View>
}
<PageContainer onClickOverlay={() => {
setShow(false)
}} show={show} round={true} overlay={true} overlayStyle={'background:rgba(0,0,0,0.3)'}>
<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>
)
}
{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

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