lex 2 роки тому
батько
коміт
e050e65861

+ 90 - 4
src/school/attendance-rules/component/range.tsx

@@ -1,16 +1,102 @@
-import { Cell, CellGroup } from 'vant'
-import { defineComponent } from 'vue'
+import OSticky from '@/components/o-sticky'
+import { Button, Cell, CellGroup, Field, Popover } from 'vant'
+import { defineComponent, reactive, Teleport } from 'vue'
 import styles from '../index.module.less'
 
 export default defineComponent({
   name: 'range-model',
   setup() {
+    const forms = reactive({
+      show1: false
+    })
     return () => (
       <div class={styles.ruleContainer}>
         <CellGroup inset>
-          <Cell>{{ title: () => <div class={styles.ruleTitle}>签退规则</div> }}</Cell>
-          <Cell>{{ label: () => <div class={styles.ruleContent}></div> }}</Cell>
+          <Cell>{{ title: () => <div class={styles.ruleTitle}>考勤定位范围</div> }}</Cell>
+          <Cell>
+            {{
+              title: () => (
+                <div class={styles.ruleContent}>
+                  签到、签退地点须在学校定位点
+                  <Field
+                    class={[styles.field, styles['field-m'], styles['field-w80']]}
+                    autocomplete="off"
+                  >
+                    {{ extra: () => <span>米</span> }}
+                  </Field>
+                  以内
+                </div>
+              )
+            }}
+          </Cell>
         </CellGroup>
+        <CellGroup inset>
+          <Cell>
+            {{
+              title: () => (
+                <div class={[styles.ruleTitle, styles.smallRuleTitle]}>
+                  <span class={styles.red}>签到</span>地点在考勤定位范围之外时,扣减当日训练补助
+                </div>
+              )
+            }}
+          </Cell>
+          <Cell>
+            {{
+              title: () => (
+                <div class={[styles.ruleContent, styles.ruleMore]}>
+                  单次扣减金额:
+                  <Field
+                    class={[styles.field, styles['field-m'], styles['field-w136']]}
+                    autocomplete="off"
+                  >
+                    {{
+                      extra: () => (
+                        <Popover
+                          v-model:show={forms.show1}
+                          actions={[
+                            {
+                              text: '元',
+                              value: 'MONEY'
+                            },
+                            {
+                              text: '%',
+                              value: 'PERCENTAGE'
+                            }
+                          ]}
+                        >
+                          {{ reference: () => <span class={[styles.unit]}>元</span> }}
+                        </Popover>
+                      )
+                    }}
+                  </Field>
+                </div>
+              )
+            }}
+          </Cell>
+        </CellGroup>
+
+        <CellGroup inset>
+          <Cell>
+            {{
+              title: () => (
+                <div class={[styles.ruleTitle, styles.smallRuleTitle]}>
+                  <span class={styles.red}>签退</span>地点在考勤定位范围之外时,扣减当日训练补助
+                </div>
+              )
+            }}
+          </Cell>
+          <Cell></Cell>
+        </CellGroup>
+
+        <Teleport to={'#app'}>
+          <OSticky position="bottom">
+            <div class={'btnGroup'}>
+              <Button type="primary" round block>
+                保存设置
+              </Button>
+            </div>
+          </OSticky>
+        </Teleport>
       </div>
     )
   }

+ 89 - 1
src/school/attendance-rules/index.module.less

@@ -13,9 +13,97 @@
 }
 
 .ruleContainer {
-  padding-top: 16px;
   overflow: hidden;
 
+  .informationBottom {
+    :global {
+      .van-sticky {
+        position: absolute;
+      }
+    }
+  }
+
+  :global {
+    .van-cell {
+      padding: 14px 12px;
+    }
+    .van-cell:after {
+      // border-color: #f2f2f2;
+    }
+
+    .van-cell-group {
+      margin: 16px 13px 0;
+      border-radius: 10px;
+    }
+  }
+
   .ruleTitle {
+    font-size: 16px;
+    font-weight: 600;
+    color: #333333;
+    line-height: 22px;
+  }
+  .smallRuleTitle {
+    font-size: 14px;
+  }
+
+  .ruleContent {
+    font-size: 14px;
+    color: #777;
+  }
+  .ruleMore {
+    padding: 6px 0 8px;
+    color: #333;
+    font-weight: 500;
+  }
+
+  .red {
+    color: #f44541;
+  }
+
+  .field {
+    background: #f2f2f2;
+    border-radius: 8px;
+    height: 35px;
+    line-height: 35px;
+    padding: 0 8px;
+    display: inline-flex;
+
+    .unit {
+      position: relative;
+      width: 40px;
+      padding-left: 12px;
+      display: flex;
+      align-items: center;
+      justify-content: center;
+      &::before {
+        position: absolute;
+        left: 0;
+        content: ' ';
+        display: inline-block;
+        width: 1px;
+        height: 25px;
+        background: #e3e3e3;
+        border-radius: 1px;
+      }
+      &::after {
+        content: ' ';
+        display: inline-block;
+        background: url('@/common/svg/arrow.png') no-repeat center center;
+        background-size: contain;
+        width: 9px;
+        height: 5px;
+        margin-left: 3px;
+      }
+    }
+  }
+  .field-m {
+    margin: 0 4px;
+  }
+  .field-w80 {
+    width: 80px;
+  }
+  .field-w136 {
+    width: 136px;
   }
 }

+ 38 - 2
src/school/orchestra/compontent/plan.module.less

@@ -1,5 +1,6 @@
 .gridContainer {
   margin: 12px 13px 12px;
+  padding: 0 15px 10px;
   background: #ffffff;
   border-radius: 10px;
   overflow: hidden;
@@ -24,6 +25,7 @@
 }
 
 .gridClass {
+  padding-bottom: 20px;
   .title {
     font-size: 24px;
   }
@@ -33,9 +35,9 @@
   }
 
   .className {
-    padding: 17px 15px 0;
+    padding: 17px 0 0;
     font-size: 16px;
-    font-weight: 500;
+    font-weight: 600;
     color: #333333;
     line-height: 22px;
     .line {
@@ -88,4 +90,38 @@
       text-align: left;
     }
   }
+
+  .classNum {
+    padding-top: 20px;
+    padding-bottom: 20px;
+    font-size: 12px;
+    color: #333333;
+    display: flex;
+    align-items: center;
+
+    .classNumItem {
+      padding-left: 13px;
+      padding-right: 5px;
+      display: flex;
+      align-items: center;
+
+      .use {
+        color: #777;
+      }
+      .nums {
+        font-size: 16px;
+        color: #333333;
+        padding: 0 6px;
+        font-weight: bold;
+      }
+    }
+    .block {
+      display: inline-block;
+      width: 12px;
+      height: 12px;
+      border-radius: 2px;
+      background-color: #ececec;
+      margin-right: 6px;
+    }
+  }
 }

