ソースを参照

Merge branch 'master' of http://git.dayaedu.com/lex/orchestra-app

mo 2 年 前
コミット
e716554882

+ 11 - 3
src/components/o-upload/index.tsx

@@ -1,4 +1,4 @@
-import { closeToast, Icon, Image, showToast, Toast, Uploader } from 'vant'
+import { closeToast, Icon, Image, showLoadingToast, showToast, Uploader } from 'vant'
 import { defineComponent } from 'vue'
 import styles from './index.module.less'
 import ColCropper from '../o-cropper'
@@ -104,6 +104,13 @@ export default defineComponent({
       // 上传文件
       try {
         // 获取签名
+        if (state.platformType === 'SCHOOL') {
+          state.platformApi = '/api-school'
+        } else if (state.platformType === 'TEACHER') {
+          state.platformApi = '/api-teacher'
+        } else if (state.platformType === 'STUDENT') {
+          state.platformApi = '/api-student'
+        }
         const signUrl = state.platformApi + '/open/getUploadSign'
         const tempName = file.name || ''
         const fileName = tempName && tempName.replace(/ /gi, '_')
@@ -122,7 +129,7 @@ export default defineComponent({
             }
           }
         })
-        Toast.loading({
+        showLoadingToast({
           message: '加载中...',
           forbidClick: true,
           loadingType: 'spinner',
@@ -147,7 +154,7 @@ export default defineComponent({
         })
         console.log(getOssUploadUrl(this.bucket) + key)
         const uploadUrl = getOssUploadUrl(this.bucket) + key
-        Toast.clear()
+        closeToast()
         this.$emit('update:modelValue', uploadUrl)
         this.onUploadChange(uploadUrl)
       } catch (error) {
@@ -156,6 +163,7 @@ export default defineComponent({
     }
   },
   render() {
+    console.log(state.platformApi, state.platformType)
     useCustomFieldValue(() => this.modelValue)
     return (
       <div class={styles['uploader-section']}>

+ 16 - 1
src/router/routes-school.ts

@@ -70,6 +70,14 @@ export default [
         }
       },
       {
+        path: '/photo-detail',
+        name: 'photo-detail',
+        component: () => import('@/school/orchestra/compontent/photo-detail'),
+        meta: {
+          title: '相册详情'
+        }
+      },
+      {
         path: '/mass-message',
         name: 'mass-message',
         component: () => import('@/school/mass-message/index'),
@@ -134,6 +142,14 @@ export default [
         }
       },
       {
+        path: '/orchestra-information',
+        name: 'orchestra-information',
+        component: () => import('@/school/orchestra/orchestra-information'),
+        meta: {
+          title: '乐团资讯'
+        }
+      },
+      {
         path: '/exercise-record',
         name: 'exercise-record',
         component: () => import('@/school/exercise-record'),
@@ -165,7 +181,6 @@ export default [
           title: '考勤详情'
         }
       },
-
       {
         path: '/ranking-list',
         name: 'ranking-list',

+ 3 - 5
src/school/companion-teacher/companion-teacher-register.tsx

@@ -337,7 +337,6 @@ export default defineComponent({
               v-model={state.forms.idcardFrontImg}
               readonly
               name="idcardFrontImg"
-              onClick={() => (state.showPicker = true)}
               rules={[{ required: true, message: '请选择身份证照片正面', trigger: 'onChange' }]}
               placeholder="请选择身份证照片正面"
             >
@@ -354,10 +353,9 @@ export default defineComponent({
             <Field
               required
               label="身份证照片反面"
-              v-model={state.forms.idcardFrontImg}
+              v-model={state.forms.idcardBackImg}
               readonly
-              name="idcardFrontImg"
-              onClick={() => (state.showPicker = true)}
+              name="idcardBackImg"
               rules={[{ required: true, message: '请选择身份证照片反面', trigger: 'onChange' }]}
               placeholder="请选择身份证照片反面"
             >
@@ -366,7 +364,7 @@ export default defineComponent({
                   <OUpload
                     style={{ width: '100%' }}
                     tips="上传身份证正面"
-                    v-model:modelValue={state.forms.idcardFrontImg}
+                    v-model:modelValue={state.forms.idcardBackImg}
                   />
                 )
               }}

+ 4 - 5
src/school/main.ts

@@ -12,6 +12,7 @@ import { browser } from '@/helpers/utils'
 
 const app = createApp(App)
 
+
 postMessage(
   {
     api: 'getVersion'
@@ -21,11 +22,9 @@ postMessage(
     console.log(res, 'version')
   }
 )
-
 // import Vconsole from 'vconsole'
 // const vconsole = new Vconsole()
 const paymentType = (window as any).paymentType // 浏览器设置
-
 if (browser().isTeacher || paymentType === 'TEACHER') {
   state.platformType = 'TEACHER'
 } else if (browser().isStudent || paymentType === 'STUDENT') {
@@ -39,10 +38,10 @@ if (browser().isTeacher || paymentType === 'TEACHER') {
 if (state.platformType === 'TEACHER') {
   state.platformApi = '/api-teacher'
 }
-if (state.platformType === 'SCHOOL') {
-  state.platformApi = '/api-school'
-} else {
+if (state.platformType === 'STUDENT') {
   state.platformApi = '/api-student'
+} else {
+  state.platformApi = '/api-school'
 }
 
 app.use(router)

+ 3 - 2
src/school/manage-teacher/manage-teacher-register.tsx

@@ -66,14 +66,15 @@ export default defineComponent({
       state.btnLoading = true
       try {
         const forms = state.forms
-        await request.post('/api-school/open/schoolTeacherStudent/registerTeacher', {
+        await request.post('/api-school/open/schoolStaff/registerTeacher', {
           data: {
             ...forms,
             schoolId: state.id
           }
         })
+        state.submitStatus = true
       } catch {
-        showToast('保存失败,请重试')
+        //
       }
       state.btnLoading = false
     }

+ 3 - 1
src/school/orchestra/compontent/information.module.less

@@ -1,5 +1,6 @@
 .searchBand {
   // margin: 12px 13px;
+  display: inline-block;
   font-size: 14px;
   font-weight: 600;
   color: #333333;
@@ -15,7 +16,8 @@
     font-size: 26px;
     font-weight: bold;
     color: #333;
-    span {
+    i {
+      font-style: normal;
       font-size: 12px;
       color: #333333;
     }

+ 191 - 53
src/school/orchestra/compontent/information.tsx

@@ -1,49 +1,153 @@
 import OSticky from '@/components/o-sticky'
-import { Button, Grid, GridItem, Icon, Image, Popover, Popup } from 'vant'
-import { defineComponent, reactive } from 'vue'
+import { Button, DatePicker, Grid, GridItem, Icon, Image, List, Picker, Popover, Popup } from 'vant'
+import { defineComponent, nextTick, onMounted, reactive } from 'vue'
 import styles from './information.module.less'
 import iconSaveImage from '../images/icon-save-image.png'
 import iconWechat from '../images/icon-wechat.png'
 import OQrcode from '@/components/o-qrcode'
+import request from '@/helpers/request'
+import { useRoute } from 'vue-router'
+import { CountUp } from 'countup.js'
+import OEmpty from '@/components/o-empty'
+import dayjs from 'dayjs'
 
 export default defineComponent({
   name: 'detail-information',
   setup() {
+    const route = useRoute()
     const state = reactive({
+      timeShow: false,
+      currentData: [dayjs().year() + ''],
       showPopover: false,
-      actions: [
-        { text: '全部乐团', color: 'var(--van-primary-color)', value: 'ALL' },
-        { text: '交付团', value: 'DELIVERY' },
-        { text: '晋升团', value: 'PROMOTION' }
-      ],
+      actionText: '上学期',
+      actionType: 'up',
       actionTerm: [
-        { text: '上学期', color: 'var(--van-primary-color)', value: 'ALL' },
-        { text: '下学期', value: 'DELIVERY' }
+        { text: '上学期', color: 'var(--van-primary-color)', value: 'up' },
+        { text: '下学期', value: 'down' }
       ],
       oPopover: false,
       check: [],
       checkboxRefs: [] as any,
-      showQrcode: false
+      showQrcode: false,
+      isLoading: false,
+      list: [] as any,
+      listState: {
+        dataShow: true, // 判断是否有数据
+        loading: false,
+        finished: false
+      },
+
+      params: {
+        startTime: dayjs().year() + '-03-01 00:00:00',
+        endTime: dayjs().year() + '-09-01 00:00:00',
+        page: 1,
+        rows: 20
+      }
+    })
+
+    // 选择学期
+    const onSelect = (val: any) => {
+      console.log(val)
+      state.actionTerm.forEach((item: any) => {
+        item.color = null
+      })
+      val.color = 'var(--van-primary-color)'
+      state.actionText = val.text
+      state.actionType = val.value
+      if (val === 'up') {
+        state.params.startTime = dayjs().year() + '-03-01 00:00:00'
+        state.params.endTime = dayjs().year() + '-09-01 00:00:00'
+      } else if (val === 'down') {
+        state.params.startTime = dayjs().year() + '-09-01 00:00:00'
+        state.params.endTime = dayjs().add(1, 'year').year() + '-03-01 00:00:00'
+      }
+      onSearch()
+    }
+
+    const onConfirmDate = (date: any) => {
+      state.currentData = date.selectedValues
+      if (state.actionType == 'up') {
+        state.params.startTime = date.selectedValues[0] + '-03-01 00:00:00'
+        state.params.endTime = date.selectedValues[0] + '-09-01 00:00:00'
+      } else if (state.actionType == 'down') {
+        state.params.startTime = date.selectedValues[0] + 1 + '-03-01 00:00:00'
+        state.params.endTime = date.selectedValues[0] + 1 + '-09-01 00:00:00'
+      }
+      state.timeShow = false
+      console.log(state.params)
+      onSearch()
+    }
+
+    const getDetails = async () => {
+      try {
+        const { data } = await request.get('/api-school/orchestra/detail/' + route.query.id)
+        // console.log(data)
+      } catch {
+        //
+      }
+    }
+
+    // 班级列表
+    const getList = async () => {
+      try {
+        if (state.isLoading) return
+        state.isLoading = true
+        const res = await request.post('/api-school/classGroup/page', {
+          data: {
+            ...state.params,
+            orchestraId: route.query.id
+          }
+        })
+        state.listState.loading = false
+        const result = res.data || {}
+        // 处理重复请求数据
+        if (state.list.length > 0 && result.pageNo === 1) {
+          return
+        }
+        const rows = result.rows || []
+        state.list = state.list.concat(rows)
+        state.listState.finished = result.current >= result.pages
+        state.params.page = result.current + 1
+        state.listState.dataShow = state.list.length > 0
+        state.isLoading = false
+      } catch {
+        state.listState.dataShow = false
+        state.listState.finished = true
+        state.isLoading = false
+      }
+    }
+
+    const onSearch = () => {
+      state.params.page = 1
+      state.list = []
+      state.listState.dataShow = true // 判断是否有数据
+      state.listState.loading = false
+      state.listState.finished = false
+      getList()
+    }
+
+    const initNumCountUp = () => {
+      nextTick(() => {
+        // 在读学生
+        new CountUp('currentStudentNum', Math.random() * 1000).start()
+        new CountUp('time1', Math.random() * 100).start()
+        new CountUp('time2', Math.random() * 100).start()
+        new CountUp('time3', Math.random() * 100).start()
+      })
+    }
+
+    onMounted(() => {
+      getDetails()
+      getList()
+      initNumCountUp()
     })
+
     return () => (
       <>
         <div style={{ padding: '12px 13px 16px', background: '#F8F8F8' }}>
-          <Popover
-            v-model:show={state.showPopover}
-            actions={state.actions}
-            showArrow={false}
-            placement="bottom-start"
-            offset={[0, 12]}
-            style={{ zIndex: '9999' }}
-          >
-            {{
-              reference: () => (
-                <div class={styles.searchBand}>
-                  全部乐团 <Icon name={state.showPopover ? 'arrow-up' : 'arrow-down'} />
-                </div>
-              )
-            }}
-          </Popover>
+          <div class={styles.searchBand} onClick={() => (state.timeShow = true)}>
+            {state.currentData[0]}年 <Icon name={state.showPopover ? 'arrow-up' : 'arrow-down'} />
+          </div>
           <Popover
             v-model:show={state.oPopover}
             actions={state.actionTerm}
@@ -51,11 +155,12 @@ export default defineComponent({
             placement="bottom"
             offset={[0, 12]}
             style={{ zIndex: '9999' }}
+            onSelect={onSelect}
           >
             {{
               reference: () => (
                 <div class={styles.searchBand} style="margin-left: 16px">
-                  上学期 <Icon name={state.oPopover ? 'arrow-up' : 'arrow-down'} />
+                  {state.actionText} <Icon name={state.oPopover ? 'arrow-up' : 'arrow-down'} />
                 </div>
               )
             }}
@@ -65,46 +170,68 @@ export default defineComponent({
         <Grid border={false} class={styles.gridContainer}>
           <GridItem>
             <p class={[styles.title, styles.red]}>
-              92<span>名</span>
+              <span id="currentStudentNum">0</span>
+              <i>名</i>
             </p>
             <p class={styles.name}>在读学生</p>
           </GridItem>
           <GridItem>
-            <p class={[styles.title, styles.red]}>92%</p>
+            <p class={[styles.title, styles.red]}>
+              <span id="time1">0</span>%
+            </p>
             <p class={styles.name}>到课率</p>
           </GridItem>
           <GridItem>
-            <p class={[styles.title, styles.red]}>92%</p>
+            <p class={[styles.title, styles.red]}>
+              <span id="time2">0</span>%
+            </p>
             <p class={styles.name}>作业提交率</p>
           </GridItem>
           <GridItem>
-            <p class={[styles.title, styles.red]}>92%</p>
+            <p class={[styles.title, styles.red]}>
+              <span id="time3">0</span>%
+            </p>
             <p class={styles.name}>练习合格率</p>
           </GridItem>
         </Grid>
 
-        {[1, 2, 3, 4, 5, 6].map((val: any) => (
-          <div class={[styles.gridContainer, styles.gridClass]}>
-            <div class={styles.className}>
-              <i class={styles.line}></i>
-              长笛班
-            </div>
-            <Grid border={false} columnNum={3}>
-              <GridItem>
-                <p class={styles.title}>18</p>
-                <p class={styles.name}>在读学生</p>
-              </GridItem>
-              <GridItem>
-                <p class={[styles.title, styles.teacher]}>张老师</p>
-                <p class={styles.name}>伴学指导</p>
-              </GridItem>
-              <GridItem>
-                <p class={styles.title}>10/16</p>
-                <p class={styles.name}>课时</p>
-              </GridItem>
-            </Grid>
-          </div>
-        ))}
+        {state.listState.dataShow ? (
+          <List
+            v-model:loading={state.listState.loading}
+            finished={state.listState.finished}
+            finishedText=" "
+            class={[styles.liveList]}
+            onLoad={getList}
+            immediateCheck={false}
+          >
+            {state.list.map((item: any) => (
+              <div class={[styles.gridContainer, styles.gridClass]}>
+                <div class={styles.className}>
+                  <i class={styles.line}></i>
+                  {item.name}
+                </div>
+                <Grid border={false} columnNum={3}>
+                  <GridItem>
+                    <p class={styles.title}>{item.preStudentNum || 0}</p>
+                    <p class={styles.name}>在读学生</p>
+                  </GridItem>
+                  <GridItem>
+                    <p class={[styles.title, styles.teacher]}>{item.teacherName || '/'}</p>
+                    <p class={styles.name}>伴学指导</p>
+                  </GridItem>
+                  <GridItem>
+                    <p class={styles.title}>
+                      {item.completeCourseScheduleNum || 0}/{item.courseScheduleNum || 0}
+                    </p>
+                    <p class={styles.name}>课时</p>
+                  </GridItem>
+                </Grid>
+              </div>
+            ))}
+          </List>
+        ) : (
+          <OEmpty btnStatus={false} classImgSize="SMALL" tips="暂无班级" />
+        )}
 
         <OSticky position="bottom">
           <div class={'btnGroup'}>
@@ -164,6 +291,17 @@ export default defineComponent({
             </div>
           </div>
         </Popup>
+
+        <Popup v-model:show={state.timeShow} position="bottom" round>
+          <DatePicker
+            v-model={state.currentData}
+            columnsType={['year']}
+            minDate={new Date(2010, 0, 1)}
+            maxDate={new Date(2055, 11, 31)}
+            onConfirm={onConfirmDate}
+            onCancel={() => (state.timeShow = false)}
+          />
+        </Popup>
       </>
     )
   }

+ 0 - 30
src/school/orchestra/compontent/phone.tsx

@@ -1,30 +0,0 @@
-import { Button, Image } from 'vant'
-import { defineComponent } from 'vue'
-import styles from './phone.module.less'
-
-export default defineComponent({
-  name: 'phone',
-  setup() {
-    return () => (
-      <div class={styles.phone}>
-        <Button icon="plus" block class={styles.addPhone}>
-          新建相册
-        </Button>
-
-        <div class={styles.phoneContainer}>
-          {[1, 2, 3, 4, 5, 6].map((item: any) => (
-            <div class={styles.item}>
-              <Image
-                class={styles.img}
-                src="https://daya.ks3-cn-beijing.ksyuncs.com/12/1670231208704.png"
-              />
-
-              <p class={styles.name}>2021年上学期</p>
-              <p class={styles.num}>80张</p>
-            </div>
-          ))}
-        </div>
-      </div>
-    )
-  }
-})

+ 95 - 0
src/school/orchestra/compontent/photo-detail.module.less

@@ -0,0 +1,95 @@
+.phoneDetail {
+  // padding: 13px;
+  --van-uploader-size: 92px !important;
+
+  .addPhone {
+    margin: 13px;
+    width: calc(100% - 26px);
+    color: var(--van-primary-text);
+    border-color: #fff;
+    border-radius: 10px;
+    font-size: 16px;
+  }
+
+  .phoneContainer {
+    display: flex;
+    justify-content: space-between;
+    flex-wrap: wrap;
+    margin: 0 13px;
+    .item {
+      margin-top: 12px;
+      position: relative;
+      .img {
+        width: 170px;
+        height: 170px;
+        border-radius: 10px;
+        overflow: hidden;
+        position: relative;
+      }
+    }
+
+    .itemBorder .img::before {
+      content: ' ';
+      position: absolute;
+      border-radius: 10px;
+      border: 2px solid #64a9ff;
+      z-index: 10;
+      top: 0;
+      left: 0;
+      right: 0;
+      bottom: 0;
+    }
+
+    --van-checkbox-border-color: transparent;
+    position: relative;
+    :global {
+      .van-checkbox {
+        position: absolute;
+        top: 16px;
+        right: 10px;
+        z-index: 9;
+        height: 25px;
+      }
+      .van-checkbox__icon--checked {
+        .van-icon {
+          border-color: #64a9ff;
+        }
+      }
+    }
+    .checkboxHide {
+      opacity: 0;
+    }
+    .iconChecked {
+      font-size: 18px;
+      border: 1px solid transparent;
+      :global {
+        .van-icon__image {
+          width: 100%;
+          height: 100%;
+        }
+      }
+    }
+  }
+
+  .dialogTitle {
+    i {
+      display: inline-block;
+      width: 4px;
+      height: 14px;
+      background: #ff8057;
+      border-radius: 2px;
+      margin-right: 6px;
+    }
+
+    text-align: left;
+    font-size: 18px;
+    font-weight: 500;
+    color: #333333;
+    line-height: 25px;
+    padding: 20px 0 20px 25px;
+  }
+}
+
+.photos {
+  padding: 0 16px 16px;
+}

+ 371 - 0
src/school/orchestra/compontent/photo-detail.tsx

@@ -0,0 +1,371 @@
+import OEmpty from '@/components/o-empty'
+import OHeader from '@/components/o-header'
+import OSticky from '@/components/o-sticky'
+import request from '@/helpers/request'
+import {
+  Button,
+  Checkbox,
+  CheckboxGroup,
+  closeToast,
+  Icon,
+  Image,
+  List,
+  Popup,
+  showDialog,
+  showImagePreview,
+  showLoadingToast,
+  showToast,
+  Uploader
+} from 'vant'
+import { defineComponent, onMounted, reactive } from 'vue'
+import { useRoute } from 'vue-router'
+import styles from './photo-detail.module.less'
+import iconDelete from '../images/icon-delete.png'
+import umiRequest from 'umi-request'
+import { getOssUploadUrl } from '@/state'
+import checkboxCheck from '../images/icon-checkbox-active.png'
+import checkboxDefault from '@/common/images/icon-checkbox-default.png'
+
+export default defineComponent({
+  name: 'photo-detail',
+  setup() {
+    const route = useRoute()
+    const state = reactive({
+      isEdit: false,
+      isLoading: false,
+      list: [] as any,
+      listState: {
+        dataShow: true, // 判断是否有数据
+        loading: false,
+        finished: false
+      },
+      params: {
+        page: 1,
+        rows: 20
+      },
+
+      showPhoto: false,
+      bucket: 'daya',
+      fileList: [] as any,
+      checkboxRefs: [] as any,
+      check: [] as any
+    })
+
+    const getList = async () => {
+      try {
+        if (state.isLoading) return
+        state.isLoading = true
+        const res = await request.post('/api-school/orchestraPhoto/page', {
+          data: {
+            ...state.params,
+            orchestraPhotoAlbumId: route.query.photoId
+          }
+        })
+        state.listState.loading = false
+        const result = res.data || {}
+        // 处理重复请求数据
+        if (state.list.length > 0 && result.pageNo === 1) {
+          return
+        }
+        const rows = result.rows || []
+        state.list = state.list.concat(rows)
+        state.listState.finished = result.current >= result.pages
+        state.params.page = result.current + 1
+        state.listState.dataShow = state.list.length > 0
+        state.isLoading = false
+      } catch {
+        state.listState.dataShow = false
+        state.listState.finished = true
+        state.isLoading = false
+      }
+    }
+
+    const beforeRead = (file: any) => {
+      // console.log(file, 'beforeRead')
+      const isLt2M = file.size / 1024 / 1024 < 5
+      if (!isLt2M) {
+        showToast(`上传文件大小不能超过 5MB`)
+        return false
+      }
+      return true
+    }
+    const beforeDelete = (file: any, detail: { index: any }) => {
+      // this.dataModel.splice(detail.index, 1)
+      return true
+    }
+    const afterRead = async (file: any, detail: any) => {
+      try {
+        file.status = 'uploading'
+        file.message = '上传中...'
+        await uploadFile(file)
+      } catch (error) {
+        //
+        closeToast()
+      }
+    }
+
+    const uploadFile = async (files: any) => {
+      // 上传文件
+      try {
+        console.log(files, 'files')
+        const file = files.file
+        // 获取签名
+        const signUrl = '/api-school/open/getUploadSign'
+        const tempName = file.name || ''
+        const fileName = tempName && tempName.replace(/ /gi, '_')
+        const key = new Date().getTime() + fileName
+
+        const res = await request.post(signUrl, {
+          data: {
+            filename: fileName,
+            bucketName: state.bucket,
+            postData: {
+              filename: fileName,
+              acl: 'public-read',
+              key: key,
+              unknowValueField: []
+            }
+          }
+        })
+        showLoadingToast({
+          message: '加载中...',
+          forbidClick: true,
+          loadingType: 'spinner',
+          duration: 0
+        })
+        const obj = {
+          policy: res.data.policy,
+          signature: res.data.signature,
+          key: key,
+          KSSAccessKeyId: res.data.kssAccessKeyId,
+          acl: 'public-read',
+          name: fileName
+        }
+        const formData = new FormData()
+        for (const key in obj) {
+          formData.append(key, obj[key])
+        }
+        formData.append('file', file, fileName)
+        await umiRequest(getOssUploadUrl(state.bucket), {
+          method: 'POST',
+          data: formData
+        })
+        // console.log(getOssUploadUrl(state.bucket) + key)
+        const uploadUrl = getOssUploadUrl(state.bucket) + key
+        closeToast()
+
+        // state.fileList.push({ url: uploadUrl })
+        files.src = uploadUrl
+        files.status = 'done'
+      } catch (error) {
+        files.status = 'failed'
+        console.log(error, 'uploadFile')
+      }
+    }
+
+    // 上传图片
+    const onSubmitPhoto = async () => {
+      try {
+        const files = state.fileList.map((file: any) => {
+          return file.src
+        })
+        console.log(files, 'onSubmitPhoto')
+
+        await request.post('/api-school/orchestraPhoto/save', {
+          data: {
+            orchestraPhotoAlbumId: route.query.photoId,
+            fileUrl: files.join(',')
+          }
+        })
+
+        setTimeout(() => {
+          showToast('添加成功')
+          state.showPhoto = false
+          state.fileList = []
+        }, 100)
+        setTimeout(() => {
+          state.params.page = 1
+          state.list = []
+          state.listState.dataShow = true // 判断是否有数据
+          state.listState.loading = false
+          state.listState.finished = false
+          getList()
+        }, 1100)
+      } catch {
+        //
+      }
+    }
+
+    // 预览图片
+    const onShowImage = (index: number) => {
+      const files = state.list.map((file: any) => {
+        return file.fileUrl
+      })
+
+      showImagePreview({
+        images: files,
+        startPosition: index,
+        closeable: true
+      })
+    }
+
+    // 选择照片
+    const onSelect = (type: string) => {
+      state.checkboxRefs[type].toggle()
+    }
+
+    // 删除
+    const onRemove = () => {
+      if (state.check.length <= 0) {
+        showToast('请选择需要删除的图片')
+        return
+      }
+      showDialog({
+        title: '确认删除',
+        message: '删除选择的照片',
+        confirmButtonText: '确认',
+        showCancelButton: true
+      }).then(async () => {
+        console.log(state.check, 'check')
+        try {
+          await request.post('/api-school/orchestraPhoto/remove', {
+            requestType: 'form',
+            data: {
+              ids: state.check.join(',')
+            }
+          })
+
+          setTimeout(() => {
+            showToast('删除成功')
+          }, 100)
+          setTimeout(() => {
+            state.params.page = 1
+            state.list = []
+            state.listState.dataShow = true // 判断是否有数据
+            state.listState.loading = false
+            state.listState.finished = false
+            getList()
+          }, 1100)
+        } catch {
+          //
+        }
+      })
+    }
+
+    onMounted(() => {
+      getList()
+    })
+
+    return () => (
+      <div class={styles.phoneDetail}>
+        <OHeader title={(route.query.name as any) || ''}>
+          {{
+            right: () => (
+              <Icon name={iconDelete} size={22} onClick={() => (state.isEdit = !state.isEdit)} />
+            )
+          }}
+        </OHeader>
+
+        <Button icon="plus" block class={styles.addPhone} onClick={() => (state.showPhoto = true)}>
+          上传照片
+        </Button>
+
+        {state.listState.dataShow ? (
+          <List
+            v-model:loading={state.listState.loading}
+            finished={state.listState.finished}
+            finishedText=" "
+            onLoad={getList}
+            immediateCheck={false}
+          >
+            <CheckboxGroup class={styles.phoneContainer} v-model={state.check}>
+              {state.list.map((item: any, index: number) => (
+                <div
+                  class={[styles.item, state.check.includes(item.id) && styles.itemBorder]}
+                  onClick={() => {
+                    if (!state.isEdit) {
+                      onShowImage(index)
+                    } else {
+                      onSelect(item.id)
+                    }
+                  }}
+                >
+                  <Checkbox
+                    name={item.id}
+                    checkedColor="#64a9ff"
+                    class={[styles.checkbox, !state.isEdit && styles.checkboxHide]}
+                    ref={(el: any) => (state.checkboxRefs[item.id] = el)}
+                    onClick={(e: any) => {
+                      e.stopPropagation()
+                    }}
+                    v-slots={{
+                      icon: (props: any) => (
+                        <Icon
+                          class={styles.iconChecked}
+                          name={props.checked ? checkboxCheck : checkboxDefault}
+                        />
+                      )
+                    }}
+                  />
+                  <Image class={styles.img} src={item.fileUrl} />
+                </div>
+              ))}
+            </CheckboxGroup>
+          </List>
+        ) : (
+          <OEmpty btnStatus={false} classImgSize="SMALL" tips="暂无相片" />
+        )}
+
+        {state.isEdit && (
+          <OSticky position="bottom">
+            <div class={'btnGroup'}>
+              <Button size="large" block round type="primary" onClick={onRemove}>
+                删除
+              </Button>
+            </div>
+          </OSticky>
+        )}
+
+        <Popup v-model:show={state.showPhoto} round style={{ width: '92%' }}>
+          <div class={styles.container}>
+            <div class={styles.dialogTitle}>
+              <i></i>
+              上传照片
+            </div>
+
+            <div class={styles.photos}>
+              <Uploader
+                v-model={state.fileList}
+                afterRead={afterRead}
+                beforeRead={beforeRead}
+                beforeDelete={beforeDelete}
+                accept="image/*"
+                maxCount={9}
+              />
+            </div>
+
+            <div class={['van-hairline--top van-dialog__footer']}>
+              <Button
+                onClick={() => {
+                  state.showPhoto = false
+                  state.fileList = []
+                }}
+                class={['van-button van-button--default van-button--large van-dialog__cancel']}
+              >
+                取消
+              </Button>
+              <Button
+                onClick={onSubmitPhoto}
+                class={[
+                  'van-button van-button--default van-button--large van-dialog__confirm van-hairline--left'
+                ]}
+              >
+                确认
+              </Button>
+            </div>
+          </div>
+        </Popup>
+      </div>
+    )
+  }
+})

+ 34 - 0
src/school/orchestra/compontent/phone.module.less → src/school/orchestra/compontent/photo.module.less

@@ -21,11 +21,21 @@
       border-radius: 10px;
       overflow: hidden;
     }
+    .default {
+      display: flex;
+      align-items: center;
+      justify-content: center;
+      background: #eaeaea;
+      .defaultImg {
+        width: 41px;
+      }
+    }
     .name {
       padding: 6px 0 4px;
       font-size: 16px;
       font-weight: 500;
       color: #333333;
+      max-width: 168px;
     }
     .num {
       font-size: 12px;
@@ -34,3 +44,27 @@
     }
   }
 }
+
+.dialogTitle {
+  i {
+    display: inline-block;
+    width: 4px;
+    height: 14px;
+    background: #ff8057;
+    border-radius: 2px;
+    margin-right: 6px;
+  }
+
+  text-align: left;
+  font-size: 18px;
+  font-weight: 500;
+  color: #333333;
+  line-height: 25px;
+  padding: 20px 0 20px 25px;
+}
+.phoneName {
+  background: #f2f2f2;
+  border-radius: 10px;
+  margin: 0 15px 30px;
+  width: auto;
+}

+ 174 - 0
src/school/orchestra/compontent/photo.tsx

@@ -0,0 +1,174 @@
+import OEmpty from '@/components/o-empty'
+import request from '@/helpers/request'
+import { Button, Dialog, Field, Image, List, Popup, showToast } from 'vant'
+import { defineComponent, onMounted, reactive } from 'vue'
+import { useRoute, useRouter } from 'vue-router'
+import styles from './photo.module.less'
+import iconPhoneDefaut from '../images/icon-photo-default.png'
+
+export default defineComponent({
+  name: 'phone',
+  setup() {
+    const route = useRoute()
+    const router = useRouter()
+    const state = reactive({
+      status: false,
+      isLoading: false,
+      photoName: null, // 相册名称
+      list: [] as any,
+      listState: {
+        dataShow: true, // 判断是否有数据
+        loading: false,
+        finished: false
+      },
+
+      params: {
+        page: 1,
+        rows: 20
+      }
+    })
+
+    const onAddPhoto = async () => {
+      try {
+        if (!state.photoName) {
+          showToast('请输入相册名称')
+          state.status = true
+          return
+        }
+        await request.post('/api-school/orchestraPhotoAlbum/save', {
+          data: {
+            orchestraId: route.query.id,
+            name: state.photoName
+          }
+        })
+        setTimeout(() => {
+          showToast('添加成功')
+          state.status = false
+        }, 100)
+        setTimeout(() => {
+          state.params.page = 1
+          state.list = []
+          state.listState.dataShow = true // 判断是否有数据
+          state.listState.loading = false
+          state.listState.finished = false
+          getList()
+        }, 1100)
+      } catch {
+        //
+      }
+    }
+
+    // 班级列表
+    const getList = async () => {
+      try {
+        if (state.isLoading) return
+        state.isLoading = true
+        const res = await request.post('/api-school/orchestraPhotoAlbum/page', {
+          data: {
+            ...state.params,
+            orchestraId: route.query.id
+          }
+        })
+        state.listState.loading = false
+        const result = res.data || {}
+        // 处理重复请求数据
+        if (state.list.length > 0 && result.pageNo === 1) {
+          return
+        }
+        const rows = result.rows || []
+        state.list = state.list.concat(rows)
+        state.listState.finished = result.current >= result.pages
+        state.params.page = result.current + 1
+        state.listState.dataShow = state.list.length > 0
+        state.isLoading = false
+      } catch {
+        state.listState.dataShow = false
+        state.listState.finished = true
+        state.isLoading = false
+      }
+    }
+
+    const onDetail = (item: any) => {
+      sessionStorage.setItem('orchestra-detail-tab', 'photo')
+      router.push({
+        path: '/photo-detail',
+        query: {
+          photoId: item.id,
+          name: item.name
+        }
+      })
+    }
+
+    onMounted(() => {
+      getList()
+    })
+    return () => (
+      <div class={styles.phone}>
+        <Button icon="plus" block class={styles.addPhone} onClick={() => (state.status = true)}>
+          新建相册
+        </Button>
+
+        {state.listState.dataShow ? (
+          <List
+            v-model:loading={state.listState.loading}
+            finished={state.listState.finished}
+            finishedText=" "
+            onLoad={getList}
+            immediateCheck={false}
+          >
+            <div class={styles.phoneContainer}>
+              {state.list.map((item: any) => (
+                <div class={styles.item} onClick={() => onDetail(item)}>
+                  {item.coverUrl ? (
+                    <Image class={styles.img} src={item.coverUrl} />
+                  ) : (
+                    <div class={[styles.img, styles.default]}>
+                      <Image src={iconPhoneDefaut} class={styles.defaultImg} />
+                    </div>
+                  )}
+
+                  <p class={[styles.name, 'van-ellipsis']}>{item.name}</p>
+                  <p class={styles.num}>{item.photoCount}张</p>
+                </div>
+              ))}
+            </div>
+          </List>
+        ) : (
+          <OEmpty btnStatus={false} classImgSize="SMALL" tips="暂无相册" />
+        )}
+
+        <Popup v-model:show={state.status} round style={{ width: '80%' }}>
+          <div class={styles.container}>
+            <div class={styles.dialogTitle}>
+              <i></i>
+              新建相册
+            </div>
+            <Field
+              class={styles.phoneName}
+              v-model={state.photoName}
+              placeholder="请输入相册名称"
+              maxlength={15}
+            />
+
+            <div class={['van-hairline--top van-dialog__footer']}>
+              <Button
+                onClick={() => (state.status = false)}
+                class={['van-button van-button--default van-button--large van-dialog__cancel']}
+              >
+                取消
+              </Button>
+              <Button
+                onClick={onAddPhoto}
+                class={[
+                  'van-button van-button--default van-button--large van-dialog__confirm van-hairline--left'
+                ]}
+              >
+                确认
+              </Button>
+            </div>
+          </div>
+        </Popup>
+      </div>
+    )
+  }
+})

+ 206 - 40
src/school/orchestra/compontent/plan.tsx

@@ -1,54 +1,220 @@
-import { Cell, Icon, Image } from 'vant'
-import { defineComponent, reactive } from 'vue'
+import OEmpty from '@/components/o-empty'
+import request from '@/helpers/request'
+import dayjs from 'dayjs'
+import { Cell, DatePicker, Icon, Image, List, Popover, Popup } from 'vant'
+import { defineComponent, onMounted, reactive } from 'vue'
+import { useRoute } from 'vue-router'
 import styles from './plan.module.less'
+import iconTeacher from '@common/images/icon_teacher.png'
 
 export default defineComponent({
   name: 'plan',
   setup() {
+    const route = useRoute()
     const state = reactive({
+      timeShow: false,
+      currentData: [dayjs().year() + ''],
       showPopover: false,
-      oPopover: false
+      actionText: '上学期',
+      actionType: 'up',
+      actionTerm: [
+        { text: '上学期', color: 'var(--van-primary-color)', value: 'up' },
+        { text: '下学期', value: 'down' }
+      ],
+      oPopover: false,
+      check: [],
+      checkboxRefs: [] as any,
+      showQrcode: false,
+      isLoading: false,
+      list: [] as any,
+      listState: {
+        dataShow: true, // 判断是否有数据
+        loading: false,
+        finished: false
+      },
+
+      params: {
+        startTime: dayjs().year() + '-03-01 00:00:00',
+        endTime: dayjs().year() + '-09-01 00:00:00',
+        page: 1,
+        rows: 20
+      }
+    })
+    // 选择学期
+    const onSelect = (val: any) => {
+      console.log(val)
+      state.actionTerm.forEach((item: any) => {
+        item.color = null
+      })
+      val.color = 'var(--van-primary-color)'
+      state.actionText = val.text
+      state.actionType = val.value
+      if (val === 'up') {
+        state.params.startTime = dayjs().year() + '-03-01 00:00:00'
+        state.params.endTime = dayjs().year() + '-09-01 00:00:00'
+      } else if (val === 'down') {
+        state.params.startTime = dayjs().year() + '-09-01 00:00:00'
+        state.params.endTime = dayjs().add(1, 'year').year() + '-03-01 00:00:00'
+      }
+      onSearch()
+    }
+
+    const onConfirmDate = (date: any) => {
+      state.currentData = date.selectedValues
+      if (state.actionType == 'up') {
+        state.params.startTime = date.selectedValues[0] + '-03-01 00:00:00'
+        state.params.endTime = date.selectedValues[0] + '-09-01 00:00:00'
+      } else if (state.actionType == 'down') {
+        state.params.startTime = date.selectedValues[0] + 1 + '-03-01 00:00:00'
+        state.params.endTime = date.selectedValues[0] + 1 + '-09-01 00:00:00'
+      }
+      state.timeShow = false
+      console.log(state.params)
+      onSearch()
+    }
+
+    // 班级列表
+    const getList = async () => {
+      try {
+        if (state.isLoading) return
+        state.isLoading = true
+        const res = await request.post('/api-school/classGroup/page', {
+          data: {
+            ...state.params,
+            orchestraId: route.query.id
+          }
+        })
+        state.listState.loading = false
+        const result = res.data || {}
+        // 处理重复请求数据
+        if (state.list.length > 0 && result.pageNo === 1) {
+          return
+        }
+        const rows = result.rows || []
+        state.list = state.list.concat(rows)
+        state.listState.finished = result.current >= result.pages
+        state.params.page = result.current + 1
+        state.listState.dataShow = state.list.length > 0
+        state.isLoading = false
+      } catch {
+        state.listState.dataShow = false
+        state.listState.finished = true
+        state.isLoading = false
+      }
+    }
+
+    const onSearch = () => {
+      state.params.page = 1
+      state.list = []
+      state.listState.dataShow = true // 判断是否有数据
+      state.listState.loading = false
+      state.listState.finished = false
+      getList()
+    }
+
+    onMounted(() => {
+      getList()
     })
     return () => (
       <div style={{ paddingTop: '12px' }}>
-        {/* <div style={{ padding: '12px 13px 16px', background: '#F8F8F8' }}>
-          <div class={styles.searchBand}>
-            2022年 <Icon name={state.showPopover ? 'arrow-up' : 'arrow-down'} />
-          </div>
-          <div class={styles.searchBand} style="margin-left: 16px">
-            上学期 <Icon name={state.oPopover ? 'arrow-up' : 'arrow-down'} />
-          </div>
-        </div> */}
-        {[1, 2, 3, 4, 5, 6, 7, 8, 9].map((item: any) => (
-          <div class={[styles.gridContainer, styles.gridClass]}>
-            <div class={styles.className}>
-              <i class={styles.line}></i>
-              长笛班
-            </div>
-            <Cell center>
-              {{
-                icon: () => (
-                  <Image
-                    class={styles.img}
-                    src="https://daya.ks3-cn-beijing.ksyuncs.com/12/1670231208704.png"
-                  />
-                ),
-                title: () => (
-                  <>
-                    <p class={styles.class}>10/16</p>
-                    <p class={styles.teacherDesc}>课时</p>
-                  </>
-                ),
-                value: () => (
-                  <>
-                    <p class={styles.courseware}>长笛第一学期长笛-第5课</p>
-                    <p class={styles.teacherDesc}>最新课件</p>
-                  </>
-                )
-              }}
-            </Cell>
+        <div style={{ padding: '12px 13px 16px', background: '#F8F8F8' }}>
+          <div class={styles.searchBand} onClick={() => (state.timeShow = true)}>
+            {state.currentData[0]}年 <Icon name={state.showPopover ? 'arrow-up' : 'arrow-down'} />
           </div>
-        ))}
+          <Popover
+            v-model:show={state.oPopover}
+            actions={state.actionTerm}
+            showArrow={false}
+            placement="bottom"
+            offset={[0, 12]}
+            style={{ zIndex: '9999' }}
+            onSelect={onSelect}
+          >
+            {{
+              reference: () => (
+                <div class={styles.searchBand} style="margin-left: 16px">
+                  {state.actionText} <Icon name={state.oPopover ? 'arrow-up' : 'arrow-down'} />
+                </div>
+              )
+            }}
+          </Popover>
+        </div>
+
+        {state.listState.dataShow ? (
+          <List
+            v-model:loading={state.listState.loading}
+            finished={state.listState.finished}
+            finishedText=" "
+            class={[styles.liveList]}
+            onLoad={getList}
+            immediateCheck={false}
+          >
+            {state.list.map((item: any) => (
+              // <div class={[styles.gridContainer, styles.gridClass]}>
+              //   <div class={styles.className}>
+              //     <i class={styles.line}></i>
+              //     {item.name}
+              //   </div>
+              //   <Grid border={false} columnNum={3}>
+              //     <GridItem>
+              //       <p class={styles.title}>{item.preStudentNum || 0}</p>
+              //       <p class={styles.name}>在读学生</p>
+              //     </GridItem>
+              //     <GridItem>
+              //       <p class={[styles.title, styles.teacher]}>{item.teacherName || '/'}</p>
+              //       <p class={styles.name}>伴学指导</p>
+              //     </GridItem>
+              //     <GridItem>
+              //       <p class={styles.title}>
+              //         {item.completeCourseScheduleNum || 0}/{item.courseScheduleNum || 0}
+              //       </p>
+              //       <p class={styles.name}>课时</p>
+              //     </GridItem>
+              //   </Grid>
+              // </div>
+              <div class={[styles.gridContainer, styles.gridClass]}>
+                <div class={styles.className}>
+                  <i class={styles.line}></i>
+                  {item.name}
+                </div>
+                <Cell center>
+                  {{
+                    icon: () => (
+                      <Image class={styles.img} src={item.teacherAvatar || iconTeacher} />
+                    ),
+                    title: () => (
+                      <>
+                        <p class={styles.class}>
+                          {item.completeCourseScheduleNum || 0}/{item.courseScheduleNum || 0}
+                        </p>
+                        <p class={styles.teacherDesc}>课时</p>
+                      </>
+                    ),
+                    value: () => (
+                      <>
+                        <p class={styles.courseware}>{item.newestLessonPlanDetailName || '/'}</p>
+                        <p class={styles.teacherDesc}>最新课件</p>
+                      </>
+                    )
+                  }}
+                </Cell>
+              </div>
+            ))}
+          </List>
+        ) : (
+          <OEmpty btnStatus={false} classImgSize="SMALL" tips="暂无班级" />
+        )}
+
+        <Popup v-model:show={state.timeShow} position="bottom" round>
+          <DatePicker
+            v-model={state.currentData}
+            columnsType={['year']}
+            minDate={new Date(2010, 0, 1)}
+            maxDate={new Date(2055, 11, 31)}
+            onConfirm={onConfirmDate}
+            onCancel={() => (state.timeShow = false)}
+          />
+        </Popup>
       </div>
     )
   }

BIN
src/school/orchestra/images/icon-checkbox-active.png


BIN
src/school/orchestra/images/icon-delete.png


BIN
src/school/orchestra/images/icon-photo-default.png


BIN
src/school/orchestra/images/icon1.png


BIN
src/school/orchestra/images/icon2.png


BIN
src/school/orchestra/images/icon3.png


BIN
src/school/orchestra/images/icon4.png


+ 20 - 6
src/school/orchestra/index.tsx

@@ -16,9 +16,9 @@ export default defineComponent({
     const form = reactive({
       showPopover: false,
       actions: [
-        { text: '全部乐团', color: 'var(--van-primary-color)' },
-        { text: '交付团' },
-        { text: '晋升团' }
+        { text: '全部乐团', color: 'var(--van-primary-color)', value: 'ALL' },
+        { text: '交付团', value: 'DELIVERY' },
+        { text: '晋升团', value: 'PROMOTION' }
       ],
       list: [] as any,
       listState: {
@@ -27,13 +27,26 @@ export default defineComponent({
         finished: false
       },
       params: {
-        keyword: null,
-        status: null,
+        type: null,
         page: 1,
         rows: 20
       }
     })
 
+    const onSelect = (val: any) => {
+      form.actions.forEach((item: any) => {
+        item.color = null
+      })
+      val.color = 'var(--van-primary-color)'
+      form.params.type = val.value === 'ALL' ? null : val.value
+      form.params.page = 1
+      form.list = []
+      form.listState.dataShow = true // 判断是否有数据
+      form.listState.loading = false
+      form.listState.finished = false
+      getList()
+    }
+
     const getList = async () => {
       try {
         const res = await request.post('/api-school/orchestra/page', {
@@ -63,7 +76,7 @@ export default defineComponent({
       router.push({
         path: '/orchestra-detail',
         query: {
-          id: item
+          id: item.id
         }
       })
     }
@@ -94,6 +107,7 @@ export default defineComponent({
               actions={form.actions}
               showArrow={false}
               placement="bottom-start"
+              onSelect={onSelect}
               offset={[0, 12]}
             >
               {{

+ 46 - 0
src/school/orchestra/modal/add-information.module.less

@@ -0,0 +1,46 @@
+.addInformation {
+  padding: 0 13px;
+
+  .title {
+    padding: 15px 0;
+    font-size: 16px;
+    font-weight: 500;
+    color: #333333;
+    display: flex;
+    align-items: center;
+  }
+
+  .icon {
+    display: inline-block;
+    width: 18px;
+    height: 18px;
+    margin-right: 6px;
+  }
+  .icon1 {
+    background: url('../images/icon1.png') no-repeat center center;
+    background-size: contain;
+  }
+  .icon2 {
+    background: url('../images/icon2.png') no-repeat center center;
+    background-size: contain;
+  }
+  .icon3 {
+    background: url('../images/icon3.png') no-repeat center center;
+    background-size: contain;
+  }
+  .icon4 {
+    background: url('../images/icon4.png') no-repeat center center;
+    background-size: contain;
+  }
+
+  .upload {
+    margin: 0;
+    background: #fff;
+    margin-bottom: 12px;
+  }
+
+  .field {
+    border-radius: 10px;
+    margin-bottom: 12px;
+  }
+}

+ 65 - 0
src/school/orchestra/modal/add-information.tsx

@@ -0,0 +1,65 @@
+import OUpload from '@/components/o-upload'
+import request from '@/helpers/request'
+import { Button, Field } from 'vant'
+import { defineComponent, reactive } from 'vue'
+import styles from './add-information.module.less'
+
+export default defineComponent({
+  name: 'add-information',
+  emits: ['close'],
+  setup(props, { slots, attrs, emit }) {
+    const forms = reactive({
+      type: 'HOT_CONSULTATION',
+      clientType: 'SCHOOL',
+      coverImage: null,
+      title: null,
+      linkUrl: null,
+      memo: null
+    })
+    const onSubmit = async () => {
+      try {
+        await request.post('/api-school/sysNewsInformation/save', {
+          data: {}
+        })
+      } catch {
+        //
+      }
+    }
+
+    return () => (
+      <div class={styles.addInformation}>
+        <div class={styles.title}>
+          <i class={[styles.icon, styles.icon1]}></i>请上传封面图片
+        </div>
+        <OUpload class={styles.upload} v-model:modelValue={forms.coverImage} />
+
+        <div class={styles.title}>
+          <i class={[styles.icon, styles.icon2]}></i>资讯标题
+        </div>
+        <Field placeholder="请输入资讯标题" class={styles.field} v-model={forms.title} />
+
+        <div class={styles.title}>
+          <i class={[styles.icon, styles.icon3]}></i>内容简介
+        </div>
+        <Field
+          placeholder="请输入资讯内容简要概述"
+          type="textarea"
+          rows={2}
+          class={styles.field}
+          v-model={forms.memo}
+        />
+
+        <div class={styles.title}>
+          <i class={[styles.icon, styles.icon4]}></i>添加链接
+        </div>
+        <Field placeholder="请输入链接" class={styles.field} v-model={forms.linkUrl} />
+
+        <div class={'btnGroup'}>
+          <Button type="primary" size="large" block round>
+            发布资讯
+          </Button>
+        </div>
+      </div>
+    )
+  }
+})

+ 7 - 4
src/school/orchestra/orchestra-detail.tsx

@@ -3,14 +3,17 @@ import OSticky from '@/components/o-sticky'
 import { Sticky, Tab, Tabs } from 'vant'
 import { defineComponent, ref } from 'vue'
 import Information from './compontent/information'
-import Phone from './compontent/phone'
+import Photo from './compontent/photo'
 import Plan from './compontent/plan'
 import styles from './orchestra-detail.module.less'
 
 export default defineComponent({
   name: 'orchestra-detail',
   setup() {
-    const tabValue = ref('information')
+    const tabs = sessionStorage.getItem('orchestra-detail-tab')
+    console.log(tabs, 'tabs')
+    const tabValue = ref(tabs || 'information')
+    sessionStorage.removeItem('orchestra-detail-tab')
     return () => (
       <div class={styles.orchestraDetail}>
         <OSticky position="top">
@@ -18,14 +21,14 @@ export default defineComponent({
           <Tabs sticky lineWidth={20} lineHeight={4} v-model:active={tabValue.value}>
             <Tab title="乐团信息" name="information"></Tab>
             <Tab title="训练进度" name="plan"></Tab>
-            <Tab title="训练照片" name="phone"></Tab>
+            <Tab title="训练照片" name="photo"></Tab>
             {/* <Tab title="乐团资讯" name="info"></Tab> */}
           </Tabs>
         </OSticky>
 
         {tabValue.value === 'information' && <Information />}
         {tabValue.value === 'plan' && <Plan />}
-        {tabValue.value === 'phone' && <Phone />}
+        {tabValue.value === 'photo' && <Photo />}
       </div>
     )
   }

+ 38 - 0
src/school/orchestra/orchestra-information.module.less

@@ -0,0 +1,38 @@
+.information {
+  .addPhone {
+    color: var(--van-primary-text);
+    border-color: #fff;
+    border-radius: 10px;
+    font-size: 16px;
+    margin: 13px;
+    width: calc(100% - 26px);
+  }
+
+  .img {
+    width: 142px;
+    height: 80px;
+    border-radius: 10px;
+    overflow: hidden;
+    margin-right: 15px;
+    flex-shrink: 0;
+  }
+
+  .title {
+    font-size: 14px;
+    font-weight: 500;
+    color: #333333;
+    line-height: 21px;
+    padding-bottom: 2px;
+  }
+  .content {
+    font-size: 12px;
+    color: #777777;
+    line-height: 17px;
+  }
+  .time {
+    padding-top: 5px;
+    font-size: 12px;
+    color: #aaaaaa;
+    line-height: 17px;
+  }
+}

+ 103 - 0
src/school/orchestra/orchestra-information.tsx

@@ -0,0 +1,103 @@
+import OEmpty from '@/components/o-empty'
+import OPopup from '@/components/o-popup'
+import request from '@/helpers/request'
+import dayjs from 'dayjs'
+import { Button, Cell, Image, List } from 'vant'
+import { defineComponent, onMounted, reactive } from 'vue'
+import { useRoute } from 'vue-router'
+import AddInformation from './modal/add-information'
+import styles from './orchestra-information.module.less'
+
+export default defineComponent({
+  name: 'orchestra-information',
+  setup() {
+    const route = useRoute()
+    const state = reactive({
+      addStatus: false,
+      isLoading: false,
+      list: [] as any,
+      listState: {
+        dataShow: true, // 判断是否有数据
+        loading: false,
+        finished: false
+      },
+      params: {
+        type: 'HOT_CONSULTATION',
+        clientType: 'SCHOOL',
+        page: 1,
+        rows: 20
+      }
+    })
+
+    const getList = async () => {
+      try {
+        if (state.isLoading) return
+        state.isLoading = true
+        const res = await request.post('/api-school/sysNewsInformation/page', {
+          data: {
+            ...state.params,
+            orchestraPhotoAlbumId: route.query.photoId
+          }
+        })
+        state.listState.loading = false
+        const result = res.data || {}
+        // 处理重复请求数据
+        if (state.list.length > 0 && result.pageNo === 1) {
+          return
+        }
+        const rows = result.rows || []
+        state.list = state.list.concat(rows)
+        state.listState.finished = result.current >= result.pages
+        state.params.page = result.current + 1
+        state.listState.dataShow = state.list.length > 0
+        state.isLoading = false
+      } catch {
+        state.listState.dataShow = false
+        state.listState.finished = true
+        state.isLoading = false
+      }
+    }
+
+    onMounted(() => {
+      getList()
+    })
+    return () => (
+      <div class={styles.information}>
+        <Button icon="plus" block class={styles.addPhone} onClick={() => (state.addStatus = true)}>
+          添加资讯
+        </Button>
+
+        {state.listState.dataShow ? (
+          <List
+            v-model:loading={state.listState.loading}
+            finished={state.listState.finished}
+            finishedText=" "
+            onLoad={getList}
+            immediateCheck={false}
+          >
+            {state.list.map((item: any, index: number) => (
+              <Cell center class={styles.cell}>
+                {{
+                  icon: () => <Image src={item.coverImage} class={styles.img} />,
+                  title: () => (
+                    <div>
+                      <div class={[styles.title, 'van-ellipsis']}>{item.title}</div>
+                      <div class={[styles.content, 'van-multi-ellipsis--l2']}>{item.memo}</div>
+                      <div class={styles.time}>{dayjs(item.createBy).format('YYYY年MM月DD日')}</div>
+                    </div>
+                  )
+                }}
+              </Cell>
+            ))}
+          </List>
+        ) : (
+          <OEmpty btnStatus={false} classImgSize="SMALL" tips="暂无资讯" />
+        )}
+
+        <OPopup v-model:modelValue={state.addStatus} style={{ background: '#f8f8f8' }}>
+          <AddInformation onClose={() => (state.addStatus = false)} />
+        </OPopup>
+      </div>
+    )
+  }
+})