lex 11 miesięcy temu
rodzic
commit
71f316ec33

BIN
src/views/tenantAllData/images/icon-address.png


BIN
src/views/tenantAllData/images/icon-arrow-active.png


BIN
src/views/tenantAllData/images/icon-arrow.png


+ 192 - 14
src/views/tenantAllData/index.module.less

@@ -30,18 +30,47 @@
       }
     }
 
-    .timerWrap {
-      display: flex;
-      flex-direction: row;
-      align-items: center;
-      font-size: 14px;
-      font-weight: 400;
-      color: #333333;
+    // .timerWrap {
+    //   display: flex;
+    //   flex-direction: row;
+    //   align-items: center;
+    //   font-size: 14px;
+    //   font-weight: 400;
+    //   color: #333333;
+
+    //   .sanIcon {
+    //     width: 12px;
+    //     height: 12px;
+    //     margin-left: 5px;
+    //   }
+    // }
+
+    :global {
+      .van-dropdown-menu__bar {
+        padding-bottom: 7Px;
+        height: auto;
+        background-color: transparent;
+      }
 
-      .sanIcon {
-        width: 12px;
-        height: 12px;
-        margin-left: 5px;
+      .van-dropdown-menu__title {
+        padding: 0;
+
+        &::after {
+          display: none;
+        }
+      }
+
+      .van-dropdown-menu__title--active {
+        .areaWrapActive {
+          span {
+            color: #028FF6;
+          }
+
+          .iconArrowActive {
+            background: url('./images/icon-arrow-active.png') no-repeat center;
+            background-size: contain;
+          }
+        }
       }
     }
   }
@@ -167,11 +196,63 @@
     .searechInfo {
       width: 273px;
     }
+
+    .timerWrap img {
+      margin-left: 4px;
+      flex-shrink: 0;
+    }
+  }
+
+  .areaWrap {
+    display: flex;
+    align-items: center;
+    justify-content: center;
+    padding: 8px 10px;
+    border-radius: 30px;
+    background-color: #fff;
+
+    .iconAddress {
+      display: inline-block;
+      width: 16px;
+      height: 18px;
+      background: url('./images/icon-address.png') no-repeat center;
+      background-size: contain;
+
+      flex-shrink: 0;
+    }
+
+    span {
+      padding: 0 4px;
+      font-weight: 600;
+      font-size: 15px;
+      color: #333333;
+      max-width: 190px;
+      white-space: nowrap;
+      overflow: hidden;
+      text-overflow: ellipsis;
+    }
+
+    .iconArrow {
+      width: 9px;
+      height: 5px;
+      display: inline-block;
+      background: url('./images/icon-arrow.png') no-repeat center;
+      background-size: contain;
+      flex-shrink: 0;
+    }
+  }
+
+  .topHeadIndex {
+    padding-bottom: 7Px;
+  }
+
+  .cardWrapIndex {
+    margin-top: 10px;
   }
 
   .sanIcon {
-    width: 12px;
-    height: 12px;
+    width: 9px;
+    height: 5px;
   }
 
   .routeSan {
@@ -268,6 +349,41 @@
   }
 }
 
