feat:日历渲染

This commit is contained in:
1708-huayu 2025-01-23 19:32:24 +08:00
parent 779a28a364
commit c2eb04b4b0
10 changed files with 202 additions and 102 deletions

View File

@ -1,5 +1,5 @@
import React, {useState} from "react";
import {Form, Calendar, CapsuleTabs, JumboTabs, Picker, PickerView, Popup} from "antd-mobile";
import {Form, Calendar, CapsuleTabs, JumboTabs, Picker, PickerView, Popup, CalendarPickerView} from "antd-mobile";
import {basicColumns} from "./constant";
import "./index.css"
import {CloseCircleFill} from "antd-mobile-icons";
@ -15,7 +15,7 @@ export default function DataPickItemPopup(props) {
return (
<Form.Item noStyle
shouldUpdate={(prevValues, curValues) => {
return prevValues.fieldName !== curValues.fieldName
return prevValues[fieldName] !== curValues[fieldName]
}}
>
{({getFieldValue, setFieldsValue}) => (
@ -32,9 +32,9 @@ export default function DataPickItemPopup(props) {
fontSize: 14,
}}
onClick={e => {
e.stopPropagation()
// 计算属性名:允许你在对象字面量中使用表达式来动态确定属性名。
setFieldsValue({[fieldName]: null})
e.stopPropagation()
}}/>) : true
}
onClick={() => {
@ -84,7 +84,7 @@ export default function DataPickItemPopup(props) {
>
<CapsuleTabs.Tab title={dateShowValue}
key='date' className="tab-content">
<Calendar
<CalendarPickerView
selectionMode='single'
defaultValue={dataPick}
onChange={val => {

View File

@ -8,14 +8,13 @@ import {
Space, Tag, Radio
} from 'antd-mobile'
import ParentTask from "../ParentTask";
import DatePickerItem from "../DataPickerItem"
import "./index.css"
import {addTask, getPTask, getTaskById, updateTask} from "../../utils";
import {useLocation, useNavigate, useOutletContext, useSearchParams} from "react-router-dom";
import dayjs from "dayjs";
import DataPickItemPopup from "../DataPickItemPopup";
export default () => {
const DetailForm= () => {
// 进入此页面的操作:添加,修改,详情(按钮为添加任务日志)
const location = useLocation();
let [params] = useSearchParams();
@ -29,6 +28,9 @@ export default () => {
const navigate = useNavigate();
// 获取form引用
const [form] = Form.useForm();
const addEditPName=(name)=>{
setPName(name)
}
useEffect(() => {
window.scrollTo(0, 0);
if (location.pathname.endsWith("addTask")) {
@ -83,6 +85,7 @@ export default () => {
console.log({res, parentMessageVOList});
setPName(parentMessageVOList[parentMessageVOList.length - 1].name);
setPidArray(parentMessageVOList.map(parent => parent.id))
form.setFieldValue("pidArray",parentMessageVOList.map(parent => parent.id))
})
}
@ -136,6 +139,8 @@ export default () => {
// 清空值
form.resetFields();
form.setFieldValue("pidArray", values.pidArray);
setPidArray(values.pidArray)
window.scrollTo(0, 0);
}
},
],
@ -193,7 +198,10 @@ export default () => {
name='code'
hidden={true}
></Form.Item>
<ParentTask pName={pName} pidArray={pidArray} disabled={updateFiledDisabled} form={form}/>
<ParentTask pName={pName} pidArray={pidArray}
disabled={updateFiledDisabled} form={form}
addEditPName={setPName}
/>
<Form.Item
name='name'
label='任务名称'
@ -241,3 +249,4 @@ export default () => {
</>
)
}
export default DetailForm;

View File

@ -26,10 +26,11 @@ const DetailSearchBar = (props) => {
// 处理主要条件
const tagList = [];
console.log("search.data.orSearchModel", search.data.orSearchModel)
await search.data.orSearchModel?.andList?.forEach((searchObj) => {
search.data.orSearchModel?.andList?.forEach((searchObj) => {
if (searchObj.name === "pid") {
getTaskById(searchObj.value).then(result=>{
tagList.push(<Tag key={result[0].name}>{result[0].name}</Tag>)
setTags([<Tag key={result.content[0].name}>{result.content[0].name}</Tag>
,...tagList])
})
} else if (searchObj.name === "state") {
const items = searchObj.value.split(',');
@ -69,7 +70,8 @@ const DetailSearchBar = (props) => {
const dict = stateDictionary.get(searchObj.value);
if (dict && tagList.length > 0) {
tagList.push(<AddOutline key="add-icon"/>)
} if (dict) {
}
if (dict) {
tagList.push(<Tag key={dict.id} color={dict.jsonValue?.color}>
{dict.itemName}
</Tag>);
@ -92,14 +94,16 @@ const DetailSearchBar = (props) => {
{tags}
</div>
{showCloseOutline && <div className="CloseOutline-CloseOutline" onClick={() => {
dispatch({type:UPDATE_SEARCH,search:{
dispatch({
type: UPDATE_SEARCH, search: {
"pageSize": 12,
"pageNumber": 1,
"data": {
"andList": [],
"orList": []
}
}});
}
});
setTags([]);
}}>
<CloseOutline key="close-icon" style={{float: "right"}}/>

View File

@ -8,7 +8,7 @@ import {getTaskByPid} from "../../utils";
const ParentTask = (props) => {
const [valueToOptions, setValueToOptions] = useState([])
const {form,disabled,pName,pidArray} = props;
const {form, disabled, pName, pidArray, addEditPName} = props;
const [parentValue, setParentValue] = useState(pidArray ?? [])
const [visible, setVisible] = useState(false)
@ -26,6 +26,7 @@ const ParentTask = (props)=>{
children: generate(option.value),
}))
}
return generate('0') ?? []
}, [valueToOptions])
@ -55,8 +56,18 @@ const ParentTask = (props)=>{
}
useEffect(() => {
fetchOptionsForValue('0', 0)
}, [])
initDate()
}, [props])
async function initDate() {
await fetchOptionsForValue('0', 0)
if (pidArray && pidArray.length > 0) {
setParentValue(pidArray)
for (const taskId of pidArray) {
await fetchOptionsForValue(taskId, 0)
}
}
}
return <Form.Item
name='pidArray'
@ -70,6 +81,7 @@ const ParentTask = (props)=>{
<Cascader
options={options}
visible={visible}
defaultValue={pidArray}
onClose={() => {
setVisible(false)
}}
@ -95,6 +107,9 @@ const ParentTask = (props)=>{
(<span>主线任务选填</span>) :
(<span style={{color: "#cccccc"}}>主线任务选填</span>)
} else {
if (addEditPName) {
addEditPName(items[items.length - 1].label)
}
return items[items.length - 1].label
}
}}

View File

@ -19,7 +19,7 @@ export function DetailLogTask() {
const [currentShow, setCurrentShow] = useState('need');
const textAreaRef = useRef(null);
const [taskLogList, setTaskLogList] = useState([]);
const [sendValue, setSendValue] = useState([]);
const [sendValue, setSendValue] = useState('');
// 点击操作面板
const [actionSheetVisible, setActionSheetVisible] = useState(false)

View File

@ -1,4 +1,4 @@
import {Button, Checkbox, DatePicker, Form, Input, Space, Switch, Tag} from "antd-mobile";
import {Button, CalendarPicker, Checkbox, DatePicker, Form, Input, Space, Switch, Tag} from "antd-mobile";
import ParentTask from "../../components/ParentTask";
import React, {useContext, useEffect} from "react";
import dayjs from "dayjs";
@ -7,6 +7,7 @@ import {useLocation, useNavigate, useOutletContext} from "react-router-dom";
import {getDictionary} from "../../utils/dictUtil";
import {MyRootContext, UPDATE_SEARCH} from "../../components/MyRootContext";
import {dayStartUtcFormat, nextDayStartUtcFormat} from "../../utils/timeFormatUtil";
import {getPTask} from "../../utils";
const DetailSearchContext = () => {
const navigate = useNavigate();
@ -16,6 +17,8 @@ const DetailSearchContext = () => {
const search = state.search
const [stateList, setStateList] = React.useState([]);
const [priorityList, setPriorityList] = React.useState([]);
const [pName, setPName] = React.useState();
const [pidArray, setPidArray] = React.useState([]);
// 使用Outlet,传值修改标题
const {setTitle} = useOutletContext();
useEffect(() => {
@ -24,6 +27,17 @@ const DetailSearchContext = () => {
initDate()
}, [])
function editParentTask(id) {
// 获取父任务信息
getPTask(id).then(res => {
let parentMessageVOList = res[0].parentMessageVOList;
console.log({res, parentMessageVOList});
setPName(parentMessageVOList[parentMessageVOList.length - 1].name);
setPidArray(parentMessageVOList.map(parent => parent.id))
form.setFieldValue("pidArray",parentMessageVOList.map(parent => parent.id))
})
}
async function initDate() {
let stateDictionary = await getDictionary("2");
let priorityDictionary = await getDictionary("1");
@ -36,8 +50,7 @@ const DetailSearchContext = () => {
let searchMap = new Map(
search.data.orSearchModel.andList.map(searchObj => [searchObj.name, searchObj]));
if (searchMap.has("pid")) {
// form.setFieldValue(task.name);
editParentTask(searchMap.get("pid").value)
}
if (searchMap.has("state")) {
form.setFieldValue("state", searchMap.get("state").value.split(','))
@ -76,7 +89,7 @@ const DetailSearchContext = () => {
const {pidArray, name, priority, state, todoDay, allOverdueTasks} = values;
if (pidArray && pidArray.length !== 0) {
searchCondition.push({"name": "name", "value": pidArray[pidArray.length - 1], "operateType": "="})
searchCondition.push({"name": "pid", "value": pidArray[pidArray.length - 1], "operateType": "="})
}
if (name && name !== "") {
searchCondition.push({"name": "name", "value": name, "operateType": "%"})
@ -148,7 +161,7 @@ const DetailSearchContext = () => {
</Button>
}
>
<ParentTask form={form}/>
<ParentTask pName={pName} pidArray={pidArray} form={form}/>
<Form.Item
name='name'
label='任务信息'
@ -216,16 +229,18 @@ const DetailSearchContext = () => {
setVisible(true)
}}
>
<DatePicker
<CalendarPicker
visible={visible}
selectionMode='single'
defaultDate={getFieldValue('todoDay')}
onClose={() => {
setVisible(false)
}}
>
{value =>
value ? dayjs(value).format('YYYY-MM-DD') : '请选择日期'
onConfirm={(val)=>setFieldsValue({todoDay:val})}
/>
{
getFieldValue('todoDay') ? dayjs(getFieldValue('todoDay')).format('YYYY-MM-DD') : '请选择日期'
}
</DatePicker>
</Form.Item>
)}
</Form.Item>

View File

@ -9,7 +9,7 @@ import {MyRootContext, UPDATE_SEARCH} from "../../components/MyRootContext";
const TaskCount = (props) => {
const {currentDay, taskCount, today, backToToday} = props;
const {currentDay, taskCount, today, backToToday, currentMonth} = props;
const navigate = useNavigate();
const [stateMap, setStateMap] = React.useState(new Map);
const [priorityMap, setPriorityMap] = React.useState(new Map);
@ -73,12 +73,10 @@ const TaskCount = (props) => {
navigate("/home/listTask")
}
useEffect(() => {
console.log("useEffect");
getDictionary("2").then(state => {
setStateMap(state)
})
getDictionary("1").then(priority => {
console.log(priority)
setPriorityMap(priority)
})
}, [])
@ -87,10 +85,10 @@ const TaskCount = (props) => {
<div style={{margin: "20px"}}>
<h2>TODO日{currentDay && dayjs(currentDay).format(DATE_FORMAT)}代办
{currentDay && <a onClick={todoDayDetail}>详情</a>}
{!dayjs(currentDay).isSame(today, 'date') &&
<Fragment><Divider direction='vertical'/><a onClick={() => backToToday()}>回到今天</a></Fragment>}
{!dayjs(currentMonth).isSame(today, 'months') &&
<Fragment><Divider direction='vertical'/><a onClick={() => backToToday()}>回到当月</a></Fragment>}
</h2>
{taskCount.filter(taskC => dayjs(taskC.todoDay).isSame(dayjs(currentDay), 'date'))?.map(taskC => {
{taskCount?.filter(taskC => dayjs(taskC.todoDay).isSame(dayjs(currentDay), 'date'))?.map(taskC => {
return <Fragment>
<h3>任务状态</h3>
{

View File

@ -0,0 +1,13 @@
.cal-day-circle {
width: 30px;
height: 30px;
border-radius: 20px;
border-style: solid;
display: flex;
justify-content: center;
align-items: center;
flex-direction: row;
flex-wrap: nowrap;
align-content: normal
}

View File

@ -1,82 +1,129 @@
import {Calendar, Tag} from "antd-mobile";
import {Calendar, Cascader, Tag} from "antd-mobile";
import dayjs from "dayjs";
import {TaskCount} from "../TaskCount";
import React, {Fragment, useEffect, useLayoutEffect, useRef} from "react";
import {
dateStartUtcFormat,
nextDateStartUtcFormat,
} from "../../utils/timeFormatUtil";
import {getTaskCount} from "../../utils";
import React, {Fragment, useEffect, useLayoutEffect, useMemo, useRef, useState} from "react";
import {getTaskByPid, getTaskCount} from "../../utils";
import {FrownFill, SmileFill} from "antd-mobile-icons";
import {NEW, OVERDUE, UNDER_WAY} from "../../utils/commonConstant";
import {dateStartUtcFormat} from "../../utils/timeFormatUtil";
import './index.css'
const ToDoCal = (props) => {
const today = new Date()
const calRef = useRef(null);
const [currentDay, setCurrentDay] = React.useState(new Date())
const today = new Date()
const [allDay,setAllDay] = React.useState([])
const [taskCount,setTaskCount] = React.useState([])
function listTaskCount(){
if (allDay.length === 0){
return
}
getTaskCount(dateStartUtcFormat(allDay[0]),
nextDateStartUtcFormat(allDay[allDay.length-1]))
.then(res => {
setTaskCount(res)
})
}
useLayoutEffect(()=>{
console.log("useLayoutEffect",allDay)
const [currentMonth, setCurrentMonth] = React.useState(dayjs().set("date", 1).format('YYYY-MM-DD'));
// Map keyvalue
const [listTaskMap, setListTaskMap] = useState(new Map());
// useLayoutEffect
useEffect(() => {
console.log("getCurrentShowDay", getCurrentShowDay())
const {startDay, endDay} = getCurrentShowDay();
listTaskCount(startDay, endDay);
}, [currentMonth])
let loading = false
async function listTaskCount(start, end) {
if (loading) {
return;
}
loading = true;
if (listTaskMap.has(currentMonth)) return
const res = await getTaskCount(start, end);
setListTaskMap(prevState => {
const newMap = new Map(prevState);
newMap.set(currentMonth, res);
return newMap;
})
loading = false;
}
/*
获取当前展示的日期
*/
function getCurrentShowDay() {
const firstDay = dayjs(currentMonth).set("date", 1);
const startDay = firstDay.subtract(firstDay.day(), 'day');
const endDay = startDay.add(6 * 7, 'day');
return {startDay: dateStartUtcFormat(startDay), endDay: dateStartUtcFormat(endDay)};
}
listTaskCount();
},[])
function backToToday() {
calRef.current.jumpToToday();
setCurrentDay(today)
}
return (
<Fragment>
<Calendar
ref={calRef}
selectionMode='single'
renderLabel={date => {
allDay.push(date)
//
return taskCount.filter(taskC => dayjs(taskC.todoDay).isSame(dayjs(date), 'date'))?.map(taskC => {
// renderLabel={date => {
// //
// return listTaskMap?.get(currentMonth)?.filter(taskC => dayjs(taskC.todoDay).isSame(dayjs(date), 'date'))?.map(taskC => {
// //
// // Object.keys()
// // Object.entries()
// if (Object.keys(taskC.state).length > 0) {
// console.log("taskC.state", taskC.state)
// if (taskC.state[OVERDUE]) {
// return <FrownFill color='var(--adm-color-danger)'/>;
// }
// // warn
// if (taskC.state[NEW] || taskC.state[UNDER_WAY]) {
// return <SmileFill color='var(--adm-color-warning)'/>;
// }
// // 绿
// return <SmileFill color='var(--adm-color-success)'/>;
// }
// })
//
// // if (dayjs(date).isSame(today, 'day')) return ''
// // if (date.getDay() === 0 || date.getDay() === 6) {
// // return ''
// // }
// }}
renderDate={date => {
return listTaskMap?.get(currentMonth)?.filter(taskC => dayjs(taskC.todoDay).isSame(dayjs(date), 'date'))?.map(taskC => {
//
// Object.keys()
// Object.entries()
if (Object.keys(taskC.state).length > 0) {
console.log("taskC.state", taskC.state)
if (taskC.state[OVERDUE]) {
return <FrownFill color='var(--adm-color-danger)'/>;
return <div className='cal-day-circle' style={{
borderColor: 'var(--adm-color-danger)',
}}><span>{dayjs(date).date()}</span></div>;
}
// warn
if (taskC.state[NEW] || taskC.state[UNDER_WAY]) {
return <SmileFill color='var(--adm-color-warning)'/>;
return <div className='cal-day-circle' style={{
borderColor: 'var(--adm-color-warning)',
}}><span>{dayjs(date).date()}</span></div>;
}
// 绿
return <SmileFill color='var(--adm-color-success)'/>;
return <div className='cal-day-circle' style={{
borderColor: 'var(--adm-color-success)',
}}><span>{dayjs(date).date()}</span></div>;
}
return <span>{dayjs(date).date()}</span>;
})
// if (dayjs(date).isSame(today, 'day')) return ''
// if (date.getDay() === 0 || date.getDay() === 6) {
// return ''
// }
}}
// renderDate={date=>{
// return <span style={{"color":"red"}}>{dayjs(date).date()}</span>
// }}
defaultValue={currentDay}
onChange={val => {
setCurrentDay(val)
}}
onPageChange={(year, month) => {
console.log(year, month)
setCurrentMonth(`${year}-${month}-01`)
}}
/>
<TaskCount currentDay={currentDay} taskCount={taskCount} today={today} backToToday={backToToday}/>
<TaskCount currentDay={currentDay} taskCount={listTaskMap?.get(currentMonth)} today={today}
currentMonth={currentMonth}
backToToday={backToToday}/>
</Fragment>
)
}

View File

@ -4,7 +4,6 @@ import {requestUtil} from "./requestUtil";
export const getDictionary = async (typeId) => {
let item1 = localStorage.getItem("huayu-dict-" + typeId);
console.log("item1: ", item1);
if (item1) {
return new Map(JSON.parse(item1).map(item => {
return [item.itemCode, item]