lex 2 jaren geleden
bovenliggende
commit
262e6cae2e

+ 7 - 0
src/helpers/constant.ts

@@ -96,3 +96,10 @@ export const programType = {
   REPRISE: '重奏',
   UNISON: '齐奏'
 } as any;
+
+// 活动状态
+export const activeStatus = {
+  NOT_START: '未开始',
+  PROCESSING: '进行中',
+  END: '已结束'
+} as any;

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

@@ -107,6 +107,14 @@ export default [
         }
       },
       {
+        path: '/activity-record-detail',
+        name: 'activity-record-detail',
+        component: () => import('@/views/activity-record/detail'),
+        meta: {
+          title: '活动详情'
+        }
+      },
+      {
         path: '/activity-record-operation',
         name: 'activity-record-operation',
         component: () => import('@/views/activity-record/operation'),

+ 138 - 0
src/views/activity-record/components/cast-item.tsx

@@ -0,0 +1,138 @@
+import { Cell, Checkbox, CheckboxGroup, Icon, Image } from 'vant';
+import { defineComponent, onMounted, reactive, ref, watch } from 'vue';
+import styles from '../index.module.less';
+// import class1 from '../images/1.png';
+import activeButtonIcon from '@/common/images/icon-check-active.png';
+import inactiveButtonIcon from '@/common/images/icon-check.png';
+import iconStudent from '@/common/images/icon-student-default.png';
+export default defineComponent({
+  name: 'group-chat',
+  props: {
+    height: {
+      type: [Number],
+      default: 0
+    },
+    bottomHeight: {
+      type: [String, Number],
+      default: 0
+    },
+    headerHeight: {
+      type: [Number],
+      default: 0
+    },
+    studentList: {
+      type: Array,
+      default: () => []
+    },
+    selectItem: {
+      type: Array,
+      default: () => []
+    }
+  },
+  emits: ['update:selectItem'],
+  setup(props, { emit }) {
+    const checkboxRefs = ref([] as any);
+    const forms = reactive({
+      height: props.height,
+      check: [] as any
+    });
+
+    const onToggle = (index: number) => {
+      //
+      checkboxRefs.value[index].toggle();
+      const list: any = [];
+      props.studentList.forEach((item: any) => {
+        if (forms.check.includes(item.studentId)) {
+          list.push({
+            studentId: item.studentId,
+            studentName: item.studentName,
+            studentAvatar: item.studentAvatar,
+            subjectId: item.subjectId
+          });
+        }
+      });
+      emit('update:selectItem', list);
+    };
+
+    watch(
+      () => props.height,
+      () => {
+        forms.height = props.height;
+        // console.log(forms.height);
+      }
+    );
+
+    watch(
+      () => props.selectItem,
+      () => {
+        initSelectItem();
+      },
+      { deep: true }
+    );
+    const initSelectItem = () => {
+      const selectItem = props.selectItem || [];
+      const temp: any = [];
+      // console.log(selectItem, 'selectItem');
+      selectItem.forEach((item: any) => {
+        temp.push(item.studentId);
+      });
+      forms.check = temp;
+    };
+
+    onMounted(async () => {
+      initSelectItem();
+    });
+    return () => (
+      <div
+        style={{
+          'min-height': `calc(100vh - ${props.headerHeight}px - ${forms.height}px - ${props.bottomHeight}px )`
+        }}>
+        <CheckboxGroup v-model={forms.check}>
+          {props.studentList.map((item: any, index: number) => (
+            <Cell
+              center
+              onClick={() => onToggle(index)}
+              class={styles.popupCell}>
+              {{
+                icon: () => (
+                  <Image
+                    src={item.studentAvatar || iconStudent}
+                    class={styles.imgLogo}
+                    fit="contain"
+                  />
+                ),
+                title: () => (
+                  <div class={styles.infos}>
+                    <div class={styles.infoTitle}>{item.studentName}</div>
+                    <div class={styles.infoContent}>{item.subjectName}</div>
+                  </div>
+                ),
+                'right-icon': () => (
+                  <Checkbox
+                    name={item.studentId}
+                    ref={e => (checkboxRefs.value[index] = e)}
+                    onClick={(e: MouseEvent) => {
+                      e.stopPropagation();
+                    }}
+                    v-slots={{
+                      icon: (props: any) => (
+                        <Icon
+                          class={styles.boxStyle}
+                          name={
+                            props.checked
+                              ? activeButtonIcon
+                              : inactiveButtonIcon
+                          }
+                        />
+                      )
+                    }}
+                  />
+                )
+              }}
+            </Cell>
+          ))}
+        </CheckboxGroup>
+      </div>
+    );
+  }
+});

+ 124 - 0
src/views/activity-record/components/cast-modal.tsx

@@ -0,0 +1,124 @@
+import MHeader from '@/components/m-header';
+import MSticky from '@/components/m-sticky';
+import { Button, Tab, Tabs } from 'vant';
+import { defineComponent, onMounted, reactive, watch } from 'vue';
+import styles from '../index.module.less';
+import CastItem from './cast-item';
+import { useRect } from '@vant/use';
+import deepClone from '@/helpers/deep-clone';
+
+export default defineComponent({
+  name: 'cast-modal',
+  props: {
+    subjectAllList: {
+      type: Array,
+      default: () => []
+    },
+    performerList: {
+      type: Array,
+      default: () => []
+    }
+  },
+  emits: ['close', 'update:performerList', 'confirm'],
+  setup(props, { emit }) {
+    const formatSubjectList = () => {
+      const performerList = props.performerList || ([] as any);
+
+      props.subjectAllList.forEach((subject: any) => {
+        const item: any = performerList.find(
+          (item: any) => item.subjectId == subject.subjectId
+        );
+        subject.selectList = item ? deepClone(item.studentList) : [];
+      });
+
+      console.log(props.subjectAllList, 'props.subjectAllList');
+      return props.subjectAllList || [];
+    };
+    const forms = reactive({
+      varName: '--popup-navbar-height',
+      popupHeight: 0,
+      height: 0,
+      bottomHeight: 0,
+      subjectList: formatSubjectList()
+    });
+
+    onMounted(() => {
+      const { height } = useRect(
+        document.querySelector('.van-tab') as HTMLElement
+      );
+      forms.height = height;
+    });
+
+    watch(
+      () => props.subjectAllList,
+      () => {
+        forms.subjectList = formatSubjectList();
+      }
+    );
+
+    watch(
+      () => props.performerList,
+      () => {
+        forms.subjectList = formatSubjectList();
+      }
+    );
+
+    const onSubmit = () => {
+      const selectList: any = [];
+      forms.subjectList.forEach((subject: any) => {
+        if (subject.selectList && subject.selectList.length > 0) {
+          selectList.push({
+            studentCount: subject.selectList.length,
+            studentList: subject.selectList,
+            subjectId: subject.subjectId,
+            subjectName: subject.subjectName
+          });
+        }
+      });
+      console.log(selectList, 'selectList');
+      emit('close');
+      emit('update:performerList', selectList);
+      emit('confirm', selectList);
+    };
+
+    return () => (
+      <div
+        class={styles.castPopupContainer}
+        style="background-color: #f8f9fc; height: 100%">
+        <MSticky
+          varName={forms.varName}
+          onBarHeight={(height: number) => {
+            forms.popupHeight = height;
+          }}>
+          <MHeader title="演员名单" />
+        </MSticky>
+        <Tabs shrink sticky offsetTop={forms.popupHeight}>
+          {forms.subjectList.map((item: any) => (
+            <Tab
+              name={item.subjectId}
+              title={item.subjectName + `(${item.studentCount})`}>
+              <CastItem
+                height={forms.height}
+                headerHeight={forms.popupHeight}
+                bottomHeight={forms.bottomHeight}
+                studentList={item.studentList}
+                v-model:selectItem={item.selectList}
+              />
+            </Tab>
+          ))}
+        </Tabs>
+        <MSticky
+          position="bottom"
+          onBarHeight={(height: any) => {
+            forms.bottomHeight = height;
+          }}>
+          <div class={'btnGroupFixed'}>
+            <Button round block type="primary" onClick={onSubmit}>
+              确认
+            </Button>
+          </div>
+        </MSticky>
+      </div>
+    );
+  }
+});

+ 70 - 12
src/views/activity-record/components/input-timer.tsx

@@ -1,20 +1,58 @@
-import { defineComponent, reactive } from 'vue';
+import { defineComponent, reactive, watch } from 'vue';
 import styles from '../operation.module.less';
-import { Button, Field } from 'vant';
+import { Button, Field, showToast } from 'vant';
+import { verifiyNumberInteger } from '@/helpers/toolsValidate';
+import { formatterTimer } from '../operation';
 
 export default defineComponent({
   name: 'input-timer',
+  props: {
+    show: {
+      type: Boolean,
+      default: false
+    },
+    time: {
+      type: Number,
+      default: null
+    }
+  },
   emits: ['close', 'confirm'],
   setup(props, { emit }) {
+    const timer = formatterTimer(props.time);
     const forms = reactive({
-      minute: null,
-      secord: null
+      minute: timer.minute || null,
+      second: timer.secord || null
     });
 
-    // 格式化
-    const onFomatter = () => {
-      //
+    // 过滤输入的数字
+    const formatter = (value: any) => {
+      if (value && value >= 0) {
+        return verifiyNumberInteger(value);
+      } else {
+        return '';
+      }
     };
+
+    watch(
+      () => props.show,
+      () => {
+        if (!props.show) {
+          const timer = formatterTimer(props.time);
+          forms.minute = timer.minute || null;
+          forms.second = timer.secord || null;
+        }
+      }
+    );
+
+    watch(
+      () => props.time,
+      () => {
+        const timer = formatterTimer(props.time);
+        console.log(timer, 'timer');
+        forms.minute = timer.minute || null;
+        forms.second = timer.secord || null;
+      }
+    );
     return () => (
       <div class={styles.popupContainer}>
         <h2 class={styles.popupTitle}>请输入节目时长</h2>
@@ -22,11 +60,22 @@ export default defineComponent({
           <div class={styles.popupTimer}>
             <Field
               v-model={forms.minute}
-              type="number"
-              // formatter={onFomatter}
+              type="tel"
+              formatter={formatter}
+              border={false}
+              maxlength={2}
+              autocomplete="off"
+            />
+            分
+            <Field
+              v-model={forms.second}
+              type="tel"
+              formatter={formatter}
+              border={false}
+              maxlength={2}
+              autocomplete="off"
             />
-            {/* <input v-model={forms.minute} type="number"></input> */}分
-            {/* <input v-model={forms.secord} type="number"></input> */}秒
+            秒
           </div>
         </div>
 
@@ -34,7 +83,16 @@ export default defineComponent({
           <Button round onClick={() => emit('close')}>
             取消
           </Button>
-          <Button type="primary" round onClick={() => emit('confirm')}>
+          <Button
+            type="primary"
+            round
+            onClick={() => {
+              if (!forms.minute || !forms.second) {
+                showToast('时长输入有误');
+                return;
+              }
+              emit('confirm', forms);
+            }}>
             确定
           </Button>
         </div>

+ 89 - 0
src/views/activity-record/components/performance-team.tsx

@@ -0,0 +1,89 @@
+import { defineComponent, reactive, ref, watch } from 'vue';
+import styles from '../operation.module.less';
+import { Button, Checkbox, CheckboxGroup, Tag } from 'vant';
+
+export default defineComponent({
+  name: 'performance-team',
+  props: {
+    show: {
+      type: Boolean,
+      default: false
+    },
+    performances: {
+      type: Array,
+      default: () => []
+    },
+    selectIds: {
+      // 选中声部编号
+      type: Array,
+      default: () => []
+    }
+  },
+  emits: ['close', 'confirm'],
+  setup(props, { emit }) {
+    const checkboxRefs = ref([] as any);
+    const forms = reactive({
+      performanceList: props.performances || [],
+      checkboxs: props.selectIds || ([] as any)
+    });
+
+    // 选择
+    watch(
+      () => props.performances,
+      () => {
+        console.log(props.performances, 'props.performances');
+        forms.performanceList = props.performances;
+      }
+    );
+
+    watch(
+      () => props.selectIds,
+      () => {
+        forms.checkboxs = props.selectIds;
+      }
+    );
+
+    watch(
+      () => props.show,
+      () => {
+        if (!props.show) forms.checkboxs = props.selectIds;
+      }
+    );
+
+    return () => (
+      <div class={styles.popupContainer}>
+        <h2 class={styles.popupTitle}>选择表演团队</h2>
+        <CheckboxGroup
+          class={[styles.searchTypeFlex, styles.multFlex]}
+          v-model={forms.checkboxs}>
+          {forms.performanceList.map((item: any, index: number) => (
+            <Tag
+              type={
+                forms.checkboxs.includes(item.subjectId) ? 'primary' : 'default'
+              }>
+              <Checkbox
+                name={item.subjectId}
+                ref={(el: any) => (checkboxRefs.value[index] = el)}
+                onClick={(e: MouseEvent) => {
+                  e.stopPropagation();
+                }}
+              />
+              {item.subjectName}
+            </Tag>
+          ))}
+        </CheckboxGroup>
+        <div class={['btnGroupPopup']}>
+          <Button round onClick={() => emit('close')}>
+            取消
+          </Button>
+          <Button
+            type="primary"
+            round
+            onClick={() => emit('confirm', forms.checkboxs)}>
+            确定
+          </Button>
+        </div>
+      </div>
+    );
+  }
+});

+ 0 - 0
src/views/activity-record/detail.module.less


+ 8 - 0
src/views/activity-record/detail.tsx

@@ -0,0 +1,8 @@
+import { defineComponent } from 'vue';
+
+export default defineComponent({
+  name: 'detail-page',
+  setup() {
+    return () => <>详情</>;
+  }
+});

+ 59 - 0
src/views/activity-record/index.module.less

@@ -56,4 +56,63 @@
       color: var(--k-font-primary);
     }
   }
+}
+
+.castPopupContainer {
+  --van-tab-font-size: 16px;
+  --van-tabs-nav-background: #F8F9FC;
+
+  :global {
+    .van-tab {
+      z-index: 1;
+    }
+
+    .van-tabs__line {
+      bottom: 26px;
+      width: 45px;
+      height: 6px;
+      background: linear-gradient(250deg, rgba(45, 199, 170, 0.22) 0%, #2DC7AA 100%);
+      z-index: 0;
+    }
+  }
+
+  .imgLogo {
+    width: 42px;
+    height: 42px;
+    overflow: hidden;
+    border-radius: 50%;
+    margin-right: 8px;
+    flex-shrink: 0;
+  }
+
+  .popupCell {
+    padding: 15px 20px;
+
+    .boxStyle {
+      background: transparent !important;
+      width: 18px;
+      height: 18px;
+      border: transparent !important;
+    }
+
+    :global {
+      .van-checkbox {
+        display: inline-block;
+        align-items: inherit;
+        overflow: inherit;
+      }
+
+      .van-checkbox__icon {
+        height: 18px;
+        line-height: 18px;
+        display: inline-block;
+        vertical-align: sub;
+      }
+
+      .van-checkbox__label {
+        line-height: 18px;
+        color: var(--k-gray-4);
+      }
+    }
+  }
 }

+ 12 - 7
src/views/activity-record/index.tsx

@@ -13,13 +13,14 @@ import {
   Tag
 } from 'vant';
 import DropDownModal from '../site-management/drop-down-modal';
-import { activityStatus } from '@/helpers/constant';
+import { activeStatus, activityStatus } from '@/helpers/constant';
 import SkeletionIndexModal from './skeletion-index.modal';
 import MFullRefresh from '@/components/m-full-refresh';
 import MEmpty from '@/components/m-empty';
 import request from '@/helpers/request';
 import iconAdd from '@/common/images/icon-add.png';
 import { useRouter } from 'vue-router';
+import dayjs from 'dayjs';
 
 export default defineComponent({
   name: 'activtiy-record',
@@ -157,7 +158,7 @@ export default defineComponent({
               onLoad={getList}
               immediateCheck={false}>
               {forms.listState.dataShow ? (
-                forms.list.map(() => (
+                forms.list.map((item: any) => (
                   <CellGroup inset class={styles.cellGroup}>
                     <Cell
                       center
@@ -167,12 +168,12 @@ export default defineComponent({
                       {{
                         icon: () => (
                           <Tag plain type="primary" class={styles.tag}>
-                            泥泞
+                            {activityStatus[item.type]}
                           </Tag>
                         ),
                         title: () => (
                           <div class={[styles.title, 'van-ellipsis']}>
-                            武汉小学23年元旦晚会武汉小学23年元旦晚会武汉小学23年元旦晚会
+                            {item.name}
                           </div>
                         )
                       }}
@@ -180,9 +181,13 @@ export default defineComponent({
                     <Cell
                       class={styles.cellTimer}
                       center
-                      title={'活动日期:2022年12月10日'}
-                      value={'进行中'}
-                      valueClass={styles.ing}></Cell>
+                      title={`活动日期:${dayjs(item.startTime).format(
+                        'YYYY年MM月DD日'
+                      )}`}
+                      value={activeStatus[item.status]}
+                      valueClass={
+                        item.status === 'PROCESSING' ? styles.ing : ''
+                      }></Cell>
                   </CellGroup>
                 ))
               ) : (

+ 116 - 14
src/views/activity-record/operation.module.less

@@ -11,6 +11,10 @@
     .van-field__control {
       font-size: 15px;
     }
+
+    .van-field__control {
+      // font-weight: 600;
+    }
   }
 }
 
@@ -24,6 +28,33 @@
   }
 }
 
+.teamCell {
+  padding-bottom: 12px !important;
+}
+
+.tagCell {
+  padding-top: 0 !important;
+
+  .tagItem {
+    position: relative;
+    padding: 6px 22px 6px 8px;
+    font-size: 14px;
+    background: #F2FFFC;
+    border-radius: 4px;
+    margin-right: 9px;
+    margin-bottom: 8px;
+    // &+.tagItem {
+    //   margin-left: 9px;
+    // }
+  }
+
+  .closeable {
+    position: absolute;
+    right: 6px;
+    font-size: 8px;
+  }
+}
+
 .searchTypeFlex {
   margin-top: 6px;
 
@@ -47,6 +78,36 @@
     }
   }
 
+  &.multFlex {
+    margin: 0 13px;
+
+    :global {
+      .van-tag {
+        margin-bottom: 8px;
+        width: 110px;
+        height: 34px;
+        font-size: 13px;
+        justify-content: center;
+        border-radius: 6px;
+
+        &+.van-tag {
+          margin-left: 8px;
+        }
+
+        &:nth-child(3n + 4) {
+          margin-left: 0;
+        }
+      }
+
+      .van-tag--primary {
+        font-weight: 600;
+        background: #F2FFFC;
+        color: var(--k-font-primary);
+        border: 1px solid #9FE2DE;
+      }
+    }
+  }
+
   :global {
     .van-tag {
       margin-bottom: 8px;
@@ -77,7 +138,8 @@
       font-weight: 600;
     }
 
-    .van-radio {
+    .van-radio,
+    .van-checkbox {
       position: absolute;
       left: 0;
       right: 0;
@@ -89,8 +151,24 @@
   }
 }
 
+.placeholder {
+  font-size: 15px;
+  color: var(--k-gray-5);
+}
+
+.performance {
+  span {
+    color: var(--k-font-primary);
+  }
+}
+
 .iconImg {
   font-size: 18px;
+
+  &.disabled {
+    cursor: not-allowed;
+    opacity: 0.5;
+  }
 }
 
 .topTitle {
@@ -103,11 +181,14 @@
 .programTimer {
   font-size: 15px;
   color: var(--k-gray-2);
+  display: flex;
+  align-items: center;
 
   span {
     display: inline-block;
     min-width: 48px;
     line-height: 31px;
+    height: 31px;
     background: #F6F6F6;
     border-radius: 4px;
     padding: 0 12px;
@@ -149,26 +230,47 @@
   }
 
   .popupTimer {
+    display: flex;
+    align-items: center;
+    justify-content: center;
     text-align: center;
     font-size: 16px;
     color: var(--k-gray-2);
     margin-bottom: 10px;
 
-    input {
-      display: inline-block;
-      line-height: 47px;
-      width: 60px;
-      padding: 0 12px;
-      border-radius: 6px;
-      background: #F6F6F6;
-      font-size: 18px;
-      font-weight: bold;
-      margin-right: 20px;
-      text-align: center;
+    :global {
+      .van-field {
+        display: inline-flex;
+        display: inline-block;
+        line-height: 47px;
+        width: 60px;
+        padding: 0 12px;
+        border-radius: 6px;
+        background: #F6F6F6;
+        font-size: 18px;
+        font-weight: bold;
+        margin-right: 20px;
 
-      &:last-child {
-        margin-left: 20px;
+        input {
+
+          text-align: center;
+        }
+
+        &:last-child {
+          margin-left: 20px;
+        }
       }
     }
   }
+
+  .tipContent {
+    padding: 0 13px 10px;
+    font-size: 16px;
+    color: var(--k-gray-2);
+    text-align: center;
+
+    span {
+      color: #FF5A56;
+    }
+  }
 }

+ 496 - 106
src/views/activity-record/operation.tsx

@@ -12,7 +12,8 @@ import {
   Popup,
   Radio,
   RadioGroup,
-  Tag
+  Tag,
+  showToast
 } from 'vant';
 import { activityStatus, programType } from '@/helpers/constant';
 import MUploader from '@/components/m-uploader';
@@ -25,18 +26,83 @@ import MSticky from '@/components/m-sticky';
 import { formatterDatePicker } from '@/helpers/utils';
 import request from '@/helpers/request';
 import InputTimer from './components/input-timer';
+import PerformanceTeam from './components/performance-team';
+import MPopup from '@/components/m-popup';
+import CastModal from './components/cast-modal';
+import dayjs from 'dayjs';
+import { useRoute, useRouter } from 'vue-router';
+
+type detailItemType = {
+  id: string | number | null;
+  name: string;
+  type: string;
+  musicGroupId: string | null;
+  musicGroupName: string | null;
+  subjectAllList: any[];
+  subjectIdList: any[];
+  time: number | null;
+  performerList: any[];
+  attachmentUrl: string[];
+  attachmentVideoUrl: string[];
+  attachmentImgUrl: string[];
+};
+
+const detailItem: detailItemType = {
+  id: null,
+  name: '',
+  type: '', // 节目类型
+  musicGroupId: null, // 表演乐团
+  musicGroupName: null, //
+  subjectAllList: [] as any, // 表演团队数据列表
+  subjectIdList: [] as any, // 表演团队
+  time: null, // 表演时间
+  performerList: [], // 演员列表
+  attachmentUrl: [] as string[],
+  attachmentVideoUrl: [] as string[], // 视频目录
+  attachmentImgUrl: [] as string[]
+};
+
+// 格式化时间
+export const formatterTimer = (timer: number) => {
+  if (!timer) {
+    return {
+      minute: null,
+      secord: null
+    };
+  } else {
+    const minute = Math.floor(timer / 60);
+    const secord = timer % 60;
+    return {
+      minute,
+      secord
+    };
+  }
+};
 
 export default defineComponent({
   name: 'operation-page',
   setup() {
+    const route = useRoute();
+    const router = useRouter();
     const forms = reactive({
+      activityDetailId: route.query.id, // 活动编号
       timerStatus: false,
-      submitEvaluateStatus: null,
       currentDate: [],
       orchestraStatus: false, // 乐团列表状态
       orchestraColumns: [] as any,
       programType: '',
-      programTimerStatus: true // 节目时长状态
+      programTimerStatus: false, // 节目时长状态
+      deleteStatus: false, // 删除弹窗
+      teamStatus: false, // 表演团队状态
+      castStatus: false, // 学员名称状态
+      selectOrchestra: [] as any, // 选中的乐团
+      // selectOrchestraIndex: 0, // index
+      deleteIndex: 0, // 删除的编号
+
+      startTime: dayjs().format('YYYY-MM-DD'),
+      name: '',
+      type: '',
+      detail: [{ ...detailItem }]
     });
 
     // 乐团列表
@@ -56,9 +122,165 @@ export default defineComponent({
       }
     };
 
+    // 获取表演团队和演员
+    const getUserList = async () => {
+      try {
+        const { data } = await request.post(
+          '/api-web/schoolActivity/userList',
+          {
+            data: {
+              activityDetailId: forms.activityDetailId,
+              musicGroupId: forms.selectOrchestra.musicGroupId,
+              subjectIds: []
+            }
+          }
+        );
+        const tempData = data || [];
+        console.log(tempData, 'tempData');
+        forms.selectOrchestra.subjectAllList = tempData;
+        forms.selectOrchestra.performerList = tempData;
+
+        // 添加默认选中的编号
+        forms.selectOrchestra.subjectIdList = [];
+        tempData.forEach((item: any) => {
+          forms.selectOrchestra.subjectIdList.push(item.subjectId);
+        });
+      } catch {
+        //
+      }
+    };
+
+    // 添加节目
+    const onAddItem = () => {
+      forms.detail.push({ ...detailItem });
+    };
+
+    // 删除节目
+    const onDelete = (index: number) => {
+      if (forms.detail.length <= 1) return;
+      forms.deleteIndex = index;
+      forms.deleteStatus = true;
+    };
+
+    // 格式化员工数量
+    const formatterStudents = (list: any) => {
+      let count = 0;
+      list.forEach((item: any) => {
+        count += item.studentCount;
+      });
+      return count;
+    };
+
+    // 格式化选中的演员
+    const formatterPerformer = (ids: any[]) => {
+      const tempList: any = [];
+      // 先从默认选中的数据中取
+      forms.selectOrchestra.performerList.forEach((item: any) => {
+        if (ids.includes(item.subjectId)) tempList.push(item);
+      });
+      // 在从总的里面取
+      forms.selectOrchestra.subjectAllList.forEach((item: any) => {
+        const tmpPerformanceIndex =
+          forms.selectOrchestra.performerList.findIndex(
+            (p: any) => p.subjectId == item.subjectId
+          );
+        if (ids.includes(item.subjectId) && tmpPerformanceIndex < 0) {
+          tempList.push(item);
+        }
+      });
+      forms.selectOrchestra.performerList = tempList;
+    };
+
     onMounted(() => {
       musicGroupPage();
     });
+
+    const checkForms = () => {
+      if (!forms.name) {
+        showToast('请填写活动活动名称');
+        return false;
+      }
+      if (forms.name.length < 3 || forms.name.length > 25) {
+        showToast('活动名称长度3~25');
+        return false;
+      }
+      if (!forms.type) {
+        showToast('请选择活动类别');
+        return false;
+      }
+
+      for (let i = 0, j = forms.detail.length; i < j; i++) {
+        const tDetail = forms.detail[i];
+        if (!tDetail.name) {
+          showToast('节目名称不能为空');
+          return false;
+        }
+        if (!tDetail.type) {
+          showToast('请选择活动类型');
+          return false;
+        }
+        if (!tDetail.musicGroupId) {
+          showToast('请选择表演乐团');
+          return false;
+        }
+        if (tDetail.subjectIdList.length <= 0) {
+          showToast('请选择表演团队');
+          return false;
+        }
+
+        if (formatterStudents(tDetail.performerList) <= 0) {
+          showToast('请选择演员');
+          return false;
+        }
+        if (!tDetail.time) {
+          showToast('请输入节目时长');
+          return;
+        }
+      }
+
+      return true;
+    };
+    const onSubmit = async () => {
+      try {
+        // 校验
+        if (!checkForms()) return;
+
+        const params = {
+          startTime: forms.startTime,
+          endTime: forms.startTime + ' 23:59:59',
+          name: forms.name,
+          type: forms.type,
+          detail: [] as any[]
+        };
+        const tempDetail: any[] = [];
+        forms.detail.forEach((item: any, index: number) => {
+          tempDetail.push({
+            sort: index + 1,
+            name: item.name,
+            type: item.type,
+            musicGroupId: item.musicGroupId,
+            subjectIdList: item.subjectIdList,
+            studentNum: formatterStudents(item.performerList),
+            studentList: item.performerList,
+            time: item.time,
+            attachmentUrl: [
+              ...item.attachmentImgUrl,
+              ...item.attachmentUrl
+            ].join(',')
+          });
+        });
+        params.detail = tempDetail;
+
+        await request.post('/api-web/schoolActivity/save', {
+          hideLoading: false,
+          data: params
+        });
+
+        router.push('/activity-record');
+      } catch {
+        //
+      }
+    };
     return () => (
       <div class={styles.operation}>
         <MHeader />
@@ -70,6 +292,7 @@ export default defineComponent({
             inputAlign="right"
             readonly
             clearable={false}
+            v-model={forms.startTime}
             onClick={() => (forms.timerStatus = true)}
             placeholder="请选择活动日期"></Field>
           <Field
@@ -77,20 +300,16 @@ export default defineComponent({
             inputAlign="right"
             placeholder="请填写活动名称"
             maxlength={25}
+            v-model={forms.name}
+            autocomplete="off"
           />
-          <Field label="活动名称" labelAlign="top">
+          <Field label="活动类别" labelAlign="top">
             {{
               input: () => (
-                <RadioGroup
-                  class={styles.searchTypeFlex}
-                  v-model={forms.submitEvaluateStatus}>
+                <RadioGroup class={styles.searchTypeFlex} v-model={forms.type}>
                   {Object.keys(activityStatus).map((item: string) => (
                     <Tag
-                      type={
-                        forms.submitEvaluateStatus === item
-                          ? 'primary'
-                          : 'default'
-                      }
+                      type={forms.type === item ? 'primary' : 'default'}
                       round>
                       <Radio name={item} />
                       {activityStatus[item]}
@@ -102,113 +321,198 @@ export default defineComponent({
           </Field>
         </CellGroup>
 
-        <CellGroup inset class={styles.topCellGroup}>
-          <Cell center>
-            {{
-              icon: () => <Icon name={iconVideo} class={styles.iconImg} />,
-              title: () => <div class={styles.topTitle}>节目二</div>,
-              value: () => <Icon name={iconDelete} class={styles.iconImg} />
-            }}
-          </Cell>
-          <Field
-            label="节目名称"
-            inputAlign="right"
-            placeholder="请填写节目名称"
-            maxlength={25}
-          />
-          <Field
-            label="节目类型"
-            inputAlign="right"
-            placeholder="请填写节目"
-            class={styles.programType}>
-            {{
-              input: () => (
-                <RadioGroup
-                  class={[styles.searchTypeFlex, styles.small]}
-                  v-model={forms.programType}>
-                  {Object.keys(programType).map((item: string) => (
-                    <Tag
-                      type={forms.programType === item ? 'primary' : 'default'}
-                      round>
-                      <Radio name={item} />
-                      {programType[item]}
-                    </Tag>
-                  ))}
-                </RadioGroup>
-              )
-            }}
-          </Field>
-          <Field
-            isLink
-            label="表演乐团"
-            inputAlign="right"
-            readonly
-            clearable={false}
-            onClick={() => (forms.orchestraStatus = true)}
-            placeholder="请选择表演乐团"
-          />
-          <Field
-            isLink
-            label="表演团队"
-            inputAlign="right"
-            readonly
-            clearable={false}
-            placeholder="请选择表演团队"
-          />
-          <Field
-            isLink
-            label="演员"
-            inputAlign="right"
-            readonly
-            clearable={false}
-            placeholder="请选择演员"
-          />
-          <Field
-            label="节目时长"
-            inputAlign="right"
-            onClick={() => (forms.programTimerStatus = true)}
-            placeholder="请选择节目时长">
-            {{
-              input: () => (
-                <div class={styles.programTimer}>
-                  <span>3</span>分<span>24</span>秒
-                </div>
-              )
-            }}
-          </Field>
-          <Field label="上传附件" labelAlign="top">
-            {{
-              input: () => (
-                <MUploader
-                  uploadIcon={iconUploadImg}
-                  maxCount={5}
-                  style={{ marginTop: '4px' }}>
-                  <MUploaderInside
-                    uploadIcon={iconUploadVideo}
-                    uploadType="VIDEO"
-                    accept=".mp4"
-                    maxCount={3}
+        {forms.detail.map((item: any, index: number) => (
+          <CellGroup inset class={styles.topCellGroup}>
+            <Cell center>
+              {{
+                icon: () => <Icon name={iconVideo} class={styles.iconImg} />,
+                title: () => <div class={styles.topTitle}>节目{index + 1}</div>,
+                value: () => (
+                  <Icon
+                    name={iconDelete}
+                    class={[
+                      styles.iconImg,
+                      forms.detail.length <= 1 ? styles.disabled : ''
+                    ]}
+                    onClick={() => onDelete(index)}
                   />
-                </MUploader>
-              )
-            }}
-          </Field>
-        </CellGroup>
+                )
+              }}
+            </Cell>
+            <Field
+              label="节目名称"
+              inputAlign="right"
+              placeholder="请填写节目名称"
+              maxlength={25}
+              v-model={item.name}
+              autocomplete="off"
+            />
+            <Field
+              label="节目类型"
+              inputAlign="right"
+              placeholder="请填写节目"
+              class={styles.programType}>
+              {{
+                input: () => (
+                  <RadioGroup
+                    class={[styles.searchTypeFlex, styles.small]}
+                    v-model={item.type}>
+                    {Object.keys(programType).map((program: string) => (
+                      <Tag
+                        type={item.type === program ? 'primary' : 'default'}
+                        round>
+                        <Radio name={program} />
+                        {programType[program]}
+                      </Tag>
+                    ))}
+                  </RadioGroup>
+                )
+              }}
+            </Field>
+            <Field
+              isLink
+              label="表演乐团"
+              inputAlign="right"
+              readonly
+              clearable={false}
+              v-model={item.musicGroupName}
+              onClick={() => {
+                forms.orchestraStatus = true;
+                forms.selectOrchestra = [];
+                forms.selectOrchestra = item;
+              }}
+              placeholder="请选择表演乐团"
+            />
+            <Field
+              isLink
+              label="表演团队"
+              inputAlign="right"
+              readonly
+              clearable={false}
+              onClick={() => {
+                if (!item.musicGroupId) {
+                  showToast('请选择表演乐团');
+                  return;
+                }
+                forms.teamStatus = true;
+                forms.selectOrchestra = [];
+                forms.selectOrchestra = item;
+              }}
+              placeholder={
+                item.subjectIdList.length > 0 ? '' : '请选择表演乐团'
+              }
+              border={item.subjectIdList.length <= 0}
+              class={item.subjectIdList.length > 0 ? styles.teamCell : ''}
+            />
+            {item.subjectIdList.length > 0 && (
+              <Cell class={styles.tagCell} center>
+                {{
+                  title: () =>
+                    item.subjectIdList.map(
+                      (subjectId: [number, string], index: number) => {
+                        let subjectName = '';
+                        item.subjectAllList.forEach((subject: any) => {
+                          if (subject.subjectId === subjectId) {
+                            subjectName = subject.subjectName;
+                          }
+                        });
+                        return (
+                          <Tag type="primary" plain class={styles.tagItem}>
+                            {subjectName}
+                            <Icon
+                              name="cross"
+                              class={styles.closeable}
+                              onClick={() => {
+                                item.subjectIdList.splice(index, 1);
+                                formatterPerformer(item.subjectIdList);
+                              }}
+                            />
+                          </Tag>
+                        );
+                      }
+                    )
+                }}
+              </Cell>
+            )}
 
+            <Field
+              isLink
+              label="演员"
+              inputAlign="right"
+              readonly
+              clearable={false}
+              onClick={() => {
+                if (item.subjectIdList.length <= 0) {
+                  showToast('请选择表演团队');
+                  return;
+                }
+                forms.castStatus = true;
+              }}
+              v-slots={{
+                input: () =>
+                  formatterStudents(item.performerList) > 0 ? (
+                    <div class={styles.performance}>
+                      共 <span>{formatterStudents(item.performerList)}</span> 名
+                    </div>
+                  ) : (
+                    <div class={styles.placeholder}>请选择演员</div>
+                  )
+              }}
+            />
+            <Field
+              label="节目时长"
+              inputAlign="right"
+              onClick={() => (forms.programTimerStatus = true)}
+              center
+              placeholder="请选择节目时长">
+              {{
+                input: () => {
+                  const timers = formatterTimer(item.time);
+                  return (
+                    <div class={styles.programTimer}>
+                      <span>{timers?.minute}</span>分
+                      <span>{timers?.secord}</span>秒
+                    </div>
+                  );
+                }
+              }}
+            </Field>
+            <Field label="上传附件" labelAlign="top">
+              {{
+                input: () => (
+                  <MUploader
+                    uploadIcon={iconUploadImg}
+                    maxCount={5}
+                    v-model:modelValue={item.attachmentImgUrl}
+                    style={{ marginTop: '6px' }}>
+                    <MUploaderInside
+                      uploadIcon={iconUploadVideo}
+                      uploadType="VIDEO"
+                      accept=".mp4"
+                      maxCount={3}
+                      v-model:modelValue={item.attachmentVideoUrl}
+                    />
+                  </MUploader>
+                )
+              }}
+            </Field>
+          </CellGroup>
+        ))}
         <div class={styles.addButtonGroup}>
           <Button
             icon="plus"
             block
             type="primary"
             plain
-            class={styles.addButton}>
+            class={styles.addButton}
+            onClick={onAddItem}>
             添加节目
           </Button>
         </div>
 
         <MSticky position="bottom">
           <div class={['btnGroupFixed', styles.bottonGroup]}>
-            <Button type="primary" round block>
+            <Button type="primary" round block onClick={onSubmit}>
               确认
             </Button>
           </div>
@@ -218,8 +522,14 @@ export default defineComponent({
         <Popup v-model:show={forms.timerStatus} round position="bottom">
           <DatePicker
             v-model={forms.currentDate}
+            minDate={new Date()}
             formatter={formatterDatePicker}
             onCancel={() => (forms.timerStatus = false)}
+            onConfirm={({ selectedValues }) => {
+              // console.log(val, 12);
+              forms.startTime = selectedValues.join('-');
+              forms.timerStatus = false;
+            }}
           />
         </Popup>
 
@@ -228,6 +538,12 @@ export default defineComponent({
           <Picker
             columns={forms.orchestraColumns}
             onCancel={() => (forms.orchestraStatus = false)}
+            onConfirm={({ selectedOptions }) => {
+              forms.selectOrchestra.musicGroupName = selectedOptions[0].text;
+              forms.selectOrchestra.musicGroupId = selectedOptions[0].value;
+              forms.orchestraStatus = false;
+              getUserList();
+            }}
           />
         </Popup>
 
@@ -236,8 +552,82 @@ export default defineComponent({
           v-model:show={forms.programTimerStatus}
           round
           style={{ width: '82%' }}>
-          <InputTimer />
+          <InputTimer
+            show={forms.programTimerStatus}
+            time={forms.selectOrchestra.time}
+            onClose={() => (forms.programTimerStatus = false)}
+            onConfirm={(val: any) => {
+              const secords =
+                Number(val.minute || 0) * 60 + Number(val.second || 0);
+              forms.selectOrchestra.time = secords;
+              forms.programTimerStatus = false;
+            }}
+          />
+        </Popup>
+
+        {/* 删除节目提示 */}
+        <Popup v-model:show={forms.deleteStatus} round style={{ width: '82%' }}>
+          <div class={styles.popupContainer}>
+            <h2 class={styles.popupTitle}>删除节目</h2>
+            <div class={styles.popupContent}>
+              <p class={styles.tipContent}>
+                删除<span>《节目{forms.deleteIndex + 1}》</span>
+                ,删除后内容不可恢复
+              </p>
+            </div>
+            <div class={['btnGroupPopup']}>
+              <Button
+                type="primary"
+                round
+                onClick={() => {
+                  forms.detail.splice(forms.deleteIndex, 1);
+                  forms.deleteStatus = false;
+                }}>
+                确定
+              </Button>
+              <Button round onClick={() => (forms.deleteStatus = false)}>
+                取消
+              </Button>
+            </div>
+          </div>
+        </Popup>
+
+        {/* 表演团队 */}
+        <Popup
+          v-model:show={forms.teamStatus}
+          round
+          position="bottom"
+          closeable>
+          <PerformanceTeam
+            show={forms.teamStatus}
+            performances={forms.selectOrchestra.subjectAllList}
+            selectIds={forms.selectOrchestra.subjectIdList}
+            onClose={() => (forms.teamStatus = false)}
+            onConfirm={(ids: any[]) => {
+              forms.selectOrchestra.subjectIdList = ids;
+              formatterPerformer(ids);
+              forms.teamStatus = false;
+            }}
+          />
         </Popup>
+
+        {/* 演员名单 */}
+        <MPopup v-model:modelValue={forms.castStatus}>
+          <CastModal
+            subjectAllList={forms.selectOrchestra.subjectAllList}
+            v-model:performerList={forms.selectOrchestra.performerList}
+            onClose={() => (forms.castStatus = false)}
+            onConfirm={(val: any) => {
+              const subjects = val || [];
+              // 选中的声部编号
+              const ids: any = [];
+              subjects.forEach((subject: any) => {
+                ids.push(subject.subjectId);
+              });
+              forms.selectOrchestra.subjectIdList = ids || [];
+            }}
+          />
+        </MPopup>
       </div>
     );
   }

+ 1 - 1
src/views/school-register/index.tsx

@@ -82,7 +82,7 @@ export default defineComponent({
             userType: forms.type,
             username: forms.username,
             mobile: forms.phone,
-            code: forms.smsCode
+            smsCode: forms.smsCode
           }
         });
         if (res.code === 999) {

+ 46 - 38
src/views/teacher-attendance/amap-gps.tsx

@@ -5,21 +5,39 @@ import MHeader from '@/components/m-header';
 import MSticky from '@/components/m-sticky';
 import iconMap from './images/icon-map.png';
 import iconMapError from './images/icon-map-error.png';
+import { useRoute } from 'vue-router';
+import request from '@/helpers/request';
 export default defineComponent({
   name: 'amap-gps',
   setup() {
+    const route = useRoute();
     // 选中地图详情地址
     const selectMapAddress = reactive({
       attendance_range: 1000,
-      lnglat: [114.343011, 30.55499] as any, // 教学点 A座
+      lnglat: [] as any, // 教学点 A座
       address: '',
-      signInLongitudeLatitude: [114.333488, 30.547087], // 签到  B座
-      signOutLongitudeLatitude: [114.34424, 30.556584], // 签退
+      signInLongitudeLatitude: [] as any, // 签到  B座
+      signOutLongitudeLatitude: [] as any, // 签退
       signInMark: null,
       signOutMark: null,
       addressMark: null
     });
 
+    const sLngLat = route.query.sLngLat as string;
+    if (route.query.sLngLat) {
+      selectMapAddress.lnglat = sLngLat.split(',');
+    }
+    // inLngLat
+    const inLngLat = route.query.inLngLat as string;
+    if (route.query.inLngLat) {
+      selectMapAddress.signInLongitudeLatitude = inLngLat.split(',');
+    }
+    // outLngLat
+    const outLngLat = route.query.outLngLat as string;
+    if (route.query.outLngLat) {
+      selectMapAddress.signOutLongitudeLatitude = outLngLat.split(',');
+    }
+
     const map = shallowRef<any>(null);
     const ininMap = () => {
       AMapLoader.load({
@@ -112,7 +130,8 @@ export default defineComponent({
                 // 连线 设置签到点与教学点的距离
                 computeDis(
                   selectMapAddress.addressMark,
-                  selectMapAddress.signInMark
+                  selectMapAddress.signInMark,
+                  'top'
                 );
                 console.log('连线 设置签到点与教学点的距离');
               }
@@ -123,7 +142,8 @@ export default defineComponent({
                 // 连线 设置签退点与教学点的距离
                 computeDis(
                   selectMapAddress.addressMark,
-                  selectMapAddress.signOutMark
+                  selectMapAddress.signOutMark,
+                  'bottom'
                 );
                 console.log('连线 设置签退点与教学点的距离');
               }
@@ -167,8 +187,7 @@ export default defineComponent({
             }
           }
           // 连线 写标记
-          function computeDis(m1: any, m2: any) {
-            console.log(m2, 'm1 m2');
+          function computeDis(m1: any, m2: any, type: string) {
             const p1 = m1.getPosition();
             const p2 = m2.getPosition();
             const textPos = p1.divideBy(2).add(p2.divideBy(2));
@@ -207,36 +226,12 @@ export default defineComponent({
             });
             text.setPosition(textPos);
             text.setMap(map.value);
-            // if (type == 'top') {
-            //   console.log(p1, p2, textPos, distance, 'computed', type);
-            //   const text = new AMap.Text({
-            //     // text: '签到点距离学校' + distance + '米',
-            //     text: distance + 'M',
-            //     // angle: a,
-            //     style: {
-            //       'font-size': '12px'
-            //     }
-            //     //设置文本标注方位
-            //   });
-
-            //   // text.setOffset(new AMap.Pixel(-40, -10));
-            //   text.setPosition(textPos);
-            //   text.setMap(map.value);
-            // } else {
-            //   const text = new AMap.Text({
-            //     // text: '签退点距离学校' + distance + '米',
-            //     text: distance + 'M',
-            //     // angle: a,
-            //     style: {
-            //       'font-size': '12px'
-            //     }
-            //     //设置文本标注方位
-            //   });
-            //   // text.setOffset(new AMap.Pixel(-40, -50));
-            //   text.setPosition(textPos);
-            //   text.setMap(map.value);
-            //   // line.setPath(path);
-            // }
+            if (type == 'top') {
+              text.setOffset(new AMap.Pixel(-40, -10));
+            } else {
+              // text.setOffset(new AMap.Pixel(-40, -50));
+              //   text.setPosition(textPos);
+            }
           }
 
           // 计算两点间的角度
@@ -255,7 +250,20 @@ export default defineComponent({
         });
     };
 
-    onMounted(() => {
+    onMounted(async () => {
+      try {
+        const { data } = await request.get(
+          '/api-web/sysConfig/queryByParamName',
+          {
+            params: {
+              paramName: 'attendance_range'
+            }
+          }
+        );
+        selectMapAddress.attendance_range = data.attendance_range || 1000;
+      } catch {
+        //
+      }
       ininMap();
     });
 

+ 93 - 70
src/views/teacher-attendance/detail.tsx

@@ -8,7 +8,7 @@ import iconWarn from '@/common/images/icon-warn.png';
 import SkeletionDetailModal from './skeletion-detail-modal';
 import MHeader from '@/components/m-header';
 import request from '@/helpers/request';
-import { useRoute } from 'vue-router';
+import { useRoute, useRouter } from 'vue-router';
 import { coursesType, teacherAttendanceStatus } from '@/helpers/constant';
 import dayjs from 'dayjs';
 import MEmpty from '@/components/m-empty';
@@ -19,6 +19,7 @@ export default defineComponent({
   setup() {
     const dropDownItemRef1 = ref();
     const route = useRoute();
+    const router = useRouter();
     const forms = reactive({
       teacherId: route.query.teacherId,
       classGroupId: route.query.classGroupId,
@@ -84,7 +85,9 @@ export default defineComponent({
           '/api-web/schoolTeacherAttendance/getClassTeacherAttendance',
           {
             params: {
-              ...forms.params
+              ...forms.params,
+              teacherId: forms.teacherId,
+              classGroupId: forms.classGroupId
             }
           }
         );
@@ -99,6 +102,18 @@ export default defineComponent({
       }
     };
 
+    const onAddressGps = (item: any) => {
+      //
+      router.push({
+        path: '/amap-gps',
+        query: {
+          sLngLat: item.schoolLongitudeLatitude, // 教学点
+          inLngLat: item.signInLongitudeLatitude, // 签到
+          outLngLat: item.signOutLongitudeLatitude // 签退
+        }
+      });
+    };
+
     onMounted(() => {
       for (const key in coursesType) {
         if (Object.prototype.hasOwnProperty.call(coursesType, key)) {
@@ -110,7 +125,7 @@ export default defineComponent({
         }
       }
 
-      // getTeacherInfo();
+      getTeacherInfo();
       getList();
     });
     return () => (
@@ -219,7 +234,8 @@ export default defineComponent({
                     ),
                     value: () => (
                       <div class={styles.timer}>
-                        {dayjs(item.classDate).format('YYYY-MM-DD HH:mm:ss')}
+                        {/* {dayjs(item.classDate).format('YYYY-MM-DD HH:mm:ss')} */}
+                        {item.classDate}
                       </div>
                     )
                   }}
@@ -231,101 +247,108 @@ export default defineComponent({
                         <span
                           class={[
                             styles.statusName,
-                            item.signInStatus === 1 ? '' : styles.error
+                            item.signInStatus ? '' : styles.error
                           ]}>
-                          {item.signInStatus === 1 ? '正常' : '异常'}
+                          {item.signInStatus ? '正常' : '异常'}
                         </span>
                         <img
-                          src={item.signInStatus === 1 ? iconSuccess : iconWarn}
+                          src={item.signInStatus ? iconSuccess : iconWarn}
                           class={styles.img}
                         />
                       </div>
                       <div class={styles.sign}>
                         <span class={styles.signTime}>
-                          签到时间 {dayjs(item.signInTime).format('HH:mm:ss')}
+                          签到时间{' '}
+                          {item.signInTime
+                            ? dayjs(item.signInTime).format('HH:mm:ss')
+                            : '--'}
                         </span>
                       </div>
                     </div>
-                    <div class={styles.detailItem}>
-                      <div class={styles.detailStatus}>
-                        <span
-                          class={[
-                            styles.statusName,
-                            item.signInAddressStatus === 'YES'
-                              ? ''
-                              : styles.error
-                          ]}>
-                          {item.signInAddressStatus === 'YES' ? '正常' : '异常'}
-                        </span>
-                        <img
-                          src={
-                            item.signInAddressStatus === 'YES'
-                              ? iconSuccess
-                              : iconWarn
-                          }
-                          class={styles.img}
-                        />
-                      </div>
-                      <div class={styles.sign}>
-                        <span class={styles.signTime}>签到地点</span>
-                        <span class={styles.locate}>
-                          查看定位
-                          <Icon name="arrow" class={styles.iconArrow} />
-                        </span>
+                    {item.teachMode === 'OFFLINE' ? (
+                      <div class={styles.detailItem}>
+                        <div class={styles.detailStatus}>
+                          <span
+                            class={[
+                              styles.statusName,
+                              item.signInAddressStatus ? '' : styles.error
+                            ]}>
+                            {item.signInAddressStatus ? '正常' : '异常'}
+                          </span>
+                          <img
+                            src={
+                              item.signInAddressStatus ? iconSuccess : iconWarn
+                            }
+                            class={styles.img}
+                          />
+                        </div>
+                        <div class={styles.sign}>
+                          <span class={styles.signTime}>签到地点</span>
+                          <span
+                            class={styles.locate}
+                            onClick={() => onAddressGps(item)}>
+                            查看定位
+                            <Icon name="arrow" class={styles.iconArrow} />
+                          </span>
+                        </div>
                       </div>
-                    </div>
+                    ) : (
+                      ''
+                    )}
+
                     <div class={styles.detailItem}>
                       <div class={styles.detailStatus}>
                         <span
                           class={[
                             styles.statusName,
-                            item.signOutStatus === 1 ? '' : styles.error
+                            item.signOutStatus ? '' : styles.error
                           ]}>
-                          {item.signOutStatus === 1 ? '正常' : '异常'}
+                          {item.signOutStatus ? '正常' : '异常'}
                         </span>
                         <img
-                          src={
-                            item.signOutStatus === 1 ? iconSuccess : iconWarn
-                          }
+                          src={item.signOutStatus ? iconSuccess : iconWarn}
                           class={styles.img}
                         />
                       </div>
                       <div class={styles.sign}>
                         <span class={styles.signTime}>
-                          签退时间 {dayjs(item.signOutTime).format('HH:mm:ss')}
+                          签退时间{' '}
+                          {item.signOutTime
+                            ? dayjs(item.signOutTime).format('HH:mm:ss')
+                            : '--'}
                         </span>
                       </div>
                     </div>
-                    <div class={styles.detailItem}>
-                      <div class={styles.detailStatus}>
-                        <span
-                          class={[
-                            styles.statusName,
-                            item.signOutAddressStatus === 'YES'
-                              ? ''
-                              : styles.error
-                          ]}>
-                          {item.signOutAddressStatus === 'YES'
-                            ? '正常'
-                            : '异常'}
-                        </span>
-                        <img
-                          src={
-                            item.signOutAddressStatus === 'YES'
-                              ? iconSuccess
-                              : iconWarn
-                          }
-                          class={styles.img}
-                        />
+                    {item.teachMode === 'OFFLINE' ? (
+                      <div class={styles.detailItem}>
+                        <div class={styles.detailStatus}>
+                          <span
+                            class={[
+                              styles.statusName,
+                              item.signOutAddressStatus ? '' : styles.error
+                            ]}>
+                            {item.signOutAddressStatus ? '正常' : '异常'}
+                          </span>
+                          <img
+                            src={
+                              item.signOutAddressStatus ? iconSuccess : iconWarn
+                            }
+                            class={styles.img}
+                          />
+                        </div>
+                        <div class={styles.sign}>
+                          <span class={styles.signTime}>签到地点</span>
+                          <span
+                            class={styles.locate}
+                            onClick={() => onAddressGps(item)}>
+                            查看定位
+                            <Icon name="arrow" class={styles.iconArrow} />
+                          </span>
+                        </div>
                       </div>
-                      <div class={styles.sign}>
-                        <span class={styles.signTime}>签到地点</span>
-                        <span class={styles.locate}>
-                          查看定位
-                          <Icon name="arrow" class={styles.iconArrow} />
-                        </span>
-                      </div>
-                    </div>
+                    ) : (
+                      ''
+                    )}
                   </div>
                 </Cell>
               </CellGroup>