|
|
@@ -0,0 +1,371 @@
|
|
|
+import { YTHeader } from "../components/generalComp/YTHeader";
|
|
|
+import { YTDateUtil } from "../utils/YTDateUtil";
|
|
|
+import { ResultType, UnitType } from "./DatePickerEnums";
|
|
|
+import { QNUIFloatingContainer } from "./YTUIFloatingContainer"
|
|
|
+import { WheelPicker } from "./WheelPicker";
|
|
|
+
|
|
|
+
|
|
|
+@Component
|
|
|
+export struct YTUIDatePickerComponent {
|
|
|
+ // 属性
|
|
|
+ @Prop @Require date: Date; // 当前选中的日期
|
|
|
+ @State dateLocal: Date = new Date();
|
|
|
+ @Prop @Require minDate: Date; // 最小可选日期,默认10年前
|
|
|
+ @Prop @Require maxDate: Date; // 最大可选日期,默认10年后
|
|
|
+ @Prop @Require unitType: UnitType; // 单位类型,默认为年月日
|
|
|
+ @State isVisible: string = '100%'; // 是否显示选择器
|
|
|
+ // 回调函数
|
|
|
+ confirm: (date: Date) => void = () => {
|
|
|
+ };
|
|
|
+ close: () => void = () => {
|
|
|
+ };
|
|
|
+ title:string = '选择日期'
|
|
|
+ @Prop headerBuilder:DatePickerHeaderGlobalBuilder
|
|
|
+ @Prop highlightBackgroundColor:ResourceColor
|
|
|
+ @Prop highlightBorderColor:ResourceColor
|
|
|
+ @Prop selectedTextStyle:PickerTextStyle
|
|
|
+ @Prop textStyle:PickerTextStyle
|
|
|
+
|
|
|
+ aboutToAppear(): void {
|
|
|
+ this.dateLocal = this.date;
|
|
|
+ console.log('aboutToAppear',YTDateUtil.formatDate(this.dateLocal))
|
|
|
+ }
|
|
|
+
|
|
|
+ // 确认选择
|
|
|
+ private onConfirm(): void {
|
|
|
+ this.confirm?.( this.dateLocal);
|
|
|
+ this.isVisible = '100%'
|
|
|
+ this.close?.()
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ // 取消选择
|
|
|
+ private onCancel(): void {
|
|
|
+ // this.confirm(ResultType.CANCEL, this.dateLocal);
|
|
|
+ this.isVisible = '100%'
|
|
|
+ this.close?.()
|
|
|
+ }
|
|
|
+
|
|
|
+ build() {
|
|
|
+ Column() {
|
|
|
+ Column() {
|
|
|
+ //标题
|
|
|
+ Column({space:12}){
|
|
|
+ YTHeader({
|
|
|
+ defaultStyle:{
|
|
|
+ backArrow:true,
|
|
|
+ title:this.title,
|
|
|
+ },
|
|
|
+ headerHeight: 44,
|
|
|
+ headerPadding:0,
|
|
|
+ rightComp:()=>{
|
|
|
+ this.headerRightBuilder()
|
|
|
+ },
|
|
|
+ leftComp:()=>{
|
|
|
+ this.headerLeftBuilder()
|
|
|
+ }
|
|
|
+ })
|
|
|
+ Divider()
|
|
|
+ .strokeWidth(1)
|
|
|
+ .color('#DFDFDF')
|
|
|
+ }
|
|
|
+ .width('100%')
|
|
|
+ .padding({top:20,bottom:20})
|
|
|
+
|
|
|
+ WheelPicker({
|
|
|
+ date: this.date,
|
|
|
+ minDate: this.minDate,
|
|
|
+ maxDate: this.maxDate,
|
|
|
+ unitType: this.unitType,
|
|
|
+ highlightBackgroundColor:this.highlightBackgroundColor,
|
|
|
+ highlightBorderColor:this.highlightBorderColor,
|
|
|
+ textStyle:this.textStyle,
|
|
|
+ selectedTextStyle:this.selectedTextStyle,
|
|
|
+ upDate: (date: Date) => {
|
|
|
+ this.dateLocal = date
|
|
|
+ }
|
|
|
+ })
|
|
|
+ }
|
|
|
+ .backgroundColor(Color.White)
|
|
|
+ .width('100%')
|
|
|
+ .borderRadius({ topLeft: 14, topRight: 14 })
|
|
|
+ .height(334)
|
|
|
+ .padding({left:20,right:20})
|
|
|
+ }
|
|
|
+ .width('100%')
|
|
|
+ .backgroundColor(Color.White)
|
|
|
+ // .onAppear(() => {
|
|
|
+ // this.isVisible = '0'
|
|
|
+ // })
|
|
|
+ .borderRadius({topLeft:24,topRight:24})
|
|
|
+ // .translate({ y: this.isVisible })
|
|
|
+ // .animation({ duration: 200 })
|
|
|
+
|
|
|
+ }
|
|
|
+ @Builder
|
|
|
+ headerRightBuilder(){
|
|
|
+ Column(){
|
|
|
+ this.headerBuilder.headerRightBuilder.builder()
|
|
|
+ }
|
|
|
+ .onClick(()=>{
|
|
|
+ this.onConfirm()
|
|
|
+ })
|
|
|
+ }
|
|
|
+
|
|
|
+ @Builder
|
|
|
+ headerLeftBuilder(){
|
|
|
+ Column(){
|
|
|
+ this.headerBuilder.headerLeftBuilder.builder()
|
|
|
+ }
|
|
|
+ .onClick(()=>{
|
|
|
+ this.onCancel()
|
|
|
+ })
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+export class DateOption {
|
|
|
+ /**
|
|
|
+ * 当前选中的日期
|
|
|
+ * @default new Date()
|
|
|
+ */
|
|
|
+ date?: Date;
|
|
|
+ /**
|
|
|
+ * 最小可选日期
|
|
|
+ * @default 当前日期的前10年
|
|
|
+ */
|
|
|
+ minDate?: Date;
|
|
|
+ /**
|
|
|
+ * 最大可选日期
|
|
|
+ * @default 当前日期的后10年
|
|
|
+ */
|
|
|
+ maxDate?: Date;
|
|
|
+ /**
|
|
|
+ * 单位类型
|
|
|
+ * @default UnitType.YEAR_MONTH_DAY (年月日)
|
|
|
+ */
|
|
|
+ unitType?: UnitType;
|
|
|
+ /**
|
|
|
+ * 确认选择回调
|
|
|
+ */
|
|
|
+ confirm?: (date: Date) => void;
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 头部左侧按钮
|
|
|
+ */
|
|
|
+ headerLeftBuilder?:WrappedBuilder<[]>
|
|
|
+ /**
|
|
|
+ * 头部右侧按钮
|
|
|
+ */
|
|
|
+ headerRightBuilder?:WrappedBuilder<[]>
|
|
|
+ /**
|
|
|
+ * 标题
|
|
|
+ */
|
|
|
+ title?:string
|
|
|
+ /**
|
|
|
+ * 高亮背景色
|
|
|
+ */
|
|
|
+ highlightBackgroundColor?:ResourceColor
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 高亮边框颜色
|
|
|
+ */
|
|
|
+ highlightBorderColor?:ResourceColor
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 选中的字体样式
|
|
|
+ */
|
|
|
+ selectedTextStyle?:PickerTextStyle
|
|
|
+
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 非选中的字体样式
|
|
|
+ */
|
|
|
+ textStyle?:PickerTextStyle
|
|
|
+}
|
|
|
+
|
|
|
+@Builder
|
|
|
+function headerLeftBuilder(){
|
|
|
+ Image($r('app.media.ic_back'))
|
|
|
+ .width(24)
|
|
|
+ .margin({ left: 16 })
|
|
|
+}
|
|
|
+
|
|
|
+@Builder
|
|
|
+function headerRightBuilder(){
|
|
|
+ Image($r("app.media.slice_sure"))
|
|
|
+ .width(24)
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+@ObservedV2
|
|
|
+export class YTDatePickerOptions extends DateOption {
|
|
|
+ @Trace
|
|
|
+ isEnd?: boolean = false
|
|
|
+ cancel?: () => void = () => {
|
|
|
+ }
|
|
|
+ headerBuilder?:DatePickerHeaderGlobalBuilder
|
|
|
+}
|
|
|
+
|
|
|
+// 组件包装器
|
|
|
+@Builder
|
|
|
+export function YTDatePickerViewBuilder(param: YTDatePickerOptions) {
|
|
|
+ Column(){
|
|
|
+ YTUIDatePickerComponent({
|
|
|
+ date: param.date|| new Date(),
|
|
|
+ minDate: param.minDate|| YTDateUtil.getYearToday(-10),
|
|
|
+ maxDate: param.maxDate||YTDateUtil.getYearToday(10),
|
|
|
+ unitType: param.unitType||UnitType.YEAR_MONTH_DAY,
|
|
|
+ confirm: param.confirm,
|
|
|
+ close: param.cancel,
|
|
|
+ title:param.title,
|
|
|
+ headerBuilder:param.headerBuilder,
|
|
|
+ highlightBackgroundColor:param.highlightBackgroundColor,
|
|
|
+ highlightBorderColor:param.highlightBorderColor,
|
|
|
+ selectedTextStyle:param.selectedTextStyle,
|
|
|
+ textStyle:param.textStyle,
|
|
|
+ });
|
|
|
+ }
|
|
|
+ .width('100%')
|
|
|
+ .translate({
|
|
|
+ y: param.isEnd ? '100%' : 0
|
|
|
+ })
|
|
|
+ .transition(TransitionEffect.translate({ y: '100%' }).animation({ duration: 200 }))
|
|
|
+}
|
|
|
+
|
|
|
+export class DatePickerHeaderGlobalBuilder {
|
|
|
+ headerLeftBuilder: WrappedBuilder<[]> = wrapBuilder(headerLeftBuilder)
|
|
|
+ headerRightBuilder: WrappedBuilder<[]> = wrapBuilder(headerRightBuilder)
|
|
|
+}
|
|
|
+
|
|
|
+// 使用浮动容器重构 AddressSelector
|
|
|
+export class YTAddressSelectorDialog {
|
|
|
+ private uiContext: UIContext;
|
|
|
+ private dialog?: QNUIFloatingContainer<YTDatePickerOptions>;
|
|
|
+
|
|
|
+ constructor(uiContext: UIContext) {
|
|
|
+ this.uiContext = uiContext;
|
|
|
+
|
|
|
+ }
|
|
|
+ // 拷贝传入的配置到携带picker的配置中(Builder仅支持传递一个参数)
|
|
|
+ private optionToPickerOption(option: DateOption): YTDatePickerOptions {
|
|
|
+ const dateOptionAndPicker = new YTDatePickerOptions();
|
|
|
+
|
|
|
+ // 显式复制每个属性(仅复制用户传入的值,保留未传参数的默认值)
|
|
|
+ if (option.date !== undefined) {
|
|
|
+ dateOptionAndPicker.date = option.date
|
|
|
+ }
|
|
|
+ if (option.minDate !== undefined) {
|
|
|
+ dateOptionAndPicker.minDate = option.minDate;
|
|
|
+ }
|
|
|
+ if (option.maxDate !== undefined) {
|
|
|
+ dateOptionAndPicker.maxDate = option.maxDate;
|
|
|
+ }
|
|
|
+ if (option.unitType !== undefined) {
|
|
|
+ dateOptionAndPicker.unitType = option.unitType;
|
|
|
+ }
|
|
|
+ if (option.headerLeftBuilder !== undefined) {
|
|
|
+ dateOptionAndPicker.headerLeftBuilder = option.headerLeftBuilder
|
|
|
+ }
|
|
|
+ if (option.title !== undefined) {
|
|
|
+ dateOptionAndPicker.title = option.title
|
|
|
+ }else {
|
|
|
+ dateOptionAndPicker.title = '选择日期'
|
|
|
+ }
|
|
|
+
|
|
|
+ dateOptionAndPicker.headerBuilder = new DatePickerHeaderGlobalBuilder()
|
|
|
+ if (option.headerLeftBuilder !== undefined) {
|
|
|
+ dateOptionAndPicker.headerBuilder.headerLeftBuilder = option.headerLeftBuilder
|
|
|
+ }else {
|
|
|
+ dateOptionAndPicker.headerBuilder.headerLeftBuilder = wrapBuilder(headerLeftBuilder)
|
|
|
+ }
|
|
|
+ if (option.headerRightBuilder !== undefined) {
|
|
|
+ dateOptionAndPicker.headerBuilder.headerRightBuilder = option.headerRightBuilder
|
|
|
+ }else {
|
|
|
+ dateOptionAndPicker.headerBuilder.headerRightBuilder = wrapBuilder(headerRightBuilder)
|
|
|
+ }
|
|
|
+ if (option.highlightBackgroundColor!==undefined) {
|
|
|
+ dateOptionAndPicker.highlightBackgroundColor = option.highlightBackgroundColor
|
|
|
+ }else {
|
|
|
+ dateOptionAndPicker.highlightBackgroundColor ='#FFFFF6D1'
|
|
|
+ }
|
|
|
+ if (option.highlightBorderColor!==undefined) {
|
|
|
+ dateOptionAndPicker.highlightBorderColor = option.highlightBorderColor
|
|
|
+ }else {
|
|
|
+ dateOptionAndPicker.highlightBorderColor =Color.Transparent
|
|
|
+ }
|
|
|
+ if (option.selectedTextStyle!==undefined) {
|
|
|
+ dateOptionAndPicker.selectedTextStyle = option.selectedTextStyle
|
|
|
+ }else {
|
|
|
+ dateOptionAndPicker.selectedTextStyle = { font: { size: 16,weight:500 }, color: '#CC353C46' }
|
|
|
+ }
|
|
|
+ if (option.textStyle!==undefined) {
|
|
|
+ dateOptionAndPicker.textStyle = option.textStyle
|
|
|
+ }else {
|
|
|
+ dateOptionAndPicker.textStyle = { font: { size: 16,weight:500 }, color: '#CC353C46' }
|
|
|
+ }
|
|
|
+ return dateOptionAndPicker;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 显示地址选择器对话框
|
|
|
+ public show(dateOption?:DateOption) {
|
|
|
+ let option:DateOption = {}
|
|
|
+ if (dateOption) {
|
|
|
+ option = dateOption
|
|
|
+ }else {
|
|
|
+ option = new DateOption()
|
|
|
+ }
|
|
|
+ const pickerOption = this.optionToPickerOption(option)
|
|
|
+ pickerOption.confirm = (date: Date) => {
|
|
|
+ option.confirm?.(date)
|
|
|
+ animateTo({
|
|
|
+ duration: 200,
|
|
|
+ }, () => {
|
|
|
+ pickerOption.isEnd = true
|
|
|
+ this.dialog?.updateParam(pickerOption)
|
|
|
+ this.dialog?.dismissDialog()
|
|
|
+ })
|
|
|
+ }
|
|
|
+ pickerOption.cancel = () => {
|
|
|
+ animateTo({
|
|
|
+ duration: 200,
|
|
|
+ }, () => {
|
|
|
+ pickerOption.isEnd = true
|
|
|
+ this.dialog?.updateParam(pickerOption)
|
|
|
+ this.dialog?.dismissDialog()
|
|
|
+ })
|
|
|
+ }
|
|
|
+ this.dialog = new QNUIFloatingContainer<YTDatePickerOptions>(this.uiContext)
|
|
|
+ this.dialog.setOptions({
|
|
|
+ alignment: DialogAlignment.Bottom,
|
|
|
+ autoCancel: true, //点击蒙层是否关闭弹窗
|
|
|
+ isModal: true, //是否为半模态
|
|
|
+ maskColor: '#0f000000',
|
|
|
+ transition: TransitionEffect.opacity(0).animation({ duration: 100 }),
|
|
|
+ offset: { dx: 0, dy: 0 } as Offset,
|
|
|
+ onWillDismiss: (action) => {
|
|
|
+ animateTo({
|
|
|
+ duration: 100,
|
|
|
+ onFinish: () => {
|
|
|
+ action.dismiss()
|
|
|
+ }
|
|
|
+ }, () => {
|
|
|
+ /* this.calendarOptionAndPicker!.isEnd = true
|
|
|
+ this.contentNode?.update(this.calendarOptionAndPicker)*/
|
|
|
+ pickerOption.isEnd = true
|
|
|
+ // console.log('测试', this.dialog?.getDialogContent())
|
|
|
+ this.dialog?.updateParam(pickerOption)
|
|
|
+ // this.dialog?.getDialogContent()?.update(pickerOption)
|
|
|
+ })
|
|
|
+
|
|
|
+ }
|
|
|
+ })
|
|
|
+ this.dialog.showDialog(YTDatePickerViewBuilder, pickerOption);
|
|
|
+ }
|
|
|
+
|
|
|
+ // 取消对话框的方法
|
|
|
+ public hide() {
|
|
|
+ this.dialog?.dismissDialog();
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+
|