| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487 | import { computed, defineComponent, onMounted, reactive, ref } from 'vue';import styles from './index.module.less';import MSticky from '@/components/m-sticky';import MHeader from '@/components/m-header';import icon_detail_bg from '../images/icon_detail_bg.png';import icon_music from '@common/images/icon-music.png';import {  Button,  Cell,  CellGroup,  Checkbox,  CheckboxGroup,  Field,  Grid,  GridItem,  Image,  Picker,  Popup,  showToast} from 'vant';import MStudent from '../component/m-student';import { IMusicGroup, IStudentDetail } from '../type';import Assignment from '../component/Assignment';import Attendance from '../component/Attendance';import icon_pen from '@common/images/icon_pen.png';import icon_phone from '../images/icon-phone.png';import icon_message from '../images/icon-message.png';import SkeletionDetail from './skeletion-detail';import { useRoute } from 'vue-router';import {  api_organizationGetGradeList,  api_studentManageQuitMusicGroup,  api_studentManageUpdateGrade,  api_studentManageUserDetail,  api_studentManageUserMusicGroup} from '../api';export default defineComponent({  name: 'student-manage-detail',  setup() {    const route = useRoute();    const studentId: string | undefined =      route.query?.studentId?.toString() || '';    const musicGroupIds: string[] =      route.query.musicGroupIds?.toString()?.split(',') || [];    const detailData = reactive({      skelet: true,      /** 加载 */      loading: false,      /** 乐团 */      groupShow: false,      /** 退团 */      quitShow: false,      /** 确定退团 */      quitConfirmShow: false,      /** 联系方式 */      cancelShow: false,      /** 年级 */      gradeShow: false,      gradeOptions: [[], []] as any,      musicGroup: [] as IMusicGroup[],      musicGroupTitle: '全部乐团',      musicGroupId: musicGroupIds[0] || '',      student: {} as IStudentDetail,      /** 年级列表 */      gradeList: null as any,      /** 退团列表 */      quitList: [] as any[],      /** 退团原因 */      reason: '',      quitLoading: false    });    const checkboxRefs = ref<any[]>([]);    /** 获取学生乐团 */    const getMusicGroup = () => {      api_studentManageUserMusicGroup(studentId).then(res => {        if (Array.isArray(res.data)) {          detailData.musicGroup = res.data.map((item: any) => {            return {              text: item.name,              value: item.id,              gradeType: item.gradeType            };          });          if (detailData.musicGroup.length === 1) {            detailData.musicGroupTitle = detailData.musicGroup[0].text;          }        }      });    };    /** 获取年级分布 */    const getGradeList = () => {      if (detailData.student.organId && detailData.musicGroup.length) {        if (detailData.gradeList) return;        console.log(detailData.musicGroup);        const gradeType = Array.from(          new Set(detailData.musicGroup.map(group => group.gradeType))        ).join(',');        console.log('🚀 ~ gradeType:', gradeType);        api_organizationGetGradeList(          detailData.student.organId,          gradeType        ).then(res => {          detailData.gradeList = res.data;          detailData.gradeOptions[0] = Object.entries(res.data).map(            (value: any) => {              return {                text: value[1],                value: value[0]              };            }          );          detailData.gradeOptions[1] = new Array(30)            .fill(1)            .map((_, index: number) => ({              text: `${index + 1}班`,              value: `${index + 1}班`            }));        });        return;      }      setTimeout(() => {        getGradeList();      }, 30);    };    const getDatail = () => {      detailData.loading = true;      api_studentManageUserDetail({        studentId: studentId,        musicGroupId: detailData.musicGroupId || ''      })        .then(res => {          if (res.data) {            if (res.data.phone) {              res.data.phone =                res.data.phone.slice(0, 3) + '****' + res.data.phone.slice(-4);            }            detailData.student = res.data;            getGradeList();          }        })        .finally(() => {          setTimeout(() => {            detailData.loading = false;            detailData.skelet = false;          }, 500);        });    };    onMounted(() => {      getMusicGroup();      getDatail();    });    const quitName = computed(() => {      const text = detailData.musicGroup        .filter(group => detailData.quitList.includes(group.value))        .map(group => {          return '“' + group.text + '”';        })        .join('、');      return `${detailData.student.studentName}从${text}`;    });    /** 设置学生班级 */    const handleSetGrade = async (selectedOptions: any[]) => {      const res = await api_studentManageUpdateGrade({        currentClass: selectedOptions[1].value, // 班级        currentGrade: selectedOptions[0].text, // 年级        currentGradeNum: selectedOptions[0].value, // 年级(数字表示)        musicGroupId: detailData.musicGroupId, // 乐团ID        studentId: detailData.student.studentId // 学生ID      });      console.log(res);      if (res.code === 200) {        showToast('修改成功');      }      getDatail();    };    /** 退团 */    const handleQuite = async () => {      if (!detailData.reason) {        showToast('请填写退团原因');        return;      }      detailData.quitLoading = true;      try {        const res = await api_studentManageQuitMusicGroup({          musicGroupId: detailData.quitList.join(','),          reason: detailData.reason,          reasonEnum: 'OTHER',          userId: detailData.student.studentId        });        detailData.quitConfirmShow = false;        if (res.code === 200) {          detailData.quitList = [];          getDatail();        }      } catch (error) {}      detailData.quitLoading = false;    };    /** 去聊天 */    const openIm = () => {      postMessage({        api: 'joinChatGroup',        content: {          type: 'single', // single 单人 multi 多人          id: detailData.student.studentId        }      });    };    /** 打电话 */    const hanldeCallPhone = () => {      postMessage({        api: 'callPhone',        content: {          phone: detailData.student.phone        }      });    };    return () => (      <div class={styles.studentDetail}>        <Image class={styles.bg} src={icon_detail_bg} />        <MSticky position="top">          <MHeader background="transparent" />        </MSticky>        <SkeletionDetail loading={detailData.skelet}>          <Cell            class={styles.musicGroup}            title={detailData.musicGroupTitle}            isLink={detailData.musicGroup.length > 1 ? true : false}            clickable={detailData.musicGroup.length > 1 ? true : false}            center            border={false}            onClick={() => {              if (detailData.musicGroup.length < 2) return;              detailData.groupShow = true;            }}>            {{              icon: () => <Image class={styles.iconMusic} src={icon_music} />            }}          </Cell>          <div class={styles.box}>            <MStudent              item={detailData.student}              valueType={                detailData.student.inGroupStatus === 'OUT'                  ? 'statued'                  : detailData.student.inGroupStatus === 'APPLY_OUT'                  ? 'statuing'                  : 'status'              }              isLink={false}              onQuit={() => (detailData.quitShow = true)}              onContact={() => (detailData.cancelShow = true)}            />          </div>          <div class={styles.infobox}>            <div class={styles.attendanceTitle}>              <span>基本信息</span>            </div>            <div class={styles.infoItem}>              <div>性别</div>              <div>{detailData.student.gender ? '男' : '女'}</div>            </div>            <div class={styles.infoItem}>              <div>联系电话</div>              <div>{detailData.student.phone}</div>            </div>            <div class={styles.infoItem}>              <div>年级</div>              <div                class={styles.edit}                onClick={() => {                  if (detailData.student.inGroupStatus === 'OUT') return;                  detailData.gradeShow = true;                }}>                {detailData.student.currentGrade}年级                {detailData.student.currentClass}                {detailData.student.inGroupStatus !== 'OUT' && (                  <Image class={styles.iconPen} src={icon_pen} />                )}              </div>            </div>            <div class={styles.infoItem}>              <div>艺术实践</div>              <div>{detailData.student.artPracticeCount}次</div>            </div>            {detailData.student.quitTime && (              <div class={styles.infoItem}>                <div>退团时间</div>                <div style={{ color: '#FF5A56' }}>                  {detailData.student.quitTime}                </div>              </div>            )}          </div>          <div class={styles.box}>            <Assignment item={detailData.student} />          </div>          <div class={styles.box}>            <Attendance item={detailData.student} />          </div>        </SkeletionDetail>        {/* 切换乐团 */}        <Popup v-model:show={detailData.groupShow} position="bottom" round>          <Picker            visibleOptionNum={5}            columns={detailData.musicGroup}            onCancel={() => (detailData.groupShow = false)}            onConfirm={value => {              const option = value.selectedOptions[0];              const oldGroupId = detailData.musicGroupId;              detailData.musicGroupId = option.value;              detailData.musicGroupTitle = option.text;              detailData.groupShow = false;              if (oldGroupId != option.value) {                getDatail();              }            }}          />        </Popup>        {/* 联系方式 */}        <Popup          v-model:show={detailData.cancelShow}          position="bottom"          round          closeable>          <div class={styles.concatBox}>            <div class={styles.concatTitle}>联系方式</div>            <div class={styles.concatContent}>              <Grid columnNum={2} border={false} center>                <GridItem text="发送消息" onClick={openIm}>                  {{                    icon: () => (                      <Image class={styles.concatIcon} src={icon_message} />                    )                  }}                </GridItem>                <GridItem text="拨打电话" onClick={hanldeCallPhone}>                  {{                    icon: () => (                      <Image class={styles.concatIcon} src={icon_phone} />                    )                  }}                </GridItem>              </Grid>            </div>          </div>        </Popup>        {/* 设置班级 */}        <Popup v-model:show={detailData.gradeShow} position="bottom" round>          <Picker            visibleOptionNum={5}            columns={detailData.gradeOptions}            onCancel={() => (detailData.gradeShow = false)}            onConfirm={value => {              detailData.gradeShow = false;              handleSetGrade(value.selectedOptions);            }}          />        </Popup>        {/* 选择退团列表 */}        <Popup          v-model:show={detailData.quitShow}          class={['popup-custom', 'van-scale']}          transition="van-scale">          <div class={styles.quitBox}>            <div class={styles.quitTitle}>选择乐团</div>            <div class={styles.quitDes}>请选择要退出的乐团:</div>            <CheckboxGroup              v-model:modelValue={detailData.quitList}              class={styles.optionBox}>              <CellGroup border={false}>                {detailData.musicGroup.map(                  (group: IMusicGroup, index: number) => {                    return (                      <Cell                        class={[                          detailData.quitList.includes(group.value) &&                            styles.cellActive                        ]}                        title={group.text}                        center                        border={false}                        onClick={() => {                          checkboxRefs.value[index]?.toggle();                        }}>                        {{                          value: () => (                            <Checkbox                              ref={el => (checkboxRefs.value[index] = el)}                              shape="square"                              name={group.value}                              onClick={(e: Event) =>                                e.stopPropagation()                              }></Checkbox>                          )                        }}                      </Cell>                    );                  }                )}              </CellGroup>            </CheckboxGroup>            <div class={['btnGroupPopup']}>              <Button round onClick={() => (detailData.quitShow = false)}>                取消              </Button>              <Button                type="primary"                round                disabled={!detailData.quitList.length}                onClick={() => {                  // detailData.quitShow = false                  detailData.quitConfirmShow = true;                }}>                下一步              </Button>            </div>          </div>        </Popup>        {/* 确定退团 */}        <Popup          v-model:show={detailData.quitConfirmShow}          class={['popup-custom', 'van-scale']}          transition="van-scale">          <div class={styles.quitBox}>            <div class={styles.quitTitle}>学员退团</div>            <div class={styles.quitDes}>              确认要将学员              <span style={{ color: '#FF5A56' }}>{quitName.value}</span>              中退团吗?            </div>            <div style={{ color: '#333' }} class={styles.quitLabel}>              <span style={{ color: '#FF5A56' }}>*</span>退团原因:            </div>            <div class={styles.quitLabel}>              <Field                style={{ padding: 0 }}                v-model={detailData.reason}                type="textarea"                rows={3}                required                placeholder="请填写退团原因"></Field>            </div>            <div class={styles.quitLabel}>              确认后,我们将在7个工作日内与学生联系退费事宜            </div>            <div class={['btnGroupPopup']}>              <Button                round                onClick={() => (detailData.quitConfirmShow = false)}>                取消              </Button>              <Button                loading={detailData.quitLoading}                type="primary"                round                onClick={() => handleQuite()}>                确定              </Button>            </div>          </div>        </Popup>      </div>    );  }});
 |