山东大学软件工程项目实训-3 规划和目前进度

#### 当前项目实训开始9

> 目前进度符合预期

1. 关于预期的低代码平台 进度如下

 + scene-ui组件库主体完成 可依托其进行页面基础设施构建

 + potato-compiler(土豆编译器: 低代码平台后端和简洁页面生成) 正在调试阶段 准备依托其进行第一个示例项目(chat in one)的构建

 + low-code 我们关于可视化布局和图形化编程的一个尝试 主要基于具有复合逻辑的组件来搭建复杂应用 通过拖动来进行页面结构样式配置

组件库已经打包到npm上了

scene-ui - npm

++ 目前获得了 1900 + 的下载量

 

 

 

当前版本0.3.13 有17个可用组件和2个公有ui函数

 

0.4.1未稳定版本包含21个可用组件和之前的2个公有函数

 

目前累计代码函数在50000行左右

 

 

 

 

 

三个子项目的github

 

 

https://github.com/skr305/scene-ui

https://github.com/skr305/potato-comp

https://github.com/skr305/low-code

https://github.com/FTZ-Noob/scene-ui-icons

文档地址

Sunburst7的博客

分工是基于子项目和组件级别的

但是用到的工具和全局的样式是统一的

并且基于同一套流程开发

示例组件: date-time

<template>

      <div class="scene-datetime">

        <div class="scene-datetime-input">

          <s-icon color="#aa00ff" name="calendar2"></s-icon>

          <input v-model="datetimeTemplate" @focus="calendarControl(true)" id="scene-datetime-input-input" type="text" readonly/>

        </div>

        <Transition name="scene-datetime">

          <KeepAlive>

            <div v-if="showCalendar">

              <div class="scene-datetime-arrow"></div>

              <div class="scene-datetime-calendar">

                <div class="scene-datetime-calendar-header">

                    <div>

                      <s-icon style="margin-right:5px" name="chevron-double-left" @click="updateDatetime('year',modelValue.getFullYear()-1)"/>

                      <s-icon name="chevron-left"  @click="updateDatetime('month',modelValue.getMonth())"/>

                    </div>

                    <div>

                      <span style="margin-right:20px">{{modelValue.getFullYear()}}</span>

                      <span style="margin-right:20px">{{englishMonthName}}</span>

                    </div>

                    <div>

                      <s-icon name="chevron-right" @click="updateDatetime('month',modelValue.getMonth()+2)"/>

                      <!-- <img src="/right_16.svg" @click="updateDatetime('month',modelValue.getMonth()+2)"> -->

                      <s-icon style="margin-left:5px" name="chevron-double-right" @click="updateDatetime('year',modelValue.getFullYear()+1)"/>

                    </div>

                </div>

                <div class="scene-datetime-calendar-body">

                  <div class="scene-datetime-calendar-body-date">

                    <div class="scene-datetime-calendar-body-date-table">

                      <div class="scene-datetime-calendar-body-date-thead">

                          <div class="scene-datetime-calendar-body-date-headcell"><strong>Mon</strong></div>

                          <div class="scene-datetime-calendar-body-date-headcell"><strong>Tue</strong></div>

                          <div class="scene-datetime-calendar-body-date-headcell"><strong>Wed</strong></div>

                          <div class="scene-datetime-calendar-body-date-headcell"><strong>Thu</strong></div>

                          <div class="scene-datetime-calendar-body-date-headcell"><strong>Fri</strong></div>

                          <div class="scene-datetime-calendar-body-date-headcell"><strong>Sat</strong></div>

                          <div class="scene-datetime-calendar-body-date-headcell"><strong>Sun</strong></div>

                      </div>

                      <div class="scene-datetime-calendar-body-date-tbody">

                        <div class="scene-datetime-calendar-body-date-tline" v-for="(dateObjectArr,index) in screenArray" :key="'r'+index">

                          <div v-for="(dateObj,index) in dateObjectArr" :key="'c'+index" class="scene-datetime-calendar-body-date-bodycell"

                            :is-selected="dateObj.isSelected"

                            :is-current-month="dateObj.isCurrentMonth"

                            @click="updateDatetime('Date',dateObj.date)"

                            >

                            {{dateObj.date.getDate()}}

                          </div>

                        </div>

                      </div>

                    </div>

                  </div>

                  <div class="scene-datetime-calendar-body-time">

                    <strong class="scene-datetime-calendar-body-time-label">Hour</strong>

                    <strong class="scene-datetime-calendar-body-time-label">Minute</strong>

                    <strong class="scene-datetime-calendar-body-time-label">Second</strong>

                    <s-scrollbar ref="hourScrollbar" :width="43" :height="210">

                      <div ref="hours">

                        <div v-for="(hour,index) in 24" :key="index" class="scene-datetime-calendar-body-time-cell" @click="updateDatetime('hour',hour-1)">{{hour-1}}</div>

                      </div>

                    </s-scrollbar>

                    <s-scrollbar ref="minuteScrollbar" :width="43" :height="210">

                      <div ref="minutes">

                        <div v-for="(minute,index) in 60" :key="index" class="scene-datetime-calendar-body-time-cell" @click="updateDatetime('minute',minute-1)">{{minute-1}}</div>

                      </div>

                    </s-scrollbar>

                    <s-scrollbar ref="secondScrollbar" :width="44" :height="210">

                      <div ref="seconds">

                        <div v-for="(second,index) in 60" :key="index" class="scene-datetime-calendar-body-time-cell" @click="updateDatetime('second',second-1)">{{second-1}}</div>

                      </div>

                    </s-scrollbar>

                  </div>

                </div>

                <div class="scene-datetime-calendar-footer">

                  <div>

                    <s-button size="small" type="text" theme="info" @click="updateDatetime('Date',new Date())">now</s-button>

                    <s-button size="small" type="text" theme="info" @click="updateDatetime('Date',createDate(modelValue.getFullYear(),modelValue.getMonth()+1,modelValue.getDate()))">clear time</s-button>

                  </div>

                  <s-button size="small" theme="success" @click="calendarControl(false)">confirm</s-button>

                </div>

              </div>

            </div>

          </KeepAlive>

        </Transition>

      </div>

