index.tsx 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385
  1. import MHeader from '@/components/m-header';
  2. import MSticky from '@/components/m-sticky';
  3. import {
  4. ActionBar,
  5. Cell,
  6. CellGroup,
  7. DropdownItem,
  8. DropdownMenu,
  9. Icon,
  10. Image,
  11. List
  12. } from 'vant';
  13. import { defineComponent, onMounted, reactive, ref } from 'vue';
  14. import styles from './index.module.less';
  15. import DropDownModal from './drop-down-modal';
  16. import iconSetting from '@/common/images/icon-setting.png';
  17. import iconMusic from '@/common/images/icon-music.png';
  18. import iconTeacher from '@/common/images/icon-teacher-default.png';
  19. import iconEmpty from './images/icon-empty.png';
  20. import MImagePreview from '@/components/m-image-preview';
  21. import SkeletonModal from './skeleton-modal';
  22. import MEmpty from '@/components/m-empty';
  23. import MFullRefresh from '@/components/m-full-refresh';
  24. import { useRouter } from 'vue-router';
  25. import request from '@/helpers/request';
  26. import dayjs from 'dayjs';
  27. export default defineComponent({
  28. name: 'site-management',
  29. setup() {
  30. const router = useRouter();
  31. const dropDownItemRef = ref();
  32. const dropDownItemRef1 = ref();
  33. const forms = reactive({
  34. isClick: false,
  35. titleTimeValue: [],
  36. titleOrchestraValue: '',
  37. listState: {
  38. dataShow: true, // 判断是否有数据
  39. loading: true,
  40. finished: false,
  41. refreshing: false
  42. },
  43. params: {
  44. startTime: null,
  45. endTime: null,
  46. musicGroupId: '',
  47. page: 1,
  48. rows: 20
  49. },
  50. timeColumns: [],
  51. orchestraColumns: [{ text: '全部乐团', value: '' }], //
  52. imageShow: false,
  53. startPosition: 0,
  54. imagePreview: [] as string[],
  55. pointCourseStatus: false, // 红点
  56. list: []
  57. });
  58. const getInitTimer = (week = 4) => {
  59. const tempTimer: any = [];
  60. for (let i = 0; i < week; i++) {
  61. const startDay = dayjs()
  62. .subtract(i, 'week')
  63. .startOf('week')
  64. .add(1, 'day');
  65. const endDay = dayjs().subtract(i, 'week').endOf('week').add(1, 'day');
  66. tempTimer.push({
  67. text:
  68. startDay.format('YYYY/MM/DD') + ' - ' + endDay.format('YYYY/MM/DD'),
  69. value: [startDay.format('YYYY-MM-DD'), endDay.format('YYYY-MM-DD')]
  70. });
  71. }
  72. // console.log(tempTimer, 'tempTimer');
  73. forms.timeColumns = tempTimer;
  74. forms.titleTimeValue = tempTimer[0].value;
  75. };
  76. const onDropDownClose = (item: any) => {
  77. item.value && item.value.toggle();
  78. };
  79. const formatName = (type: string) => {
  80. if (type === 'orchestra') {
  81. let name = '';
  82. forms.orchestraColumns.forEach((item: any) => {
  83. if (forms.titleOrchestraValue === item.value) {
  84. name = item.text;
  85. }
  86. });
  87. return name;
  88. }
  89. };
  90. const getList = async () => {
  91. try {
  92. if (forms.isClick) return;
  93. forms.isClick = true;
  94. const { data } = await request.post(
  95. '/api-web/classGroup/teachingPointCourse',
  96. {
  97. data: {
  98. ...forms.params,
  99. startTime: forms.titleTimeValue[0] || null,
  100. endTime: forms.titleTimeValue[1] || null
  101. }
  102. }
  103. );
  104. const result = data || {};
  105. // 判断是否有数据
  106. if (forms.listState.refreshing) {
  107. forms.list = result.rows || [];
  108. } else {
  109. forms.list = forms.list.concat(result.rows || []);
  110. }
  111. forms.listState.finished = result.pageNo >= result.totalPage;
  112. forms.params.page = result.pageNo + 1;
  113. } catch {
  114. forms.listState.finished = true;
  115. } finally {
  116. forms.listState.dataShow = forms.list.length > 0;
  117. forms.listState.refreshing = false;
  118. forms.listState.loading = false;
  119. forms.isClick = false;
  120. }
  121. };
  122. // 红点
  123. const teachingPointCourse = async () => {
  124. try {
  125. const { data } = await request.post(
  126. '/api-web/classGroup/teachingPointRemind'
  127. );
  128. forms.pointCourseStatus = data || false;
  129. } catch {
  130. //
  131. }
  132. };
  133. // 乐团列表
  134. const musicGroupPage = async () => {
  135. try {
  136. const { data } = await request.get(
  137. '/api-web/cooperationOrgan/musicGroupPage'
  138. );
  139. (data || []).forEach((item: any) => {
  140. forms.orchestraColumns.push({
  141. text: item.name,
  142. value: item.id
  143. });
  144. });
  145. } catch {
  146. //
  147. }
  148. };
  149. const onRefresh = () => {
  150. forms.params.page = 1;
  151. getList();
  152. };
  153. onMounted(async () => {
  154. musicGroupPage();
  155. getInitTimer();
  156. await getList();
  157. teachingPointCourse();
  158. });
  159. return () => (
  160. <div class={styles.siteManagement}>
  161. <MSticky position="top">
  162. <MHeader>
  163. {{
  164. right: () => (
  165. <Icon
  166. class={styles.iconSetting}
  167. name={iconSetting}
  168. dot={forms.pointCourseStatus}
  169. onClick={() => {
  170. router.push('/site-settings');
  171. }}
  172. />
  173. )
  174. }}
  175. </MHeader>
  176. <DropdownMenu>
  177. <DropdownItem
  178. ref={dropDownItemRef}
  179. v-model={forms.titleTimeValue}
  180. options={forms.timeColumns as any}
  181. onChange={() => {
  182. forms.list = [];
  183. forms.listState.dataShow = true;
  184. onRefresh();
  185. }}></DropdownItem>
  186. <DropdownItem
  187. ref={dropDownItemRef1}
  188. title={formatName('orchestra')}>
  189. <DropDownModal
  190. selectValues={forms.titleOrchestraValue}
  191. columns={forms.orchestraColumns}
  192. open={dropDownItemRef1.value.state.showPopup}
  193. onDropDownClose={() => onDropDownClose(dropDownItemRef1)}
  194. onDropDownConfirm={(values: any) => {
  195. forms.titleOrchestraValue = values[0];
  196. onDropDownClose(dropDownItemRef1);
  197. forms.params.musicGroupId = forms.titleOrchestraValue || '';
  198. forms.list = [];
  199. forms.listState.dataShow = true;
  200. onRefresh();
  201. }}
  202. />
  203. </DropdownItem>
  204. </DropdownMenu>
  205. </MSticky>
  206. <SkeletonModal v-model:show={forms.listState.loading}>
  207. <MFullRefresh
  208. v-model:modelValue={forms.listState.refreshing}
  209. onRefresh={() => onRefresh()}
  210. style={{
  211. minHeight: `calc(100vh - var(--header-height))`
  212. }}>
  213. <List
  214. finished={forms.listState.finished}
  215. finishedText=" "
  216. style={{ overflow: 'hidden' }}
  217. onLoad={getList}
  218. immediateCheck={false}>
  219. {forms.listState.dataShow ? (
  220. forms.list.map((item: any) => {
  221. const signPhotoList = item.signPhoto
  222. ? item.signPhoto.split(',')
  223. : [];
  224. const signOutPhotoList = item.signOutPhoto
  225. ? item.signOutPhoto.split(',')
  226. : [];
  227. return (
  228. <div class={styles.siteItem}>
  229. <CellGroup class={styles.cellGroup} border={false}>
  230. <Cell border={false} center>
  231. {{
  232. title: () => (
  233. <div class={styles.orchestraName}>
  234. <img src={iconMusic} class={styles.iconMusic} />
  235. <p class={styles.overhide}>
  236. {item.musicGroupName}
  237. </p>
  238. </div>
  239. ),
  240. default: () => (
  241. <p class={[styles.address, styles.overhide]}>
  242. {item.teachingPoint}
  243. </p>
  244. )
  245. }}
  246. </Cell>
  247. <Cell center class={styles.username}>
  248. {{
  249. icon: () => (
  250. <Image
  251. src={item.teacherAvatar || iconTeacher}
  252. class={styles.iconTeacher}
  253. fit="contain"
  254. />
  255. ),
  256. title: () => (
  257. <div>
  258. <div class={styles.classname}>
  259. {item.courseName}
  260. </div>
  261. <div class={styles.name}>
  262. {item.teacherName}
  263. </div>
  264. </div>
  265. )
  266. }}
  267. </Cell>
  268. </CellGroup>
  269. <CellGroup class={styles.cellGroup}>
  270. <div class={[styles.photoGroup]}>
  271. <div class={styles.photoUp}>
  272. <h3>
  273. <span class={styles.photoTitle}>课前照片</span>
  274. </h3>
  275. {item.signPhoto ? (
  276. <div class={styles.photoList}>
  277. {signPhotoList.map(
  278. (img: string, index: number) =>
  279. index <= 2 && (
  280. <div
  281. class={styles.photo}
  282. onClick={() => {
  283. forms.imagePreview = signPhotoList;
  284. forms.imageShow = true;
  285. forms.startPosition = index;
  286. }}>
  287. <Image src={img} />
  288. {signPhotoList.length > 3 &&
  289. index === 2 ? (
  290. <div class={styles.photoMore}>
  291. +{signPhotoList.length - 3}
  292. </div>
  293. ) : (
  294. ''
  295. )}
  296. </div>
  297. )
  298. )}
  299. </div>
  300. ) : (
  301. <div class={styles.photoEmpty}>
  302. <img src={iconEmpty} class={styles.iconEmpty} />
  303. <p>老师未上传照片~</p>
  304. </div>
  305. )}
  306. </div>
  307. <div class={styles.photoDown}>
  308. <h3>
  309. <span class={styles.photoTitle}>课后照片</span>
  310. </h3>
  311. {item.signOutPhoto ? (
  312. <div class={styles.photoList}>
  313. {signOutPhotoList.map(
  314. (img: string, index: number) =>
  315. index <= 2 && (
  316. <div
  317. class={styles.photo}
  318. onClick={() => {
  319. forms.imagePreview = signOutPhotoList;
  320. forms.imageShow = true;
  321. forms.startPosition = index;
  322. }}>
  323. <Image
  324. src={img + '@base@tag=imgScale&w=120'}
  325. fit="cover"
  326. />
  327. {signOutPhotoList.length > 3 &&
  328. index === 2 ? (
  329. <div class={styles.photoMore}>
  330. +{signOutPhotoList.length - 3}
  331. </div>
  332. ) : (
  333. ''
  334. )}
  335. </div>
  336. )
  337. )}
  338. </div>
  339. ) : (
  340. <div class={styles.photoEmpty}>
  341. <img src={iconEmpty} class={styles.iconEmpty} />
  342. <p>老师未上传照片~</p>
  343. </div>
  344. )}
  345. </div>
  346. </div>
  347. </CellGroup>
  348. </div>
  349. );
  350. })
  351. ) : (
  352. <MEmpty
  353. style={{
  354. minHeight: `calc(100vh - var(--header-height))`
  355. }}
  356. description="暂无数据"
  357. />
  358. )}
  359. </List>
  360. </MFullRefresh>
  361. </SkeletonModal>
  362. <MImagePreview
  363. v-model:show={forms.imageShow}
  364. images={forms.imagePreview}
  365. startPosition={forms.startPosition}
  366. />
  367. </div>
  368. );
  369. }
  370. });