index.tsx 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308
  1. import {
  2. Button,
  3. Checkbox,
  4. CheckboxGroup,
  5. Icon,
  6. Image,
  7. Loading,
  8. Radio,
  9. RadioGroup,
  10. Sticky,
  11. Toast
  12. } from 'vant'
  13. import { defineComponent, PropType } from 'vue'
  14. import styles from './index.module.less'
  15. import checkBoxActive from '@/teacher/teacher-cert/images/checkbox_active.png'
  16. import checkBoxDefault from '@/teacher/teacher-cert/images/checkbox_default.png'
  17. import ColResult from '@/components/col-result'
  18. export default defineComponent({
  19. name: 'SubjectList',
  20. props: {
  21. onChoice: {
  22. type: Function,
  23. default: (item: any) => {}
  24. },
  25. choiceSubjectIds: {
  26. type: Array,
  27. default: []
  28. },
  29. subjectList: {
  30. type: Array,
  31. default: []
  32. },
  33. max: {
  34. // 最多可选数量
  35. type: Number,
  36. default: 5
  37. },
  38. selectType: {
  39. // 选择类型,Radio:单选,Checkbox:多选
  40. type: String as PropType<'Checkbox' | 'Radio'>,
  41. default: 'Checkbox'
  42. },
  43. single: {
  44. // 单选模式
  45. type: Boolean,
  46. default: false
  47. }
  48. },
  49. data() {
  50. return {
  51. checkBox: [],
  52. checkboxRefs: [] as any,
  53. radio: null as any // 单选
  54. }
  55. },
  56. async mounted() {
  57. if (this.selectType === 'Radio') {
  58. this.radio = this.choiceSubjectIds[0]
  59. } else {
  60. this.checkBox = this.choiceSubjectIds as never[]
  61. }
  62. },
  63. watch: {
  64. choiceSubjectIds(val: any, oldVal) {
  65. // 同步更新显示数据
  66. this.checkBox = [...val] as never[]
  67. }
  68. },
  69. methods: {
  70. onSelect(id: number) {
  71. if (this.selectType === 'Checkbox') {
  72. if (
  73. this.max === this.checkBox.length &&
  74. !this.checkBox.includes(id as never)
  75. ) {
  76. Toast(`乐器最多选择${this.max}个`)
  77. }
  78. this.checkboxRefs[id].toggle()
  79. } else if (this.selectType === 'Radio') {
  80. this.radio = id
  81. }
  82. }
  83. },
  84. render() {
  85. return (
  86. <div class={styles.subjects}>
  87. <div class={styles.subjectContainer}>
  88. {this.subjectList.length ? (
  89. this.selectType === 'Checkbox' ? (
  90. <CheckboxGroup v-model={this.checkBox} max={this.max}>
  91. <div class={styles.subjectMaxLength}>
  92. 最多可选择{this.max}个乐器
  93. </div>
  94. {!this.single &&
  95. this.subjectList.map((item: any) =>
  96. item.subjects && item.subjects.length > 0 ? (
  97. <>
  98. <div class={styles.title}>{item.name}</div>
  99. <div class={styles['subject-list']}>
  100. {item.subjects &&
  101. item.subjects.map((sub: any) => (
  102. <div
  103. class={styles['subject-item']}
  104. onClick={() => this.onSelect(sub.id)}
  105. >
  106. <Image
  107. src={sub.img || 'xxx'}
  108. width="100%"
  109. height="100%"
  110. fit="cover"
  111. v-slots={{
  112. loading: () => (
  113. <Loading type="spinner" size={20} />
  114. )
  115. }}
  116. />
  117. <div class={styles.topBg}>
  118. <Checkbox
  119. name={sub.id}
  120. class={styles.checkbox}
  121. disabled
  122. ref={(el: any) =>
  123. (this.checkboxRefs[sub.id] = el)
  124. }
  125. v-slots={{
  126. icon: (props: any) => (
  127. <Icon
  128. name={
  129. props.checked
  130. ? checkBoxActive
  131. : checkBoxDefault
  132. }
  133. size="20"
  134. />
  135. )
  136. }}
  137. />
  138. <p class={styles.name}>{sub.name}</p>
  139. </div>
  140. </div>
  141. ))}
  142. </div>
  143. </>
  144. ) : null
  145. )}
  146. {this.single ? (
  147. <div class={styles['subject-list']}>
  148. {this.subjectList.map((item: any) => (
  149. <div
  150. class={styles['subject-item']}
  151. onClick={() => this.onSelect(item.id)}
  152. >
  153. <Image
  154. src={item.img || 'xxx'}
  155. width="100%"
  156. height="100%"
  157. fit="cover"
  158. v-slots={{
  159. loading: () => <Loading type="spinner" size={20} />
  160. }}
  161. />
  162. <div class={styles.topBg}>
  163. <Checkbox
  164. name={item.id}
  165. class={styles.checkbox}
  166. disabled
  167. ref={(el: any) => (this.checkboxRefs[item.id] = el)}
  168. v-slots={{
  169. icon: (props: any) => (
  170. <Icon
  171. name={
  172. props.checked
  173. ? checkBoxActive
  174. : checkBoxDefault
  175. }
  176. size="20"
  177. />
  178. )
  179. }}
  180. />
  181. <p class={styles.name}>{item.name}</p>
  182. </div>
  183. </div>
  184. ))}
  185. </div>
  186. ) : null}
  187. </CheckboxGroup>
  188. ) : (
  189. <RadioGroup v-model={this.radio}>
  190. {!this.single &&
  191. this.subjectList.map((item: any) =>
  192. item.subjects && item.subjects.length > 0 ? (
  193. <>
  194. <div class={styles.title}>{item.name}</div>
  195. <div class={styles['subject-list']}>
  196. {item.subjects &&
  197. item.subjects.map((sub: any) => (
  198. <div
  199. class={styles['subject-item']}
  200. onClick={() => this.onSelect(sub.id)}
  201. >
  202. <Image
  203. src={sub.img || 'xxx'}
  204. width="100%"
  205. height="100%"
  206. fit="cover"
  207. v-slots={{
  208. loading: () => (
  209. <Loading type="spinner" size={20} />
  210. )
  211. }}
  212. />
  213. <div class={styles.topBg}>
  214. <Radio
  215. name={sub.id}
  216. class={styles.checkbox}
  217. v-slots={{
  218. icon: (props: any) => (
  219. <Icon
  220. name={
  221. props.checked
  222. ? checkBoxActive
  223. : checkBoxDefault
  224. }
  225. size="20"
  226. />
  227. )
  228. }}
  229. />
  230. <p class={styles.name}>{sub.name}</p>
  231. </div>
  232. </div>
  233. ))}
  234. </div>
  235. </>
  236. ) : null
  237. )}
  238. {this.single ? (
  239. <div class={styles['subject-list']}>
  240. {this.subjectList.map((item: any) => (
  241. <div
  242. class={styles['subject-item']}
  243. onClick={() => this.onSelect(item.id)}
  244. >
  245. <Image
  246. src={item.img || 'xxx'}
  247. width="100%"
  248. height="100%"
  249. fit="cover"
  250. v-slots={{
  251. loading: () => <Loading type="spinner" size={20} />
  252. }}
  253. />
  254. <div class={styles.topBg}>
  255. <Radio
  256. name={item.id}
  257. class={styles.checkbox}
  258. v-slots={{
  259. icon: (props: any) => (
  260. <Icon
  261. name={
  262. props.checked
  263. ? checkBoxActive
  264. : checkBoxDefault
  265. }
  266. size="20"
  267. />
  268. )
  269. }}
  270. />
  271. <p class={styles.name}>{item.name}</p>
  272. </div>
  273. </div>
  274. ))}
  275. </div>
  276. ) : null}
  277. </RadioGroup>
  278. )
  279. ) : (
  280. <ColResult tips="暂无声部数据" btnStatus={false} />
  281. )}
  282. </div>
  283. {this.subjectList.length > 0 && (
  284. <Sticky offsetBottom={0} position="bottom">
  285. <div class={'btnGroup'}>
  286. <Button
  287. round
  288. block
  289. type="primary"
  290. style={{ width: '96%', margin: '0 auto' }}
  291. onClick={() =>
  292. this.onChoice(
  293. this.selectType === 'Checkbox' ? this.checkBox : this.radio
  294. )
  295. }
  296. >
  297. 确定
  298. </Button>
  299. </div>
  300. </Sticky>
  301. )}
  302. </div>
  303. )
  304. }
  305. })