feat:日历头样式,更多显示,打包处理

This commit is contained in:
1708-huayu 2025-08-19 18:52:33 +08:00
parent 34b85a177c
commit ae11147281
18 changed files with 189 additions and 53 deletions

View File

@ -1,2 +1,2 @@
NEXT_PUBLIC_TODO_REQUEST_URL=https://www.huaruyu.com/todo-server
NEXT_PUBLIC_SECURITY_REQUEST_URL=https://www.huaruyu.com/security-server
NEXT_PUBLIC_TODO_REQUEST_URL=/todoWeb
NEXT_PUBLIC_SECURITY_REQUEST_URL=/securityWeb

View File

@ -1,14 +1,15 @@
```shell
scp -r out/ shixiaohua@10.104.11.99:/home/shixiaohua/docker/todo-web
scp -r cert/ shixiaohua@10.104.11.99:/home/shixiaohua/docker/todo-web
scp nginx.conf shixiaohua@10.104.11.99:/home/shixiaohua/docker/todo-web
scp Dockerfile shixiaohua@10.104.11.99:/home/shixiaohua/docker/todo-web
scp -r out/ shixiaohua@10.104.11.101:/home/shixiaohua/docker/todo-web
scp -r cert/ shixiaohua@10.104.11.101:/home/shixiaohua/docker/todo-web
scp nginx.conf shixiaohua@10.104.11.101:/home/shixiaohua/docker/todo-web
scp Dockerfile shixiaohua@10.104.11.101:/home/shixiaohua/docker/todo-web
ssh shixiaohua@10.104.11.99
```
docker操作
```shell
scp nginx.conf shixiaohua@10.104.11.101:/home/shixiaohua/docker/todo-web
docker stop task-manager-nginx
docker rm task-manager-nginx
docker rmi task-manager-nginx

View File

@ -13,6 +13,11 @@ events {
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
limit_req_zone $binary_remote_addr zone=general_limit:10m rate=20r/s;
limit_req_zone $binary_remote_addr zone=api_limit:10m rate=5r/s;
log_format blocked '$time_local|$remote_addr|$request|$status|$http_referer';
# HTTPS 服务器监听端口
# 443
# HTTP 服务器监听端口
@ -90,6 +95,19 @@ http {
client_body_buffer_size 16k;
client_max_body_size 100M;
}
location ^~ /todoWeb/ {
# 预检请求的处理
if ($request_method = 'OPTIONS') {
return 204;
}
# rewrite ^/todo-server/(.*)$ /$1 break;
proxy_pass http://localhost:8092/;
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
client_body_buffer_size 16k;
client_max_body_size 100M;
}
location ^~ /security-server/ {
# 预检请求的处理
if ($request_method = 'OPTIONS') {
@ -103,6 +121,20 @@ http {
client_body_buffer_size 16k;
client_max_body_size 100M;
}
location ^~ /securityWeb/ {
# 预检请求的处理
if ($request_method = 'OPTIONS') {
return 204;
}
# rewrite ^/security-server/(.*)$ /$1 break;
proxy_pass http://localhost:8091/;
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
client_body_buffer_size 16k;
client_max_body_size 100M;
}
location /task/ {
# 预检请求的处理

View File

@ -13,6 +13,11 @@ events {
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
limit_req_zone $binary_remote_addr zone=general_limit:10m rate=20r/s;
limit_req_zone $binary_remote_addr zone=api_limit:10m rate=5r/s;
log_format blocked '$time_local|$remote_addr|$request|$status|$http_referer';
# HTTPS 服务器监听端口
# 443
# HTTP 服务器监听端口
@ -90,6 +95,19 @@ http {
client_body_buffer_size 16k;
client_max_body_size 100M;
}
location ^~ /todoWeb/ {
# 预检请求的处理
if ($request_method = 'OPTIONS') {
return 204;
}
# rewrite ^/todo-server/(.*)$ /$1 break;
proxy_pass http://huayu-platform-todo:8092/;
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
client_body_buffer_size 16k;
client_max_body_size 100M;
}
location ^~ /security-server/ {
# 预检请求的处理
if ($request_method = 'OPTIONS') {
@ -103,6 +121,20 @@ http {
client_body_buffer_size 16k;
client_max_body_size 100M;
}
location ^~ /securityWeb/ {
# 预检请求的处理
if ($request_method = 'OPTIONS') {
return 204;
}
# rewrite ^/security-server/(.*)$ /$1 break;
proxy_pass http://huayu-platform-security:8091/;
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
client_body_buffer_size 16k;
client_max_body_size 100M;
}
location /task/ {
# 预检请求的处理

View File

@ -12,6 +12,11 @@ const nextConfig = {
distDir: 'docker/out',
// 严格模式下react-beautiful-dnd无法使用
reactStrictMode:false,
eslint: {
// Warning: This allows production builds to successfully complete even if
// your project has ESLint errors.
ignoreDuringBuilds: true,
},
};
export default nextConfig;

View File

@ -1,10 +1,5 @@
import type {Metadata} from "next";
import "@/ui/globals.css";
export const metadata: Metadata = {
title: "马上行计划管理",
description: "马上行计划管理",
};
/**
* Root Layout (Required)
* @param children
@ -20,7 +15,7 @@ export default function RootLayout({
<head>
<title></title>
<link rel="icon" href="/favicon.ico"/>
<script src="/static/iconfont.js"></script>
<script src="/static/iconfont.js" async ></script>
{/*FOUCFlash of Unstyled Content*/}
{/*<link rel="preload" href="https://cdn.jsdelivr.net/npm/antd/dist/antd.min.css" as="style"/>*/}
{/*<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/antd/dist/antd.min.css"/>*/}

View File

@ -5,9 +5,9 @@ import {useEffect} from "react";
export default function Home() {
const {replace} = useRouter();
useEffect(()=>{
const pathName = usePathname()
const searchParams = useSearchParams()
useEffect(()=>{
console.log({pathName},{searchParams})
if(localStorage.getItem('platform-security')){
if (!pathName){
@ -21,7 +21,7 @@ export default function Home() {
}else {
replace("/login")
}
},[])
},)
dayjs.locale('zh-cn')
return (
<main className="flex min-h-screen flex-col p-6">

View File

@ -66,7 +66,7 @@ export default function Layout({children}: { children: React.ReactNode }) {
// @ts-ignore
document.getElementById('tenLeft').style.fontSize = divHeight/6*4 + 'px';
refreshDate()
}, [useContext(LocalContext)]);
}, [data]);
return (
<div>
<div className='firstRow' style={{display: 'flex'}}>

View File

@ -0,0 +1,20 @@
import React, {Fragment} from 'react';
import {DateHeaderProps} from "react-big-calendar";
import {solarToLunar} from "lunar-calendar";
import {lunarDateShow} from "@/utils/timeFormatUtil";
// 定义为 React 函数组件
const CalHeader: React.FC<DateHeaderProps> = ({date, label, drilldownView, onDrillDown}) => {
if (!drilldownView) {
return <span>{label}</span>
}
return (
<div className="rbc-button-link " style={{display: "flex", justifyContent: "space-between"}}
onClick={onDrillDown}>
<div>{label}</div>
<div>{lunarDateShow(date)}</div>
</div>
)
};
export default CalHeader;

View File

@ -159,7 +159,7 @@ const DiaryOption = (props: SelectDiary) => {
})
})
setDiaryReduceList(returnResult.reverse());
}, [diaryList, currentIndex]);
}, [diaryList, currentIndex,props.taskId]);
const listRef = useRef<ListRef>(null);
const onScroll = (e: React.UIEvent<HTMLElement, UIEvent>) => {

View File

@ -183,7 +183,7 @@ const CronGenerator: React.FC<CronGeneratorProps> = ({setCronFunction,setExpecte
console.log({fullCronExpression})
setCanReadCron(cronToChinese(fullCronExpression))
}
}, [fullCronExpression]);
}, [fullCronExpression,cron]);
const onClickConfirmCron = () => {
if (fullCronExpression) {

View File

@ -206,7 +206,7 @@ const TaskRemindComponent = (props: ITaskRemind) => {
) : (
props.remindTypeList.map((remindType, index) => (
// <div key={index}>{remindType.split(",").join(", ")}</div>
<Fragment>
<Fragment key={remindType}>
<ConfigProvider
theme={{
components: {

View File

@ -103,7 +103,7 @@ const TeamMember = (props: { taskId: string, closeOpen?: () => void, reloadData?
return () => {
isMounted = false;
};
}, [open])
}, [open,props.taskId])
const removeTeam = (teamMember: TeamMemberVO) => {
removeTeamAPI(teamMember).then(res => {
if (res.data.status.success) {

View File

@ -11,6 +11,12 @@ declare module 'lunar-calendar' {
lunarDayName: string;
solarTerm: string;
// 其他农历字段...
// 二十四节气
term:string;
// 农历节日
lunarFestival:string;
// 公历节日
solarFestival:string;
}
export function solarToLunar(

View File

@ -1,15 +1,16 @@
'use client'
import React, {Fragment, useContext, useEffect, useState} from "react";
import {Button, Checkbox, CheckboxOptionType, DatePicker, MenuProps, message, Select, Space} from "antd";
import {Button, Checkbox, CheckboxOptionType, DatePicker, MenuProps, message, Popconfirm, Select, Space} from "antd";
import {usePathname, useRouter} from "next/navigation";
import {DetailModelForm} from "@/ui/task/project/DetailModelForm";
import {OPERATION_BUTTON_TYPE, taskStateList} from "@/lib/task/project/data";
import {deleteTask, OPERATION_BUTTON_TYPE, taskStateList} from "@/lib/task/project/data";
import style from '@/ui/task/TitleOperation.module.css'
import LocalContext from "@/ui/LocalContent";
import {RequestDateType} from "@/ui/task/RequestDateType";
import dayjs, {Dayjs} from "dayjs";
import {useSearchParams} from "next/dist/client/components/navigation";
import Dropdown from "antd/es/dropdown/dropdown";
import {QuestionCircleOutlined} from "@ant-design/icons";
interface TitleOperationProps {
setTaskState: (value: string) => void;
@ -42,7 +43,7 @@ export const TitleOperation: React.FC<TitleOperationProps> = ({
expectStartTimeParseResult[0] && expectStartTimeParseResult[0].value ? dayjs(expectStartTimeParseResult[0].value.toString()) : undefined,
expectStartTimeParseResult[1] && expectStartTimeParseResult[1].value ? dayjs(expectStartTimeParseResult[1].value.toString()) : undefined
];
const [nickName,setNickName]=useState("微信用户")
const [nickName, setNickName] = useState("微信用户")
const typeList: CheckboxOptionType<string>[] = [
{label: '计划', value: '0,1,2,3'},
{label: '打卡', value: '4'},
@ -61,7 +62,7 @@ export const TitleOperation: React.FC<TitleOperationProps> = ({
useEffect(() => {
let userMessage = localStorage.getItem('user-message');
if (userMessage){
if (userMessage) {
let parse = JSON.parse(userMessage);
setNickName(parse.nickname)
}
@ -69,8 +70,8 @@ export const TitleOperation: React.FC<TitleOperationProps> = ({
const onClick: MenuProps['onClick'] = ({key}) => {
if (key == "1") {
localStorage.removeItem('platform-security')
replace(`/login`)
// localStorage.removeItem('platform-security')
// replace(`/login`)
} else if (key == "2") {
replace(pathName)
setPathParam(undefined)
@ -80,13 +81,33 @@ export const TitleOperation: React.FC<TitleOperationProps> = ({
const items: MenuProps['items'] = [
{
label: '退出登录',
label: <Popconfirm
title="退出登录"
description="确认要退出登录?"
icon={<QuestionCircleOutlined style={{color: 'red'}}/>}
okText="确认"
cancelText="取消"
onConfirm={() => {
localStorage.removeItem('platform-security')
replace(`/login`)
}}
><a>退</a></Popconfirm>,
key: '1',
},
];
const itemsPid: MenuProps['items'] = [
{
label: '退出登录',
label: <Popconfirm
title="退出登录"
description="确认要退出登录?"
icon={<QuestionCircleOutlined style={{color: 'red'}}/>}
okText="确认"
cancelText="取消"
onConfirm={() => {
localStorage.removeItem('platform-security')
replace(`/login`)
}}
><a>退</a></Popconfirm>,
key: '1',
},
{
@ -142,16 +163,16 @@ export const TitleOperation: React.FC<TitleOperationProps> = ({
allowClear
style={{minWidth: '100px'}}
placeholder="任务状态"
defaultValue={data.taskState!=''&&data.taskState.split(",").length>0?data.taskState.split(","):[]}
defaultValue={data.taskState != '' && data.taskState.split(",").length > 0 ? data.taskState.split(",") : []}
onChange={(value) => {
console.log('onChange',{value})
if(value.length == 0){
console.log('onChange', {value})
if (value.length == 0) {
setTaskState("")
}else {
} else {
setTaskState(value.join(','))
}
}}
onClear={()=>{
onClear={() => {
console.log('onChange,点击了清除无效果')
setTaskState("")
}}
@ -209,8 +230,8 @@ export const TitleOperation: React.FC<TitleOperationProps> = ({
}
</Space>
<Dropdown menu={{items: pathParam ? itemsPid : items, onClick}}>
<div style={{display:"flex", height: "32px", alignItems: "center"}}>
<svg style={{ height: "32px",width: "32px",marginRight:"0.5rem" }} className="icon" aria-hidden="true">
<div style={{display: "flex", height: "32px", alignItems: "center"}}>
<svg style={{height: "32px", width: "32px", marginRight: "0.5rem"}} className="icon" aria-hidden="true">
<use xlinkHref="#icon-user__easyico"></use>
</svg>
<span>{nickName}</span>

View File

@ -32,12 +32,17 @@ import {editClickRecordRangeAPI} from "@/components/service/ScheduleTask";
import {CopyOutlined, ExclamationCircleFilled, LoadingOutlined} from "@ant-design/icons";
import {copyToClipboard} from "@/lib/copyToClipboard";
import {solarToLunar} from "lunar-calendar";
import CalendarHeader from "antd/es/calendar/Header";
import CalHeader from "@/components/CalHeader";
import {lunarDateShow} from "@/utils/timeFormatUtil";
const {confirm} = Modal;
/**
* https://github.com/jquense/react-big-calendar?tab=readme-ov-file
* @constructor
*/
const localizer = dayjsLocalizer(dayjs)
const DragAndDropCalendar = withDragAndDrop(Calendar)
const CalShow: React.FC = () => {
dayjs.locale('zh-cn')
@ -75,14 +80,7 @@ const CalShow: React.FC = () => {
}
})
const dateFormat = (date: Date, culture?: Culture, localizer?: DateLocalizer) => {
const solarDate = new Date(date);
const lunarDate = solarToLunar(
solarDate.getFullYear(),
solarDate.getMonth() + 1,
solarDate.getDate()
);
console.log({lunarDate})
return `${solarDate.getDate()}/农历:${lunarDate.lunarMonthName}-${lunarDate.lunarDayName}`;
return `${date.getDate()}/${lunarDateShow(date)}`;
};
const handleViewChange = (newView: View) => {
setView(newView);
@ -177,11 +175,11 @@ const CalShow: React.FC = () => {
end: dayjs(taskState.expectedEndTime).toDate(),
title: <Fragment><TaskNameAndIcon task={taskState}/>
<div>
{taskState.description && <CopyOutlined onClick={(e) => {
{view != 'month' && taskState.description && <CopyOutlined onClick={(e) => {
e.preventDefault(); // 阻止默认行为(如果有)
e.stopPropagation(); // 阻止事件冒泡
copyToClipboard(taskState.description)
}}/>} {taskState.description}</div>
}}/>} {view != 'month' && taskState.description}</div>
</Fragment>,
// style: {
// backgroundColor: 'green',
@ -381,7 +379,7 @@ const CalShow: React.FC = () => {
range.start = rangeLet[0];
// }
// if (range.end.valueOf() < rangeLet[0].valueOf()) {
range.end = dayjs(rangeLet[0]).add(1,'d').toDate()
range.end = dayjs(rangeLet[0]).add(1, 'd').toDate()
// }
}
// 为周的时候类型为数组,周一到周日七天
@ -390,7 +388,7 @@ const CalShow: React.FC = () => {
range.start = rangeLet[0];
// }
// if (range.end.valueOf() < rangeLet[6].valueOf()) {
range.end = dayjs(rangeLet[6]).add(1,'d').toDate()
range.end = dayjs(rangeLet[6]).add(1, 'd').toDate()
// }
}
// 为月的时候类型为对象
@ -399,7 +397,7 @@ const CalShow: React.FC = () => {
range.start = rangeLet.start
// }
// if (range.end.valueOf() < rangeLet.end.valueOf()) {
range.end = dayjs(rangeLet.end).add(1,'d').toDate()
range.end = dayjs(rangeLet.end).add(1, 'd').toDate()
// }
}
@ -426,7 +424,7 @@ const CalShow: React.FC = () => {
messages={calMessages}
formats={{
dayFormat: dateFormat,
dateFormat: dateFormat,
// dateFormat: dateFormat,
monthHeaderFormat: (date) => {
const solarDate = new Date(date);
const lunarDate = solarToLunar(
@ -464,6 +462,13 @@ const CalShow: React.FC = () => {
resizable
onEventResize={moveEvent}
onEventDrop={moveEvent}
// 组件设置
components={
{
month: {
dateHeader: CalHeader
}
}}
/>
</div>
}

View File

@ -123,7 +123,7 @@ export const DetailForm: React.FC<DetailFormProps> = (props) => {
if (props.operationId === OPERATION_BUTTON_TYPE.ADD_CHILD) {
addTask(request).then(response => {
console.log('response', response)
if (response.status.success) {
if (response.data.status.success) {
message.success("添加任务成功:" + response.data)
props.handleCancel()
}
@ -140,11 +140,11 @@ export const DetailForm: React.FC<DetailFormProps> = (props) => {
}
updateTask(request).then(response => {
console.log('response', response)
if (response.status.success) {
if (response.data.status.success) {
message.success("修改任务成功:" + response.data)
props.handleCancel()
}else {
message.error(response.status.message)
message.error(response.data.status.message)
}
}
)

View File

@ -1,5 +1,6 @@
import dayjs, { Dayjs, isDayjs } from "dayjs";
import utc from "dayjs/plugin/utc";
import {solarToLunar} from "lunar-calendar";
dayjs.extend(utc)
const DATE_FORMAT = "YYYY-MM-DD"
// 到秒没啥意义
@ -236,8 +237,26 @@ function dayjsWeek(day: Dayjs): string {
}
return ""
}
function lunarDateShow(date:Date){
const lunarDate = solarToLunar(
date.getFullYear(),
date.getMonth() + 1,
date.getDate()
);
if(lunarDate.term){
return lunarDate.term;
}
if(lunarDate.lunarFestival){
return lunarDate.lunarFestival;
}
if(lunarDate.solarFestival){
return lunarDate.solarFestival
}
return lunarDate.lunarMonthName+lunarDate.lunarDayName;
}
export {
DATE_TIME_FORMAT, DATE_FORMAT, DATE_TIME_FORMAT_SIMPLE,
dayStartUtcFormat, nextDayStartUtcFormat, betweenTime,
dateStartUtcFormat, nextDateStartUtcFormat, cronToChinese, dayjsWeek
dateStartUtcFormat, nextDateStartUtcFormat, cronToChinese, dayjsWeek,lunarDateShow
}