财务管理系统页面解读

页面顺序

index页面(第一页面)

顶部日期及总收入总支出对应代码

 <view class="calendar-content" id="calendar-content">
      <view class="bg" />
      <view class=" date-title">
		  <!-- 从底部弹起的滚动选择器。时期选择器 -->
        <picker
          class="date-picker"
          mode="date"
          @change="onPickerChange"
          fields="month"
          :value="pickerDate"
          :end="pickerEnd"
        >
          <view class="now-date x-c">
            <text>{{ pickerDateText.year }}年{{ pickerDateText.month }}月</text><!-- 顶部显示日期,与112行相关 -->
            <i class="iconfont icon-bottom icon-down" />
          </view>
        </picker>
        <view class="statement">
          <view class="statement-text">
            <text class="statement-text-title">总收入</text>
            <view class="statement-text-total">
              <text class="statement-text-total-char">¥</text>
              <text>{{ indexStat.income }}</text>
            </view>
          </view>
          <view class="statement-text">
            <text class="statement-text-title">总支出</text>
            <view class="statement-text-total">
              <text class="statement-text-total-char">¥</text>
              <text>{{ indexStat.expend }}</text>
            </view>
          </view>
        </view>
      </view>

日历部分

mb-ba-calender属于自定义组件,定义于src\components\base\mbill-calendar.vue

 <view class="calendar">
        <mb-ba-calendar
          ref="calendar"
          :expand="expand"
          :tags="bill.indexTags"
          :date="calendarDate"
          @change="onDayChange"
          @changemonth="onMonthChange"
          @sizechange="onSizeChange"
        />
      </view>
    </view>

帐单列表部分

<mb-b-day-group>属于自定义组件

<scroll-view
      class="statement-item"
      :style="{
        height: scrollHeight + 'px',
      }"
      scroll-y="true"
      :refresher-enabled="true"
      :refresher-triggered="triggered"
	  lower-threshold="50"
      @scrolltolower="onLowerBottom"
      @refresherpulling="onPulling"
      @refresherrefresh="onRefresh"
      @refresherrestore="onRestore"
      @refresherabort="onAbort"
    >
	  <mb-b-day-group :groups="indexBills" />
      <mb-ba-login-hint v-if="!hasLogin" />
      <mb-ba-empty v-if="!indexBills || (indexBills.length <= 0 && hasLogin)" />
	  <uni-load-more status="no-more" v-if="hasLogin && indexBills.length>0"></uni-load-more>
    </scroll-view>
    <mb-b-day-list-popup
      :height=70
      :show="popShow"
      :date="popDate"
      @change="onBillsOnDayPopup"
    />
	<uni-fab ref="fab" :pattern="pattern" @fabClick="fabClick" horizontal='right' vertical='bottom'/>

- `<calendar-content>` 是日历的容器,包含了背景、日期选择器、总收入和总支出等元素。

- `<calendar>` 是日历组件的容器。 - `<calendar-expand>` 用于展开和收缩日历。

- `<scroll-view>` 是账单列表的滚动视图。

- `<mb-b-day-group>` 是账单分组组件。

- `<mb-ba-login-hint>` 和 `<mb-ba-empty>` 用于显示登录提示和空数据提示。

- `<uni-load-more>` 是加载更多组件。

- `<mb-b-day-list-popup>` 是账单列表弹窗组件。

- `<uni-fab>` 是浮动操作按钮组件。

脚本部分

脚本区基本内容说明链接:页面 | uni-app官网

代码部分带有功能注释

