From a030d1c92ee63630ad2c8600d362b507786e53d7 Mon Sep 17 00:00:00 2001 From: oneao Date: Thu, 5 Feb 2026 22:46:50 +0800 Subject: [PATCH] u --- code/allapp/allapp-rn/src/app/(tabs)/love.tsx | 66 +++- .../src/app/money/analysis/index.tsx | 1 - .../components/common/ao/DateMorePicker.tsx | 314 ++++++++++++++---- .../src/components/common/ao/Tab.tsx | 2 - code/allapp/allapp-rn/test.html | 234 ++++++++----- 5 files changed, 449 insertions(+), 168 deletions(-) diff --git a/code/allapp/allapp-rn/src/app/(tabs)/love.tsx b/code/allapp/allapp-rn/src/app/(tabs)/love.tsx index ddca6d11..761c9402 100644 --- a/code/allapp/allapp-rn/src/app/(tabs)/love.tsx +++ b/code/allapp/allapp-rn/src/app/(tabs)/love.tsx @@ -1,28 +1,60 @@ -import SegmentedControl from '@react-native-segmented-control/segmented-control' import React, { useState } from 'react' -import { ScrollView, StyleSheet, Text, TouchableOpacity, View } from 'react-native' -import { AButton, ADateMorePicker, ATab } from '@/components/common/ao' +import { Text, View } from 'react-native' +import { AButton, ADateMorePicker } from '@/components/common/ao' export default function DemoDatePickerUI() { - const [show, setShow] = useState(false) + const [visible, setVisible] = useState(false) + const [mode, setMode] = useState('') + const [result, setResult] = useState<{ + startTime: string + endTime: string + }>({ + startTime: '', + endTime: '', + }) return ( - - { - setShow(true) - }} - className="mt-20" - > - 测试 + + {/* 当前选择结果展示 */} + + 当前选择: + + {result.startTime || result.endTime + ? ( + <> + + 开始时间: + {result.startTime || '-'} + + + 结束时间: + {result.endTime || '-'} + + + ) + : ( + 未选择 + )} + + + {/* 打开选择器 */} + setVisible(true)}> + 打开日期选择器 + + {/* 日期选择器 */} { - setShow(false) + visible={visible} + onClose={() => setVisible(false)} + mode={mode} + startDate={result.startTime} + endDate={result.endTime} + onConfirm={(value) => { + setMode(value.mode) + // setResult(value) + setVisible(false) }} - > - + /> ) } diff --git a/code/allapp/allapp-rn/src/app/money/analysis/index.tsx b/code/allapp/allapp-rn/src/app/money/analysis/index.tsx index 45932fdd..14bf0e1e 100644 --- a/code/allapp/allapp-rn/src/app/money/analysis/index.tsx +++ b/code/allapp/allapp-rn/src/app/money/analysis/index.tsx @@ -177,7 +177,6 @@ export default function Analysis() { ? ( diff --git a/code/allapp/allapp-rn/src/components/common/ao/DateMorePicker.tsx b/code/allapp/allapp-rn/src/components/common/ao/DateMorePicker.tsx index 03bcef4d..513f8313 100644 --- a/code/allapp/allapp-rn/src/components/common/ao/DateMorePicker.tsx +++ b/code/allapp/allapp-rn/src/components/common/ao/DateMorePicker.tsx @@ -1,104 +1,292 @@ import SegmentedControl from '@react-native-segmented-control/segmented-control' -import { DateRangePicker } from '@yz1311/react-native-wheel-picker' +import { DatePicker, DateRangePicker } from '@yz1311/react-native-wheel-picker' +import dayjs from 'dayjs' import { useEffect, useState } from 'react' import { ScrollView, Text, View } from 'react-native' +import { getCurrentDate, toDate } from '@/utils/time' import Button from './Button' import Drawer from './Drawer' +import LucideIcon from './LucideIcon' import Tab from './Tab' -export type DatePickerMode = 'year' | 'month' | 'date' | 'time' | 'datetime' -export type DateFormatType - = | 'YYYY' - | 'YYYY-MM' - | 'YYYY-MM-DD' - | 'HH:mm:ss' - | 'YYYY-MM-DD HH:mm:ss' +/** ================= 类型 ================= */ + +export type PickerMode + = | 'unlimited' + | 'date' + | 'month' + | 'year' + | 'time' + | 'datetime' + | 'range' + +type PickerModeInternal = PickerMode | 'custom' +type TabKey = 'custom' | PickerMode +type DatePickerMode = 'date' | 'month' | 'year' | 'time' | 'datetime' interface DateMorePickerProps { + mode?: PickerMode startDate?: Date | string endDate?: Date | string visible?: boolean onClose?: () => void - onConfirm?: (value: string) => void - mode?: DatePickerMode - format?: DateFormatType + onConfirm?: (value: { + mode: PickerMode + startTime: string + endTime: string + }) => void + onChange?: (mode: PickerMode) => void } export default function DateMorePicker({ + mode, + startDate, + endDate, visible, onClose, + onConfirm, + onChange, }: DateMorePickerProps) { - const [localVisible, setLocalVisible] = useState(visible || false) - const [index, setIndex] = useState(0) + const [localVisible, setLocalVisible] = useState(false) + + const coreModes: DatePickerMode[] = ['date', 'month', 'year', 'time', 'datetime'] + const coreLabels = ['日', '月', '年', '时间', '日期'] + + /** ================= 内部编辑态 ================= */ + + const [internalMode, setInternalMode] = useState('date') + const [internalStart, setInternalStart] = useState(getCurrentDate()) + const [internalEnd, setInternalEnd] = useState(getCurrentDate()) + const [activeTab, setActiveTab] = useState('custom') + + /** ================= 重置编辑态(关键) ================= */ + + const resetInternalState = () => { + setInternalMode(mode || 'date') + setInternalStart(startDate ?? getCurrentDate()) + setInternalEnd(endDate ?? getCurrentDate()) + setActiveTab('custom') + } useEffect(() => { - setLocalVisible(!!visible) + if (visible) { + resetInternalState() + setLocalVisible(true) + } }, [visible]) - function handleClose() { + /** ================= 快速选择逻辑(修复时间归零) ================= */ + + const handleModeChange = (next: PickerModeInternal) => { + const now = dayjs() + + switch (next) { + case 'custom': + setInternalMode('date') + break + + case 'unlimited': + setInternalStart('') + setInternalEnd('') + setInternalMode('unlimited') + break + + case 'range': { + const base = now.startOf('day') + setInternalStart(base.toDate()) + setInternalEnd(base.toDate()) + setInternalMode('range') + break + } + + case 'date': { + const base = now.startOf('day') + setInternalStart(base.toDate()) + setInternalEnd(base.toDate()) + setInternalMode('date') + break + } + + case 'month': { + const base = now.startOf('month') + setInternalStart(base.toDate()) + setInternalEnd(base.toDate()) + setInternalMode('month') + break + } + + case 'year': { + const base = now.startOf('year') + setInternalStart(base.toDate()) + setInternalEnd(base.toDate()) + setInternalMode('year') + break + } + + case 'time': { + const base = now.second(0) + setInternalStart(base.toDate()) + setInternalEnd(base.toDate()) + setInternalMode('time') + break + } + + case 'datetime': { + setInternalStart(now.toDate()) + setInternalEnd(now.toDate()) + setInternalMode('datetime') + break + } + } + + onChange?.(next === 'custom' ? 'date' : next) + } + + const handleClose = () => { setLocalVisible(false) onClose?.() } - return ( - - - - - 快速选择 - {}} - /> - + /** ================= 确认(提交) ================= */ - - 选择模式 - - setIndex(e.nativeEvent.selectedSegmentIndex)} - /> - + const formatMap: Record = { + unlimited: '', + range: 'YYYY-MM-DD', + date: 'YYYY-MM-DD', + month: 'YYYY-MM', + year: 'YYYY', + time: 'HH:mm:ss', + datetime: 'YYYY-MM-DD HH:mm:ss', + } + + const handleConfirm = () => { + if (!onConfirm) + return + + let startStr = '' + let endStr = '' + + if (internalMode === 'unlimited') { + startStr = '' + endStr = '' + } + else if (internalMode === 'range') { + startStr = dayjs(internalStart).format(formatMap.range) + endStr = dayjs(internalEnd).format(formatMap.range) + } + else { + const fmt = formatMap[internalMode] + startStr = dayjs(internalStart).format(fmt) + endStr = startStr + } + + onConfirm({ + mode: internalMode, + startTime: startStr, + endTime: endStr, + }) + + handleClose() + } + + /** ================= UI ================= */ + + return ( + + + + {/* 快速选择 */} + + 快速选择 + { + setActiveTab(key as TabKey) + handleModeChange(key as PickerModeInternal) + }} + /> + {/* 模式选择 */} + {!['unlimited', 'range'].includes(internalMode) && ( + + 选择模式 + { + const next = coreModes[e.nativeEvent.selectedSegmentIndex] + setInternalMode(next) + setInternalStart(dayjs().toDate()) + setActiveTab('custom') + }} + /> + + )} + + {/* Picker */} - + {internalMode === 'unlimited' && ( + + + 不限时间 + + )} + + {internalMode === 'range' && ( + { + setInternalStart(start) + setInternalEnd(end) + if (activeTab !== 'range') + setActiveTab('custom') + }} + /> + )} + + {coreModes.includes(internalMode as DatePickerMode) && ( + { + setInternalStart(value) + setActiveTab('custom') + }} + /> + )} - + {/* 按钮 */} + - diff --git a/code/allapp/allapp-rn/src/components/common/ao/Tab.tsx b/code/allapp/allapp-rn/src/components/common/ao/Tab.tsx index 7fa3f911..1c749503 100644 --- a/code/allapp/allapp-rn/src/components/common/ao/Tab.tsx +++ b/code/allapp/allapp-rn/src/components/common/ao/Tab.tsx @@ -3,8 +3,6 @@ import type { } from 'react-native' import React, { useEffect, useRef, useState } from 'react' import { - NativeScrollEvent, - NativeSyntheticEvent, ScrollView, Text, TouchableWithoutFeedback, diff --git a/code/allapp/allapp-rn/test.html b/code/allapp/allapp-rn/test.html index c22c4e5e..3e583052 100644 --- a/code/allapp/allapp-rn/test.html +++ b/code/allapp/allapp-rn/test.html @@ -1,97 +1,161 @@ - - -可编辑表格示例 - + + 日期选择 Picker Demo + + +
+

日期选择器 Demo

+ + +
+
+ {{ cat }} +
+
+ + + -

可编辑表格示例

+ +
+
+ {{ item.label }} +
+
- - - - - - - - - - + + - -
- - - - - + }).use(ElementPlus).mount('#app') +