YTDataPickerSelector.ets 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371
  1. import { YTHeader } from "../components/generalComp/YTHeader";
  2. import { YTDateUtil } from "../utils/YTDateUtil";
  3. import { ResultType, UnitType } from "./DatePickerEnums";
  4. import { QNUIFloatingContainer } from "./YTUIFloatingContainer"
  5. import { WheelPicker } from "./WheelPicker";
  6. @Component
  7. export struct YTUIDatePickerComponent {
  8. // 属性
  9. @Prop @Require date: Date; // 当前选中的日期
  10. @State dateLocal: Date = new Date();
  11. @Prop @Require minDate: Date; // 最小可选日期,默认10年前
  12. @Prop @Require maxDate: Date; // 最大可选日期,默认10年后
  13. @Prop @Require unitType: UnitType; // 单位类型,默认为年月日
  14. @State isVisible: string = '100%'; // 是否显示选择器
  15. // 回调函数
  16. confirm: (date: Date) => void = () => {
  17. };
  18. close: () => void = () => {
  19. };
  20. title:string = '选择日期'
  21. @Prop headerBuilder:DatePickerHeaderGlobalBuilder
  22. @Prop highlightBackgroundColor:ResourceColor
  23. @Prop highlightBorderColor:ResourceColor
  24. @Prop selectedTextStyle:PickerTextStyle
  25. @Prop textStyle:PickerTextStyle
  26. aboutToAppear(): void {
  27. this.dateLocal = this.date;
  28. console.log('aboutToAppear',YTDateUtil.formatDate(this.dateLocal))
  29. }
  30. // 确认选择
  31. private onConfirm(): void {
  32. this.confirm?.( this.dateLocal);
  33. this.isVisible = '100%'
  34. this.close?.()
  35. }
  36. // 取消选择
  37. private onCancel(): void {
  38. // this.confirm(ResultType.CANCEL, this.dateLocal);
  39. this.isVisible = '100%'
  40. this.close?.()
  41. }
  42. build() {
  43. Column() {
  44. Column() {
  45. //标题
  46. Column({space:12}){
  47. YTHeader({
  48. defaultStyle:{
  49. backArrow:true,
  50. title:this.title,
  51. },
  52. headerHeight: 44,
  53. headerPadding:0,
  54. rightComp:()=>{
  55. this.headerRightBuilder()
  56. },
  57. leftComp:()=>{
  58. this.headerLeftBuilder()
  59. }
  60. })
  61. Divider()
  62. .strokeWidth(1)
  63. .color('#DFDFDF')
  64. }
  65. .width('100%')
  66. .padding({top:20,bottom:20})
  67. WheelPicker({
  68. date: this.date,
  69. minDate: this.minDate,
  70. maxDate: this.maxDate,
  71. unitType: this.unitType,
  72. highlightBackgroundColor:this.highlightBackgroundColor,
  73. highlightBorderColor:this.highlightBorderColor,
  74. textStyle:this.textStyle,
  75. selectedTextStyle:this.selectedTextStyle,
  76. upDate: (date: Date) => {
  77. this.dateLocal = date
  78. }
  79. })
  80. }
  81. .backgroundColor(Color.White)
  82. .width('100%')
  83. .borderRadius({ topLeft: 14, topRight: 14 })
  84. .height(334)
  85. .padding({left:20,right:20})
  86. }
  87. .width('100%')
  88. .backgroundColor(Color.White)
  89. // .onAppear(() => {
  90. // this.isVisible = '0'
  91. // })
  92. .borderRadius({topLeft:24,topRight:24})
  93. // .translate({ y: this.isVisible })
  94. // .animation({ duration: 200 })
  95. }
  96. @Builder
  97. headerRightBuilder(){
  98. Column(){
  99. this.headerBuilder.headerRightBuilder.builder()
  100. }
  101. .onClick(()=>{
  102. this.onConfirm()
  103. })
  104. }
  105. @Builder
  106. headerLeftBuilder(){
  107. Column(){
  108. this.headerBuilder.headerLeftBuilder.builder()
  109. }
  110. .onClick(()=>{
  111. this.onCancel()
  112. })
  113. }
  114. }
  115. export class DateOption {
  116. /**
  117. * 当前选中的日期
  118. * @default new Date()
  119. */
  120. date?: Date;
  121. /**
  122. * 最小可选日期
  123. * @default 当前日期的前10年
  124. */
  125. minDate?: Date;
  126. /**
  127. * 最大可选日期
  128. * @default 当前日期的后10年
  129. */
  130. maxDate?: Date;
  131. /**
  132. * 单位类型
  133. * @default UnitType.YEAR_MONTH_DAY (年月日)
  134. */
  135. unitType?: UnitType;
  136. /**
  137. * 确认选择回调
  138. */
  139. confirm?: (date: Date) => void;
  140. /**
  141. * 头部左侧按钮
  142. */
  143. headerLeftBuilder?:WrappedBuilder<[]>
  144. /**
  145. * 头部右侧按钮
  146. */
  147. headerRightBuilder?:WrappedBuilder<[]>
  148. /**
  149. * 标题
  150. */
  151. title?:string
  152. /**
  153. * 高亮背景色
  154. */
  155. highlightBackgroundColor?:ResourceColor
  156. /**
  157. * 高亮边框颜色
  158. */
  159. highlightBorderColor?:ResourceColor
  160. /**
  161. * 选中的字体样式
  162. */
  163. selectedTextStyle?:PickerTextStyle
  164. /**
  165. * 非选中的字体样式
  166. */
  167. textStyle?:PickerTextStyle
  168. }
  169. @Builder
  170. function headerLeftBuilder(){
  171. Image($r('app.media.ic_back'))
  172. .width(24)
  173. .margin({ left: 16 })
  174. }
  175. @Builder
  176. function headerRightBuilder(){
  177. Image($r("app.media.slice_sure"))
  178. .width(24)
  179. }
  180. @ObservedV2
  181. export class YTDatePickerOptions extends DateOption {
  182. @Trace
  183. isEnd?: boolean = false
  184. cancel?: () => void = () => {
  185. }
  186. headerBuilder?:DatePickerHeaderGlobalBuilder
  187. }
  188. // 组件包装器
  189. @Builder
  190. export function YTDatePickerViewBuilder(param: YTDatePickerOptions) {
  191. Column(){
  192. YTUIDatePickerComponent({
  193. date: param.date|| new Date(),
  194. minDate: param.minDate|| YTDateUtil.getYearToday(-10),
  195. maxDate: param.maxDate||YTDateUtil.getYearToday(10),
  196. unitType: param.unitType||UnitType.YEAR_MONTH_DAY,
  197. confirm: param.confirm,
  198. close: param.cancel,
  199. title:param.title,
  200. headerBuilder:param.headerBuilder,
  201. highlightBackgroundColor:param.highlightBackgroundColor,
  202. highlightBorderColor:param.highlightBorderColor,
  203. selectedTextStyle:param.selectedTextStyle,
  204. textStyle:param.textStyle,
  205. });
  206. }
  207. .width('100%')
  208. .translate({
  209. y: param.isEnd ? '100%' : 0
  210. })
  211. .transition(TransitionEffect.translate({ y: '100%' }).animation({ duration: 200 }))
  212. }
  213. export class DatePickerHeaderGlobalBuilder {
  214. headerLeftBuilder: WrappedBuilder<[]> = wrapBuilder(headerLeftBuilder)
  215. headerRightBuilder: WrappedBuilder<[]> = wrapBuilder(headerRightBuilder)
  216. }
  217. // 使用浮动容器重构 AddressSelector
  218. export class YTAddressSelectorDialog {
  219. private uiContext: UIContext;
  220. private dialog?: QNUIFloatingContainer<YTDatePickerOptions>;
  221. constructor(uiContext: UIContext) {
  222. this.uiContext = uiContext;
  223. }
  224. // 拷贝传入的配置到携带picker的配置中(Builder仅支持传递一个参数)
  225. private optionToPickerOption(option: DateOption): YTDatePickerOptions {
  226. const dateOptionAndPicker = new YTDatePickerOptions();
  227. // 显式复制每个属性(仅复制用户传入的值,保留未传参数的默认值)
  228. if (option.date !== undefined) {
  229. dateOptionAndPicker.date = option.date
  230. }
  231. if (option.minDate !== undefined) {
  232. dateOptionAndPicker.minDate = option.minDate;
  233. }
  234. if (option.maxDate !== undefined) {
  235. dateOptionAndPicker.maxDate = option.maxDate;
  236. }
  237. if (option.unitType !== undefined) {
  238. dateOptionAndPicker.unitType = option.unitType;
  239. }
  240. if (option.headerLeftBuilder !== undefined) {
  241. dateOptionAndPicker.headerLeftBuilder = option.headerLeftBuilder
  242. }
  243. if (option.title !== undefined) {
  244. dateOptionAndPicker.title = option.title
  245. }else {
  246. dateOptionAndPicker.title = '选择日期'
  247. }
  248. dateOptionAndPicker.headerBuilder = new DatePickerHeaderGlobalBuilder()
  249. if (option.headerLeftBuilder !== undefined) {
  250. dateOptionAndPicker.headerBuilder.headerLeftBuilder = option.headerLeftBuilder
  251. }else {
  252. dateOptionAndPicker.headerBuilder.headerLeftBuilder = wrapBuilder(headerLeftBuilder)
  253. }
  254. if (option.headerRightBuilder !== undefined) {
  255. dateOptionAndPicker.headerBuilder.headerRightBuilder = option.headerRightBuilder
  256. }else {
  257. dateOptionAndPicker.headerBuilder.headerRightBuilder = wrapBuilder(headerRightBuilder)
  258. }
  259. if (option.highlightBackgroundColor!==undefined) {
  260. dateOptionAndPicker.highlightBackgroundColor = option.highlightBackgroundColor
  261. }else {
  262. dateOptionAndPicker.highlightBackgroundColor ='#FFFFF6D1'
  263. }
  264. if (option.highlightBorderColor!==undefined) {
  265. dateOptionAndPicker.highlightBorderColor = option.highlightBorderColor
  266. }else {
  267. dateOptionAndPicker.highlightBorderColor =Color.Transparent
  268. }
  269. if (option.selectedTextStyle!==undefined) {
  270. dateOptionAndPicker.selectedTextStyle = option.selectedTextStyle
  271. }else {
  272. dateOptionAndPicker.selectedTextStyle = { font: { size: 16,weight:500 }, color: '#CC353C46' }
  273. }
  274. if (option.textStyle!==undefined) {
  275. dateOptionAndPicker.textStyle = option.textStyle
  276. }else {
  277. dateOptionAndPicker.textStyle = { font: { size: 16,weight:500 }, color: '#CC353C46' }
  278. }
  279. return dateOptionAndPicker;
  280. }
  281. // 显示地址选择器对话框
  282. public show(dateOption?:DateOption) {
  283. let option:DateOption = {}
  284. if (dateOption) {
  285. option = dateOption
  286. }else {
  287. option = new DateOption()
  288. }
  289. const pickerOption = this.optionToPickerOption(option)
  290. pickerOption.confirm = (date: Date) => {
  291. option.confirm?.(date)
  292. animateTo({
  293. duration: 200,
  294. }, () => {
  295. pickerOption.isEnd = true
  296. this.dialog?.updateParam(pickerOption)
  297. this.dialog?.dismissDialog()
  298. })
  299. }
  300. pickerOption.cancel = () => {
  301. animateTo({
  302. duration: 200,
  303. }, () => {
  304. pickerOption.isEnd = true
  305. this.dialog?.updateParam(pickerOption)
  306. this.dialog?.dismissDialog()
  307. })
  308. }
  309. this.dialog = new QNUIFloatingContainer<YTDatePickerOptions>(this.uiContext)
  310. this.dialog.setOptions({
  311. alignment: DialogAlignment.Bottom,
  312. autoCancel: true, //点击蒙层是否关闭弹窗
  313. isModal: true, //是否为半模态
  314. maskColor: '#0f000000',
  315. transition: TransitionEffect.opacity(0).animation({ duration: 100 }),
  316. offset: { dx: 0, dy: 0 } as Offset,
  317. onWillDismiss: (action) => {
  318. animateTo({
  319. duration: 100,
  320. onFinish: () => {
  321. action.dismiss()
  322. }
  323. }, () => {
  324. /* this.calendarOptionAndPicker!.isEnd = true
  325. this.contentNode?.update(this.calendarOptionAndPicker)*/
  326. pickerOption.isEnd = true
  327. // console.log('测试', this.dialog?.getDialogContent())
  328. this.dialog?.updateParam(pickerOption)
  329. // this.dialog?.getDialogContent()?.update(pickerOption)
  330. })
  331. }
  332. })
  333. this.dialog.showDialog(YTDatePickerViewBuilder, pickerOption);
  334. }
  335. // 取消对话框的方法
  336. public hide() {
  337. this.dialog?.dismissDialog();
  338. }
  339. }