<script setup>
	import { ref, onMounted, provide, getCurrentInstance, reactive, watch, computed } from 'vue';
	import { onReachBottom, onShow, onLoad } from '@dcloudio/uni-app';
	import * as datetime from "@/common/utils/datetime";
	import { store, mutations } from '@/uni_modules/uni-id-pages/common/store.js'
	import { storeToRefs } from 'pinia';
	import { useBillStore } from "@/store/bill";
	const bill = useBillStore();
	//const { indexStat, indexBills } = bill;// 数据不是响应式的
	const { indexStat, indexBills } = storeToRefs(bill);
	// console.log(indexStat, indexBills);
	const { proxy, ctx } = getCurrentInstance();
	let db = uniCloud.database();
	const now = new Date();
	const calendarDate = reactive({
         year: now.getFullYear(),
         month: now.getMonth() + 1,
    })
	let hasLogin = computed(()=>{
		return store.hasLogin
	})	
    const  pickerDate = ref(datetime.getCurDate());
    const  pickerDateText=reactive({
        year:now.getFullYear(),
        month:now.getMonth() + 1
    })
    const  pickerEnd = datetime.getCurDate()
	// const  status = ref('loading')
	const  expand = ref(true)
    const  popShow = ref(false)
    const  popDate = ref({})	
    const  dateTitleHeight = 62
    const  tabbarHeight = getApp().globalData.tabbarHeight	        
    const  expandHeight = ref(25)
    const  scrollHeight = ref(0)    
    const  state=1
    const  triggered = ref(false)
    const  freshing = ref(false)
	const  pattern = {
		buttonColor: '#ff9f18',
		iconColor: 'ghostwhite'
	}
	
	let indexTotal = 0
	let pH = 0
	let scrollMaxHeight = 0
    let indexPage = {
        page:1,
        size:50
    }
	let loading = false
	  
  onLoad( async () => {
	// console.log('onLoad')  
    //console.log('1:', account.defUser, account.token );//isLogin defUser
    //console.log(getCurrentPages()[getCurrentPages().length-1].route)
    getFixedHeight();
    triggered.value = true;	
	// initData();
	// const res = await getDataList();
	// console.log(res);	
  })
  onShow(() => {
	// console.log('onShow')
	initData();
	// status.value = 'more'
    // console.log(getCurrentPages()[getCurrentPages().length-1].$page);
  })
  const fabClick = () =>{
      // if (!hasLogin) {
      //   proxy.$tip.toast("暂未登录,请先登录!");
      //   return;
      // }
	  uni.navigateTo({
	  	url:'../bill/edit'
	  })
  }
  const getDataList = () => {
	return new Promise((resolve, reject) => {	
		db.collection('mbill_category').get().then((res)=>{
			resolve(res.result.data)
		});
	})
  }
  const completedEditCallback = () =>{
	  console.log('completedEditCallback');
  }
  // 初始化数据
  const initData = () => {
      // console.log('初始化数据')
      return new Promise((resolve, reject) => {
        // console.log(pickerDate.value);
		if(hasLogin.value){
			indexPage.page = 1;
			bill.getIndexTotalStat(pickerDate.value).then((res)=>{
				// if (indexPage.page * indexPage.size >= indexStat.value.count){
				// 	status.value = 'no-more'
				// } else{
				// 	status.value = 'more'
				// }
			});
			bill.getIndexBillTags(pickerDate.value);
			getMonthBills(true)
			  .then((res) => resolve(res))
			  .catch((err) => reject(err));
		}
		triggered.value = false;  
      });
    }
    //#region 接口请求
    // 初始化、切换月份重新加载账单
    const getMonthBills = (init = false) => {
	  // console.log(indexPage.page , indexStat.value.count);
      if (loading) return;
      loading = true;
      return bill.getIndexBills({
          date: pickerDate.value,
          page: indexPage,
          isInit: init,
      })
          .then((res) => {
		      // console.log(indexBills.value);
              indexTotal = res;
        })
        .finally(() => {
              loading = false;
		      // if (indexPage.page * indexPage.size >= indexStat.value.count){
			     // status.value = 'no-more'
		      // } else{
			     // status.value = 'more'
		      // }
        });
    }

    //#endregion

    //#region 组件初始化
	
    // 获取固定高度值
    const getFixedHeight = () =>{
      let that = this;
      uni.getSystemInfo({
        success(res) {
          pH = res.windowHeight - 5; // 多出的5px,不让底部触底
        },
      });
    }

    // 动态计算scroll view 高度
    const getDynamicHeight = (h) => {
      // console.log(h);
      if (h) {
        // 10 为日历原本有上下为5的边距
        scrollHeight.value = pH - tabbarHeight - h - expandHeight.value - dateTitleHeight;
        scrollMaxHeight = scrollHeight.value;
        return;
      }
      let query = uni.createSelectorQuery();
      query.select("#calendar-content").fields({ size: true });
      query.exec((data) => {
        // console.log(data);
        let elHeight = data[0].height;
        scrollHeight.value = pH - tabbarHeight - elHeight - expandHeight.value;
        scrollMaxHeight = scrollHeight.value;
        // 30 为时间时间选择栏的上下为15的边距
        // console.log("初始化高度", scrollMaxHeight);
      });
    }

    // 日历月份变更
    const onMonthChange = (date) =>{
      // console.log('onMonthChange');
	  // console.log("date", date);
      pickerDateText.month = date.month;
	  pickerDateText.year = date.year;
      pickerDate.value = `${date.year}-${date.month}`;
      initData();
    }

    // 选中具体日期时弹窗展示账单
    const onDayChange =(e) =>{
      // console.log('onDayChange');
      if (!hasLogin.value) {
        proxy.$tip.toast("暂未登录,请先登录!");
        return;
      }
      //console.log("选中日期:", e);
      popDate.value = e;
      popShow.value = true;
    }

    // 选择日期
    const onPickerChange =({ detail }) =>{
	  // console.log('1:', calendarDate);
      let d = new Date(detail.value);
      let select = datetime.getCurDateObj(d);
      // console.log(select.year, pickerDateText.year);
	  if (
        select.year == pickerDateText.year &&
        select.month == pickerDateText.month
      )
	  return;
      calendarDate.year = select.year;
	  calendarDate.month = select.month;	  
      pickerDate.value = datetime.getCurDate(d);
	  // console.log(datetime.getCurDate(d));
      pickerDateText.year = calendarDate.year;
	  pickerDateText.month = calendarDate.month;
      // console.log('2:', calendarDate);
	  initData();
    }

    // 弹窗状态改变触发
    const onBillsOnDayPopup =(e) =>{
      //this.setTabBarShow(!e.show);
	  if(!e.show)
	  wx.showTabBar();
      popShow.value = e.show;
    }

    // 日历size发生变更
    const onSizeChange =(h) =>{
      //console.log("日历尺寸", h);
      getDynamicHeight(h);
    }

    // 展开、收缩scroll-view
    const onExpandView =() =>{
      let minHeight = dateTitleHeight;
      // console.log(minHeight);
      if (expand.value) {
        scrollHeight.value =
          pH - minHeight - tabbarHeight - expandHeight.value;
          expand.value = false;
      } else {
        scrollHeight.value = scrollMaxHeight;
        expand.value = true;
      }
    }

    // 自定义下拉刷新控件被下拉
    const onPulling =(e) => {
      // console.log("onpulling", e);
      if (e.detail.deltaY < 0) return; // 防止上滑页面也触发下拉
      triggered.value = true;
    }

    // 自定义下拉刷新被触发
	const onRefresh = async () => {    
      if (freshing.value) return;
      freshing.value = true;
      // console.log("下拉刷新数据");
      initData().finally((res) => {
        triggered.value = false;
        freshing.value = false;
      });
    }
    
	// 自定义下拉刷新被复位
    const onRestore =() =>{
      triggered.value = "restore"; // 需要重置
    }
    // 自定义下拉刷新被中止
    const onAbort =() =>{}

    // scroll触底事件
    const onLowerBottom = () =>{
      // console.log("触底加载");
      // if (indexPage.page * indexPage.size >= indexTotal) return;	  
      // console.log("加载...");
      indexPage.page += 1;
      getMonthBills();
    }
    //#endregion
  
