u
This commit is contained in:
1 parent
2b76078a77
commit
a030d1c92e
5 files changed
+449
-168
No files matched your search
@@ -1,28 +1,60 @@
|
|||||||
import SegmentedControl from '@react-native-segmented-control/segmented-control'
|
|
||||||
import React, { useState } from 'react'
|
import React, { useState } from 'react'
|
||||||
import { ScrollView, StyleSheet, Text, TouchableOpacity, View } from 'react-native'
|
import { Text, View } from 'react-native'
|
||||||
import { AButton, ADateMorePicker, ATab } from '@/components/common/ao'
|
import { AButton, ADateMorePicker } from '@/components/common/ao'
|
||||||
|
|
||||||
export default function DemoDatePickerUI() {
|
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 (
|
return (
|
||||||
<View className="flex-1">
|
<View className="flex-1 p-4 bg-white">
|
||||||
<AButton
|
{/* 当前选择结果展示 */}
|
||||||
onPress={() => {
|
<View className="mb-4 p-3 rounded bg-gray-100">
|
||||||
setShow(true)
|
<Text className="text-gray-600 mb-1">当前选择:</Text>
|
||||||
}}
|
|
||||||
className="mt-20"
|
{result.startTime || result.endTime
|
||||||
>
|
? (
|
||||||
测试
|
<>
|
||||||
|
<Text>
|
||||||
|
开始时间:
|
||||||
|
{result.startTime || '-'}
|
||||||
|
</Text>
|
||||||
|
<Text>
|
||||||
|
结束时间:
|
||||||
|
{result.endTime || '-'}
|
||||||
|
</Text>
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
: (
|
||||||
|
<Text className="text-gray-400">未选择</Text>
|
||||||
|
)}
|
||||||
|
</View>
|
||||||
|
|
||||||
|
{/* 打开选择器 */}
|
||||||
|
<AButton onPress={() => setVisible(true)}>
|
||||||
|
打开日期选择器
|
||||||
</AButton>
|
</AButton>
|
||||||
|
|
||||||
|
{/* 日期选择器 */}
|
||||||
<ADateMorePicker
|
<ADateMorePicker
|
||||||
visible={show}
|
visible={visible}
|
||||||
onClose={() => {
|
onClose={() => setVisible(false)}
|
||||||
setShow(false)
|
mode={mode}
|
||||||
|
startDate={result.startTime}
|
||||||
|
endDate={result.endTime}
|
||||||
|
onConfirm={(value) => {
|
||||||
|
setMode(value.mode)
|
||||||
|
// setResult(value)
|
||||||
|
setVisible(false)
|
||||||
}}
|
}}
|
||||||
>
|
/>
|
||||||
</ADateMorePicker>
|
|
||||||
</View>
|
</View>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -177,7 +177,6 @@ export default function Analysis() {
|
|||||||
? (
|
? (
|
||||||
<VictoryPie
|
<VictoryPie
|
||||||
height={250}
|
height={250}
|
||||||
animate={{ duration: 1000 }}
|
|
||||||
data={pieRecords}
|
data={pieRecords}
|
||||||
theme={VictoryTheme.material}
|
theme={VictoryTheme.material}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -1,104 +1,292 @@
|
|||||||
import SegmentedControl from '@react-native-segmented-control/segmented-control'
|
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 { useEffect, useState } from 'react'
|
||||||
import { ScrollView, Text, View } from 'react-native'
|
import { ScrollView, Text, View } from 'react-native'
|
||||||
|
import { getCurrentDate, toDate } from '@/utils/time'
|
||||||
import Button from './Button'
|
import Button from './Button'
|
||||||
import Drawer from './Drawer'
|
import Drawer from './Drawer'
|
||||||
|
import LucideIcon from './LucideIcon'
|
||||||
import Tab from './Tab'
|
import Tab from './Tab'
|
||||||
|
|
||||||
export type DatePickerMode = 'year' | 'month' | 'date' | 'time' | 'datetime'
|
/** ================= 类型 ================= */
|
||||||
export type DateFormatType
|
|
||||||
= | 'YYYY'
|
export type PickerMode
|
||||||
| 'YYYY-MM'
|
= | 'unlimited'
|
||||||
| 'YYYY-MM-DD'
|
| 'date'
|
||||||
| 'HH:mm:ss'
|
| 'month'
|
||||||
| 'YYYY-MM-DD HH:mm:ss'
|
| 'year'
|
||||||
|
| 'time'
|
||||||
|
| 'datetime'
|
||||||
|
| 'range'
|
||||||
|
|
||||||
|
type PickerModeInternal = PickerMode | 'custom'
|
||||||
|
type TabKey = 'custom' | PickerMode
|
||||||
|
type DatePickerMode = 'date' | 'month' | 'year' | 'time' | 'datetime'
|
||||||
|
|
||||||
interface DateMorePickerProps {
|
interface DateMorePickerProps {
|
||||||
|
mode?: PickerMode
|
||||||
startDate?: Date | string
|
startDate?: Date | string
|
||||||
endDate?: Date | string
|
endDate?: Date | string
|
||||||
visible?: boolean
|
visible?: boolean
|
||||||
onClose?: () => void
|
onClose?: () => void
|
||||||
onConfirm?: (value: string) => void
|
onConfirm?: (value: {
|
||||||
mode?: DatePickerMode
|
mode: PickerMode
|
||||||
format?: DateFormatType
|
startTime: string
|
||||||
|
endTime: string
|
||||||
|
}) => void
|
||||||
|
onChange?: (mode: PickerMode) => void
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function DateMorePicker({
|
export default function DateMorePicker({
|
||||||
|
mode,
|
||||||
|
startDate,
|
||||||
|
endDate,
|
||||||
visible,
|
visible,
|
||||||
onClose,
|
onClose,
|
||||||
|
onConfirm,
|
||||||
|
onChange,
|
||||||
}: DateMorePickerProps) {
|
}: DateMorePickerProps) {
|
||||||
const [localVisible, setLocalVisible] = useState(visible || false)
|
const [localVisible, setLocalVisible] = useState(false)
|
||||||
const [index, setIndex] = useState(0)
|
|
||||||
|
const coreModes: DatePickerMode[] = ['date', 'month', 'year', 'time', 'datetime']
|
||||||
|
const coreLabels = ['日', '月', '年', '时间', '日期']
|
||||||
|
|
||||||
|
/** ================= 内部编辑态 ================= */
|
||||||
|
|
||||||
|
const [internalMode, setInternalMode] = useState<PickerMode>('date')
|
||||||
|
const [internalStart, setInternalStart] = useState<Date | string>(getCurrentDate())
|
||||||
|
const [internalEnd, setInternalEnd] = useState<Date | string>(getCurrentDate())
|
||||||
|
const [activeTab, setActiveTab] = useState<TabKey>('custom')
|
||||||
|
|
||||||
|
/** ================= 重置编辑态(关键) ================= */
|
||||||
|
|
||||||
|
const resetInternalState = () => {
|
||||||
|
setInternalMode(mode || 'date')
|
||||||
|
setInternalStart(startDate ?? getCurrentDate())
|
||||||
|
setInternalEnd(endDate ?? getCurrentDate())
|
||||||
|
setActiveTab('custom')
|
||||||
|
}
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setLocalVisible(!!visible)
|
if (visible) {
|
||||||
|
resetInternalState()
|
||||||
|
setLocalVisible(true)
|
||||||
|
}
|
||||||
}, [visible])
|
}, [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)
|
setLocalVisible(false)
|
||||||
onClose?.()
|
onClose?.()
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
/** ================= 确认(提交) ================= */
|
||||||
<Drawer
|
|
||||||
visible={localVisible}
|
|
||||||
hideModal={handleClose}
|
|
||||||
showHeader={false}
|
|
||||||
height="60%"
|
|
||||||
>
|
|
||||||
<View className="flex-1 p-3">
|
|
||||||
<View
|
|
||||||
className="gap-2"
|
|
||||||
style={{ flexShrink: 0 }}
|
|
||||||
>
|
|
||||||
<View>
|
|
||||||
<Text className="text-lg mb-1">快速选择</Text>
|
|
||||||
<Tab
|
|
||||||
data={[
|
|
||||||
{ label: '自定义', key: '自定义' },
|
|
||||||
{ label: '不限', key: '不限' },
|
|
||||||
{ label: '今天', key: '今天' },
|
|
||||||
{ label: '本月', key: '本月' },
|
|
||||||
{ label: '本年', key: '本年' },
|
|
||||||
{ label: '范围', key: '范围' },
|
|
||||||
]}
|
|
||||||
onChange={() => {}}
|
|
||||||
/>
|
|
||||||
</View>
|
|
||||||
|
|
||||||
<View>
|
const formatMap: Record<PickerMode, string> = {
|
||||||
<Text className="text-lg mb-1">选择模式</Text>
|
unlimited: '',
|
||||||
<SegmentedControl
|
range: 'YYYY-MM-DD',
|
||||||
values={['日', '月', '年', '时间', '日期']}
|
date: 'YYYY-MM-DD',
|
||||||
selectedIndex={index}
|
month: 'YYYY-MM',
|
||||||
style={{ width: '100%', borderRadius: 2 }}
|
year: 'YYYY',
|
||||||
sliderStyle={{ borderRadius: 2 }}
|
time: 'HH:mm:ss',
|
||||||
onChange={(e: any) =>
|
datetime: 'YYYY-MM-DD HH:mm:ss',
|
||||||
setIndex(e.nativeEvent.selectedSegmentIndex)}
|
}
|
||||||
/>
|
|
||||||
</View>
|
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 (
|
||||||
|
<Drawer visible={localVisible} hideModal={handleClose} showHeader={false} height="50%">
|
||||||
|
<View className="flex-1 p-3">
|
||||||
|
|
||||||
|
{/* 快速选择 */}
|
||||||
|
<View className="mb-2">
|
||||||
|
<Text className="text-lg mb-1">快速选择</Text>
|
||||||
|
<Tab
|
||||||
|
defaultKey={activeTab}
|
||||||
|
data={[
|
||||||
|
{ label: '自定义', key: 'custom' },
|
||||||
|
{ label: '不限', key: 'unlimited' },
|
||||||
|
{ label: '今天', key: 'date' },
|
||||||
|
{ label: '本月', key: 'month' },
|
||||||
|
{ label: '本年', key: 'year' },
|
||||||
|
{ label: '范围', key: 'range' },
|
||||||
|
]}
|
||||||
|
onChange={(key) => {
|
||||||
|
setActiveTab(key as TabKey)
|
||||||
|
handleModeChange(key as PickerModeInternal)
|
||||||
|
}}
|
||||||
|
/>
|
||||||
</View>
|
</View>
|
||||||
|
|
||||||
|
{/* 模式选择 */}
|
||||||
|
{!['unlimited', 'range'].includes(internalMode) && (
|
||||||
|
<View className="mb-2">
|
||||||
|
<Text className="text-lg mb-1">选择模式</Text>
|
||||||
|
<SegmentedControl
|
||||||
|
values={coreLabels}
|
||||||
|
selectedIndex={coreModes.indexOf(internalMode as DatePickerMode)}
|
||||||
|
style={{ width: '100%', borderRadius: 2 }}
|
||||||
|
sliderStyle={{ borderRadius: 2 }}
|
||||||
|
onChange={(e: any) => {
|
||||||
|
const next = coreModes[e.nativeEvent.selectedSegmentIndex]
|
||||||
|
setInternalMode(next)
|
||||||
|
setInternalStart(dayjs().toDate())
|
||||||
|
setActiveTab('custom')
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</View>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{/* Picker */}
|
||||||
<ScrollView
|
<ScrollView
|
||||||
style={{ flex: 1 }}
|
style={{ flex: 1 }}
|
||||||
showsVerticalScrollIndicator={false}
|
contentContainerStyle={{
|
||||||
showsHorizontalScrollIndicator={false}
|
width: '100%',
|
||||||
|
alignItems: 'center',
|
||||||
|
justifyContent: 'center',
|
||||||
|
paddingVertical: 10,
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
<DateRangePicker
|
{internalMode === 'unlimited' && (
|
||||||
isModal={false}
|
<View className="items-center">
|
||||||
showHeader={false}
|
<LucideIcon icon="Clock" size={38} color="#555" />
|
||||||
/>
|
<Text className="mt-2 text-lg">不限时间</Text>
|
||||||
|
</View>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{internalMode === 'range' && (
|
||||||
|
<DateRangePicker
|
||||||
|
isModal={false}
|
||||||
|
showHeader={false}
|
||||||
|
style={{ width: '100%', height: '100%' }}
|
||||||
|
onValueChange={(start, end) => {
|
||||||
|
setInternalStart(start)
|
||||||
|
setInternalEnd(end)
|
||||||
|
if (activeTab !== 'range')
|
||||||
|
setActiveTab('custom')
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{coreModes.includes(internalMode as DatePickerMode) && (
|
||||||
|
<DatePicker
|
||||||
|
key={internalMode}
|
||||||
|
isModal={false}
|
||||||
|
showHeader={false}
|
||||||
|
mode={internalMode as DatePickerMode}
|
||||||
|
date={toDate(internalStart)}
|
||||||
|
style={{ height: '100%' }}
|
||||||
|
onDateChange={(value) => {
|
||||||
|
setInternalStart(value)
|
||||||
|
setActiveTab('custom')
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
</ScrollView>
|
</ScrollView>
|
||||||
|
|
||||||
<View
|
{/* 按钮 */}
|
||||||
className="flex-row gap-3 pt-2"
|
<View className="flex-row gap-3 pt-2">
|
||||||
style={{ flexShrink: 0 }}
|
|
||||||
>
|
|
||||||
<Button className="flex-1" variant="outline" onPress={handleClose}>
|
<Button className="flex-1" variant="outline" onPress={handleClose}>
|
||||||
取消
|
取消
|
||||||
</Button>
|
</Button>
|
||||||
<Button className="flex-1">
|
<Button className="flex-1" onPress={handleConfirm}>
|
||||||
确认
|
确认
|
||||||
</Button>
|
</Button>
|
||||||
</View>
|
</View>
|
||||||
|
|||||||
@@ -3,8 +3,6 @@ import type {
|
|||||||
} from 'react-native'
|
} from 'react-native'
|
||||||
import React, { useEffect, useRef, useState } from 'react'
|
import React, { useEffect, useRef, useState } from 'react'
|
||||||
import {
|
import {
|
||||||
NativeScrollEvent,
|
|
||||||
NativeSyntheticEvent,
|
|
||||||
ScrollView,
|
ScrollView,
|
||||||
Text,
|
Text,
|
||||||
TouchableWithoutFeedback,
|
TouchableWithoutFeedback,
|
||||||
|
|||||||
+149
-85
@@ -1,97 +1,161 @@
|
|||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html lang="en">
|
<html lang="en">
|
||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
<title>日期选择 Picker Demo</title>
|
||||||
<title>可编辑表格示例</title>
|
<link rel="stylesheet" href="https://unpkg.com/element-plus/dist/index.css" />
|
||||||
<style>
|
<style>
|
||||||
body {
|
body {
|
||||||
font-family: Arial, sans-serif;
|
font-family: sans-serif;
|
||||||
padding: 20px;
|
padding: 20px;
|
||||||
}
|
}
|
||||||
table {
|
.category-tabs {
|
||||||
border-collapse: collapse;
|
display: flex;
|
||||||
width: 100%;
|
gap: 10px;
|
||||||
table-layout: fixed;
|
margin-bottom: 10px;
|
||||||
}
|
flex-wrap: wrap;
|
||||||
th, td {
|
}
|
||||||
border: 1px solid #ccc;
|
.category-tab {
|
||||||
padding: 5px;
|
padding: 6px 12px;
|
||||||
text-align: center;
|
border: 1px solid #ccc;
|
||||||
}
|
border-radius: 4px;
|
||||||
input[type="text"], input[type="date"] {
|
cursor: pointer;
|
||||||
width: 90%;
|
transition: all 0.2s;
|
||||||
box-sizing: border-box;
|
}
|
||||||
}
|
.category-tab.active {
|
||||||
input[type="checkbox"] {
|
background-color: #409eff;
|
||||||
transform: scale(1.2);
|
color: white;
|
||||||
}
|
border-color: #409eff;
|
||||||
button {
|
}
|
||||||
margin-top: 10px;
|
.shortcut-options {
|
||||||
padding: 5px 10px;
|
display: flex;
|
||||||
}
|
gap: 10px;
|
||||||
</style>
|
margin-top: 10px;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
.shortcut-option {
|
||||||
|
padding: 6px 12px;
|
||||||
|
border: 1px solid #ccc;
|
||||||
|
border-radius: 4px;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: all 0.2s;
|
||||||
|
}
|
||||||
|
.shortcut-option.active {
|
||||||
|
background-color: #67c23a;
|
||||||
|
color: white;
|
||||||
|
border-color: #67c23a;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
<div id="app">
|
||||||
|
<h2>日期选择器 Demo</h2>
|
||||||
|
|
||||||
|
<!-- 分类标签 -->
|
||||||
|
<div class="category-tabs">
|
||||||
|
<div
|
||||||
|
v-for="cat in categories"
|
||||||
|
:key="cat"
|
||||||
|
class="category-tab"
|
||||||
|
:class="{ active: selectedCategory === cat }"
|
||||||
|
@click="selectCategory(cat)"
|
||||||
|
>
|
||||||
|
{{ cat }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 日期选择器 -->
|
||||||
|
<el-date-picker
|
||||||
|
v-model="dateValue"
|
||||||
|
:type="pickerType"
|
||||||
|
placeholder="请选择日期"
|
||||||
|
:value-format="valueFormat"
|
||||||
|
style="width: 100%;"
|
||||||
|
></el-date-picker>
|
||||||
|
|
||||||
<h2>可编辑表格示例</h2>
|
<!-- 快捷选项 -->
|
||||||
|
<div class="shortcut-options">
|
||||||
|
<div
|
||||||
|
v-for="item in shortcuts"
|
||||||
|
:key="item.label"
|
||||||
|
class="shortcut-option"
|
||||||
|
:class="{ active: activeShortcut === item.label }"
|
||||||
|
@click="applyShortcut(item)"
|
||||||
|
>
|
||||||
|
{{ item.label }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<table id="editableTable">
|
<div style="margin-top: 20px;">
|
||||||
<thead>
|
<strong>选择的值:</strong> {{ dateValue }}
|
||||||
<tr>
|
</div>
|
||||||
<!-- 生成 20 个列标题 -->
|
</div>
|
||||||
<script>
|
|
||||||
for(let i=1; i<=20; i++){
|
<script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
|
||||||
document.write(`<th>列${i}</th>`);
|
<script src="https://unpkg.com/element-plus/dist/index.full.js"></script>
|
||||||
}
|
<script>
|
||||||
</script>
|
const { createApp, ref } = Vue
|
||||||
</tr>
|
const { ElDatePicker } = ElementPlus
|
||||||
</thead>
|
|
||||||
<tbody>
|
createApp({
|
||||||
<!-- 初始 20 行 -->
|
setup() {
|
||||||
<script>
|
const categories = ['日', '月', '年', '时间', '日期', '范围', '不限']
|
||||||
function createRow(rowIndex){
|
const selectedCategory = ref('日')
|
||||||
let row = '<tr>';
|
const dateValue = ref(null)
|
||||||
for(let i=1;i<=20;i++){
|
const activeShortcut = ref(null)
|
||||||
if(i % 3 === 1){ // 文本输入
|
|
||||||
row += `<td><input type="text" placeholder="文本${rowIndex}-${i}"></td>`;
|
const shortcuts = [
|
||||||
} else if(i % 3 === 2){ // 日期选择
|
{ label: '今天', getValue: () => new Date() },
|
||||||
row += `<td><input type="date"></td>`;
|
{ label: '本月', getValue: () => {
|
||||||
} else { // 复选框
|
const now = new Date()
|
||||||
row += `<td><input type="checkbox"></td>`;
|
return [new Date(now.getFullYear(), now.getMonth(), 1), new Date(now.getFullYear(), now.getMonth() + 1, 0)]
|
||||||
|
}},
|
||||||
|
{ label: '本年', getValue: () => {
|
||||||
|
const now = new Date()
|
||||||
|
return [new Date(now.getFullYear(), 0, 1), new Date(now.getFullYear(), 11, 31)]
|
||||||
|
}},
|
||||||
|
]
|
||||||
|
|
||||||
|
const pickerType = Vue.computed(() => {
|
||||||
|
switch(selectedCategory.value){
|
||||||
|
case '日': return 'date'
|
||||||
|
case '月': return 'month'
|
||||||
|
case '年': return 'year'
|
||||||
|
case '时间': return 'time'
|
||||||
|
case '日期': return 'date'
|
||||||
|
case '范围': return 'daterange'
|
||||||
|
case '不限': return 'date'
|
||||||
|
default: return 'date'
|
||||||
}
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const valueFormat = Vue.computed(() => {
|
||||||
|
switch(selectedCategory.value){
|
||||||
|
case '日': return 'yyyy-MM-dd'
|
||||||
|
case '月': return 'yyyy-MM'
|
||||||
|
case '年': return 'yyyy'
|
||||||
|
case '时间': return 'HH:mm:ss'
|
||||||
|
case '日期': return 'yyyy-MM-dd'
|
||||||
|
case '范围': return 'yyyy-MM-dd'
|
||||||
|
case '不限': return 'yyyy-MM-dd'
|
||||||
|
default: return 'yyyy-MM-dd'
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
function selectCategory(cat) {
|
||||||
|
selectedCategory.value = cat
|
||||||
|
dateValue.value = null
|
||||||
|
activeShortcut.value = null
|
||||||
}
|
}
|
||||||
row += '</tr>';
|
|
||||||
return row;
|
function applyShortcut(item) {
|
||||||
|
activeShortcut.value = item.label
|
||||||
|
dateValue.value = item.getValue()
|
||||||
|
}
|
||||||
|
|
||||||
|
return { categories, selectedCategory, dateValue, pickerType, valueFormat, shortcuts, activeShortcut, selectCategory, applyShortcut }
|
||||||
}
|
}
|
||||||
|
}).use(ElementPlus).mount('#app')
|
||||||
for(let r=1;r<=20;r++){
|
</script>
|
||||||
document.write(createRow(r));
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
|
|
||||||
<button onclick="addRow()">新增行</button>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
function addRow(){
|
|
||||||
const tbody = document.querySelector('#editableTable tbody');
|
|
||||||
const rowCount = tbody.rows.length + 1;
|
|
||||||
let newRow = '<tr>';
|
|
||||||
for(let i=1;i<=20;i++){
|
|
||||||
if(i % 3 === 1){
|
|
||||||
newRow += `<td><input type="text" placeholder="文本${rowCount}-${i}"></td>`;
|
|
||||||
} else if(i % 3 === 2){
|
|
||||||
newRow += `<td><input type="date"></td>`;
|
|
||||||
} else {
|
|
||||||
newRow += `<td><input type="checkbox"></td>`;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
newRow += '</tr>';
|
|
||||||
tbody.insertAdjacentHTML('beforeend', newRow);
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
Reference in new issue
Block a user