</template>

<script lang='ts'>

import {computed, defineComponent, ref, watch, nextTick, onMounted} from 'vue'

import sButton from '../button/button.vue'

import sScrollbar from '../scrollbar/scrollbar.vue'

import sIcon from '../icon/icon.vue'

import {datetimeProps, datetimeEmits} from './datetime'

import {englishMonths, DateObject, getDateCountByYearAndMonth, getYearMonthDateHourMinuteSecond, createDate, getFullScreen} from '../../core/lib/date'

import {turnTo2dArray} from '../../core/lib/array'

import '../../styles/global.css'

/**

 * 修改modelValue的七种模式

 */

type modelType = 'year' | 'month' | 'date' | 'hour' | 'minute' | 'second' | 'Date';

export default defineComponent({

  name:'scene-datetime',

  props:datetimeProps,

  emits:datetimeEmits,

  components:{ sButton, sScrollbar,sIcon},

  setup(props,{emit,attrs,slots,expose}){

    // 模板引用

    const hours = ref<HTMLElement>()

    const minutes = ref<HTMLElement>()

    const seconds = ref<HTMLElement>()

    const hourScrollbar = ref<any>()

    const minuteScrollbar = ref<any>()

    const secondScrollbar = ref<any>()

    // 是否显示下拉日历

    let showCalendar = ref(false);

    // 控制下拉日历的显示

    function calendarControl(open: boolean){

      if(open){

        showCalendar.value = true

        nextTick(()=>{updateTimeCSS()}) //更新时间部分CSS样式

      }

      else{

        showCalendar.value = false

      }

    }

    // 更新时间部分样式

    function updateTimeCSS(){

      let hourDivCollection = hours.value?.children

      let minuteDivCollection = minutes.value?.children

      let secondDivCollection = seconds.value?.children

      for(let i=0;i<24;i++){

        hourDivCollection?.item(i)!.removeAttribute('is-selected')

      }

      hourDivCollection?.item(props.modelValue.getHours() as number)!.setAttribute('is-selected','true')

      hourScrollbar.value!.moveTo(props.modelValue.getHours() as number * 33,'Y')     // 调用滚动条内部的方法,自动滚动使得当前时间块到顶部

      for(let i=0;i<60;i++){

        minuteDivCollection?.item(i)?.removeAttribute('is-selected')

        secondDivCollection?.item(i)!.removeAttribute('is-selected')

      }

      minuteDivCollection?.item(props.modelValue.getMinutes() as number)?.setAttribute('is-selected','true')

      minuteScrollbar.value!.moveTo(props.modelValue.getMinutes() as number * 33,'Y') // 调用滚动条内部的方法,自动滚动使得当前时间块到顶部

      secondDivCollection?.item(props.modelValue.getSeconds() as number)!.setAttribute('is-selected','true')

      secondScrollbar.value!.moveTo(props.modelValue.getSeconds() as number * 33,'Y') // 调用滚动条内部的方法,自动滚动使得当前时间块到顶部

    }

    // 显示在input中的日期

    let datetimeTemplate = computed(()=>`${props.modelValue.getFullYear()}-${props.modelValue.getMonth()+1}-${props.modelValue.getDate()} ${props.modelValue.getHours()}:${props.modelValue.getMinutes()}:${props.modelValue.getSeconds()}`)

    // 当前显示的英文月份

    const englishMonthName = computed(()=>{

      return englishMonths.get((props.modelValue.getMonth()+1).toString())

    })

    // 当前显示的日历中的日期

    let screenArray = computed(()=>turnTo2dArray<DateObject>(getFullScreen(props.modelValue),6,7))

    /**

     * 修改v-model 绑定的日期时间(有7种修改模式),

     * 这里不能用 Date()自带的set函数,否则监听不到响应式的变化

     */

    function updateDatetime(model: modelType, value: number | Date){

      let oldDate = new Date(props.modelValue) // 未修改的日期时间

      let [year,month,date,hour,minute,second] = getYearMonthDateHourMinuteSecond(props.modelValue)

      switch(model){

        case 'year':

          emit('update:modelValue',createDate(value as number,month,date,hour,minute,second))

          emit('change',props.modelValue,oldDate)

          break

        case 'month':

          if(value === 0)

            emit('update:modelValue',createDate(year-1,12,date,hour,minute,second))

          else if(value === 13)

            emit('update:modelValue',createDate(year+1,1,date,hour,minute,second))

          else{

            // 需要更改的月份的总天数

            let MonthDateCount: number = getDateCountByYearAndMonth(year,value as number)

            if(date > MonthDateCount)// 修改的日期在更改的月份不存在,改为最后一天

              emit('update:modelValue',createDate(year,value as number,MonthDateCount,hour,minute,second))

            else

              emit('update:modelValue',createDate(year,value as number,date,hour,minute,second))

          }

          emit('change',props.modelValue,oldDate)

          break

        case 'date':

          emit('update:modelValue',createDate(year,month,value as number,hour,minute,second))

          emit('change',props.modelValue,oldDate)

          break

        case 'hour':

          emit('update:modelValue',createDate(year,month,date,value as number,minute,second))

          emit('change',props.modelValue,oldDate)

          break

        case 'minute':

          emit('update:modelValue',createDate(year,month,date,hour,value as number,second))

          emit('change',props.modelValue,oldDate)

          break

        case 'second':

          emit('update:modelValue',createDate(year,month,date,hour,minute,value as number))

          emit('change',props.modelValue,oldDate)

          break

        case 'Date':

          emit('update:modelValue', value as Date)

          emit('change',props.modelValue,oldDate)

          break

      }

      nextTick(()=>{

        updateTimeCSS()

      }) //更新时间部分CSS样式

    }

    return{

      hours,

      minutes,

      seconds,

      hourScrollbar,

      minuteScrollbar,

      secondScrollbar,

      showCalendar,

      screenArray,

      englishMonthName,

      datetimeTemplate,

      calendarControl,

      updateDatetime,

      createDate,

    }

  }

})

