Przeglądaj źródła

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

lex 2 lat temu
rodzic
commit
5eb9846b3b

+ 2 - 2
src/router/index.ts

@@ -5,7 +5,7 @@ import { postMessage } from '@/helpers/native-message'
 import routesTeacher from './routes-teacher'
 import routesStudent from './routes-student'
 import routesSchool from './routes-school'
-
+;(window as any).paymentType = 'SCHOOL'
 const paymentType = (window as any).paymentType
 let routes: any = []
 let baseUrl = null as any
@@ -45,7 +45,7 @@ router.beforeEach((to, from, next) => {
 })
 
 let isOpen = false
-router.onError(error => {
+router.onError((error) => {
   if (error instanceof Error) {
     const isChunkLoadFailed = error.name.indexOf('chunk')
     const targetPath = router.currentRoute.value.fullPath

+ 19 - 4
src/router/routes-school.ts

@@ -6,9 +6,7 @@ type metaType = {
 }
 
 // 不需要登录的路由
-const noLoginRouter = [
-
-]
+const noLoginRouter = []
 
 export default [
   {
@@ -60,7 +58,8 @@ export default [
         meta: {
           title: '群发记录'
         }
-      }, {
+      },
+      {
         path: '/create-message',
         name: 'create-message',
         component: () => import('@/school/mass-message/create-message'),
@@ -95,6 +94,22 @@ export default [
         meta: {
           title: '管理老师'
         }
+      },
+      {
+        path: '/exercise-record',
+        name: 'exercise-record',
+        component: () => import('@/school/exercise-record'),
+        meta: {
+          title: '练习记录'
+        }
+      },
+      {
+        path: '/exercis-detail',
+        name: 'exercis-detail',
+        component: () => import('@/school/exercise-record/exercis-detail'),
+        meta: {
+          title: '测评详情'
+        }
       }
     ]
   },

+ 126 - 0
src/school/exercise-record/exercis-detail.module.less

@@ -0,0 +1,126 @@
+@img: '../images';
+
+.topWrap {
+  height: 316px;
+  background: url('@{img}/detail-bg.png') center center/ cover;
+  margin-bottom: -90px;
+  .topInfo {
+    padding: 34px 15px 30px;
+    display: flex;
+    flex-direction: row;
+    align-items: center;
+    justify-content: space-between;
+    .topInfoLeft {
+      width: 50%;
+      display: flex;
+      flex-direction: row;
+      align-items: center;
+      .headWrap {
+        border-radius: 50%;
+        overflow: hidden;
+        border: 2px solid #fff;
+        width: 68px;
+        height: 68px;
+        margin-right: 15px;
+        img {
+          width: 100%;
+          height: 100%;
+        }
+      }
+      .infoMsg {
+        p {
+          font-size: 20px;
+          font-weight: 600;
+          color: #000000;
+          line-height: 28px;
+          margin-bottom: 6px;
+        }
+        .tag {
+          padding: 2px 11px;
+          // min-width: 50px;
+          background: #ff8057;
+          border-radius: 12px;
+          height: 24px;
+          font-size: 14px;
+          font-family: PingFangSC-Medium, PingFang SC;
+          font-weight: 500;
+          color: #ffffff;
+          line-height: 20px;
+          text-align: center;
+        }
+      }
+    }
+    .topInfoRight {
+      width: 50%;
+      display: flex;
+      flex-direction: row;
+      align-items: center;
+      justify-content: flex-end;
+      .infoDay {
+        margin-right: 30px;
+      }
+      .infoDayMain {
+        font-size: 24px;
+        font-weight: bold;
+        color: #333333;
+        line-height: 28px;
+        margin-bottom: 7px;
+        span {
+          font-size: 12px;
+          font-weight: 400;
+          color: #333333;
+          line-height: 17px;
+        }
+      }
+      .infoDaysub {
+        font-size: 12px;
+        font-weight: 400;
+        color: #333333;
+        line-height: 17px;
+      }
+    }
+  }
+  .chioseWrap {
+    display: flex;
+    flex-direction: row;
+    align-items: center;
+    // justify-content: space-around;
+    background-color: transparent;
+  }
+}
+
+.DialogTitle {
+  display: flex;
+  flex-direction: row;
+  align-items: center;
+  padding: 20px 25px;
+  span {
+    width: 4px;
+    height: 14px;
+    background: #ff8057;
+    border-radius: 2px;
+    margin-right: 6px;
+  }
+  p {
+    height: 25px;
+    font-size: 18px;
+    font-weight: 500;
+    color: #333333;
+    line-height: 25px;
+  }
+}
+.DialogConent {
+  padding: 0 25px 20px;
+  p {
+    font-size: 16px;
+    line-height: 22px;
+    color: #333;
+  }
+}
+:global {
+  .exercisDetailDialog {
+    .van-dialog__header {
+      padding-top: 0px !important;
+    }
+  }
+}

+ 228 - 0
src/school/exercise-record/exercis-detail.tsx

@@ -0,0 +1,228 @@
+import OHeader from '@/components/o-header'
+import OSticky from '@/components/o-sticky'
+import dayjs from 'dayjs'
+import {
+  Icon,
+  Popover,
+  DatePicker,
+  DatePickerColumnType,
+  Popup,
+  List,
+  PullRefresh,
+  showToast,
+  Dialog
+} from 'vant'
+import DetailItem from './modals/detail-item'
+import { defineComponent, reactive, ref } from 'vue'
+import { useRouter } from 'vue-router'
+import styles from './exercis-detail.module.less'
+import request from '@/helpers/request'
+import questIcon from '../images/quest-icon.png'
+import defaultIcon from '@/school/images/default-icon.jpg'
+export default defineComponent({
+  name: 'exercis-detail',
+  setup() {
+    const router = useRouter()
+    const state = reactive({
+      showPopoverTime: false,
+      showPopoverOrchestra: false,
+      currentDate: [dayjs().format('YYYY'), dayjs().format('MM')],
+      actions: [
+        { text: '全部乐团', color: 'var(--van-primary-color)' },
+        { text: '交付团' },
+        { text: '晋升团' }
+      ]
+    })
+    const forms = reactive({
+      practiceMonth: state.currentDate[0] + '' + state.currentDate[1],
+      practiceMonthName: state.currentDate[0] + '年' + state.currentDate[1] + '月',
+      orchestraId: '',
+      orchestraName: '',
+      page: 1,
+      rows: 20
+    })
+    const showTip = ref(false)
+    const minDate = ref(new Date(dayjs().subtract(5, 'year').format('YYYY-MM-DD')))
+    const maxDate = ref(new Date(dayjs().add(5, 'year').format('YYYY-MM-DD')))
+    const columnsType = ref<DatePickerColumnType[]>(['year', 'month'])
+    const refreshing = ref(false)
+    const loading = ref(false)
+    const finished = ref(false)
+    const showContact = ref(false)
+    const list = ref([])
+    const getList = async () => {
+      loading.value = true
+      try {
+        const res = await request.post('/api-school/student/page', {
+          data: { ...forms }
+        })
+        if (refreshing.value) {
+          // list.value = []
+          refreshing.value = false
+        }
+        if (list.value.length > 0 && res.data.pageNo === 1) {
+          return
+        }
+
+        showContact.value = list.value.length > 0
+        forms.page = res.data.current + 1
+        list.value = list.value.concat(res.data.rows || [])
+        loading.value = false
+
+        finished.value = res.data.current >= res.data.pages
+      } catch (e: any) {
+        // console.log(e, 'e')
+        const message = e.message
+        showToast(message)
+        showContact.value = false
+        finished.value = true
+      }
+    }
+    const onBack = () => {
+      console.log('返回')
+    }
+
+    const checkTimer = (val: any) => {
+      forms.practiceMonth = val.selectedValues[0] + val.selectedValues[1]
+      forms.practiceMonthName = val.selectedValues[0] + '年' + val.selectedValues[1] + '月'
+      state.showPopoverTime = false
+      getList()
+    }
+
+    const onRefresh = () => {
+      finished.value = false
+      // 重新加载数据
+      // 将 loading 设置为 true,表示处于加载状态
+      loading.value = true
+      getList()
+    }
+    return () => (
+      <>
+        <OSticky position="top" background="#F8F8F8">
+          <div class={styles.topWrap}>
+            <OHeader isBack={true} onHeaderBack={onBack} border={false} background={'transparent'}>
+              {{
+                right: () => (
+                  <Icon
+                    name={questIcon}
+                    size={22}
+                    color="#333"
+                    onClick={() => {
+                      showTip.value = true
+                    }}
+                  />
+                )
+              }}
+            </OHeader>
+            <div class={styles.topInfo}>
+              <div class={styles.topInfoLeft}>
+                <div class={styles.headWrap}>
+                  <img src={defaultIcon} alt="" />
+                </div>
+                <div class={styles.infoMsg}>
+                  <p>邓同学</p>
+                  <div class={styles.tag}>长笛</div>
+                </div>
+              </div>
+              <div class={styles.topInfoRight}>
+                <div class={styles.infoDay}>
+                  <p class={styles.infoDayMain}>
+                    10 <span>天</span>
+                  </p>
+                  <p class={styles.infoDaysub}>练习天数</p>
+                </div>
+                <div class={styles.infoTime}>
+                  <p class={styles.infoDayMain}>
+                    260 <span>分钟</span>
+                  </p>
+                  <p class={styles.infoDaysub}>练习天数</p>
+                </div>
+              </div>
+            </div>
+            <div class={styles.chioseWrap}>
+              <div style={{ padding: '12px 13px', background: 'transparent' }}>
+                <div
+                  class={styles.searchBand}
+                  onClick={() => {
+                    state.showPopoverTime = true
+                  }}
+                >
+                  {forms.practiceMonthName}
+                  <Icon name={state.showPopoverTime ? 'arrow-up' : 'arrow-down'} />
+                </div>
+              </div>
+
+              <div style={{ padding: '12px 13px', background: 'transparent' }}>
+                <Popover
+                  v-model:show={state.showPopoverOrchestra}
+                  actions={state.actions}
+                  showArrow={false}
+                  placement="bottom-start"
+                  offset={[0, 12]}
+                >
+                  {{
+                    reference: () => (
+                      <div class={styles.searchBand}>
+                        全部乐团
+                        <Icon name={state.showPopoverOrchestra ? 'arrow-up' : 'arrow-down'} />
+                      </div>
+                    )
+                  }}
+                </Popover>
+              </div>
+            </div>
+          </div>
+        </OSticky>
+        <PullRefresh v-model={refreshing.value} onRefresh={onRefresh}>
+          <List
+            v-model:loading={loading.value}
+            finished={finished.value}
+            finished-text="没有更多了"
+            onLoad={getList}
+          >
+            {list.value.map((item: any) => (
+              <DetailItem item={item} />
+            ))}
+          </List>
+        </PullRefresh>
+
+        <Popup v-model:show={state.showPopoverTime} position="bottom" style="{ height: '30%' }">
+          <DatePicker
+            onCancel={() => {
+              state.showPopoverTime = false
+            }}
+            onConfirm={checkTimer}
+            v-model={state.currentDate}
+            title="选择年月"
+            minDate={minDate.value}
+            maxDate={maxDate.value}
+            columnsType={columnsType.value}
+          />
+        </Popup>
+        <Dialog
+          class="exercisDetailDialog"
+          v-model:show={showTip.value}
+          title="提示框"
+          confirmButtonText="我知道了"
+          vSlots={{
+            title: () => (
+              <div class={styles.DialogTitle}>
+                <span></span>
+                <p>什么是练习数据</p>
+              </div>
+            ),
+            default: () => (
+              <div class={styles.DialogConent}>
+                <p>
+                  练习数据是学生通过云教练自主练习的数据统计,可根据时间段查询学生的练习天数和练习时长{' '}
+                </p>
+                <p>练习天数:当天又曲目播放或测评记录即算练习</p>
+                <p>练习时长:曲目播放和曲目测评的时长总和</p>
+              </div>
+            )
+          }}
+        ></Dialog>
+      </>
+    )
+  }
+})

+ 7 - 0
src/school/exercise-record/index.module.less

@@ -0,0 +1,7 @@
+.chioseWrap {
+  display: flex;
+  flex-direction: row;
+  align-items: center;
+  justify-content: space-around;
+  background-color: #f8f8f8;
+}

+ 229 - 0
src/school/exercise-record/index.tsx

@@ -0,0 +1,229 @@
+import OHeader from '@/components/o-header'
+import OSearch from '@/components/o-search'
+import OSticky from '@/components/o-sticky'
+import dayjs from 'dayjs'
+import {
+  Cell,
+  Icon,
+  Popover,
+  Tag,
+  DatePicker,
+  DatePickerColumnType,
+  Popup,
+  List,
+  PullRefresh,
+  ActionSheet,
+  showToast
+} from 'vant'
+import StudentItem from './modals/student-item'
+import { defineComponent, reactive, ref } from 'vue'
+import { useRouter } from 'vue-router'
+import styles from './index.module.less'
+import request from '@/helpers/request'
+
+export default defineComponent({
+  name: 'exercise-record',
+  setup() {
+    const router = useRouter()
+    const state = reactive({
+      showPopoverTime: false,
+      showPopoverOrchestra: false,
+      showPopoverSubject: false,
+      showPopoverSort: false,
+      actions: [
+        { text: '全部乐团', color: 'var(--van-primary-color)' },
+        { text: '交付团' },
+        { text: '晋升团' }
+      ],
+      actionSorts: [
+        { text: '按天数', value: 'PRACTICE_DAY' },
+        { text: '按时长', value: 'PRACTICE_TIMES' }
+      ],
+      currentDate: [dayjs().format('YYYY'), dayjs().format('MM')]
+    })
+    const forms = reactive({
+      practiceMonth: state.currentDate[0] + '' + state.currentDate[1],
+      practiceMonthName: state.currentDate[0] + '年' + state.currentDate[1] + '月',
+      orchestraId: '',
+      orchestraName: '',
+      subjectId: '',
+      subjectName: '',
+      sortType: '',
+      sortTypeName: '',
+      page: 1,
+      rows: 20
+    })
+    const minDate = ref(new Date(dayjs().subtract(5, 'year').format('YYYY-MM-DD')))
+    const maxDate = ref(new Date(dayjs().add(5, 'year').format('YYYY-MM-DD')))
+    const columnsType = ref<DatePickerColumnType[]>(['year', 'month'])
+    const refreshing = ref(false)
+    const loading = ref(false)
+    const finished = ref(false)
+    const showContact = ref(false)
+    const list = ref([])
+    const onDetail = (item: any) => {
+      console.log(item)
+      router.push({
+        path: '/orchestra-detail',
+        query: {
+          id: item
+        }
+      })
+    }
+    const getList = async () => {
+      loading.value = true
+      try {
+        const res = await request.post('/api-school/student/page', {
+          data: { ...forms }
+        })
+        if (refreshing.value) {
+          list.value = []
+          refreshing.value = false
+        }
+        if (list.value.length > 0 && res.data.pageNo === 1) {
+          return
+        }
+
+        showContact.value = list.value.length > 0
+        forms.page = res.data.current + 1
+        list.value = list.value.concat(res.data.rows || [])
+        loading.value = false
+
+        finished.value = res.data.current >= res.data.pages
+      } catch (e: any) {
+        // console.log(e, 'e')
+        const message = e.message
+        showToast(message)
+        showContact.value = false
+        finished.value = true
+      }
+    }
+    const onBack = () => {
+      console.log('返回')
+    }
+
+    const checkTimer = (val: any) => {
+      forms.practiceMonth = val.selectedValues[0] + val.selectedValues[1]
+      forms.practiceMonthName = val.selectedValues[0] + '年' + val.selectedValues[1] + '月'
+      state.showPopoverTime = false
+      getList()
+    }
+    const checkSort = (val: any) => {
+      forms.sortType = val.value
+      forms.sortTypeName = val.text
+      getList()
+    }
+
+    const onRefresh = () => {
+      finished.value = false
+      // 重新加载数据
+      // 将 loading 设置为 true,表示处于加载状态
+      loading.value = true
+      getList()
+    }
+    return () => (
+      <>
+        <OSticky position="top" background="#F8F8F8">
+          <OHeader isBack={true} onHeaderBack={onBack}></OHeader>
+          <OSearch placeholder="学生编号" onSearch={getList}></OSearch>
+          <div class={styles.chioseWrap}>
+            <div style={{ padding: '12px 13px', background: '#F8F8F8' }}>
+              <div
+                class={styles.searchBand}
+                onClick={() => {
+                  state.showPopoverTime = true
+                }}
+              >
+                {forms.practiceMonthName}
+                <Icon name={state.showPopoverTime ? 'arrow-up' : 'arrow-down'} />
+              </div>
+            </div>
+
+            <div style={{ padding: '12px 13px', background: '#F8F8F8' }}>
+              <Popover
+                v-model:show={state.showPopoverSubject}
+                actions={state.actions}
+                showArrow={false}
+                placement="bottom-start"
+                offset={[0, 12]}
+              >
+                {{
+                  reference: () => (
+                    <div class={styles.searchBand}>
+                      全部乐团
+                      <Icon name={state.showPopoverSubject ? 'arrow-up' : 'arrow-down'} />
+                    </div>
+                  )
+                }}
+              </Popover>
+            </div>
+            <div style={{ padding: '12px 13px', background: '#F8F8F8' }}>
+              <Popover
+                v-model:show={state.showPopoverSubject}
+                actions={state.actions}
+                showArrow={false}
+                placement="bottom-start"
+                offset={[0, 12]}
+              >
+                {{
+                  reference: () => (
+                    <div class={styles.searchBand}>
+                      全部声部
+                      <Icon name={state.showPopoverSubject ? 'arrow-up' : 'arrow-down'} />
+                    </div>
+                  )
+                }}
+              </Popover>
+            </div>
+
+            <div style={{ padding: '12px 13px', background: '#F8F8F8' }}>
+              <Popover
+                v-model:show={state.showPopoverSort}
+                actions={state.actionSorts}
+                showArrow={false}
+                placement="bottom-end"
+                offset={[0, 12]}
+                onSelect={checkSort}
+              >
+                {{
+                  reference: () => (
+                    <div class={styles.searchBand}>
+                      按天数
+                      <Icon name={state.showPopoverSort ? 'arrow-up' : 'arrow-down'} />
+                    </div>
+                  )
+                }}
+              </Popover>
+            </div>
+          </div>
+        </OSticky>
+        <PullRefresh v-model={refreshing.value} onRefresh={onRefresh}>
+          <List
+            v-model:loading={loading.value}
+            finished={finished.value}
+            finished-text="没有更多了"
+            onLoad={getList}
+          >
+            {list.value.map((item: any) => (
+              <StudentItem item={item} />
+            ))}
+          </List>
+        </PullRefresh>
+
+        <Popup v-model:show={state.showPopoverTime} position="bottom" style="{ height: '30%' }">
+          <DatePicker
+            onCancel={() => {
+              state.showPopoverTime = false
+            }}
+            onConfirm={checkTimer}
+            v-model={state.currentDate}
+            title="选择年月"
+            minDate={minDate.value}
+            maxDate={maxDate.value}
+            columnsType={columnsType.value}
+          />
+        </Popup>
+      </>
+    )
+  }
+})

+ 71 - 0
src/school/exercise-record/modals/detail-item.module.less

@@ -0,0 +1,71 @@
+.itemWrap {
+  background: #ffffff;
+  border-radius: 10px;
+  padding: 12px 15px 20px;
+  margin: 0 13px;
+  .itemTop {
+    display: flex;
+    flex-direction: row;
+    justify-content: space-between;
+    align-items: center;
+    border-bottom: 1px solid #f2f2f2;
+    padding-bottom: 12px;
+    .itemTopLeft {
+      .itemTopMain {
+        height: 22px;
+        font-size: 16px;
+        font-weight: 500;
+        color: #333333;
+        line-height: 22px;
+        margin-bottom: 6px;
+      }
+      .itemTopSub {
+        font-weight: 400;
+        color: #777777;
+        line-height: 17px;
+      }
+    }
+    .itemTopRight {
+      .imgWrap {
+        width: 87px;
+        height: 33px;
+        background: #e9e3ff;
+        border-radius: 19px;
+        img {
+          width: 100%;
+          height: 100%;
+        }
+      }
+    }
+  }
+  .itemBottom {
+    margin-top: 15px;
+    display: flex;
+    flex-direction: row;
+    align-items: center;
+    justify-content: space-around;
+    text-align: center;
+    .itemBottomDot {
+      width: 25%;
+      .dotMain {
+        font-size: 26px;
+        font-weight: bold;
+        color: #333333;
+        line-height: 30px;
+        margin-bottom: 4px;
+        span {
+          font-size: 12px;
+          font-weight: 400;
+          color: #333333;
+          line-height: 17px;
+        }
+      }
+      .dotSub {
+        font-size: 12px;
+        font-weight: 400;
+        color: #777777;
+        line-height: 17px;
+      }
+    }
+  }
+}

+ 58 - 0
src/school/exercise-record/modals/detail-item.tsx

@@ -0,0 +1,58 @@
+import { defineComponent, reactive, ref } from 'vue'
+import styles from './detail-item.module.less'
+import defaultIcon from '@/school/images/default-icon.jpg'
+import msgIcon from '@/school/images/msg-icon.png'
+import sendmsgIcon from '@/school/images/sendmsg-icon.png'
+import phoneIcon from '@/school/images/phone-icon.png'
+import { Icon, ActionSheet } from 'vant'
+export default defineComponent({
+  props: ['item'],
+  name: 'detail-item',
+  setup(props) {
+    return () => (
+      <>
+        <div>
+          <div class={styles.itemWrap}>
+            <div class={styles.itemTop}>
+              <div class={styles.itemTopLeft}>
+                <p class={styles.itemTopMain}>洋娃娃和小熊跳舞</p>
+                <p class={styles.itemTopSub}>2022-07-07 10:20:36</p>
+              </div>
+              <div class={styles.itemTopRight}>
+                <div class={styles.imgWrap}>
+                  <img src="" alt="" />
+                </div>
+              </div>
+            </div>
+            <div class={styles.itemBottom}>
+              <div class={styles.itemBottomDot}>
+                <p class={styles.dotMain} style={{ color: '#F67146' }}>
+                  38 <span>分</span>{' '}
+                </p>
+                <p class={styles.dotSub}> 综合得分</p>
+              </div>
+              <div class={styles.itemBottomDot}>
+                <p class={styles.dotMain}>
+                  40 <span>分</span>{' '}
+                </p>
+                <p class={styles.dotSub}>音准 </p>
+              </div>
+              <div class={styles.itemBottomDot}>
+                <p class={styles.dotMain}>
+                  40 <span>分</span>{' '}
+                </p>
+                <p class={styles.dotSub}>节奏 </p>
+              </div>
+              <div class={styles.itemBottomDot}>
+                <p class={styles.dotMain}>
+                  40 <span>分</span>{' '}
+                </p>
+                <p class={styles.dotSub}>完成度 </p>
+              </div>
+            </div>
+          </div>
+        </div>
+      </>
+    )
+  }
+})

+ 176 - 0
src/school/exercise-record/modals/student-item.module.less

@@ -0,0 +1,176 @@
+.itemWrap {
+  width: calc(100% -30px);
+  height: 121px;
+  background: #ffffff;
+  border-radius: 10px;
+  margin: 0 15px 12px;
+  .itemTop {
+    padding: 8px 15px 8px;
+    display: flex;
+    flex-direction: row;
+    align-items: center;
+    justify-content: space-between;
+    border-bottom: 1px solid #f2f2f2;
+    .itemTopLeft {
+      display: flex;
+      flex-direction: row;
+      align-items: center;
+      .headIcon {
+        width: 30px;
+        height: 30px;
+        border-radius: 50%;
+        overflow: hidden;
+        margin-right: 12px;
+        img {
+          width: 100%;
+          height: 100%;
+        }
+      }
+      .name {
+        font-size: 16px;
+        font-family: PingFangSC-Medium, PingFang SC;
+        font-weight: 500;
+        color: #333333;
+        line-height: 30px;
+        margin-right: 10px;
+      }
+      .tag {
+        padding: 1px 8px;
+        min-width: 40px;
+        height: 19px;
+        background: #ffe7da;
+        border-radius: 4px;
+        font-size: 12px;
+        font-family: PingFangSC-Medium, PingFang SC;
+        font-weight: 500;
+        color: #f67146;
+        text-align: center;
+        line-height: 17px;
+      }
+    }
+    .itemTopRight {
+      width: 24px;
+      height: 24px;
+      padding: 2px;
+      img {
+        width: 100%;
+        height: 100%;
+      }
+    }
+  }
+  .itemBottom {
+    padding: 0 10px 10px;
+    display: flex;
+    flex-direction: row;
+    align-items: center;
+    text-align: center;
+    .msgMain {
+      font-size: 26px;
+      font-family: DINAlternate-Bold, DINAlternate;
+      font-weight: bold;
+      color: #f67146;
+      line-height: 30px;
+      span {
+        height: 17px;
+        font-size: 12px;
+        font-family: PingFangSC-Regular, PingFang SC;
+        font-weight: 400;
+        color: #777777;
+        line-height: 17px;
+      }
+    }
+    .msgsub {
+      margin-top: 4px;
+      height: 20px;
+      font-size: 14px;
+      font-family: PingFangSC-Regular, PingFang SC;
+      font-weight: 400;
+      color: #333333;
+      line-height: 20px;
+    }
+    .itemBottomLeft {
+      width: 50%;
+      position: relative;
+      &::after {
+        content: '';
+        width: 1px;
+        height: 20px;
+        background: #f2f2f2;
+        border-radius: 1px;
+        right: 0;
+        top: 50%;
+        margin-top: -10px;
+        position: absolute;
+      }
+    }
+    .itemBottomRight {
+      width: 50%;
+      position: relative;
+      .arrow {
+        position: absolute;
+        bottom: 14px;
+        right: 15px;
+        color: #f2f2f2;
+      }
+    }
+  }
+}
+:global {
+  .bottomSheet {
+    .van-action-sheet__description {
+      padding: 0 !important;
+      &::after {
+        border: none !important;
+      }
+    }
+  }
+}
+.bottomTitle {
+  padding: 15px 15px 20px;
+  text-align: left;
+  display: flex;
+  flex-direction: row;
+  align-items: center;
+  justify-content: space-between;
+  height: 22px;
+  font-size: 16px;
+  font-family: PingFangSC-Medium, PingFang SC;
+  font-weight: 500;
+  color: #333333;
+  line-height: 22px;
+  .bottomTitleLeft {
+    display: flex;
+    flex-direction: row;
+    align-items: center;
+    span {
+      width: 4px;
+      height: 12px;
+      background: #ff8057;
+      border-radius: 2px;
+      display: inline-block;
+      margin-right: 6px;
+    }
+  }
+}
+.bottomConent {
+  padding: 20px 15px 57px;
+  display: flex;
+  flex-direction: row;
+  align-items: center;
+  .bottomImgWrap {
+    width: 47px;
+    height: 47px;
+    margin-bottom: 6px;
+    img {
+      width: 100%;
+      height: 100%;
+    }
+  }
+  .bottomConentLeft,
+  .bottomConentRight {
+    width: 50%;
+    display: flex;
+    flex-direction: column;
+    align-items: center;
+  }
+}

+ 89 - 0
src/school/exercise-record/modals/student-item.tsx

@@ -0,0 +1,89 @@
+import { defineComponent, reactive, ref } from 'vue'
+import styles from './student-item.module.less'
+import defaultIcon from '@/school/images/default-icon.jpg'
+import msgIcon from '@/school/images/msg-icon.png'
+import sendmsgIcon from '@/school/images/sendmsg-icon.png'
+import phoneIcon from '@/school/images/phone-icon.png'
+import { Icon, ActionSheet } from 'vant'
+export default defineComponent({
+  props: ['item'],
+  name: 'student-item',
+  setup(props) {
+    const showContact = ref(false)
+    const startContact = () => {
+      showContact.value = true
+    }
+    const closeSheet = () => {
+      showContact.value = false
+    }
+    return () => (
+      <>
+        <div>
+          <div class={styles.itemWrap}>
+            <div class={styles.itemTop}>
+              <div class={styles.itemTopLeft}>
+                <div class={styles.headIcon}>
+                  <img src={defaultIcon} alt="" />
+                </div>
+                <p class={styles.name}>xxx</p>
+                <div class={styles.tag}>长笛</div>
+              </div>
+              <div class={styles.itemTopRight}>
+                <div class={styles.msgIcon} onClick={startContact}>
+                  <img src={msgIcon} alt="" />
+                </div>
+              </div>
+            </div>
+            <div class={styles.itemBottom}>
+              <div class={styles.itemBottomLeft}>
+                <p class={styles.msgMain}>
+                  10 <span>天</span>
+                </p>
+                <p class={styles.msgsub}>练习天数</p>
+              </div>
+              <div class={styles.itemBottomRight}>
+                <p class={styles.msgMain}>
+                  10 <span>分钟</span>
+                </p>
+                <p class={styles.msgsub}>练习时长</p>
+                <Icon class={styles.arrow} name="arrow"></Icon>
+              </div>
+            </div>
+          </div>
+        </div>
+        <ActionSheet
+          class="bottomSheet"
+          v-model:show={showContact.value}
+          vSlots={{
+            description: () => (
+              <div class={styles.bottomTitle}>
+                <div class={styles.bottomTitleLeft}>
+                  <span></span>
+                  <p>联系方式</p>
+                </div>
+                <div class={styles.bottomTitleRight} onClick={closeSheet}>
+                  <Icon class={styles.cross} name="cross"></Icon>
+                </div>
+              </div>
+            )
+          }}
+        >
+          <div class={styles.bottomConent}>
+            <div class={styles.bottomConentLeft}>
+              <div class={styles.bottomImgWrap}>
+                <img src={sendmsgIcon} alt="" />
+              </div>
+              <p>发送消息</p>
+            </div>
+            <div class={styles.bottomConentRight}>
+              <div class={styles.bottomImgWrap}>
+                <img src={phoneIcon} alt="" />
+              </div>
+              <p>拨打电话</p>
+            </div>
+          </div>
+        </ActionSheet>
+      </>
+    )
+  }
+})

BIN
src/school/images/default-icon.jpg


BIN
src/school/images/detail-bg.png


BIN
src/school/images/msg-icon.png


BIN
src/school/images/phone-icon.png


BIN
src/school/images/quest-icon.png


BIN
src/school/images/sendmsg-icon.png


+ 4 - 2
src/school/main.ts

@@ -4,7 +4,7 @@ import router from '../router/index'
 import { postMessage } from '@/helpers/native-message'
 
 import 'normalize.css'
-import 'vant/lib/index.css';
+import 'vant/lib/index.css'
 
 import '../styles/index.less'
 import { state } from '@/state'
@@ -25,6 +25,7 @@ postMessage(
 // 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') {
@@ -37,7 +38,8 @@ if (browser().isTeacher || paymentType === 'TEACHER') {
 
 if (state.platformType === 'TEACHER') {
   state.platformApi = '/api-teacher'
-} if (state.platformType === 'SCHOOL') {
+}
+if (state.platformType === 'SCHOOL') {
   state.platformApi = '/api-school'
 } else {
   state.platformApi = '/api-student'

+ 1 - 0
src/styles/index.less

@@ -17,6 +17,7 @@
   --van-primary: #ff8057 !important;
   --van-picker-confirm-action-color: #ff8057 !important;
   --van-primary-text: #f67146 !important;
+  // --van-popover-light-text-color: var(--van-primary) !important;
   // --van-orange: #ff976a;
   // --van-orange-dark: #ed6a0c;
   // --van-orange-light: #fffbe8;