header.tsx 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230
  1. import { Sticky, Cell, Tag, Icon, Popup, Tabs, Tab, Dialog } from 'vant'
  2. import {
  3. RouterView,
  4. useRouter,
  5. useRoute,
  6. onBeforeRouteUpdate
  7. } from 'vue-router'
  8. import { defineComponent, onMounted, reactive, ref, watch } from 'vue'
  9. import mitt from 'mitt'
  10. import Search from '@/components/col-search'
  11. import { useLocalStorage } from '@vueuse/core'
  12. import styles from './index.module.less'
  13. import classNames from 'classnames'
  14. import SelectTag from './select-tag'
  15. import { getRandomKey, musicBuy } from '../music'
  16. import SelectSubject from './select-subject'
  17. import { SubjectEnum, useSubjectId } from '@/helpers/hooks'
  18. import { state } from '@/state'
  19. export const mitter = mitt()
  20. const selectTagRef = ref()
  21. export default defineComponent({
  22. name: 'MusicSearchHeader',
  23. setup() {
  24. const subjects: any = useSubjectId(SubjectEnum.SEARCH)
  25. // 判断是否已有数据
  26. if (!subjects.id) {
  27. const users = state.user.data
  28. const subjectId = users.subjectId
  29. ? Number(users.subjectId.split(',')[0])
  30. : ''
  31. const subjectName = users.subjectName
  32. ? users.subjectName.split(',')[0]
  33. : ''
  34. if (subjectId) {
  35. useSubjectId(
  36. SubjectEnum.SEARCH,
  37. JSON.stringify({
  38. id: subjectId,
  39. name: subjectName
  40. }),
  41. 'set'
  42. )
  43. }
  44. }
  45. const searchInputRef = ref()
  46. localStorage.setItem('behaviorId', getRandomKey())
  47. const router = useRouter()
  48. const route = useRoute()
  49. const keyword = ref('')
  50. const tagids = ref('')
  51. const tagVisibility = ref(false)
  52. const words = useLocalStorage<string[]>('music-search', [])
  53. const activeTab = ref('songe')
  54. onBeforeRouteUpdate(() => {
  55. const getSubject: any = useSubjectId(SubjectEnum.SEARCH)
  56. subject.name = getSubject.name || '全部声部'
  57. subject.id = getSubject.id
  58. if (route.path === '/music-songbook/search') {
  59. keyword.value = ''
  60. tagids.value = ''
  61. activeTab.value = 'songe'
  62. try {
  63. selectTagRef.value?.resetTags?.()
  64. } catch (error) {
  65. console.log(error)
  66. }
  67. }
  68. return true
  69. })
  70. watch(activeTab, val => {
  71. mitter.emit('changeTab', val)
  72. })
  73. const onSearch = val => {
  74. keyword.value = val
  75. const indexOf = words.value.indexOf(val)
  76. if (indexOf > -1) {
  77. words.value.splice(indexOf, 1)
  78. }
  79. if (val) {
  80. words.value.unshift(val)
  81. words.value.length = Math.min(words.value.length, 5)
  82. }
  83. mitter.emit('search', val)
  84. }
  85. const onComfirm = (tags, name = '') => {
  86. const data = Object.values(tags).flat().filter(Boolean).join(',')
  87. tagids.value = data
  88. mitter.emit('confirm', tags)
  89. tagVisibility.value = false
  90. }
  91. const onComfirmSubject = (item: any) => {
  92. // console.log('onSort', item)
  93. subject.name = item.name
  94. subject.id = item.id
  95. useSubjectId(
  96. SubjectEnum.SEARCH,
  97. JSON.stringify({
  98. id: item.id,
  99. name: item.name
  100. }),
  101. 'set'
  102. )
  103. mitter.emit('confirmSubject', subject)
  104. subject.show = false
  105. }
  106. onMounted(() => {})
  107. const getSubject: any = useSubjectId(SubjectEnum.SEARCH)
  108. const subject = reactive({
  109. show: false,
  110. name: getSubject.name || '全部声部',
  111. id: getSubject.id || ''
  112. })
  113. return () => {
  114. return (
  115. <div class={styles.search}>
  116. <Sticky class={styles.sticky}>
  117. <Search
  118. modelValue={keyword.value}
  119. // showAction
  120. ref={searchInputRef}
  121. onSearch={onSearch}
  122. // onFilter={() => (tagVisibility.value = true)}
  123. // filterDot={!!tagids.value}
  124. onClick={() => {
  125. if (route.path === '/music-songbook') {
  126. router.push({
  127. path: '/music-songbook/search'
  128. })
  129. }
  130. }}
  131. v-slots={{
  132. left: () => (
  133. <div
  134. class={styles.label}
  135. onClick={() => (subject.show = true)}
  136. >
  137. {subject.name}
  138. <Icon
  139. classPrefix="iconfont"
  140. name="down"
  141. size={12}
  142. color="#333"
  143. />
  144. </div>
  145. )
  146. }}
  147. />
  148. {route.path === '/music-songbook/search' && (
  149. <Tabs
  150. color="var(--van-primary)"
  151. background="transparent"
  152. lineWidth={20}
  153. shrink
  154. v-model:active={activeTab.value}
  155. onChange={val => (activeTab.value = val)}
  156. >
  157. <Tab title="单曲" name="songe"></Tab>
  158. <Tab title="专辑" name="album"></Tab>
  159. </Tabs>
  160. )}
  161. </Sticky>
  162. {words.value.length > 0 && route.path === '/music-songbook/search' && (
  163. <div class={classNames(styles.keywords, 'van-hairline--bottom')}>
  164. <div class={styles.content}>
  165. {words.value.map(item => (
  166. <Tag
  167. round
  168. class={styles.searchKeyword}
  169. key={item}
  170. onClick={() => onSearch(item)}
  171. >
  172. {item}
  173. </Tag>
  174. ))}
  175. </div>
  176. <Icon
  177. class={styles.remove}
  178. name="delete-o"
  179. onClick={() => (words.value = [])}
  180. />
  181. </div>
  182. )}
  183. <RouterView />
  184. <Popup
  185. show={tagVisibility.value}
  186. round
  187. closeable
  188. position="bottom"
  189. style={{ height: '60%' }}
  190. teleport="body"
  191. onUpdate:show={val => (tagVisibility.value = val)}
  192. >
  193. <SelectTag
  194. ref={selectTagRef}
  195. onConfirm={onComfirm}
  196. onCancel={() => {}}
  197. />
  198. </Popup>
  199. {/* 声部弹框 */}
  200. <Popup
  201. show={subject.show}
  202. position="bottom"
  203. round
  204. closeable
  205. safe-area-inset-bottom
  206. onClose={() => (subject.show = false)}
  207. onClosed={() => (subject.show = false)}
  208. >
  209. <SelectSubject
  210. searchParams={subject}
  211. onComfirm={onComfirmSubject}
  212. />
  213. </Popup>
  214. </div>
  215. )
  216. }
  217. }
  218. })