Prechádzať zdrojové kódy

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

lex 2 rokov pred
rodič
commit
2f387c6564
44 zmenil súbory, kde vykonal 1583 pridanie a 223 odobranie
  1. 17 13
      package-lock.json
  2. 32 0
      src/router/routes-common.ts
  3. 9 1
      src/router/routes-school.ts
  4. 9 2
      src/school/attendance/components/teacher-attendDetail.module.less
  5. 22 13
      src/school/attendance/components/teacher-attendDetail.tsx
  6. 7 3
      src/school/attendance/modals/teacherAtt-item.module.less
  7. 13 8
      src/school/attendance/modals/teacherAtt-item.tsx
  8. 280 0
      src/school/orchestra/compontent/photo-create.tsx
  9. 7 8
      src/school/orchestra/compontent/photo.module.less
  10. 12 4
      src/school/orchestra/compontent/photo.tsx
  11. 20 20
      src/school/school-detail/eidt-school.tsx
  12. 27 0
      src/school/school-detail/index.module.less
  13. 19 5
      src/school/school-detail/index.tsx
  14. 2 2
      src/school/school-detail/modals/teacher-item.module.less
  15. 56 49
      src/teacher/attendance/modals/teacherAtt-item.module.less
  16. 22 31
      src/teacher/attendance/modals/teacherAtt-item.tsx
  17. 8 30
      src/views/accompany/music-list.tsx
  18. 6 9
      src/views/coursewarePlay/index.module.less
  19. 25 19
      src/views/coursewarePlay/index.tsx
  20. 1 1
      src/views/exercise-record/exercis-detail.module.less
  21. 9 2
      src/views/exercise-record/exercis-detail.tsx
  22. 2 2
      src/views/exercise-record/modals/detail-item.tsx
  23. 2 1
      src/views/layout/auth.tsx
  24. BIN
      src/views/mine-orchestra/images/bg.png
  25. BIN
      src/views/mine-orchestra/images/icon-or.png
  26. BIN
      src/views/mine-orchestra/images/icon-photo-default.png
  27. BIN
      src/views/mine-orchestra/images/icon_change.png
  28. 44 0
      src/views/mine-orchestra/index.module.less
  29. 118 0
      src/views/mine-orchestra/index.tsx
  30. 60 0
      src/views/mine-orchestra/my-class/index.module.less
  31. 135 0
      src/views/mine-orchestra/my-class/index.tsx
  32. 35 0
      src/views/mine-orchestra/my-photo/index.module.less
  33. 108 0
      src/views/mine-orchestra/my-photo/index.tsx
  34. BIN
      src/views/mine-orchestra/orchestra-deeds/images/icon-edit.png
  35. BIN
      src/views/mine-orchestra/orchestra-deeds/images/icon-step-calendar.png
  36. BIN
      src/views/mine-orchestra/orchestra-deeds/images/icon-step.png
  37. BIN
      src/views/mine-orchestra/orchestra-deeds/images/icon-upload-video-cover.png
  38. BIN
      src/views/mine-orchestra/orchestra-deeds/images/icon-upload-video.png
  39. BIN
      src/views/mine-orchestra/orchestra-deeds/images/icon-upload.png
  40. 81 0
      src/views/mine-orchestra/orchestra-deeds/index.module.less
  41. 138 0
      src/views/mine-orchestra/orchestra-deeds/index.tsx
  42. 105 0
      src/views/mine-orchestra/photo-list/detail.tsx
  43. 36 0
      src/views/mine-orchestra/photo-list/index.module.less
  44. 116 0
      src/views/mine-orchestra/photo-list/index.tsx

+ 17 - 13
package-lock.json

@@ -3148,9 +3148,9 @@
       }
     },
     "node_modules/caniuse-lite": {
-      "version": "1.0.30001363",
-      "resolved": "https://registry.npmmirror.com/caniuse-lite/-/caniuse-lite-1.0.30001363.tgz",
-      "integrity": "sha512-HpQhpzTGGPVMnCjIomjt+jvyUu8vNFo3TaDiZ/RcoTrlOq/5+tC8zHdsbgFB6MxmaY+jCpsH09aD80Bb4Ow3Sg==",
+      "version": "1.0.30001450",
+      "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001450.tgz",
+      "integrity": "sha512-qMBmvmQmFXaSxexkjjfMvD5rnDL0+m+dUMZKoDYsGG8iZN29RuYh9eRoMvKsT6uMAWlyUUGDEQGJJYjzCIO9ew==",
       "funding": [
         {
           "type": "opencollective",
@@ -3160,8 +3160,7 @@
           "type": "tidelift",
           "url": "https://tidelift.com/funding/github/npm/caniuse-lite"
         }
-      ],
-      "license": "CC-BY-4.0"
+      ]
     },
     "node_modules/capital-case": {
       "version": "1.0.4",
@@ -11524,7 +11523,8 @@
       "version": "2.0.1",
       "resolved": "https://registry.npmmirror.com/@vitejs/plugin-vue/-/plugin-vue-2.0.1.tgz",
       "integrity": "sha512-wtdMnGVvys9K8tg+DxowU1ytTrdVveXr3LzdhaKakysgGXyrsfaeds2cDywtvujEASjWOwWL/OgWM+qoeM8Plg==",
-      "dev": true
+      "dev": true,
+      "requires": {}
     },
     "@vitejs/plugin-vue-jsx": {
       "version": "1.3.8",
@@ -11808,7 +11808,8 @@
       "version": "5.3.1",
       "resolved": "https://registry.npmmirror.com/acorn-jsx/-/acorn-jsx-5.3.1.tgz",
       "integrity": "sha512-K0Ptm/47OKfQRpNQ2J/oIN/3QYiK6FwW+eJbILhsdxh2WTLdl+30o8aGdTbm5JbffpFFAg/g+zi1E+jvJha5ng==",
-      "dev": true
+      "dev": true,
+      "requires": {}
     },
     "aggregate-error": {
       "version": "3.1.0",
@@ -12064,9 +12065,9 @@
       "dev": true
     },
     "caniuse-lite": {
-      "version": "1.0.30001363",
-      "resolved": "https://registry.npmmirror.com/caniuse-lite/-/caniuse-lite-1.0.30001363.tgz",
-      "integrity": "sha512-HpQhpzTGGPVMnCjIomjt+jvyUu8vNFo3TaDiZ/RcoTrlOq/5+tC8zHdsbgFB6MxmaY+jCpsH09aD80Bb4Ow3Sg=="
+      "version": "1.0.30001450",
+      "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001450.tgz",
+      "integrity": "sha512-qMBmvmQmFXaSxexkjjfMvD5rnDL0+m+dUMZKoDYsGG8iZN29RuYh9eRoMvKsT6uMAWlyUUGDEQGJJYjzCIO9ew=="
     },
     "capital-case": {
       "version": "1.0.4",
@@ -15131,7 +15132,8 @@
       "version": "6.0.0",
       "resolved": "https://registry.npmmirror.com/postcss-pxtorem/-/postcss-pxtorem-6.0.0.tgz",
       "integrity": "sha512-ZRXrD7MLLjLk2RNGV6UA4f5Y7gy+a/j1EqjAfp9NdcNYVjUMvg5HTYduTjSkKBkRkfqbg/iKrjMO70V4g1LZeg==",
-      "dev": true
+      "dev": true,
+      "requires": {}
     },
     "postcss-value-parser": {
       "version": "4.2.0",
@@ -15332,7 +15334,8 @@
     "qrcode.vue": {
       "version": "3.3.3",
       "resolved": "https://registry.npmmirror.com/qrcode.vue/-/qrcode.vue-3.3.3.tgz",
-      "integrity": "sha512-OsD4tQjIbxg/K6D5ZkWjBdYI9eg9K2i8qeYILdEAX5mdAydSAxV7xKmmZSP/hA12olLqEMZ9ryqDQrwa9jEMgw=="
+      "integrity": "sha512-OsD4tQjIbxg/K6D5ZkWjBdYI9eg9K2i8qeYILdEAX5mdAydSAxV7xKmmZSP/hA12olLqEMZ9ryqDQrwa9jEMgw==",
+      "requires": {}
     },
     "qs": {
       "version": "6.10.3",
@@ -16307,7 +16310,8 @@
     "vue-demi": {
       "version": "0.13.2",
       "resolved": "https://registry.npmmirror.com/vue-demi/-/vue-demi-0.13.2.tgz",
-      "integrity": "sha512-41ukrclEbMddAyP7PvxMSYqnOSzPV6r7GNnyTSKSCNTaz19GehxmTiXyP9kwHSUv2+Dr6hHqiUiF7L1VAw2KdQ=="
+      "integrity": "sha512-41ukrclEbMddAyP7PvxMSYqnOSzPV6r7GNnyTSKSCNTaz19GehxmTiXyP9kwHSUv2+Dr6hHqiUiF7L1VAw2KdQ==",
+      "requires": {}
     },
     "vue-echarts": {
       "version": "6.2.3",

+ 32 - 0
src/router/routes-common.ts

@@ -143,6 +143,38 @@ export const router: RouteRecordRaw[] = [
       title: '补助确认'
     }
   },
+  {
+    path: '/mine-orchestra',
+    name: 'mine-orchestra',
+    component: () => import('@/views/mine-orchestra/index'),
+    meta: {
+      title: '我的乐团'
+    }
+  },
+  {
+    path: '/photo-list',
+    name: 'photo-list',
+    component: () => import('@/views/mine-orchestra/photo-list/index'),
+    meta: {
+      title: '我的乐团'
+    }
+  },
+  {
+    path: '/photo-list',
+    name: 'photo-list',
+    component: () => import('@/views/mine-orchestra/photo-list/index'),
+    meta: {
+      title: '我的乐团'
+    }
+  },
+  {
+    path: '/photo-list-detail',
+    name: 'photo-list-detail',
+    component: () => import('@/views/mine-orchestra/photo-list/detail'),
+    meta: {
+      title: '我的乐团'
+    }
+  },
 ]
 
 // 不需要登录的路由

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

@@ -349,7 +349,15 @@ export default [
         meta: {
           title: '单元测验'
         }
-      }
+      },
+      {
+        path: '/orchestra-photo-create',
+        name: 'orchestra-photo-create',
+        component: () => import('@/school/orchestra/compontent/photo-create'),
+        meta: {
+          title: '创建相册'
+        }
+      },
 
       //
     ]