+
+.popSearchList {
+  width: 128px;
+  background: #FFFFFF;
+  box-shadow: 0 2px 12px 0px rgba(50, 50, 51, 0.12);
+  padding: 0 8px;
+  border-radius: 8px;
+  overflow: hidden;
+
+  .popSearchItem {
+    overflow: hidden;
+
+
+
+
+    .popSearchItemChild {
+      margin: 5px 0;
+      padding: 6px 14px;
+      font-size: 14px;
+      color: #323233;
+      line-height: 20px;
+      text-shadow: 0 2px 12px rgba(50, 50, 51, 0.12);
+      border-radius: 4px;
+
+      &.popSearchItemActive {
+        background: #EEF8FF;
+        font-weight: 500;
+        color: #028FF6;
+      }
+    }
+  }
+}
+
+
+
 .topHeadSchool {
   font-size: 14px;
   display: flex;
@@ -347,7 +463,14 @@
 
 .timerWrap {
   font-size: 14px;
-  width: 120px;
+  width: 105px;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+
+  &.timerWrapActive {
+    color: #028FF6;
+  }
 }
 
 .schoolList {
@@ -480,4 +603,59 @@
   height: 47px;
   max-width: 264px;
   margin: 29px auto 0;
+}
+
+.areaList {
+  display: flex;
+  flex: 1;
+
+  overflow-x: hidden;
+  overflow-y: auto;
+  min-height: 240px;
+  max-height: 300px;
+
+  .areaItem {
+    flex: 1;
+    max-width: 33.33%;
+    padding: 8px 5px;
+  }
+
+  .areaItemChild {
+    padding: 0 8px;
+    border-radius: 6px;
+    background: #fff;
+    font-size: 14px;
+    line-height: 36px;
+    height: 36px;
+    color: #333333;
+    margin-bottom: 4px;
+    white-space: nowrap;
+    overflow: hidden;
+    text-overflow: ellipsis;
+    display: block;
+  }
+
+  .areaItemChildActive {
+    font-weight: 500;
+    color: #028FF6;
+    background: #EEF8FF;
+  }
+}
+
+.btnGroup {
+  padding: 9px 13px;
+  display: flex;
+  align-items: center;
+
+  :global {
+    .van-button {
+      height: 44px;
+      font-weight: 400;
+      font-size: 16px;
+    }
+
+    .van-button+.van-button {
+      margin-left: 15px;
+    }
+  }
 }

+ 347 - 74
src/views/tenantAllData/index.tsx

@@ -11,14 +11,19 @@ import {
   Tab,
   Tabs,
   DatePicker,
-  Button
+  Button,
+  DropdownMenu,
+  DropdownItem,
+  Popover
 } from 'vant';
 import MSticky from '@/components/m-sticky';
 import personIcon from './images/personIcon.png';
 import homeIcon from './images/homeIcon.png';
 import memberIcon from './images/memberIcon.png';
 import memberRateIcon from './images/memberRateIcon.png';
-import sanIcon from './images/san.png';
+// import sanIcon from './images/san.png';
+import iconArrow from './images/icon-arrow.png';
+import iconArrowActive from './images/icon-arrow-active.png';
 import iconQrcode from './images/icon-qrcode.png';
 import qrcodeBg from './images/qrcode-bg.png';
 import qrbg from './images/qr-bg.png';
@@ -35,6 +40,8 @@ import numeral from 'numeral';
 import MQrcode from '@/components/m-qrcode';
 import html2canvas from 'html2canvas';
 import MWxTip from '@/components/m-wx-tip';
+import deepClone from '@/helpers/deep-clone';
+import { number } from 'echarts';
 export default defineComponent({
   name: 'tenant-apply-data',
   setup() {
@@ -57,6 +64,7 @@ export default defineComponent({
       sortKey: 'CLASS' as 'CLASS' | 'MEMBER',
       sortId: 'desc',
       sortName: '报名人数降序',
+      sortType: 'desc',
       sortList: [
         { value: 'desc', text: '报名人数降序' },
         { value: 'asc', text: '报名人数升序' },
@@ -66,9 +74,28 @@ export default defineComponent({
       page: 1,
       rows: 20,
       isClick: false,
+      showDropdown: false,
       qrcodeStatus: false,
       url: '1', // 二维码
-      urlItem: {} as any
+      urlItem: {} as any,
+
+      provinceList: [] as any, // 省
+      cityList: [] as any, // 市
+      areaList: [] as any, // 区
+      // 确认之后
+      searchConfirmObj: {
+        type: 'province' as 'province' | 'city' | 'area' | '',
+        label: '全部地区',
+        value: null as any,
+        list: [] as any
+      },
+      // 弹窗
+      searchObj: {
+        type: 'province' as 'province' | 'city' | 'area' | '',
+        label: '全部地区',
+        value: null as any,
+        list: [] as any
+      }
     });
 
     const refreshing = ref(false);
@@ -77,32 +104,32 @@ export default defineComponent({
     const showContact = ref(false);
     const list = ref([]);
 
-    const getSchoolList = async () => {
-      try {
-        const { data } = await request.get('/edu-app/open/school/list', {
-          params: {
-            tenantId: forms.id
-          }
-        });
-        const temp = [
-          {
-            value: '',
-            text: '全部学校'
-          }
-        ];
-        if (Array.isArray(data)) {
-          data.forEach((item: any) => {
-            temp.push({
-              value: item.id,
-              text: item.name
-            });
-          });
-          forms.classList = temp;
-        }
-      } catch {
-        //
-      }
-    };
+    // const getSchoolList = async () => {
+    //   try {
+    //     const { data } = await request.get('/edu-app/open/school/list', {
+    //       params: {
+    //         tenantId: forms.id
+    //       }
+    //     });
+    //     const temp = [
+    //       {
+    //         value: '',
+    //         text: '全部学校'
+    //       }
+    //     ];
+    //     if (Array.isArray(data)) {
+    //       data.forEach((item: any) => {
+    //         temp.push({
+    //           value: item.id,
+    //           text: item.name
+    //         });
+    //       });
+    //       forms.classList = temp;
+    //     }
+    //   } catch {
+    //     //
+    //   }
+    // };
 
     const getList = async () => {
       if (forms.isClick) {
@@ -115,18 +142,27 @@ export default defineComponent({
         refreshing.value = false;
       }
       try {
+        const params: any = {
+          tenantId: forms.id,
+          page: forms.page,
+          rows: forms.rows,
+          year: forms.yearName,
+          keyword: forms.keyword,
+          sort: forms.sortId,
+          sortKey: forms.sortKey
+        };
+
+        if (forms.searchConfirmObj.type === 'province') {
+          params.provinceCode = forms.searchConfirmObj.value;
+        } else if (forms.searchConfirmObj.type === 'city') {
+          params.cityCode = forms.searchConfirmObj.value;
+        } else if (forms.searchConfirmObj.type === 'area') {
+          params.regionCode = forms.searchConfirmObj.value;
+        }
         const res = await request.post(
           '/edu-app/open/school/schoolRegisterPage',
           {
-            data: {
-              tenantId: forms.id,
-              page: forms.page,
-              rows: forms.rows,
-              year: forms.yearName,
-              keyword: forms.keyword,
-              sort: forms.sortId,
-              sortKey: forms.sortKey
-            }
+            data: params
           }
         );
 
@@ -213,6 +249,66 @@ export default defineComponent({
       return Math.round((memberNum / studentNum) * 1000) / 10;
     };
 
+    const dropdownItemRef = ref();
+    const getAreas = async () => {
+      try {
+        const { data } = await request.get(
+          '/edu-app/open/sysArea/queryProvince?tenantId=' + forms.id
+        );
+        forms.provinceList = data || [];
+      } catch {
+        //
+      }
+    };
+
+    const formatParentAreaId = (id: any, list: any, ids = [] as any) => {
+      for (const item of list) {
+        if (item.code == id) {
+          return [...ids, id];
+        }
+        if (item.areas && item.areas.length > 0) {
+          const cIds: any = formatParentAreaId(id, item.areas, [
+            ...ids,
+            item.code
+          ]);
+          if (cIds.includes(id)) {
+            return cIds;
+          }
+        }
+      }
+      return ids;
+    };
+
+    /** 切换状态 */
+    const onChangeArea = (type: 'province' | 'city' | 'area', item: any) => {
+      forms.searchObj.type = type;
+      forms.searchObj.value = item.code;
+      forms.searchObj.label = item.name;
+      forms.searchObj.list = formatParentAreaId(item.code, forms.provinceList);
+      if (type === 'province') {
+        forms.cityList = item.areas || [];
+        forms.areaList = [];
+      } else if (type === 'city') {
+        forms.areaList = item.areas || [];
+      } else if (type === 'area') {
+        //
+      }
+    };
+
+    const formatAreaDefaultData = (index: number, ids: number[], item: any) => {
+      const type: any = ['province', 'city', 'area'];
+      if (ids.length <= 0) return;
+      item.forEach((item: any) => {
+        if (item.code === ids[index]) {
+          onChangeArea(type[index], item);
+
+          if (ids[index]) {
+            formatAreaDefaultData(index + 1, ids, item.areas || []);
+          }
+        }
+      });
+    };
+
     onMounted(async () => {
       if (route.query.name) {
         document.title = route.query.name + '报名统计';
@@ -221,18 +317,28 @@ export default defineComponent({
       }
 
       // await getSchoolList();
+      getAreas();
       await getStat();
       await getList();
     });
     const getStat = async () => {
       try {
+        const params: any = {
+          tenantId: forms.id,
+          year: forms.yearName
+        };
+
+        if (forms.searchConfirmObj.type === 'province') {
+          params.provinceCode = forms.searchConfirmObj.value;
+        } else if (forms.searchConfirmObj.type === 'city') {
+          params.cityCode = forms.searchConfirmObj.value;
+        } else if (forms.searchConfirmObj.type === 'area') {
+          params.regionCode = forms.searchConfirmObj.value;
+        }
         const { data } = await request.post(
           '/edu-app/open/school/schoolRegisterStat',
           {
-            data: {
-              tenantId: forms.id,
-              year: forms.yearName
-            }
+            data: params
           }
         );
         forms.statObj = data;
@@ -246,27 +352,138 @@ export default defineComponent({
         <MSticky position="top">
           <div class={styles.top}>
             <div class={styles.topWrap}>
-              <div class={styles.topHead}>
+              <div class={[styles.topHead, styles.topHeadIndex]}>
                 <img src={topDot} class={styles.topDot} alt="" />
                 汇总数据
               </div>
-              {/* <div
-                class={styles.timerWrap}
-                onClick={() => {
-                  forms.yearStatus = true;
-                }}>
-                {forms.yearName}年{' '}
-                <img
-                  src={sanIcon}
-                  class={[
-                    styles.sanIcon,
-                    forms.yearStatus ? styles.routeSan : ''
-                  ]}
-                  alt=""
-                />
-              </div> */}
+
+              <DropdownMenu>
+                <DropdownItem
+                  ref={dropdownItemRef}
+                  onOpen={() => {
+                    forms.searchObj = deepClone(forms.searchConfirmObj);
+
+                    if (forms.searchObj.list.length > 0) {
+                      formatAreaDefaultData(
+                        0,
+                        forms.searchObj.list,
+                        forms.provinceList
+                      );
+                    }
+                  }}>
+                  {{
+                    title: () => (
+                      <div class={[styles.areaWrap, 'areaWrapActive']}>
+                        <i class={styles.iconAddress}></i>
+                        <span>{forms.searchConfirmObj.label}</span>
+                        <i class={[styles.iconArrow, 'iconArrowActive']}></i>
+                      </div>
+                    ),
+                    default: () => (
+                      <div class={styles.areaSection}>
+                        <div class={[styles.areaList]}>
+                          {forms.provinceList.length > 0 && (
+                            <div
+                              class={[
+                                styles.areaItem,
+                                forms.cityList.length > 0 &&
+                                  'van-hairline--right'
+                              ]}>
+                              {forms.provinceList.map((item: any) => (
+                                <span
+                                  onClick={() => onChangeArea('province', item)}
+                                  class={[
+                                    styles.areaItemChild,
+                                    forms.searchObj.list.includes(item.code) &&
+                                      styles.areaItemChildActive
+                                  ]}>
+                                  {item.name}
+                                </span>
+                              ))}
+                            </div>
+                          )}
+
+                          {forms.cityList.length > 0 && (
+                            <div
+                              class={[
+                                styles.areaItem,
+                                forms.areaList.length > 0 &&
+                                  'van-hairline--right'
+                              ]}>
+                              {forms.cityList.map((item: any) => (
+                                <span
+                                  onClick={() => onChangeArea('city', item)}
+                                  class={[
+                                    styles.areaItemChild,
+                                    forms.searchObj.list.includes(item.code) &&
+                                      styles.areaItemChildActive
+                                  ]}>
+                                  {item.name}
+                                </span>
+                              ))}
+                            </div>
+                          )}
+
+                          {forms.areaList.length > 0 && (
+                            <div class={[styles.areaItem]}>
+                              {forms.areaList.map((item: any) => (
+                                <span
+                                  onClick={() => onChangeArea('area', item)}
+                                  class={[
+                                    styles.areaItemChild,
+                                    forms.searchObj.list.includes(item.code) &&
+                                      styles.areaItemChildActive
+                                  ]}>
+                                  {item.name}
+                                </span>
+                              ))}
+                            </div>
+                          )}
+                        </div>
+                        <div class={[styles.btnGroup, 'van-hairline--top']}>
+                          <Button
+                            round
+                            block
+                            onClick={async () => {
+                              forms.searchObj.type = '';
+                              forms.searchObj.label = '全部地区';
+                              forms.searchObj.value = null;
+                              forms.searchObj.list = [];
+                              forms.searchConfirmObj = deepClone(
+                                forms.searchObj
+                              );
+                              dropdownItemRef.value?.toggle(false);
+                              forms.page = 1;
+                              refreshing.value = true;
+                              await getStat();
+                              await getList();
+                            }}>
+                            重置
+                          </Button>
+                          <Button
+                            round
+                            type="primary"
+                            block
+                            onClick={async () => {
+                              forms.searchConfirmObj = deepClone(
+                                forms.searchObj
+                              );
+                              dropdownItemRef.value?.toggle(false);
+                              forms.page = 1;
+                              refreshing.value = true;
+                              await getStat();
+                              await getList();
+                            }}>
+                            确定
+                          </Button>
+                        </div>
+                      </div>
+                    )
+                  }}
+                </DropdownItem>
+              </DropdownMenu>
             </div>
-            <div class={styles.cardWrap}>
+            <div class={[styles.cardWrap, styles.cardWrapIndex]}>
               <div class={[styles.schoolCard, styles.cardItem]}>
                 <div class={styles.cardNum}>
                   {numeral(forms.statObj.schoolNum).format('0,0')}
@@ -330,19 +547,75 @@ export default defineComponent({
                   }}></OSearch>
               </div>
 
-              <div
-                class={styles.timerWrap}
-                onClick={() => (forms.perponStatus = true)}>
-                {forms.sortName}{' '}
-                <img
-                  src={sanIcon}
-                  class={[
-                    styles.sanIcon,
-                    forms.perponStatus ? styles.routeSan : ''
-                  ]}
-                  alt=""
-                />
-              </div>
+              <Popover
+                v-model:show={forms.perponStatus}
+                showArrow={false}
+                placement="bottom-end"
+                offset={[0, 12]}>
+                {{
+                  reference: () => (
+                    <div
+                      class={[
+                        styles.timerWrap,
+                        forms.perponStatus && styles.timerWrapActive
+                      ]}
+                      // onClick={() => (forms.perponStatus = true)}
+                    >
+                      {forms.sortName}
+                      <img
+                        src={forms.perponStatus ? iconArrowActive : iconArrow}
+                        class={[styles.sanIcon]}
+                        alt=""
+                      />
+                    </div>
+                  ),
+                  default: () => (
+                    <div class={styles.popSearchList}>
+                      {forms.sortList.map((item: any, index: number) => (
+                        <div
+                          class={[
+                            styles.popSearchItem,
+                            index < forms.sortList.length - 1 &&
+                              'van-hairline--bottom'
+                          ]}>
+                          <div
+                            class={[
+                              styles.popSearchItemChild,
+                              forms.sortType === item.value &&
+                                styles.popSearchItemActive
+                            ]}
+                            onClick={() => {
+                              const selectedOption = item;
+                              if (
+                                selectedOption.value === 'desc' ||
+                                selectedOption.value === 'asc'
+                              ) {
+                                forms.sortId = selectedOption.value;
+                                forms.sortKey = 'CLASS';
+                              }
+                              if (selectedOption.value === 'mdesc') {
+                                forms.sortId = 'desc';
+                                forms.sortKey = 'MEMBER';
+                              }
+                              if (selectedOption.value === 'masc') {
+                                forms.sortId = 'asc';
+                                forms.sortKey = 'MEMBER';
+                              }
+
+                              forms.sortType = selectedOption.value;
+                              forms.sortName = selectedOption.text;
+                              refreshing.value = true;
+                              getList();
+                              forms.perponStatus = false;
+                            }}>
+                            {item.text}
+                          </div>
+                        </div>
+                      ))}
+                    </div>
+                  )
+                }}
+              </Popover>
             </div>
           </div>
         </MSticky>
@@ -446,7 +719,7 @@ export default defineComponent({
           />
         </Popup>
 
-        <Popup
+        {/* <Popup
           v-model:show={forms.perponStatus}
           position="bottom"
           round
@@ -479,7 +752,7 @@ export default defineComponent({
               forms.perponStatus = false;
             }}
           />
-        </Popup>
+        </Popup> */}
 
         <Popup v-model:show={forms.qrcodeStatus} class={styles.popupQrcode}>
           <i

+ 78 - 5
src/views/tenantAllData/tenantDataSchool.tsx

@@ -11,7 +11,8 @@ import {
   Tab,
   Tabs,
   DatePicker,
-  Button
+  Button,
+  Popover
 } from 'vant';
 import MSticky from '@/components/m-sticky';
 import personIcon from './images/personIcon.png';
@@ -19,6 +20,8 @@ import homeIcon from './images/icon-class.png';
 import memberIcon from './images/memberIcon.png';
 import memberRateIcon from './images/memberRateIcon.png';
 import sanIcon from './images/san.png';
+import iconArrow from './images/icon-arrow.png';
+import iconArrowActive from './images/icon-arrow-active.png';
 import request from '@/helpers/request';
 import topDot from './images/topDot.png';
 import { useRoute, useRouter } from 'vue-router';
@@ -56,6 +59,7 @@ export default defineComponent({
       sortKey: 'CLASS' as 'CLASS' | 'MEMBER',
       sortId: 'desc',
       sortName: '报名人数降序',
+      sortType: 'desc',
       sortList: [
         { value: 'desc', text: '报名人数降序' },
         { value: 'asc', text: '报名人数升序' },
@@ -281,7 +285,7 @@ export default defineComponent({
                   }}></OSearch>
               </div>
 
-              <div
+              {/* <div
                 class={styles.timerWrap}
                 onClick={() => (forms.perponStatus = true)}>
                 {forms.sortName}{' '}
@@ -293,7 +297,76 @@ export default defineComponent({
                   ]}
                   alt=""
                 />
-              </div>
+              </div> */}
+              <Popover
+                v-model:show={forms.perponStatus}
+                showArrow={false}
+                placement="bottom-end"
+                offset={[0, 12]}>
+                {{
+                  reference: () => (
+                    <div
+                      class={[
+                        styles.timerWrap,
+                        forms.perponStatus && styles.timerWrapActive
+                      ]}
+                      // onClick={() => (forms.perponStatus = true)}
+                    >
+                      {forms.sortName}
+                      <img
+                        src={forms.perponStatus ? iconArrowActive : iconArrow}
+                        class={[styles.sanIcon]}
+                        alt=""
+                      />
+                    </div>
+                  ),
+                  default: () => (
+                    <div class={styles.popSearchList}>
+                      {forms.sortList.map((item: any, index: number) => (
+                        <div
+                          class={[
+                            styles.popSearchItem,
+                            index < forms.sortList.length - 1 &&
+                              'van-hairline--bottom'
+                          ]}>
+                          <div
+                            class={[
+                              styles.popSearchItemChild,
+                              forms.sortType === item.value &&
+                                styles.popSearchItemActive
+                            ]}
+                            onClick={() => {
+                              const selectedOption = item;
+                              if (
+                                selectedOption.value === 'desc' ||
+                                selectedOption.value === 'asc'
+                              ) {
+                                forms.sortId = selectedOption.value;
+                                forms.sortKey = 'CLASS';
+                              }
+                              if (selectedOption.value === 'mdesc') {
+                                forms.sortId = 'desc';
+                                forms.sortKey = 'MEMBER';
+                              }
+                              if (selectedOption.value === 'masc') {
+                                forms.sortId = 'asc';
+                                forms.sortKey = 'MEMBER';
+                              }
+
+                              forms.sortType = selectedOption.value;
+                              forms.sortName = selectedOption.text;
+                              refreshing.value = true;
+                              getList();
+                              forms.perponStatus = false;
+                            }}>
+                            {item.text}
+                          </div>
+                        </div>
+                      ))}
+                    </div>
+                  )
+                }}
+              </Popover>
             </div>
           </div>
         </MSticky>
@@ -383,7 +456,7 @@ export default defineComponent({
           />
         </Popup>
 
-        <Popup
+        {/* <Popup
           v-model:show={forms.perponStatus}
           position="bottom"
           round
@@ -416,7 +489,7 @@ export default defineComponent({
               forms.perponStatus = false;
             }}
           />
-        </Popup>
+        </Popup> */}
 
         <MWxTip />
       </div>