</script>

<style scoped>

/**

* 动画的效果

*/

.scene-datetime-enter-active,

.scene-datetime-leave-active {

  transition: all 0.4s ease;

}

.scene-datetime-enter-from,

.scene-datetime-leave-to{

  visibility:hidden;

  opacity: 0;

}

.scene-datetime{

  position: relative;

  display: inline-flex;

  flex-direction: column;

  justify-content: space-between;

  align-items: center;

  font-family: var(--scene-font-family);

}

/* 日期输入区域 */

.scene-datetime-input{

  display: flex;

  border: var(--scene-border-size) solid var(--scene-border-color-light);

  border-radius: var(--scene-border-radius);

  box-sizing: border-box;

  width: 240px;

  height: 32px;

  padding-left: 5px;

  justify-content: space-between;

  align-items: center;

}

.scene-datetime-input:hover{

  border: var(--scene-border-size) solid var(--scene-border-color-dark);

}

/* 日期输入区域的子元素有获取焦点时 */

.scene-datetime-input:focus-within{

  border: var(--scene-border-size) solid var(--scene-theme-color-main);

}

/* 日期输入框边上的图标 */

#scene-datetime-input-img{

  width: 28px;

  height: 32px;

  box-sizing: border-box;

  padding: 8px 5px 8px 7px;

}

/* 日期输入框 */

#scene-datetime-input-input{

  width: 212px;

  height: 26px;

  line-height: 26px;

  box-sizing: border-box;

  padding: 0 5px;

  outline: none;

  border: none;

  font-size: var(--scene-font-size);

  font-family: var(--scene-font-family);

  letter-spacing: var(--scene-letter-spacing);

  color: var(--scene-font-color-dark)

}