+ 73 - 243
src/school/orchestra/compontent/plan.tsx

@@ -4,7 +4,7 @@ import dayjs from 'dayjs'
 import isSameOrBefore from 'dayjs/plugin/isSameOrBefore'
 import isSameOrAfter from 'dayjs/plugin/isSameOrAfter'
 dayjs.extend(isSameOrBefore, isSameOrAfter)
-import { ActionSheet, Cell, DatePicker, Icon, Image, List, Popover, Popup } from 'vant'
+import { ActionSheet, Cell, DatePicker, Icon, Image, List, Popover, Popup, Progress } from 'vant'
 import { computed, defineComponent, onMounted, reactive } from 'vue'
 import { useRoute } from 'vue-router'
 import styles from './plan.module.less'
@@ -25,23 +25,8 @@ export default defineComponent({
     }
   },
   setup(props) {
-    const startTime = computed(() => props.termTimes.start)
-    const endTime = computed(() => props.termTimes.end)
     const route = useRoute()
     const state = reactive({
-      timeShow: false,
-      currentData: [dayjs().year() + ''],
-      showPopover: false,
-      actionText: '上学期',
-      actionType: 'up',
-      actionTerm: [
-        { name: '上学期', selected: true, value: 'up' },
-        { name: '下学期', value: 'down' }
-      ],
-      oPopover: false,
-      check: [],
-      checkboxRefs: [] as any,
-      showQrcode: false,
       isLoading: false,
       list: [] as any,
       listState: {
@@ -51,254 +36,99 @@ export default defineComponent({
       },
 
       params: {
-        startTime: dayjs(dayjs().year() + startTime.value).format('YYYY-MM-DD HH:mm:ss'),
-        endTime: dayjs(dayjs().year() + endTime.value)
-          .add(1, 'year')
-          .subtract(1, 'day')
-          .format('YYYY-MM-DD HH:mm:ss'),
         page: 1,
-        rows: 20
+        rows: 100
       }
     })
-    // 选择学期
-    const onSelect = (val: any) => {
-      state.actionTerm.forEach((item: any) => {
-        item.selected = false
-      })
-      val.selected = true
-      state.actionText = val.name
-      state.actionType = val.value
-
-      if (val.value === 'up') {
-        state.params.startTime = dayjs(Number(state.currentData[0]) + startTime.value).format(
-          'YYYY-MM-DD HH:mm:ss'
-        )
-        state.params.endTime = dayjs(Number(state.currentData[0]) + endTime.value)
-          .add(1, 'year')
-          .subtract(1, 'day')
-          .format('YYYY-MM-DD HH:mm:ss')
-      } else if (val.value === 'down') {
-        state.params.startTime = dayjs(Number(state.currentData[0]) + endTime.value)
-          .add(1, 'year')
-          .format('YYYY-MM-DD HH:mm:ss')
-        state.params.endTime = dayjs(Number(state.currentData[0]) + startTime.value)
-          .add(1, 'year')
-          .subtract(1, 'day')
-          .format('YYYY-MM-DD HH:mm:ss')
-      }
-      state.oPopover = false
-      onSearch()
-    }
-
-    const onConfirmDate = (date: any) => {
-      state.currentData = date.selectedValues
-
-      const year = Number(state.currentData[0]) + 1
-      if (state.actionType === 'up') {
-        state.params.startTime = dayjs(year + startTime.value).format('YYYY-MM-DD HH:mm:ss')
-        state.params.endTime = dayjs(year + endTime.value)
-          .add(1, 'year')
-          .subtract(1, 'day')
-          .format('YYYY-MM-DD HH:mm:ss')
-      } else if (state.actionType === 'down') {
-        state.params.startTime = dayjs(year + endTime.value).format('YYYY-MM-DD HH:mm:ss')
-        state.params.endTime = dayjs(year + startTime.value)
-          .subtract(1, 'day')
-          .format('YYYY-MM-DD HH:mm:ss')
-      }
-      state.timeShow = false
-      onSearch()
-    }
 
     // 班级列表
     const getList = async () => {
       try {
-        if (state.isLoading) return
-        state.isLoading = true
-        const res = await request.post('/api-school/classGroup/page', {
-          data: {
-            ...state.params,
-            orchestraId: route.query.id
+        // if (state.isLoading) return
+        // state.isLoading = true
+        const { data } = await request.post(
+          '/api-school/orchestraDataStatistics/orchestraTrainingProgress',
+          {
+            data: {
+              orchestraId: route.query.id
+            }
           }
-        })
-        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.list = data || []
         state.listState.dataShow = state.list.length > 0
-        state.isLoading = false
       } catch {
         state.listState.dataShow = false
-        state.listState.finished = true
-        state.isLoading = false
       }
     }
 
-    const onSearch = () => {
-      state.params.page = 1
-      state.list = []
-      state.listState.dataShow = true // 判断是否有数据
-      state.listState.loading = false
-      state.listState.finished = false
-      getList()
-    }
-
     onMounted(async () => {
-      const sysStartTime = dayjs(dayjs().year() + startTime.value).format('YYYY-MM-DD')
-      const sysEndTime = dayjs(dayjs().year() + endTime.value).format('YYYY-MM-DD')
-      const nowTime = dayjs().format('YYYY-MM-DD')
-      console.log(nowTime, sysStartTime)
-      const before = dayjs(nowTime).isBefore(dayjs(sysStartTime))
-      const after = dayjs(nowTime).isBefore(dayjs(sysEndTime))
-      const year = dayjs().year()
-
-      // console.log(before, after, year)
-      if (before && after) {
-        state.currentData = [year - 1 + '']
-        state.params.startTime = dayjs(year - 1 + startTime.value).format('YYYY-MM-DD HH:mm:ss')
-        state.params.endTime = dayjs(dayjs().year() + endTime.value)
-          .subtract(1, 'day')
-          .format('YYYY-MM-DD HH:mm:ss')
-        // 上学期
-      }
-
-      if (!before && !after) {
-        state.params.startTime = dayjs(dayjs().year() + startTime.value).format(
-          'YYYY-MM-DD HH:mm:ss'
-        )
-        state.params.endTime = dayjs(dayjs().year() + endTime.value)
-          .add(1, 'year')
-          .subtract(1, 'day')
-          .format('YYYY-MM-DD HH:mm:ss')
-        // 下一年的上学期
-      }
-
-      if (before && !after) {
-        state.params.startTime = dayjs(year + endTime.value).format('YYYY-MM-DD HH:mm:ss')
-        state.params.endTime = dayjs(year + startTime.value)
-          .subtract(1, 'day')
-          .format('YYYY-MM-DD HH:mm:ss')
-
-        // 下学期
-        state.actionTerm.forEach((item: any) => {
-          if (item.value === 'down') {
-            item.color = 'var(--van-primary-color)'
-            state.actionText = item.text
-            state.actionType = item.value
-          } else {
-            item.color = ''
-          }
-        })
-        state.currentData = [year - 1 + '']
-        state.actionText = '下学期'
-        state.actionType = 'down'
-        state.actionTerm.forEach((item: any) => {
-          if (item.value === 'down') {
-            item.selected = true
-          } else {
-            item.selected = false
-          }
-        })
-      }
-
       await getList()
     })
     return () => (
-      <div>
-        <div class={['searchGroup', 'van-hairline--top']}>
-          <div
-            class={['searchItem', state.timeShow ? 'searchItem-active' : '']}
-            onClick={() => (state.timeShow = true)}
-          >
-            {state.currentData[0]}年 <i class={'arrow'}></i>
-          </div>
-          <div
-            class={['searchItem', state.oPopover ? 'searchItem-active' : '']}
-            onClick={() => (state.oPopover = true)}
-          >
-            {state.actionText} <i class={'arrow'}></i>
-          </div>
-        </div>
-
-        <div style="height: calc(100vh - var(--header-height) - var(--van-tabs-line-height) - 1.17333rem); overflow: hidden; overflow-y: auto;">
-          {state.listState.dataShow ? (
-            <List
-              // v-model:loading={state.listState.loading}
-              finished={state.listState.finished}
-              finishedText=" "
-              class={[styles.liveList]}
-              onLoad={getList}
-              immediateCheck={false}
-            >
-              {state.list.map((item: any) => (
-                <div class={[styles.gridContainer, styles.gridClass]}>
-                  <div class={styles.className}>
-                    <i class={styles.line}></i>
-                    {item.name}
-                  </div>
-                  <Cell center class={styles.gridCell}>
-                    {{
-                      icon: () => (
-                        <Image
-                          class={styles.img}
-                          src={item.teacherAvatar || iconTeacher}
-                          fit="cover"
-                        />
-                      ),
-                      title: () => (
-                        <>
-                          <p class={styles.class}>
-                            {item.completeCourseScheduleNum || 0}/{item.courseScheduleNum || 0}
-                          </p>
-                          <p class={styles.teacherDesc}>课时</p>
-                        </>
-                      ),
-                      value: () => (
-                        <>
-                          <p class={styles.courseware}>{item.newestLessonPlanDetailName || '-'}</p>
-                          <p class={styles.teacherDesc}>最新课件</p>
-                        </>
-                      )
+      <div style="height: calc(100vh - var(--header-height) - var(--van-tabs-line-height)); overflow: hidden; overflow-y: auto;">
+        {state.listState.dataShow ? (
+          <div class={[styles.gridContainer]}>
+            {state.list.map((item: any) => (
+              <div class={styles.gridClass}>
+                <div class={styles.className}>
+                  <i
+                    class={styles.line}
+                    style={{
+                      backgroundColor:
+                        item.coursewareNum < item.endCourseNum ? '#FF8057' : '#64A9FF'
                     }}
-                  </Cell>
+                  ></i>
+                  {item.classGroupName}
+                </div>
+                <div class={styles.classNum}>
+                  <div class={styles.classNumItem}>
+                    <i
+                      class={styles.block}
+                      style={{
+                        backgroundColor:
+                          item.coursewareNum < item.endCourseNum ? '#FF8057' : '#4DA6FE'
+                      }}
+                    ></i>
+                    <span class={styles.use}>已使用</span>
+                    <span
+                      class={styles.nums}
+                      style={{
+                        color: item.coursewareNum < item.endCourseNum ? '#F44541' : '#333'
+                      }}
+                    >
+                      {item.coursewareNum || 0}
+                    </span>
+                    课件
+                  </div>
+                  <div class={styles.classNumItem}>
+                    <i class={styles.block}></i>
+                    <span class={styles.use}>已结束</span>
+                    <span class={styles.nums}>{item.endCourseNum || 0}</span>节课
+                  </div>
                 </div>
-              ))}
-            </List>
-          ) : (
-            <OEmpty btnStatus={false} tips="暂无班级" />
-          )}
-        </div>
-
-        <OActionSheet
-          v-model:show={state.oPopover}
-          actions={state.actionTerm}
-          onSelect={onSelect}
-          teleport={'body'}
-        />
 
-        <Popup
-          v-model:show={state.timeShow}
-          position="bottom"
-          round
-          class={'popupBottomSearch'}
-          teleport={'body'}
-        >
-          <DatePicker
-            v-model={state.currentData}
-            columnsType={['year']}
-            minDate={new Date(2010, 0, 1)}
-            maxDate={new Date(2055, 11, 31)}
-            formatter={formatterDatePicker}
-            onConfirm={onConfirmDate}
-            onCancel={() => (state.timeShow = false)}
-          />
-        </Popup>
+                <Progress
+                  color={
+                    item.coursewareNum < item.endCourseNum
+                      ? 'linear-gradient(90deg, #FF9C63 0%, #FF6944 100%)'
+                      : 'linear-gradient(90deg, #68D3FC 0%, #459AFF 100%)'
+                  }
+                  trackColor="#ECECEC"
+                  showPivot={false}
+                  style={{
+                    borderRadius: '12px'
+                  }}
+                  percentage={
+                    item.endCourseNum ? (item.coursewareNum / item.endCourseNum) * 100 : 0
+                  }
+                  strokeWidth={12}
+                />
+              </div>
+            ))}
+          </div>
+        ) : (
+          <OEmpty btnStatus={false} tips="暂无班级" />
+        )}
       </div>
     )
   }