teacher-follow.tsx 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324
  1. import { Cell, Dialog, Icon, Image, List, Rate, Sticky, Toast } from 'vant'
  2. import { defineComponent } from 'vue'
  3. import styles from './model/teacher-header.module.less'
  4. import iconTeacher from '@common/images/icon_teacher.png'
  5. import musicCert from '@common/images/music_cert.png'
  6. import teacherCert from '@common/images/teacher_cert.png'
  7. import request from '@/helpers/request'
  8. import ColResult from '@/components/col-result'
  9. import { postMessage } from '@/helpers/native-message'
  10. import ColSearch from '@/components/col-search'
  11. import IconXueli from '@common/images/icon-xueli.png'
  12. import IconJiaozi from '@common/images/icon-jiaozi.png'
  13. import dayjs from 'dayjs'
  14. export const getAssetsHomeFile = (fileName: string) => {
  15. const path = `./images/${fileName}`
  16. const modules = import.meta.globEager('./images/*')
  17. return modules[path].default
  18. }
  19. export default defineComponent({
  20. name: 'teacher-follow',
  21. data() {
  22. return {
  23. userInfo: {} as any,
  24. starGrade: 0,
  25. subjectNameList: [],
  26. list: [],
  27. dataShow: true, // 判断是否有数据
  28. loading: false,
  29. finished: false,
  30. params: {
  31. username: '',
  32. page: 1,
  33. rows: 20
  34. }
  35. }
  36. },
  37. mounted() {
  38. this.getList()
  39. },
  40. methods: {
  41. getSubjectNameList(subject: string) {
  42. const subjectList = subject.split(',')
  43. return subjectList || []
  44. },
  45. onSearch(val: string) {
  46. this.params.username = val
  47. this.onSort()
  48. },
  49. onSort() {
  50. this.params.page = 1
  51. this.list = []
  52. this.dataShow = true // 判断是否有数据
  53. this.loading = false
  54. this.finished = false
  55. this.getList()
  56. },
  57. async getList() {
  58. try {
  59. const params = this.params
  60. const res = await request.post('/api-student/student/queryMyFollow', {
  61. data: {
  62. ...params
  63. }
  64. })
  65. this.loading = false
  66. const result = res.data || {}
  67. // 处理重复请求数据
  68. if (this.list.length > 0 && result.pageNo === 1) {
  69. return
  70. }
  71. this.list = this.list.concat(result.rows || [])
  72. this.finished = result.pageNo >= result.totalPage
  73. this.params.page = result.pageNo + 1
  74. this.dataShow = this.list.length > 0
  75. } catch {
  76. this.dataShow = false
  77. this.finished = true
  78. }
  79. },
  80. async onUnLike(item: any) {
  81. Dialog.confirm({
  82. message: '确定取消关注吗?',
  83. confirmButtonColor: 'var(--van-primary)'
  84. }).then(async () => {
  85. try {
  86. await request.get('/api-student/teacher/starOrUnStar', {
  87. params: {
  88. userId: item.userId,
  89. starStatus: 0
  90. }
  91. })
  92. Toast('取消关注成功')
  93. setTimeout(() => {
  94. this.onSort()
  95. }, 1000)
  96. } catch {}
  97. })
  98. },
  99. // 检验是否有对应徽章
  100. checkBadge(type: string, item: any) {
  101. // tag : 老师点亮图标
  102. // STYLE:个人风采
  103. // VIDEO:视频课
  104. // LIVE:直播课,
  105. // MUSIC:曲目 逗号隔开
  106. let status = false
  107. switch (type) {
  108. case 'STYLE':
  109. case 'VIDEO':
  110. case 'LIVE':
  111. case 'MUSIC':
  112. if (item.tag) {
  113. status = item.tag.indexOf(type) > -1
  114. }
  115. break
  116. case 'VIP':
  117. if (item.membershipStartTime && item.membershipEndTime) {
  118. const startTime = dayjs(item.membershipStartTime).valueOf()
  119. const endTime = dayjs(item.membershipEndTime).valueOf()
  120. const nowTime = dayjs().valueOf()
  121. status = nowTime >= startTime && nowTime <= endTime
  122. } else {
  123. status = false
  124. }
  125. break
  126. case 'DEGREE':
  127. status = item.degreeFlag ? true : false
  128. break
  129. case 'TEACHER':
  130. status = item.teacherFlag ? true : false
  131. break
  132. default:
  133. status = false
  134. break
  135. }
  136. return status
  137. }
  138. },
  139. render() {
  140. return (
  141. <div class={styles.teacherFollow}>
  142. <Sticky position="top" offsetTop={0}>
  143. <ColSearch onSearch={this.onSearch} />
  144. </Sticky>
  145. {this.dataShow ? (
  146. <List
  147. class={styles.liveList}
  148. v-model:loading={this.loading}
  149. immediateCheck={false}
  150. finished={this.finished}
  151. finishedText="没有更多了"
  152. >
  153. {this.list.map((item: any) => (
  154. <div
  155. class={[styles.headerCount, styles.headerFollow]}
  156. onClick={(e: MouseEvent) => {
  157. e.stopPropagation()
  158. sessionStorage.removeItem('teacherHomeTabs')
  159. this.$router.push({
  160. path: '/teacherHome',
  161. query: {
  162. teacherId: item.userId,
  163. tabs: 'single'
  164. }
  165. })
  166. }}
  167. >
  168. <div class={styles.followContainer}>
  169. <div class={styles.teacherContent}>
  170. <div
  171. class={styles.teacherIcon}
  172. onClick={e => {
  173. // 判断是否在直播中
  174. if (item.liveFlag === 1) {
  175. e.stopPropagation()
  176. postMessage({
  177. api: 'joinLiveRoom',
  178. content: {
  179. roomId: item.roomUid,
  180. teacherId: item.userId
  181. }
  182. })
  183. }
  184. }}
  185. >
  186. <Image
  187. class={[
  188. styles.avatar,
  189. this.checkBadge('VIP', item.teacher) &&
  190. styles.avatarActive
  191. ]}
  192. round
  193. src={item.avatar || iconTeacher}
  194. fit="cover"
  195. />
  196. {item.liveFlag === 1 && (
  197. <p class={styles.liveTag}>直播中</p>
  198. )}
  199. <Image
  200. class={styles.teacherIconVip}
  201. src={
  202. this.checkBadge('VIP', item.teacher)
  203. ? getAssetsHomeFile('vip_active.png')
  204. : getAssetsHomeFile('vip_default.png')
  205. }
  206. />
  207. </div>
  208. </div>
  209. <div>
  210. <div class={styles.teacherInfo}>
  211. <div class={styles.teacherInfoName}>
  212. {item.userName || `游客${item.userId || ''}`}
  213. </div>
  214. {this.checkBadge('DEGREE', item.teacher) && (
  215. <img src={IconXueli} />
  216. )}
  217. {this.checkBadge('TEACHER', item.teacher) && (
  218. <img src={IconJiaozi} />
  219. )}
  220. </div>
  221. <div class={styles.teacherHonor}>
  222. <div>勋章:</div>
  223. <div class={styles.teacherIcons}>
  224. <Image
  225. class={styles.iconOther}
  226. src={
  227. this.checkBadge('STYLE', item.teacher)
  228. ? getAssetsHomeFile('cert_active.png')
  229. : getAssetsHomeFile('cert_default.png')
  230. }
  231. />
  232. <Image
  233. class={styles.iconOther}
  234. src={
  235. this.checkBadge('VIDEO', item.teacher)
  236. ? getAssetsHomeFile('video_active.png')
  237. : getAssetsHomeFile('video_default.png')
  238. }
  239. />
  240. <Image
  241. class={styles.iconOther}
  242. src={
  243. this.checkBadge('LIVE', item.teacher)
  244. ? getAssetsHomeFile('live_active.png')
  245. : getAssetsHomeFile('live_default.png')
  246. }
  247. />
  248. <Image
  249. class={styles.iconOther}
  250. src={
  251. this.checkBadge('MUSIC', item.teacher)
  252. ? getAssetsHomeFile('music_active.png')
  253. : getAssetsHomeFile('music_default.png')
  254. }
  255. />
  256. </div>
  257. <div class={styles.score}>评分: </div>
  258. <div class={styles.level}>
  259. {item.starGrade ? (
  260. <Rate
  261. readonly
  262. modelValue={item.starGrade}
  263. iconPrefix="iconfont"
  264. color="#FFC459"
  265. void-icon="star_default"
  266. icon="star_active"
  267. size={15}
  268. />
  269. ) : (
  270. <span style={{ fontSize: '12px', color: '#999999' }}>
  271. 暂无评分
  272. </span>
  273. )}
  274. </div>
  275. </div>
  276. <div class={styles.piNameSubject}>
  277. <Image
  278. class={styles.subjectSection}
  279. src={getAssetsHomeFile('icon_subject.png')}
  280. fit="contain"
  281. />
  282. <div class={styles.subjectList}>
  283. {this.getSubjectNameList(item.subjectName).map(
  284. (item: any) => (
  285. <span class={styles.subject}>{item}</span>
  286. )
  287. )}
  288. </div>
  289. </div>
  290. </div>
  291. </div>
  292. <div class={styles['teacher-bottom']}>
  293. <div class={styles['teacher-data']}>
  294. <div class={styles['teacher-data_item']}>
  295. 粉丝 <span>{item.fansNum || 0}</span>
  296. </div>
  297. <div class={styles['teacher-data_item']}>
  298. 已上课时 <span>{item.expTime || 0}</span>
  299. </div>
  300. </div>
  301. <div
  302. class={styles.unlinkeBtn}
  303. onClick={(e: MouseEvent) => {
  304. e.stopPropagation()
  305. this.onUnLike(item)
  306. }}
  307. >
  308. 取消关注
  309. </div>
  310. </div>
  311. </div>
  312. ))}
  313. </List>
  314. ) : (
  315. <ColResult btnStatus={false} classImgSize="SMALL" tips="暂无关注" />
  316. )}
  317. </div>
  318. )
  319. }
  320. })