/* 日期选择器的箭头 */

.scene-datetime-arrow{

    position: absolute;

    width: 10px;

    height: 10px;

    background: white;

    top: 40px;

    left: calc(50%);

    border-top: var(--scene-border-size) solid var(--scene-border-color-light);

    border-right: var(--scene-border-size) solid var(--scene-border-color-light);

    transform: rotate(-45deg);

    z-index: var(--scene-index-advanced);

}

/* 日期选择器的下拉日历 */

.scene-datetime-calendar{

  position: absolute;

  top: 45px;

  left: calc(-50%);

  border-radius: var(--scene-border-radius);

  width: 450px;

  height: 350px;

  background: white;

  z-index: var(--scene-index-heighter);

  border: var(--scene-border-size) solid var(--scene-border-color-light);

  box-shadow: var(--scene-box-shadow);

  display: flex;

  flex-direction: column;

  justify-content: center;

  align-items: center;

}

/* 日期选项器的头部 */

.scene-datetime-calendar-header{

  /* 总高度35px  */

  box-sizing: border-box;

  display: flex;

  justify-content: space-between;

  align-items: center;

  padding: 7px 10px 0;

  width: 450px;

  height: 35px;

  border-bottom: var(--scene-border-inner-size) solid var(--scene-border-color-light);

}

/* 日期选择器的主体 */

.scene-datetime-calendar-body{

  box-sizing: border-box;

  display: flex;

  width: 450px;

  height: 280px;

  padding: 10px;

}

/* 日期选择器的日期部分 */

.scene-datetime-calendar-body-date{

  box-sizing: border-box;

  width: calc(300px - 10px);

  height: calc(280px - 20px);

}

/* 日历表的样式 */

.scene-datetime-calendar-body-date-table{

  width: 100%;

  height: 100%;

}

/* 日历表头 */

.scene-datetime-calendar-body-date-thead{

  width: 100%;

  height: 13%;

  margin-bottom: 4px;

  display: flex;

  justify-content: space-between;

  align-items: stretch;

  border-bottom: var(--scene-border-inner-size) solid var(--scene-border-color-light);

}

/* 日历表头每一格 */

.scene-datetime-calendar-body-date-headcell{

  width: 14.28%;

  display: flex;

  justify-content: center;

  align-items: center;

  font-size: 12px;

}

/* 日历表主体 */

.scene-datetime-calendar-body-date-tbody{

  width: 100%;

  height: 85%;

  display: flex;

  flex-direction: column;

}

/* 每一行 */

.scene-datetime-calendar-body-date-tline{

  width: 100%;

  height: 16.6%;

  display: flex;

}

/* 每一格 */

.scene-datetime-calendar-body-date-bodycell{

  margin: 5px;

  width: calc(14.28% - 10px);

  border-radius: 2px;

  display: flex;

  justify-content: center;

  align-items: center;

  cursor: pointer;

  font-size: 12px;

}

.scene-datetime-calendar-body-date-bodycell:hover{

  color:var(--scene-theme-color-main);

}

.scene-datetime-calendar-body-date-bodycell[is-selected="true"]{

  background:var(--scene-theme-color-main);

  color: white;

}

.scene-datetime-calendar-body-date-bodycell[is-current-month="false"]{

  color: var(--scene-color-dark-gray);

}

/* 日期选择器的时间部分 */

.scene-datetime-calendar-body-time{

  box-sizing: border-box;

  width: calc(150px - 10px);

  height: calc(280px - 20px);

  padding: 10px 0 10px 10px;

  /** content 宽:130px 高:240px*/

  display: flex;

  flex-flow: row wrap;

}

/* 时间部分表头 */

.scene-datetime-calendar-body-time-label{

  width: 43px;

  height: 30px;

  font-size: 12px;

}

/* 日历时间部分的每一个格 */

.scene-datetime-calendar-body-time-cell{

  display: flex;

  justify-content: center;

  align-items: center;

  border-radius: 2px;

  margin: 7px 6px;

  height: 26px;

  font-size: 12px;

  cursor: pointer;

}

.scene-datetime-calendar-body-time-cell:hover{

  color: var(--scene-theme-color-main);

}

.scene-datetime-calendar-body-time-cell[is-selected="true"]{

  background:var(--scene-theme-color-main);

  color: white;

}

/* 日期选择器的底部 */

.scene-datetime-calendar-footer{

  box-sizing: border-box;

  display: flex;

  justify-content: space-between;

  align-items: center;

  border-top: var(--scene-border-inner-size) solid var(--scene-border-color-light);

  width: 450px;

  height: 35px;

  padding: 0 10px;

}

</style>

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值