+ 9 - 2
src/school/attendance/components/teacher-attendDetail.module.less

@@ -72,11 +72,18 @@
           line-height: 22px;
         }
         .infoMsgSub {
+          width: 230px;
+          overflow: hidden;
+          text-overflow: ellipsis;
+          white-space: nowrap;
           font-size: 12px;
           font-weight: 400;
           color: #777777;
           line-height: 17px;
         }
+        .infoMsgSubTeacher {
+          width: 260px !important;
+        }
       }
     }
   }
@@ -134,10 +141,10 @@
     }
   }
   .passWrap {
-    background-color: #ddecff;
+    background-color: #fff;
   }
   .goWrap {
-    background-color: #ffe1e1;
+    background-color: #fff;
   }
   .error {
     color: #f44541;

+ 22 - 13
src/school/attendance/components/teacher-attendDetail.tsx

@@ -137,7 +137,14 @@ export default defineComponent({
                   <p class={styles.infoMsgMain}>
                     {teacherAttInfo.value?.classGroupName}-{teacherAttInfo.value?.teacherName}
                   </p>
-                  <p class={styles.infoMsgSub}>{teacherAttInfo.value?.orchestraName}</p>
+                  <p
+                    class={[
+                      styles.infoMsgSub,
+                      platformApi.value == '/api-teacher' ? styles.infoMsgSubTeacher : ''
+                    ]}
+                  >
+                    {teacherAttInfo.value?.orchestraName}
+                  </p>
                 </div>
               </div>
               {platformApi.value == '/api-teacher' ? null : (
@@ -172,12 +179,13 @@ export default defineComponent({
                   />
                 </div>
                 <p class={styles.signTime}>
-                  签到时间
-                  <span>
-                    {teacherAttInfo.value?.signInTime
-                      ? dayjs(teacherAttInfo.value?.signInTime).format('HH:mm:ss')
-                      : '未签到'}
-                  </span>
+                  {teacherAttInfo.value?.signInTime ? '签到时间' : ''}
+
+                  {teacherAttInfo.value?.signInTime ? (
+                    <span>{dayjs(teacherAttInfo.value?.signInTime).format('HH:mm:ss')}</span>
+                  ) : (
+                    '未签到'
+                  )}
                 </p>
               </div>
             </div>
@@ -242,12 +250,13 @@ export default defineComponent({
                   />
                 </div>
                 <p class={styles.signTime}>
-                  签退时间
-                  <span>
-                    {teacherAttInfo.value?.signOutTime
-                      ? dayjs(teacherAttInfo.value?.signOutTime).format('HH:mm:ss')
-                      : '未签退'}
-                  </span>
+                  {teacherAttInfo.value?.signOutTime ? '签退时间' : ''}
+
+                  {teacherAttInfo.value?.signOutTime ? (
+                    <span>{dayjs(teacherAttInfo.value?.signOutTime).format('HH:mm:ss')}</span>
+                  ) : (
+                    '未签退'
+                  )}
                 </p>
               </div>
             </div>

+ 7 - 3
src/school/attendance/modals/teacherAtt-item.module.less

@@ -58,6 +58,10 @@
           line-height: 22px;
         }
         .infoMsgSub {
+          width: 260px;
+          white-space: nowrap;
+          overflow: hidden;
+          text-overflow: ellipsis;
           font-size: 12px;
           font-weight: 400;
           color: #777777;
@@ -88,7 +92,7 @@
         .signTime {
           height: 31px;
           line-height: 31px;
-          font-size: 20px;
+          font-size: 17px;
           font-weight: 600;
           color: #333333;
           line-height: 28px;
@@ -118,10 +122,10 @@
       }
     }
     .passWrap {
-      background-color: #ddecff;
+      background-color: #f2f2f2;
     }
     .goWrap {
-      background-color: #ffe1e1;
+      background-color: #f2f2f2;
     }
   }
 }

+ 13 - 8
src/school/attendance/modals/teacherAtt-item.tsx

@@ -50,32 +50,37 @@ export default defineComponent({
               <div class={props.item.signInStatus === 'NORMAL' ? styles.passWrap : styles.goWrap}>
                 <div class={styles.attInfoDot}>
                   <div class={styles.attInfoDotTitle}>
-                    <span>签到时间</span>
+                    <span>签到状态</span>
                     <img
                       src={props.item.signInStatus === 'NORMAL' ? successIcon : errorIcon}
                       alt=""
                     />
                   </div>
+
                   <p class={styles.signTime}>
-                    {props.item.signInTime
-                      ? dayjs(props.item.signInTime).format('HH:mm:ss')
-                      : '未签到'}
+                    {props.item.signInStatus === 'NORMAL' ? (
+                      '正常'
+                    ) : (
+                      <span style={{ color: '#F44541' }}>异常</span>
+                    )}
                   </p>
                 </div>
               </div>
               <div class={props.item.signOutStatus === 'NORMAL' ? styles.passWrap : styles.goWrap}>
                 <div class={styles.attInfoDot}>
                   <div class={styles.attInfoDotTitle}>
-                    <span>签退时间</span>
+                    <span>签退状态</span>
                     <img
                       src={props.item.signOutStatus === 'NORMAL' ? successIcon : errorIcon}
                       alt=""
                     />
                   </div>
                   <p class={styles.signTime}>
-                    {props.item.signOutTime
-                      ? dayjs(props.item.signOutTime).format('HH:mm:ss')
-                      : '未签到'}
+                    {props.item.signOutStatus === 'NORMAL' ? (
+                      '正常'
+                    ) : (
+                      <span style={{ color: '#F44541' }}>异常</span>
+                    )}
                   </p>
                 </div>
               </div>

+ 280 - 0
src/school/orchestra/compontent/photo-create.tsx

@@ -0,0 +1,280 @@
+import OEmpty from '@/components/o-empty'
+import request from '@/helpers/request'
+import {
+  ActionSheet,
+  Button,
+  Dialog,
+  Field,
+  Image,
+  List,
+  Popover,
+  Popup,
+  showConfirmDialog,
+  showToast,
+  Sticky
+} 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'
+import OHeader from '@/components/o-header'
+
+export default defineComponent({
+  name: 'phone',
+  props: {
+    height: {
+      type: [String, Number],
+      default: 'auto'
+    }
+  },
+  setup(props) {
+    const route = useRoute()
+    const router = useRouter()
+    const state = reactive({
+      oPopover: false,
+      status: false,
+      isLoading: false,
+      photoName: null, // 相册名称
+      list: [] as any,
+      listState: {
+        dataShow: true, // 判断是否有数据
+        loading: false,
+        finished: false
+      },
+      params: {
+        page: 1,
+        rows: 20
+      },
+      selectItem: {} as any,
+      selectType: 'add'
+    })
+
+    const onAddPhoto = async () => {
+      try {
+        if (!state.photoName) {
+          showToast('请输入相册名称')
+          state.status = true
+          return
+        }
+        if (state.selectType === 'add') {
+          await request.post('/api-school/orchestraPhotoAlbum/save', {
+            data: {
+              orchestraId: route.query.orchestraId,
+              name: state.photoName,
+              parentId: route.query.parentId
+            }
+          })
+          setTimeout(() => {
+            showToast('添加成功')
+          }, 100)
+        } else {
+          await request.post('/api-school/orchestraPhotoAlbum/update', {
+            data: {
+              id: state.selectItem.id,
+              orchestraId: route.query.id,
+              parentId: route.query.parentId,
+              name: state.photoName
+            }
+          })
+          setTimeout(() => {
+            showToast('修改成功')
+          }, 100)
+        }
+        state.status = false
+        setTimeout(() => {
+          state.photoName = null
+          onSearch()
+        }, 1100)
+      } catch {
+        //
+      }
+    }
+
+    const onSearch = () => {
+      state.params.page = 1
+      state.list = []
+      state.listState.dataShow = true // 判断是否有数据
+      state.listState.loading = false
+      state.listState.finished = false
+      getList()
+    }
+
+    // 班级列表
+    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.orchestraId,
+            parentId: route.query.parentId
+          }
+        })
+        state.listState.loading = false
+        const result = res.data || {}
+        // 处理重复请求数据
+        if (state.list.length > 0 && result.current === 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
+        }
+      })
+    }
+
+    const onRename = async () => {
+      state.photoName = state.selectItem.name
+      state.status = true
+    }
+
+    const onRemove = async () => {
+      showConfirmDialog({
+        message: '您确认删除该相册吗?'
+      }).then(async () => {
+        try {
+          await request.post('/api-school/orchestraPhotoAlbum/remove', {
+            requestType: 'form',
+            data: {
+              id: state.selectItem.id
+            }
+          })
+          setTimeout(() => {
+            showToast('删除成功')
+          }, 100)
+
+          setTimeout(() => {
+            onSearch()
+          }, 1100)
+        } catch {
+          //
+        }
+      })
+    }
+
+    onMounted(() => {
+      getList()
+    })
+    return () => (
+      <>
+        <Sticky position="top">
+          <OHeader title={'创建相册'}></OHeader>
+          <Button
+            style={{margin: '12px auto 0 auto', width: '90%'}}
+            icon="plus"
+            block
+            class={styles.addPhone}
+            onClick={() => {
+              state.status = true
+              state.selectType = 'add'
+            }}
+          >
+            新建相册
+          </Button>
+        </Sticky>
+        <div class={styles.phone}>
+          {state.listState.dataShow ? (
+            <List
+              v-model:loading={state.listState.loading}
+              finished={state.listState.finished}
+              finishedText=" "
+              onLoad={getList}
+              immediateCheck={false}
+              class={styles.informationGroup}
+            >
+              <div class={styles.phoneContainer}>
+                {state.list.map((item: any) => (
+                  <div class={styles.item} onClick={() => onDetail(item)}>
+                    {/* <i class={styles.more}></i> */}
+                    <i
+                      class={styles.more}
+                      onClick={(e: any) => {
+                        e.stopPropagation()
+                        state.oPopover = true
+                        state.selectItem = item
+                        state.selectType = 'update'
+                      }}
+                    ></i>
+
+                    {item.coverUrl ? (
+                      <Image class={styles.img} src={item.coverUrl} fit="cover" />
+                    ) : (
+                      <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} tips="暂无相册" />
+          )}
+
+          <Popup v-model:show={state.status} round style={{ width: '80%' }}>
+            <div class={styles.container}>
+              <div class={styles.dialogTitle}>
+                <i></i>
+                {state.selectType === 'add' ? '新建相册' : '重命名相册'}
+              </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>
+
+          <ActionSheet
+            cancelText="取消"
+            v-model:show={state.oPopover}
+            closeOnClickAction
+            actions={[
+              { name: '重命名', callback: () => onRename() },
+              { name: '删除', color: '#F44541', callback: () => onRemove() }
+            ]}
+          />
+        </div>
+      </>
+    )
+  }
+})

+ 7 - 8
src/school/orchestra/compontent/photo.module.less

@@ -1,13 +1,12 @@
 .phone {
   padding: 0 13px 32px;
-
-  .addPhone {
-    margin-top: 12px;
-    color: var(--van-primary-text);
-    border-color: #fff;
-    border-radius: 10px;
-    font-size: 16px;
-  }
+}
+.addPhone {
+  margin-top: 12px;
+  color: var(--van-primary-text);
+  border-color: #fff;
+  border-radius: 10px;
+  font-size: 16px;
 }
 
 .phoneContainer {

+ 12 - 4
src/school/orchestra/compontent/photo.tsx

@@ -129,12 +129,20 @@ export default defineComponent({
     const onDetail = (item: any) => {
       sessionStorage.setItem('orchestra-detail-tab', 'photo')
       router.push({
-        path: '/photo-detail',
-        query: {
-          photoId: item.id,
-          name: item.name
+        path: '/orchestra-photo-create',
+        query:{
+          orchestraId: route.query.id,
+          name: item.name,
+          parentId: item.id
         }
       })
+      // router.push({
+      //   path: '/photo-detail',
+      //   query: {
+      //     photoId: item.id,
+      //     name: item.name
+      //   }
+      // })
     }
 
     const onRename = async () => {

+ 20 - 20
src/school/school-detail/eidt-school.tsx

@@ -181,39 +181,39 @@ export default defineComponent({
               ></Field> */}
               {/*    onClick={() => (state.showArea = true)} */}
               <Field
-                label-align="top"
-                v-model={forms.address}
+                label-align="left"
+                rows={3}
+                v-model={forms.emergencyContact}
                 maxlength={50}
-                placeholder="请选择地址"
-                disabled
-                onClick={() => setAddress()}
+                placeholder="请输入姓名"
               >
-                {{
-                  extra: () => (
-                    <div class={styles.loctionIconWrap}>
-                      <Image width={19} height={18} src={locIcon}></Image>
-                    </div>
-                  ),
-                  label: () => <p class={styles.addP}>地址</p>
-                }}
+                {{ label: () => <p class={styles.addP}>负责人</p> }}
               </Field>
               <Field
-                label-align="top"
+                label-align="left"
                 rows={3}
                 v-model={forms.email}
                 maxlength={50}
-                placeholder="请输入邮箱"
+                placeholder="请输入邮箱账号"
               >
-                {{ label: () => <p class={styles.addP}>邮箱</p> }}
+                {{ label: () => <p class={styles.addP}>邮箱账号</p> }}
               </Field>
               <Field
                 label-align="top"
-                rows={3}
-                v-model={forms.emergencyContact}
+                v-model={forms.address}
                 maxlength={50}
-                placeholder="请输入负责人姓名"
+                placeholder="请选择地址"
+                disabled
+                onClick={() => setAddress()}
               >
-                {{ label: () => <p class={styles.addP}>负责人</p> }}
+                {{
+                  extra: () => <div class={styles.loctionIconWrap}></div>,
+                  label: () => (
+                    <p class={[styles.addP, styles.addDet]}>
+                      学校地址 <Image width={19} height={18} src={locIcon}></Image>
+                    </p>
+                  )
+                }}
               </Field>
             </CellGroup>
             <OUpload

+ 27 - 0
src/school/school-detail/index.module.less

@@ -63,6 +63,16 @@
         font-weight: 500;
         color: #333333;
         line-height: 21px;
+        span {
+          display: inline-block;
+          width: 68px;
+          text-align: left;
+          margin-right: 20px;
+          font-size: 15px;
+          font-weight: 400;
+          color: #777777;
+          line-height: 21px;
+        }
         &:last-child {
           margin-bottom: 0;
         }
@@ -71,6 +81,13 @@
       // }
     }
   }
+  .flexP {
+    display: flex;
+    flex-direction: row;
+    p {
+      flex: 1;
+    }
+  }
   .teacherList {
     margin: 0 13px 54px;
     .teacherTitle {
@@ -115,6 +132,9 @@
   display: flex;
   flex-direction: column;
   align-items: center;
+  p {
+    width: 50px;
+  }
   :global {
     .van-button {
       line-height: 44px;
@@ -130,6 +150,13 @@
   color: #333333;
   line-height: 22px;
 }
+.addDet {
+  width: 100%;
+  display: flex;
+  flex-direction: row;
+  align-items: center;
+  justify-content: space-between;
+}
 .schoolDtailWrap {
   padding: 14px 12px;
   display: flex;

+ 19 - 5
src/school/school-detail/index.tsx

@@ -104,11 +104,25 @@ export default defineComponent({
               </div>
             </div>
             <div class={styles.detailInfo}>
-              <p>地址:{state.info.address}</p>
-              <p>学年制:{schoolSystem[state.info.schoolSystem]} </p>
-              <p>邮箱:{state.info.email}</p>
-              <p>管理老师:{state.info.educationalAdministrationUsername}</p>
-              <p>负责人:{state.info.emergencyContact}</p>
+              <p>
+                <span>负责人</span>
+                {state.info.emergencyContact}
+              </p>
+              <p>
+                <span>管理老师</span>
+                {state.info.educationalAdministrationUsername}
+              </p>
+              <p>
+                <span>学年制</span>
+                {schoolSystem[state.info.schoolSystem]}{' '}
+              </p>
+              <p>
+                <span>邮箱账号</span>
+                {state.info.email}
+              </p>
+              <p class={styles.flexP}>
+                <span>学校地址</span> <p>{state.info.address}</p>
+              </p>
             </div>
           </div>
           <div class={styles.teacherList}>

+ 2 - 2
src/school/school-detail/modals/teacher-item.module.less

@@ -65,11 +65,11 @@
     color: #333333;
     line-height: 20px;
     p {
-      width: 42px;
+      width: 48px;
       margin-bottom: 6px;
     }
     .statusTagWrap {
-      flex: 1;
+      width: 265px;
       display: flex;
       flex-direction: row;
       align-items: top;

+ 56 - 49
src/teacher/attendance/modals/teacherAtt-item.module.less

@@ -37,13 +37,19 @@
   }
   .itemWrapBottom {
     padding-top: 15px;
-
+    display: flex;
+    flex-direction: row;
+    align-items: center;
+    justify-content: space-between;
     .courseInfo {
       display: flex;
       flex-direction: row;
       align-items: center;
-      padding-bottom: 15px;
+      // padding-bottom: 15px;
       justify-content: space-between;
+      flex-wrap: nowrap;
+      overflow: hidden;
+      text-overflow: ellipsis;
       .headImgs {
         width: 42px;
         height: 42px;
@@ -59,10 +65,14 @@
           line-height: 22px;
         }
         .infoMsgSub {
+          width: 175px;
           font-size: 12px;
           font-weight: 400;
           color: #777777;
           line-height: 17px;
+          white-space: nowrap;
+          overflow: hidden;
+          text-overflow: ellipsis;
         }
       }
     }
@@ -84,61 +94,58 @@
       line-height: 20px;
       font-weight: 500;
     }
-    .attInfo {
+    .itemWrapBottomRight {
       display: flex;
       flex-direction: row;
       align-items: center;
-      justify-content: space-between;
-      .attInfoDot {
-        text-align: left;
-        padding: 12px;
-        .attInfoDotTitle {
-          width: 100%;
-          display: flex;
-          flex-direction: row;
-          margin-bottom: 7px;
-          align-items: center;
-          img {
-            width: 18px;
-            height: 18px;
-            margin-left: 60px;
+      .attInfo {
+        display: flex;
+        flex-direction: row;
+        align-items: center;
+        justify-content: space-between;
+        .attInfoDot {
+          text-align: left;
+          padding: 12px;
+          .attInfoDotTitle {
+            width: 100%;
+            display: flex;
+            flex-direction: row;
+            margin-bottom: 7px;
+            align-items: center;
+            img {
+              width: 18px;
+              height: 18px;
+              margin-left: 60px;
+            }
+          }
+          .signTime {
+            font-size: 20px;
+            font-weight: 600;
+            color: #333333;
+            line-height: 28px;
           }
         }
-        .signTime {
-          font-size: 20px;
+      }
+      .goWrap {
+        align-items: center;
+        text-align: center;
+        border-radius: 7px;
+        padding: 8px 13px;
+        background: #f6f6f6;
+        margin-right: 8px;
+        .goWrapMain {
+          font-size: 14px;
           font-weight: 600;
-          color: #333333;
-          line-height: 28px;
+          color: #3891ff;
+          line-height: 20px;
+        }
+        .goWrapSub {
+          font-size: 12px;
+          font-weight: 400;
+          color: #777777;
+          line-height: 17px;
         }
       }
     }
-    .passWrap,
-    .goWrap {
-      display: flex;
-      flex-direction: row;
-      align-items: center;
-      border-radius: 10px;
-      justify-content: space-between;
-      text-align: center;
-      .itemBottomMain {
-        font-size: 30px;
-        font-weight: bold;
-        color: #333333;
-        line-height: 35px;
-        margin-bottom: 2px;
-      }
-      .itemBottomSub {
-        font-size: 14px;
-        font-weight: 400;
-        color: #333333;
-        line-height: 20px;
-      }
-    }
-    .passWrap {
-      background-color: #ddecff;
-    }
-    .goWrap {
-      background-color: #ffe1e1;
-    }
   }
 }

+ 22 - 31
src/teacher/attendance/modals/teacherAtt-item.tsx

@@ -31,9 +31,6 @@ export default defineComponent({
                 {dayjs(props.item.endTime).format('HH:mm')}
               </p>
             </div>
-            <div class={styles.itemWrapTopRight}>
-              <Icon name="arrow"></Icon>
-            </div>
           </div>
           <div class={styles.itemWrapBottom}>
             <div class={styles.courseInfo}>
@@ -47,39 +44,33 @@ export default defineComponent({
                 <div class={styles.typeTagNo}>非补助课</div>
               )} */}
             </div>
-            <div class={styles.attInfo}>
-              <div class={props.item.signInStatus === 'NORMAL' ? styles.passWrap : styles.goWrap}>
-                <div class={styles.attInfoDot}>
-                  <div class={styles.attInfoDotTitle}>
-                    <span>签到时间</span>
-                    <img
-                      src={props.item.signInStatus === 'NORMAL' ? successIcon : errorIcon}
-                      alt=""
-                    />
-                  </div>
-                  <p class={styles.signTime}>
-                    {props.item.signInTime
-                      ? dayjs(props.item.signInTime).format('HH:mm:ss')
-                      : '未签到'}
+            <div class={styles.itemWrapBottomRight}>
+              <div class={styles.attInfo}>
+                {/* */}
+                <div class={styles.goWrap}>
+                  <p class={styles.goWrapMain}>
+                    {props.item.signInStatus === 'NORMAL' ? (
+                      <span>正常</span>
+                    ) : (
+                      <span style={{ color: '#F44541' }}>异常</span>
+                    )}
                   </p>
+                  <p class={styles.goWrapSub}>签到</p>
                 </div>
-              </div>
-              <div class={props.item.signOutStatus === 'NORMAL' ? styles.passWrap : styles.goWrap}>
-                <div class={styles.attInfoDot}>
-                  <div class={styles.attInfoDotTitle}>
-                    <span>签退时间</span>
-                    <img
-                      src={props.item.signOutStatus === 'NORMAL' ? successIcon : errorIcon}
-                      alt=""
-                    />
-                  </div>
-                  <p class={styles.signTime}>
-                    {props.item.signOutTime
-                      ? dayjs(props.item.signOutTime).format('HH:mm:ss')
-                      : '未签到'}
+                <div class={styles.goWrap}>
+                  <p class={styles.goWrapMain}>
+                    {props.item.signOutStatus === 'NORMAL' ? (
+                      <span>正常</span>
+                    ) : (
+                      <span style={{ color: '#F44541' }}>异常</span>
+                    )}
                   </p>
+                  <p class={styles.goWrapSub}>签退</p>
                 </div>
               </div>
+              <div class={styles.itemWrapTopRight}>
+                <Icon name="arrow"></Icon>
+              </div>
             </div>
           </div>
         </div>

+ 8 - 30
src/views/accompany/music-list.tsx

@@ -34,7 +34,7 @@ export default defineComponent({
     const route = useRoute()
     const imgDefault = getImage('icon-music.svg')
     const data = reactive({
-      loading: true,
+      loading: false,
       finished: false,
       refreshing: false,
       pagenation: {
@@ -86,12 +86,14 @@ export default defineComponent({
     })
 
     const getList = async () => {
+      if (data.loading) return
+      data.loading = true
       try {
         const res: any = await request.post(state.platformApi + '/musicSheet/page', {
           data: {
             ...data.pagenation,
-            keyword: data.keyword
-            // musicTag: data.value2 || data.value1
+            keyword: data.keyword,
+            musicSheetCategoriesId: data.value2 || data.value1
           }
         })
         if (Array.isArray(res?.data?.rows)) {
@@ -107,9 +109,7 @@ export default defineComponent({
           data.finished = true
         }
       } catch (error) {}
-      nextTick(() => {
-        data.loading = false
-      })
+      data.loading = false
     }
     const onRefresh = () => {
       console.log('下拉刷新')
@@ -124,6 +124,7 @@ export default defineComponent({
     // 重置搜索
     const onSearch = () => {
       data.pagenation.page = 1
+      data.list = []
       data.finished = false
       data.loading = false
       data.list = []
@@ -204,29 +205,6 @@ export default defineComponent({
           </div>
         </div>
         {headerData.height && <div style={{ height: headerData.height + 'px' }}></div>}
-        {/* <Cell
-          center
-          title="胜强测试"
-          isLink
-          onClick={() => {
-            let src = `http://192.168.3.114:3000/orchestra-music-score/?id=1603573996544364546`
-            console.log("🚀 ~ 去云教练的src", src)
-            if (browser().isApp) {
-              postMessage({
-                api: 'openAccompanyWebView',
-                content: {
-                  url: src,
-                  orientation: 0,
-                  isHideTitle: true,
-                  statusBarTextColor: false,
-                  isOpenLight: true
-                }
-              })
-            } else {
-                location.href = src
-            }
-          }}
-        ></Cell> */}
         <OFullRefresh
           v-model:modelValue={data.refreshing}
           onRefresh={onRefresh}
@@ -235,7 +213,7 @@ export default defineComponent({
           <List
             loading-text=" "
             immediateCheck={false}
-            v-model:loading={data.loading}
+            loading={data.loading}
             v-model:finished={data.finished}
             finishedText="没有更多了"
             onLoad={() => {

+ 6 - 9
src/views/coursewarePlay/index.module.less

@@ -19,13 +19,14 @@
   pointer-events: none;
 }
 .headerContainer {
-  position: absolute;
+  position: fixed;
   top: 0;
   left: 0;
   right: 0;
   z-index: 10;
   display: flex;
   align-items: center;
+  justify-content: space-between;
   background: linear-gradient(180deg, rgba(0, 0, 0, 0.6), transparent);
 }
 .backBtn {
@@ -225,20 +226,16 @@
   justify-content: center;
   align-items: center;
 }
-.playRecordTimeWrap{
-  position: fixed;
-  top: 0;
-}
 .playRecordTime {
-  position: fixed;
-  top: 33px;
-  left: 16px;
+  width: 90px;
+  margin-right: 10px;
   background: rgba(0, 0, 0, 0.4);
   border-radius: 20px;
-  font-size: 6px;
+  font-size: 12px;
   padding: 6px;
   display: flex;
   align-items: center;
+  justify-content: center;
   color: #fff;
   .timeLoad {
     width: 5px;

+ 25 - 19
src/views/coursewarePlay/index.tsx

@@ -76,13 +76,13 @@ export default defineComponent({
       }
     }
     const handleInit = (type = 0) => {
-      postMessage({
-        api: 'courseLoading',
-        content: {
-          show: true,
-          type: 'fullscreen'
-        }
-      })
+      // postMessage({
+      //   api: 'courseLoading',
+      //   content: {
+      //     show: true,
+      //     type: 'fullscreen'
+      //   }
+      // })
       //设置容器16:9
       setContainer()
       // 横屏
@@ -152,7 +152,10 @@ export default defineComponent({
       if (!route.query.courseId) return
       try {
         const res = await request.get(
-          `${state.platformApi}/courseSchedule/detail/${route.query.courseId}`
+          `${state.platformApi}/courseSchedule/detail/${route.query.courseId}`,
+          {
+            hideLoading: true
+          }
         )
         if (res?.data) {
           data.isCourse = res.data.status === 'ING' ? true : false
@@ -226,20 +229,23 @@ export default defineComponent({
       }
       // console.log('🚀 ~ list', list)
       data.itemList = list
-      setTimeout(() => {
-        postMessage({
-          api: 'courseLoading',
-          content: {
-            show: false,
-            type: 'fullscreen'
-          }
-        })
-      }, 300)
+      // setTimeout(() => {
+      //   postMessage({
+      //     api: 'courseLoading',
+      //     content: {
+      //       show: false,
+      //       type: 'fullscreen'
+      //     }
+      //   })
+      // }, 300)
     }
     const getDetail = async () => {
       try {
         const res: any = await request.get(
-          state.platformApi + `/lessonCoursewareDetail/detail/${route.query.id}`
+          state.platformApi + `/lessonCoursewareDetail/detail/${route.query.id}`,
+          {
+            hideLoading: true
+          }
         )
         if (Array.isArray(res?.data)) {
           data.detail = res.data
@@ -622,6 +628,7 @@ export default defineComponent({
                   返回
                 </div>
                 <div class={styles.menu}>{popupData.tabName}</div>
+                {data.isCourse && <PlayRecordTime list={data.itemList} />}
               </div>
             )}
           </Transition>
@@ -708,7 +715,6 @@ export default defineComponent({
             />
           </Popup>
         </div>
-        <PlayRecordTime list={data.itemList} />
       </div>
     )
   }

+ 1 - 1
src/views/exercise-record/exercis-detail.module.less

@@ -72,7 +72,7 @@
         line-height: 28px;
         margin-bottom: 7px;
         font-family: 'DINA';
-        font-weight: bold;
+        font-weight: 400;
         span {
           margin-left: 2px;
           font-size: 12px;

+ 9 - 2
src/views/exercise-record/exercis-detail.tsx

@@ -16,12 +16,13 @@ import {
 } from 'vant'
 import OFullRefresh from '@/components/o-full-refresh'
 import DetailItem from './modals/detail-item'
-import { defineComponent, onMounted, reactive, ref, onDeactivated } from 'vue'
+import { defineComponent, onMounted, reactive, ref, onDeactivated, computed } from 'vue'
 import { useRoute, useRouter } from 'vue-router'
 import styles from './exercis-detail.module.less'
 import request from '@/helpers/request'
 import questIcon from '@/school/images/quest-icon.png'
 import defaultIcon from '@/school/images/default-icon.png'
+import iconStudent from '@common/images/icon_student.png'
 import { state as globalState } from '@/state'
 
 export default defineComponent({
@@ -173,7 +174,13 @@ export default defineComponent({
               <div class={styles.topInfoLeft}>
                 <div class={styles.headWrap}>
                   <Image
-                    src={infoDetail.value.avatar ? infoDetail.value.avatar : defaultIcon}
+                    src={
+                      infoDetail.value.avatar
+                        ? infoDetail.value.avatar
+                        : platformApi.value == '/api-student'
+                        ? iconStudent
+                        : defaultIcon
+                    }
                     fit="cover"
                     width="68px"
                     height="68px"

+ 2 - 2
src/views/exercise-record/modals/detail-item.tsx

@@ -94,14 +94,14 @@ export default defineComponent({
               <div class={styles.itemBottomDot}>
                 <p class={styles.dotMain} style={{ color: '#F67146' }}>
                   {props.item.score || 0}
-                  <span>分</span>
+                  <span>分</span>{' '}
                 </p>
                 <p class={styles.dotSub}> 综合得分</p>
               </div>
               <div class={styles.itemBottomDot}>
                 <p class={styles.dotMain}>
                   {props.item.intonation || 0}
-                  <span>分</span>
+                  <span>分</span>{' '}
                 </p>
                 <p class={styles.dotSub}>音准 </p>
               </div>

+ 2 - 1
src/views/layout/auth.tsx

@@ -47,7 +47,8 @@ export default defineComponent({
         try {
           const res = await request.get(state.platformApi + '/appLoginUser/getUserInfo', {
             initRequest: true, // 初始化接口
-            requestType: 'form'
+            requestType: 'form',
+            hideLoading: true
           })
           // 初始化学校信息
           if (state.platformType === 'SCHOOL') {

BIN
src/views/mine-orchestra/images/bg.png


BIN
src/views/mine-orchestra/images/icon-or.png


BIN
src/views/mine-orchestra/images/icon-photo-default.png


BIN
src/views/mine-orchestra/images/icon_change.png


+ 44 - 0
src/views/mine-orchestra/index.module.less

@@ -0,0 +1,44 @@
+.mineOrchestra {
+  padding-top: 12px;
+}
+.select {
+  height: 45px;
+  .icon {
+    width: 17px;
+    height: 17px;
+    margin-right: 4px;
+    flex-shrink: 0;
+  }
+  :global {
+    .van-cell__title {
+      overflow: hidden;
+      white-space: nowrap;
+      text-overflow: ellipsis;
+    }
+    .van-cell__right-icon {
+      color: #333;
+      transform: rotate(90deg);
+      margin: 0 0 0 4px;
+    }
+  }
+}
+.tabs {
+  --van-tab-active-text-color: var(--van-primary-color);
+  :global {
+    .van-tab {
+      font-size: 15px;
+      color: #333;
+    }
+    .van-tab--active {
+      color: var(--van-primary-color);
+    }
+    .van-tabs__line {
+      bottom: 20px;
+    }
+  }
+}
+.content {
+  height: calc(100vh - 57px -  var(--van-tabs-line-height) - var(--header-height));
+  overflow: hidden;
+  overflow-y: auto;
+}

+ 118 - 0
src/views/mine-orchestra/index.tsx

@@ -0,0 +1,118 @@
+import OHeader from '@/components/o-header'
+import OSticky from '@/components/o-sticky'
+import request from '@/helpers/request'
+import { state } from '@/state'
+import { Cell, CellGroup, Picker, Popup, Tab, Tabs } from 'vant'
+import { defineComponent, onMounted, reactive, ref } from 'vue'
+import styles from './index.module.less'
+import iconOrchestra from './images/icon-or.png'
+import MyClass from './my-class'
+import OEmpty from '@/components/o-empty'
+import OFullRefresh from '@/components/o-full-refresh'
+import OrchestraDeeds from './orchestra-deeds'
+import MyPhoto from './my-photo'
+
+export default defineComponent({
+  name: 'my-orchestra',
+  setup(props, ctx) {
+    const tabActive = ref('乐团相册')
+    const data = reactive({
+      orchestraList: [] as any[],
+      loading: true
+    })
+    const modelData = reactive({
+      orchestra: {} as any,
+      orchestraStatus: false
+    })
+    const getOrchestras = async () => {
+      data.loading = true
+      try {
+        const res: any = await request.post(`${state.platformApi}/orchestra/page`, {
+          data: { page: 1, rows: 1000 }
+        })
+        if (Array.isArray(res?.data?.rows)) {
+          data.orchestraList = res.data.rows
+          modelData.orchestra = res.data.rows[0] || {}
+        }
+      } catch {}
+      data.loading = false
+    }
+    onMounted(() => {
+      getOrchestras()
+    })
+
+    return () => (
+      <div class={styles.mineOrchestra}>
+        <OSticky
+          onGetHeight={(height: number) => {
+            document.documentElement.style.setProperty('--header-height', height + 'px')
+          }}
+        >
+          <OHeader title="我的乐团" />
+        </OSticky>
+        <OFullRefresh
+          v-model:modelValue={data.loading}
+          onRefresh={() => {
+            data.orchestraList = []
+            getOrchestras()
+          }}
+          style="min-height: calc(100vh - var(--van-nav-bar-height) - var(--header-height))"
+        >
+          <CellGroup inset>
+            <Cell
+              class={styles.select}
+              center
+              isLink
+              onClick={() => (modelData.orchestraStatus = true)}
+            >
+              {{
+                icon: () => <img class={styles.icon} src={iconOrchestra} />,
+                title: () => <div class="van-ellipsis">{modelData.orchestra.name}</div>
+              }}
+            </Cell>
+          </CellGroup>
+          {!!data.orchestraList.length && (
+            <Tabs v-model:active={tabActive.value} class={styles.tabs} lazyRender={true} background="transparent" animated swipeable>
+              <Tab name="我的班级" title="我的班级">
+                <div class={styles.content}>
+                  <MyClass orchestraId={modelData.orchestra?.id || ''} />
+                </div>
+              </Tab>
+              <Tab name="乐团相册" title="乐团相册">
+                <div class={styles.content}>
+                    <MyPhoto orchestraId={modelData.orchestra?.id || ''} />
+                </div>
+              </Tab>
+              <Tab name="乐团事迹" title="乐团事迹">
+                <div class={styles.content}>
+                    <OrchestraDeeds orchestraId={modelData.orchestra?.id || ''} />
+                </div>
+              </Tab>
+            </Tabs>
+          )}
+          {!data.loading && !data.orchestraList.length && (
+            <OEmpty btnStatus={false} tips="暂无乐团" />
+          )}
+        </OFullRefresh>
+
+        <Popup v-model:show={modelData.orchestraStatus} position="bottom" round>
+          <Picker
+            columns={data.orchestraList}
+            columnsFieldNames={{ text: 'name', value: 'id' }}
+            onCancel={() => (modelData.orchestraStatus = false)}
+            onConfirm={({ selectedValues }: any) => {
+              const val = selectedValues[0] || ''
+              modelData.orchestraStatus = false
+              if (val == modelData.orchestra?.id) {
+                return
+              }
+              const active = data.orchestraList.find((n: any) => n.id == val) || {}
+              modelData.orchestra = active
+              console.log(active)
+            }}
+          />
+        </Popup>
+      </div>
+    )
+  }
+})

+ 60 - 0
src/views/mine-orchestra/my-class/index.module.less

@@ -0,0 +1,60 @@
+.myClass {
+  padding: 12px 0;
+}
+.itemDiv {
+  border-radius: 10px;
+  overflow: hidden;
+  background-color: #fff;
+  margin: 0 12px 12px 12px;
+  .iconImg {
+    width: 44px;
+    height: 44px;
+    border-radius: 50%;
+    overflow: hidden;
+    margin-right: 8px;
+  }
+  .messageImg {
+    width: 24px;
+    height: 24px;
+  }
+  .tag {
+    padding: 0 8px;
+    height: 19px;
+    line-height: 19px;
+    background: #ff8057;
+    border-radius: 4px;
+    color: #fff;
+    font-size: 12px;
+    margin-left: 6px;
+  }
+  :global {
+    .van-cell {
+      padding: 0 12px;
+      height: 68px;
+      .van-tag {
+        margin-left: 4px;
+      }
+      .van-cell__label {
+        color: #777;
+      }
+      .van-cell__value {
+        flex: none;
+      }
+    }
+  }
+  .content {
+    display: flex;
+    align-items: center;
+  }
+}
+.grid {
+  .title {
+    font-size: 24px;
+    color: #333;
+    margin-bottom: 4px;
+  }
+  .name {
+    font-size: 12px;
+    color: #777;
+  }
+}

+ 135 - 0
src/views/mine-orchestra/my-class/index.tsx

@@ -0,0 +1,135 @@
+import { Cell, CellGroup, Grid, GridItem, Image, List, Tag } from 'vant'
+import { defineComponent, onMounted, reactive } from 'vue'
+import styles from './index.module.less'
+import iconTeacher from '@common/images/icon_teacher.png'
+import iconMessage from '@common/images/icon-muit-message.png'
+import { postMessage } from '@/helpers/native-message'
+import request from '@/helpers/request'
+import { state } from '@/state'
+import { openDefaultWebView } from '../../../state'
+
+export default defineComponent({
+  name: 'my-orchestra',
+  props: {
+    orchestraId: {
+      type: String,
+      default: ''
+    }
+  },
+  setup(props) {
+    console.log('🚀 ~ props', props)
+    const onMessage = async (item: any) => {
+      console.log(item)
+      postMessage({
+        api: 'joinChatGroup',
+        content: {
+          type: 'multi', // single 单人 multi 多人
+          id: item.imGroupId
+        }
+      })
+    }
+    const openClassDetail = (item: any) => {
+      openDefaultWebView(`/classDetail?classId=${item.id}`)
+    }
+    const data = reactive({
+      pages: {
+        page: 1,
+        rows: 20
+      },
+      classList: [] as any[],
+      loading: false,
+      finished: false
+    })
+    const modelData = reactive({
+      orchestra: {} as any,
+      orchestraStatus: false
+    })
+    const getClassList = async () => {
+      data.loading = true
+      try {
+        const res: any = await request.post(`${state.platformApi}/classGroup/page`, {
+          data: {
+            ...data.pages,
+            orchestraId: props.orchestraId
+          }
+        })
+        console.log(data)
+        data.pages.page += 1
+        if (Array.isArray(res?.data?.rows)) {
+          const list = res.data.rows.map((n: any) => {
+            return {
+              ...n,
+              courseNum: Number(n.courseScheduleNum) - Number(n.completeCourseScheduleNum)
+            }
+          })
+          data.classList = ([] as any[]).concat(data.classList, list)
+          data.finished = res.data.rows.length == 0 ? true : false
+        }
+      } catch {}
+      data.loading = false
+    }
+    onMounted(() => {
+      getClassList()
+    })
+    return () => (
+      <div class={styles.myClass}>
+        <List
+          v-model:loading={data.loading}
+          finishedText="没有更多数据"
+          finished={data.finished}
+          onLoad={getClassList}
+          immediateCheck={false}
+        >
+          {Array.isArray(data.classList) &&
+            data.classList.map((item: any) => (
+              <div class={styles.itemDiv} onClick={() => openClassDetail(item)}>
+                <Cell center label={item.orchestraName}>
+                  {{
+                    icon: () => (
+                      <Image
+                        src={item.teacherAvatar || iconTeacher}
+                        class={styles.iconImg}
+                        fit="cover"
+                      />
+                    ),
+                    title: () => (
+                      <div class={styles.content}>
+                        <div class={['van-ellipsis', styles.teacherName]}>{item.teacherName}</div>
+                        <div class={styles.tag}>
+                          {item.name}
+                        </div>
+                      </div>
+                    ),
+                    value: () => (
+                      <Image
+                        class={styles.messageImg}
+                        src={iconMessage}
+                        onClick={(e: Event) => {
+                          e.stopPropagation()
+                          onMessage(item)
+                        }}
+                      />
+                    )
+                  }}
+                </Cell>
+                <Grid border={false} columnNum={3} class={styles.grid}>
+                  <GridItem>
+                    <p class={styles.title}>{item.preStudentNum || 0}</p>
+                    <p class={styles.name}>学生人数</p>
+                  </GridItem>
+                  <GridItem>
+                    <p class={[styles.title]}>{item.courseNum || 0}</p>
+                    <p class={styles.name}>剩余课时</p>
+                  </GridItem>
+                  <GridItem>
+                    <p class={styles.title}>{item.courseScheduleNum || 0}</p>
+                    <p class={styles.name}>总课时</p>
+                  </GridItem>
+                </Grid>
+              </div>
+            ))}
+        </List>
+      </div>
+    )
+  }
+})

+ 35 - 0
src/views/mine-orchestra/my-photo/index.module.less

@@ -0,0 +1,35 @@
+.photoWrap{
+  display: flex;
+  flex-wrap: wrap;
+  padding: 12px;
+  box-sizing: border-box;
+  justify-content: space-between;
+  div{
+    box-sizing: border-box;
+  }
+}
+.photoItem{
+  position: relative;
+  width: 49%;
+  margin-bottom: 12px;
+  .gridImg{
+    display: flex;
+    justify-content: center;
+    align-items: center;
+    height: calc(100vw / 2);
+    width: 100%;
+  }
+  .iconImage{
+    display: flex;
+    justify-content: center;
+  }
+  .gridName{
+    font-size: 16px;
+    color:#333;
+    padding: 6px 0 4px 0;
+  }
+  .gridDes {
+    color: #777;
+    font-size: 12px;
+  }
+}

+ 108 - 0
src/views/mine-orchestra/my-photo/index.tsx

@@ -0,0 +1,108 @@
+import OEmpty from '@/components/o-empty'
+import OHeader from '@/components/o-header'
+import request from '@/helpers/request'
+import { state } from '@/state'
+import { Grid, GridItem, Image, List, showImagePreview } from 'vant'
+import { defineComponent, onMounted, reactive } from 'vue'
+import { useRoute, useRouter } from 'vue-router'
+import styles from './index.module.less'
+import iconImage from '../images/icon-photo-default.png'
+export default defineComponent({
+  name: 'photo-detail',
+  props: {
+    orchestraId: {
+      type: String,
+      default: ''
+    }
+  },
+  setup(props) {
+    const route = useRoute()
+    const router = useRouter()
+    const data = reactive({
+      loading: false,
+      finished: false,
+      pages: {
+        page: 1,
+        rows: 20
+      },
+      list: [] as any[]
+    })
+
+    const getList = async () => {
+      data.loading = true
+      try {
+        const res = await request.post(`${state.platformApi}/orchestraPhotoAlbum/page`, {
+          data: {
+            ...data.pages,
+            orchestraId: props.orchestraId
+          }
+        })
+        if (Array.isArray(res?.data?.rows)) {
+          data.list = data.list.concat(res.data.rows)
+          data.pages.page += 1
+          if (!res.data.rows.length) {
+            data.finished = true
+          }
+        }
+      } catch {}
+      data.loading = false
+    }
+
+    // 预览图片
+    const onShowImage = (index: number) => {
+      const files = data.list.map((file: any) => {
+        return file.fileUrl
+      })
+
+      showImagePreview({
+        images: files,
+        startPosition: index,
+        closeable: true
+      })
+    }
+
+    onMounted(() => {
+      getList()
+      document.title = (route.query.name as any) || ''
+    })
+
+    return () => (
+      <div class={styles.phoneDetail}>
+        {!data.loading && !!data.list.length && (
+          <List
+            v-model:loading={data.loading}
+            finished={data.finished}
+            finishedText="没有更多数据"
+            onLoad={getList}
+            immediateCheck={false}
+          >
+            <div class={styles.photoWrap}>
+              {data.list.map((item: any, index: number) => (
+                <div class={styles.photoItem} onClick={() => {
+                  router.push({
+                    path: '/photo-list',
+                    query: {
+                      id: item.id
+                    }
+                  })
+                }}>
+                  {item.coverUrl ? (
+                    <Image class={styles.gridImg} src={item.coverUrl} fit="cover" />
+                  ) : (
+                    <div class={styles.gridImg}>
+                      <Image src={iconImage} fit="cover" />
+                    </div>
+                  )}
+
+                  <div class={styles.gridName}>{item.name}</div>
+                  <div class={styles.gridDes}>{item.photoCount}张</div>
+                </div>
+              ))}
+            </div>
+          </List>
+        )}
+        {!data.loading && !data.list.length && <OEmpty btnStatus={false} tips="暂无相册" />}
+      </div>
+    )
+  }
+})

BIN
src/views/mine-orchestra/orchestra-deeds/images/icon-edit.png


BIN
src/views/mine-orchestra/orchestra-deeds/images/icon-step-calendar.png


BIN
src/views/mine-orchestra/orchestra-deeds/images/icon-step.png


BIN
src/views/mine-orchestra/orchestra-deeds/images/icon-upload-video-cover.png


BIN
src/views/mine-orchestra/orchestra-deeds/images/icon-upload-video.png


BIN
src/views/mine-orchestra/orchestra-deeds/images/icon-upload.png


+ 81 - 0
src/views/mine-orchestra/orchestra-deeds/index.module.less

@@ -0,0 +1,81 @@
+.cellGroup {
+  margin: 12px 13px 0;
+  overflow: hidden;
+  border-radius: 10px;
+  :global {
+    .van-cell {
+      font-size: 16px;
+      color: #333333;
+      padding: 16px 12px;
+    }
+  }
+}
+
+.storySteps {
+  background-color: transparent;
+  padding-top: 12px;
+
+  :global {
+    .van-step--vertical {
+      padding-right: 13px;
+      &::after {
+        border-width: 0 !important;
+      }
+    }
+  }
+
+  .stepTimes {
+    display: flex;
+    align-items: center;
+    justify-content: space-between;
+    font-size: 20px;
+    font-weight: bold;
+    color: #333333;
+
+    .stepTime {
+      font-family: 'DINA';
+    }
+
+    .stepEdit {
+      font-size: 14px;
+      font-weight: 400;
+      color: #777777;
+      display: flex;
+      align-items: center;
+      :global {
+        .van-icon {
+          font-size: 14px;
+          margin-right: 3px;
+        }
+      }
+    }
+  }
+
+  .content {
+    padding-top: 8px;
+    font-size: 14px;
+    color: #666666;
+    line-height: 20px;
+  }
+
+  .storySwipe {
+    padding-top: 6px;
+    --van-swipe-indicator-size: 8px;
+
+    .swipeImg {
+      width: 100%;
+      height: 200px;
+      border-radius: 10px;
+      overflow: hidden;
+    }
+  }
+
+  .iconActive {
+    width: 18px;
+    height: 18px;
+  }
+  .iconInactive {
+    width: 12px;
+    height: 12px;
+  }
+}

+ 138 - 0
src/views/mine-orchestra/orchestra-deeds/index.tsx

@@ -0,0 +1,138 @@
+import OHeader from '@/components/o-header'
+import {
+  Cell,
+  CellGroup,
+  Icon,
+  Image,
+  List,
+  Picker,
+  Popup,
+  Step,
+  Steps,
+  Swipe,
+  SwipeItem
+} from 'vant'
+import { defineComponent, onMounted, reactive } from 'vue'
+import { useRoute, useRouter } from 'vue-router'
+import styles from './index.module.less'
+import iconStep from './images/icon-step.png'
+import iconStepCalendar from './images/icon-step-calendar.png'
+import request from '@/helpers/request'
+import OEmpty from '@/components/o-empty'
+import dayjs from 'dayjs'
+import OVideo from '@/components/o-video'
+import {state as globalState} from '@/state'
+
+export default defineComponent({
+  name: 'orchestra-story',
+  props: {
+    orchestraId: {
+      type: String,
+      default: ''
+    }
+  },
+  setup(props) {
+    const state = reactive({
+      isClick: false,
+      list: [] as any,
+      listState: {
+        dataShow: true, // 判断是否有数据
+        loading: false,
+        finished: false,
+        refreshing: false,
+        height: 0 // 页面头部高度,为了处理下拉刷新用的
+      },
+      params: {
+        type: null,
+        page: 1,
+        rows: 20
+      }
+    })
+
+    const getList = async () => {
+      try {
+        if (state.isClick) return
+        state.isClick = true
+        const res = await request.post(`${globalState.platformApi}/orchestraStory/page`, {
+          data: {
+            orchestraId: props.orchestraId
+          }
+        })
+        state.listState.loading = false
+        state.listState.refreshing = false
+        const result = res.data || {}
+        // 处理重复请求数据
+        if (state.list.length > 0 && result.current === 1) {
+          return
+        }
+        state.list = state.list.concat(result.rows || [])
+        state.listState.finished = result.current >= result.pages
+        state.params.page = result.current + 1
+        state.listState.dataShow = state.list.length > 0
+        state.isClick = false
+      } catch {
+        state.listState.dataShow = false
+        state.listState.finished = true
+        state.listState.refreshing = false
+        state.isClick = false
+      }
+    }
+
+    onMounted(() => {
+      getList()
+    })
+    return () => (
+      <div class={styles.orchestraStory}>
+        {state.listState.dataShow ? (
+          <List
+            v-model:loading={state.listState.loading}
+            finished={state.listState.finished}
+            finishedText=" "
+            class={[styles.liveList]}
+            onLoad={getList}
+            immediateCheck={false}
+          >
+            <Steps direction="vertical" class={styles.storySteps}>
+              {state.list.map((item: any) => (
+                <Step
+                  v-slots={{
+                    'inactive-icon': () => <Image src={iconStep} class={styles.iconInactive} />,
+                    'active-icon': () => <Image src={iconStepCalendar} class={styles.iconActive} />
+                  }}
+                >
+                  <div class={styles.stepTimes}>
+                    <div class={styles.stepTime}>
+                      {dayjs(item.createTime).format('YYYY年MM月DD日')}
+                    </div>
+                  </div>
+                  <p class={[styles.content, 'van-multi-ellipsis--l2']}>{item.content}</p>
+
+                  <Swipe class={styles.storySwipe}>
+                    {item.attachments &&
+                      item.attachments.map((child: any) => (
+                        <SwipeItem>
+                          {item.type === 'IMAGE' && (
+                            <Image src={child.url} class={styles.swipeImg} fit="cover" />
+                          )}
+                          {item.type === 'VIDEO' && (
+                            <OVideo
+                              src={child.url}
+                              height={'100%'}
+                              poster={child.coverImage}
+                              class={styles.swipeImg}
+                            />
+                          )}
+                        </SwipeItem>
+                      ))}
+                  </Swipe>
+                </Step>
+              ))}
+            </Steps>
+          </List>
+        ) : (
+          <OEmpty btnStatus={false} tips="暂无事迹" />
+        )}
+      </div>
+    )
+  }
+})

+ 105 - 0
src/views/mine-orchestra/photo-list/detail.tsx

@@ -0,0 +1,105 @@
+import OEmpty from '@/components/o-empty'
+import OHeader from '@/components/o-header'
+import request from '@/helpers/request'
+import { state } from '@/state'
+import { Grid, GridItem, Image, List, showImagePreview } from 'vant'
+import { defineComponent, onMounted, reactive } from 'vue'
+import { useRoute } from 'vue-router'
+import styles from './index.module.less'
+import iconImage from '../images/icon-photo-default.png'
+import OSticky from '@/components/o-sticky'
+export default defineComponent({
+  name: 'photo-detail',
+  props: {
+    orchestraId: {
+      type: String,
+      default: ''
+    }
+  },
+  setup(props) {
+    const route = useRoute()
+    console.log("🚀 ~ route", route)
+    const data = reactive({
+      loading: false,
+      finished: false,
+      pages: {
+        page: 1,
+        rows: 20
+      },
+      list: [] as any[]
+    })
+
+    const getList = async () => {
+      data.loading = true
+      try {
+        const res = await request.post(`${state.platformApi}/orchestraPhoto/page`, {
+          data: {
+            ...data.pages,
+            orchestraPhotoAlbumId: route.query.orchestraPhotoAlbumId
+          }
+        })
+        if (Array.isArray(res?.data?.rows)) {
+          data.list = [1,2,2,2,2,2,2,2,2]// data.list.concat(res.data.rows)
+          data.pages.page += 1
+          if (!res.data.rows.length) {
+            data.finished = true
+          }
+        }
+      } catch {}
+      data.loading = false
+    }
+
+    // 预览图片
+    const onShowImage = (index: number) => {
+      const files = data.list.map((file: any) => {
+        return file.fileUrl
+      })
+
+      showImagePreview({
+        images: files,
+        startPosition: index,
+        closeable: true
+      })
+    }
+
+    onMounted(() => {
+      getList()
+      document.title = (route.query.name as any) || ''
+    })
+
+    return () => (
+      <div>
+        <OSticky>
+            <OHeader title={(route.query.name as string) || '我的乐团'} />
+        </OSticky>
+        <div class={styles.phoneDetail}>
+          {!data.loading && !!data.list.length && (
+            <List
+              v-model:loading={data.loading}
+              finished={data.finished}
+              finishedText="没有更多数据"
+              onLoad={getList}
+              immediateCheck={false}
+            >
+              <Grid columnNum={3}>
+                {data.list.map((item: any, index: number) => (
+                  <GridItem onClick={() => onShowImage(index)}>
+                    {item.fileUrl ? (
+                      <Image class={styles.gridImg} style={{height: 'calc(100vw / 3)'}} src={item.fileUrl} fit="cover" />
+                    ) : (
+                      <div class={styles.gridImg}>
+                        <Image src={iconImage} fit="cover" />
+                      </div>
+                    )}
+
+                  </GridItem>
+                ))}
+              </Grid>
+            </List>
+          )}
+          {!data.loading && !data.list.length && <OEmpty btnStatus={false} tips="暂无相册" />}
+        </div>
+      </div>
+    )
+  }
+})

+ 36 - 0
src/views/mine-orchestra/photo-list/index.module.less

@@ -0,0 +1,36 @@
+.photoWrap{
+    display: flex;
+    flex-wrap: wrap;
+    padding: 12px;
+    box-sizing: border-box;
+    justify-content: space-between;
+    div{
+      box-sizing: border-box;
+    }
+  }
+  .photoItem{
+    position: relative;
+    width: 49%;
+    margin-bottom: 12px;
+    .gridImg{
+      display: flex;
+      justify-content: center;
+      align-items: center;
+      width: 100%;
+      height: calc(100vw / 2);
+    }
+    .iconImage{
+      display: flex;
+      justify-content: center;
+    }
+    .gridName{
+      font-size: 16px;
+      color:#333;
+      padding: 6px 0 4px 0;
+    }
+    .gridDes {
+      color: #777;
+      font-size: 12px;
+    }
+  }
+  

+ 116 - 0
src/views/mine-orchestra/photo-list/index.tsx

@@ -0,0 +1,116 @@
+import OEmpty from '@/components/o-empty'
+import OHeader from '@/components/o-header'
+import request from '@/helpers/request'
+import { state } from '@/state'
+import { Grid, GridItem, Image, List, showImagePreview } from 'vant'
+import { defineComponent, onMounted, reactive } from 'vue'
+import { useRoute, useRouter } from 'vue-router'
+import styles from './index.module.less'
+import iconImage from '../images/icon-photo-default.png'
+import OSticky from '@/components/o-sticky'
+export default defineComponent({
+  name: 'photo-detail',
+  props: {
+    orchestraId: {
+      type: String,
+      default: ''
+    }
+  },
+  setup(props) {
+    const route = useRoute()
+    const router = useRouter()
+    console.log("🚀 ~ route", route)
+    const data = reactive({
+      loading: false,
+      finished: false,
+      pages: {
+        page: 1,
+        rows: 20
+      },
+      list: [] as any[]
+    })
+
+    const getList = async () => {
+      data.loading = true
+      try {
+        const res = await request.post(`${state.platformApi}/orchestraPhotoAlbum/page`, {
+          data: {
+            ...data.pages,
+            orchestraId: props.orchestraId,
+            parentId: route.query.id
+          }
+        })
+        if (Array.isArray(res?.data?.rows)) {
+          data.list = data.list.concat(res.data.rows)
+          data.pages.page += 1
+          if (!res.data.rows.length) {
+            data.finished = true
+          }
+        }
+      } catch {}
+      data.loading = false
+    }
+
+    // 预览图片
+    const onShowImage = (index: number) => {
+      const files = data.list.map((file: any) => {
+        return file.fileUrl
+      })
+
+      showImagePreview({
+        images: files,
+        startPosition: index,
+        closeable: true
+      })
+    }
+
+    onMounted(() => {
+      getList()
+      document.title = (route.query.name as any) || ''
+    })
+
+    return () => (
+      <div>
+        <OSticky>
+            <OHeader title={(route.query.name as string) || '我的乐团'} />
+        </OSticky>
+        <div class={styles.phoneDetail}>
+          {!data.loading && !!data.list.length && (
+            <List
+              v-model:loading={data.loading}
+              finished={data.finished}
+              finishedText="没有更多数据"
+              onLoad={getList}
+              immediateCheck={false}
+            >
+              <div class={styles.photoWrap}>
+                {data.list.map((item: any, index: number) => (
+                  <div class={styles.photoItem} onClick={() => {
+                    router.push({
+                        path: '/photo-list-detail',
+                        query:{
+                            orchestraPhotoAlbumId: item.id
+                        }
+                    })
+                  }}>
+                    {item.coverUrl ? (
+                      <Image class={styles.gridImg} src={item.coverUrl} fit="cover" />
+                    ) : (
+                      <div class={styles.gridImg}>
+                        <Image src={iconImage} fit="cover" />
+                      </div>
+                    )}
+
+                    <div class={styles.gridName}>{item.name || ''}</div>
+                    <div class={styles.gridDes}>{item.photoCount || 0}张</div>
+                  </div>
+                ))}
+              </div>
+            </List>
+          )}
+          {!data.loading && !data.list.length && <OEmpty btnStatus={false} tips="暂无相册" />}
+        </div>
+      </div>
+    )
+  }
+})