</script>

- `pickerDate` 和 `pickerDateText` 用于存储日期选择器的值和文本。

- `pickerEnd` 是日期选择器的结束日期。

- `expand` 用于控制日历的展开和收缩状态。

- `popShow` 和 `popDate` 用于控制账单列表弹窗的显示和日期。

- `dateTitleHeight`、`tabbarHeight` 和 `expandHeight` 是一些固定高度的值。

- `scrollHeight` 用于动态计算滚动视图的高度。

- `state` 是一个状态变量。

- `triggered` 和 `freshing` 用于控制下拉刷新的状态。

- `pattern` 是浮动操作按钮的样式。

- `indexTotal` 是账单总数。

- `pH` 是屏幕高度。

- `loading` 用于控制数据加载状态。

 - `indexPage` 是页码和每页大小。

- `getDataList` 是获取数据列表的方法。

- `completedEditCallback` 是编辑完成后的回调函数。

- `initData` 是初始化数据的方法。

- `getMonthBills` 是获取月账单数据的方法。

- `getFixedHeight` 是获取固定高度的方法。

- `getDynamicHeight` 是动态计算滚动视图高度的方法。

- `onMonthChange` 是日历月份变更的回调函数。

- `onDayChange` 是选中日期时的回调函数。

- `onPickerChange` 是日期选择器变更的回调函数。

- `onBillsOnDayPopup` 是账单列表弹窗状态变更的回调函数。

- `onSizeChange` 是日历尺寸变更的回调函数。

- `onExpandView` 是展开和收缩滚动视图的方法。

- `onPulling`、`onRefresh`、`onRestore` 和 `onAbort` 是下拉刷新的回调函数。 - `onLowerBottom` 是滚动视图触底的回调函数。

style样式区

<style lang="scss" scoped>
  .test {
    font-size: 240rpx;
    color: $primary-color;
  }
  .calendar-content {
  .bg {
    z-index: -1;
    position: absolute;
    top: 0;
    background-color: $primary-color;
    width: 100%;
    height: 210rpx;
    border-radius: 0 0 30rpx 30rpx;
  }
  .date-title {
    display: flex;
    flex-direction: row;
    justify-content: space-between;
    margin: 30rpx;
    align-items: center;
    height: 64rpx;
    .date-picker {
      .now-date {
        font-size: 30rpx;
        font-weight: bold;
        align-items: baseline;
        .icon-down {
          font-size: 20rpx;
          margin-left: 10rpx;
        }
      }
    }
    .statement {
      display: flex;
    }

    .statement-text {
      margin-left: 40rpx;
      display: flex;
      flex-direction: column;
      align-items: center;

      &-title {
        font-size: 30rpx;
      }
      &-total {
        font-size: 35rpx;
        font-weight: bold;
        &-char {
          font-size: 28rpx;
        }
      }
    }
  }
  .calendar {
    margin: 0 20rpx;
  }
}
.calendar-expand {
  width: 100%;
  text-align: center;
}

.statement-item {
  // background: white;
  padding-top: 36rpx;
  border-radius: 30rpx 30rpx 0 0;
  // padding-bottom: 36rpx;
  // margin-bottom: 36rpx;
  // background-color: red;
}

.popup-box {
  .asset {
    height: 700rpx;
  }
}
</style>

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值