Compare commits
No commits in common. "5eaf84df480b0ed2f4c6de0ea1f54caec7dec232" and "2cc85e67dce525bc56d597feb6c5fbc0fab86781" have entirely different histories.
5eaf84df48
...
2cc85e67dc
|
@ -1,2 +1,2 @@
|
||||||
NEXT_PUBLIC_TODO_REQUEST_URL=/todoWeb
|
NEXT_PUBLIC_TODO_REQUEST_URL=https://www.huaruyu.com/todo-server
|
||||||
NEXT_PUBLIC_SECURITY_REQUEST_URL=/securityWeb
|
NEXT_PUBLIC_SECURITY_REQUEST_URL=https://www.huaruyu.com/security-server
|
|
@ -1,15 +1,14 @@
|
||||||
```shell
|
```shell
|
||||||
scp -r out/ shixiaohua@10.104.11.101:/home/shixiaohua/docker/todo-web
|
scp -r out/ shixiaohua@10.104.11.99:/home/shixiaohua/docker/todo-web
|
||||||
scp -r cert/ shixiaohua@10.104.11.101:/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.101:/home/shixiaohua/docker/todo-web
|
scp nginx.conf shixiaohua@10.104.11.99:/home/shixiaohua/docker/todo-web
|
||||||
scp Dockerfile shixiaohua@10.104.11.101:/home/shixiaohua/docker/todo-web
|
scp Dockerfile shixiaohua@10.104.11.99:/home/shixiaohua/docker/todo-web
|
||||||
ssh shixiaohua@10.104.11.99
|
ssh shixiaohua@10.104.11.99
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
docker操作
|
docker操作
|
||||||
```shell
|
```shell
|
||||||
scp nginx.conf shixiaohua@10.104.11.101:/home/shixiaohua/docker/todo-web
|
|
||||||
docker stop task-manager-nginx
|
docker stop task-manager-nginx
|
||||||
docker rm task-manager-nginx
|
docker rm task-manager-nginx
|
||||||
docker rmi task-manager-nginx
|
docker rmi task-manager-nginx
|
||||||
|
@ -31,9 +30,4 @@ docker run -d -p 3001:80 -p 3002:443 --network task-manager --restart unless-sto
|
||||||
# 复制证书到云服务器
|
# 复制证书到云服务器
|
||||||
scp -r cert/ root@121.36.71.28:/usr/local/software/nginx-1.28.0/
|
scp -r cert/ root@121.36.71.28:/usr/local/software/nginx-1.28.0/
|
||||||
|
|
||||||
|
|
||||||
scp -r out/ root@121.36.71.28:/usr/share/nginx/html
|
|
||||||
|
|
||||||
cp -rf ./* ../
|
|
||||||
|
|
||||||
```
|
```
|
|
@ -13,11 +13,6 @@ events {
|
||||||
http {
|
http {
|
||||||
include /etc/nginx/mime.types;
|
include /etc/nginx/mime.types;
|
||||||
default_type application/octet-stream;
|
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 服务器监听端口
|
# HTTPS 服务器监听端口
|
||||||
# 443
|
# 443
|
||||||
# HTTP 服务器监听端口
|
# HTTP 服务器监听端口
|
||||||
|
@ -72,28 +67,7 @@ http {
|
||||||
try_files $uri $uri.html $uri/ =404;
|
try_files $uri $uri.html $uri/ =404;
|
||||||
# try_files $uri $uri/ =404;
|
# try_files $uri $uri/ =404;
|
||||||
}
|
}
|
||||||
# 第二个页面的配置
|
|
||||||
location /todo {
|
|
||||||
# 关键配置:禁用重定向中的端口和绝对路径
|
|
||||||
absolute_redirect off;
|
|
||||||
port_in_redirect off;
|
|
||||||
|
|
||||||
# 指定根目录
|
|
||||||
alias /usr/share/nginx/html/todo;
|
|
||||||
index index.html index.htm;
|
|
||||||
|
|
||||||
# 正确的文件查找逻辑:所有路由都返回 index.html
|
|
||||||
try_files $uri $uri/ /todo/index.html;
|
|
||||||
|
|
||||||
# 安全头部
|
|
||||||
add_header X-Frame-Options "SAMEORIGIN" always;
|
|
||||||
add_header X-Content-Type-Options "nosniff" always;
|
|
||||||
|
|
||||||
# 确保不会重定向到带端口的URL
|
|
||||||
add_header X-Forwarded-Host $host;
|
|
||||||
add_header X-Forwarded-Port 443;
|
|
||||||
add_header X-Forwarded-Proto https;
|
|
||||||
}
|
|
||||||
# 第二个页面的配置
|
# 第二个页面的配置
|
||||||
location ^~ /mobile/ {
|
location ^~ /mobile/ {
|
||||||
# index index.html index.htm;
|
# index index.html index.htm;
|
||||||
|
@ -116,9 +90,6 @@ http {
|
||||||
client_body_buffer_size 16k;
|
client_body_buffer_size 16k;
|
||||||
client_max_body_size 100M;
|
client_max_body_size 100M;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
location ^~ /security-server/ {
|
location ^~ /security-server/ {
|
||||||
# 预检请求的处理
|
# 预检请求的处理
|
||||||
if ($request_method = 'OPTIONS') {
|
if ($request_method = 'OPTIONS') {
|
||||||
|
@ -132,20 +103,6 @@ http {
|
||||||
client_body_buffer_size 16k;
|
client_body_buffer_size 16k;
|
||||||
client_max_body_size 100M;
|
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/ {
|
location /task/ {
|
||||||
# 预检请求的处理
|
# 预检请求的处理
|
||||||
|
|
|
@ -13,11 +13,6 @@ events {
|
||||||
http {
|
http {
|
||||||
include /etc/nginx/mime.types;
|
include /etc/nginx/mime.types;
|
||||||
default_type application/octet-stream;
|
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 服务器监听端口
|
# HTTPS 服务器监听端口
|
||||||
# 443
|
# 443
|
||||||
# HTTP 服务器监听端口
|
# HTTP 服务器监听端口
|
||||||
|
@ -95,19 +90,6 @@ http {
|
||||||
client_body_buffer_size 16k;
|
client_body_buffer_size 16k;
|
||||||
client_max_body_size 100M;
|
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/ {
|
location ^~ /security-server/ {
|
||||||
# 预检请求的处理
|
# 预检请求的处理
|
||||||
if ($request_method = 'OPTIONS') {
|
if ($request_method = 'OPTIONS') {
|
||||||
|
@ -121,20 +103,6 @@ http {
|
||||||
client_body_buffer_size 16k;
|
client_body_buffer_size 16k;
|
||||||
client_max_body_size 100M;
|
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/ {
|
location /task/ {
|
||||||
# 预检请求的处理
|
# 预检请求的处理
|
||||||
|
|
|
@ -1,11 +1,5 @@
|
||||||
/** @type {import('next').NextConfig} */
|
/** @type {import('next').NextConfig} */
|
||||||
const isProduction = process.env.NODE_ENV === 'production'
|
|
||||||
const nextConfig = {
|
const nextConfig = {
|
||||||
// 核心配置:构建前清空输出目录
|
|
||||||
cleanDistDir: true,
|
|
||||||
basePath: isProduction ? "/todo" : '',
|
|
||||||
// 静态文件前缀
|
|
||||||
assetPrefix: isProduction ? "/todo" : '',
|
|
||||||
// Middleware cannot be used with "output: export".
|
// Middleware cannot be used with "output: export".
|
||||||
output: 'export',
|
output: 'export',
|
||||||
// Optional: Change links `/me` -> `/me/` and emit `/me.html` -> `/me/index.html`
|
// Optional: Change links `/me` -> `/me/` and emit `/me.html` -> `/me/index.html`
|
||||||
|
@ -13,15 +7,11 @@ const nextConfig = {
|
||||||
|
|
||||||
// Optional: Prevent automatic `/me` -> `/me/`, instead preserve `href`
|
// Optional: Prevent automatic `/me` -> `/me/`, instead preserve `href`
|
||||||
// skipTrailingSlashRedirect: true,
|
// skipTrailingSlashRedirect: true,
|
||||||
|
|
||||||
// Optional: Change the output directory `out` -> `dist`
|
// Optional: Change the output directory `out` -> `dist`
|
||||||
distDir: 'docker/outd',
|
distDir: 'docker/out',
|
||||||
// 严格模式下react-beautiful-dnd无法使用
|
// 严格模式下react-beautiful-dnd无法使用
|
||||||
reactStrictMode:false,
|
reactStrictMode:false,
|
||||||
eslint: {
|
|
||||||
// Warning: This allows production builds to successfully complete even if
|
|
||||||
// your project has ESLint errors.
|
|
||||||
ignoreDuringBuilds: true,
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export default nextConfig;
|
export default nextConfig;
|
||||||
|
|
|
@ -16,7 +16,6 @@
|
||||||
"axios": "^1.6.8",
|
"axios": "^1.6.8",
|
||||||
"dayjs": "^1.11.13",
|
"dayjs": "^1.11.13",
|
||||||
"js-cookie": "^3.0.5",
|
"js-cookie": "^3.0.5",
|
||||||
"lunar-calendar": "^0.1.4",
|
|
||||||
"next": "14.2.29",
|
"next": "14.2.29",
|
||||||
"postcss": "8.4.31",
|
"postcss": "8.4.31",
|
||||||
"react": "^18",
|
"react": "^18",
|
||||||
|
@ -4841,14 +4840,6 @@
|
||||||
"node": "14 || >=16.14"
|
"node": "14 || >=16.14"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/lunar-calendar": {
|
|
||||||
"version": "0.1.4",
|
|
||||||
"resolved": "https://registry.npmmirror.com/lunar-calendar/-/lunar-calendar-0.1.4.tgz",
|
|
||||||
"integrity": "sha512-5r87vbg5yg56z/jkf3A+Ur+ZggUTiJw1VATT9P7RELQgWcTNhfJ+OLkNYroSna6r65bMqyaAgapo9vRN40L75A==",
|
|
||||||
"engines": {
|
|
||||||
"node": "*"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/luxon": {
|
"node_modules/luxon": {
|
||||||
"version": "3.4.4",
|
"version": "3.4.4",
|
||||||
"resolved": "https://registry.npmmirror.com/luxon/-/luxon-3.4.4.tgz",
|
"resolved": "https://registry.npmmirror.com/luxon/-/luxon-3.4.4.tgz",
|
||||||
|
@ -11509,11 +11500,6 @@
|
||||||
"resolved": "https://registry.npmmirror.com/lru-cache/-/lru-cache-10.2.0.tgz",
|
"resolved": "https://registry.npmmirror.com/lru-cache/-/lru-cache-10.2.0.tgz",
|
||||||
"integrity": "sha512-2bIM8x+VAf6JT4bKAljS1qUWgMsqZRPGJS6FSahIMPVvctcNhyVp7AJu7quxOW9jwkryBReKZY5tY5JYv2n/7Q=="
|
"integrity": "sha512-2bIM8x+VAf6JT4bKAljS1qUWgMsqZRPGJS6FSahIMPVvctcNhyVp7AJu7quxOW9jwkryBReKZY5tY5JYv2n/7Q=="
|
||||||
},
|
},
|
||||||
"lunar-calendar": {
|
|
||||||
"version": "0.1.4",
|
|
||||||
"resolved": "https://registry.npmmirror.com/lunar-calendar/-/lunar-calendar-0.1.4.tgz",
|
|
||||||
"integrity": "sha512-5r87vbg5yg56z/jkf3A+Ur+ZggUTiJw1VATT9P7RELQgWcTNhfJ+OLkNYroSna6r65bMqyaAgapo9vRN40L75A=="
|
|
||||||
},
|
|
||||||
"luxon": {
|
"luxon": {
|
||||||
"version": "3.4.4",
|
"version": "3.4.4",
|
||||||
"resolved": "https://registry.npmmirror.com/luxon/-/luxon-3.4.4.tgz",
|
"resolved": "https://registry.npmmirror.com/luxon/-/luxon-3.4.4.tgz",
|
||||||
|
|
|
@ -18,7 +18,6 @@
|
||||||
"axios": "^1.6.8",
|
"axios": "^1.6.8",
|
||||||
"dayjs": "^1.11.13",
|
"dayjs": "^1.11.13",
|
||||||
"js-cookie": "^3.0.5",
|
"js-cookie": "^3.0.5",
|
||||||
"lunar-calendar": "^0.1.4",
|
|
||||||
"next": "14.2.29",
|
"next": "14.2.29",
|
||||||
"postcss": "8.4.31",
|
"postcss": "8.4.31",
|
||||||
"react": "^18",
|
"react": "^18",
|
||||||
|
|
|
@ -1,5 +1,10 @@
|
||||||
|
import type {Metadata} from "next";
|
||||||
import "@/ui/globals.css";
|
import "@/ui/globals.css";
|
||||||
|
|
||||||
|
export const metadata: Metadata = {
|
||||||
|
title: "马上行计划管理",
|
||||||
|
description: "马上行计划管理",
|
||||||
|
};
|
||||||
/**
|
/**
|
||||||
* Root Layout (Required)
|
* Root Layout (Required)
|
||||||
* @param children
|
* @param children
|
||||||
|
@ -15,7 +20,7 @@ export default function RootLayout({
|
||||||
<head>
|
<head>
|
||||||
<title>马上行计划管理</title>
|
<title>马上行计划管理</title>
|
||||||
<link rel="icon" href="/favicon.ico"/>
|
<link rel="icon" href="/favicon.ico"/>
|
||||||
<script src="/static/iconfont.js" async ></script>
|
<script src="/static/iconfont.js"></script>
|
||||||
{/*FOUC,Flash of Unstyled Content*/}
|
{/*FOUC,Flash of Unstyled Content*/}
|
||||||
{/*<link rel="preload" href="https://cdn.jsdelivr.net/npm/antd/dist/antd.min.css" as="style"/>*/}
|
{/*<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"/>*/}
|
{/*<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/antd/dist/antd.min.css"/>*/}
|
||||||
|
|
|
@ -5,9 +5,9 @@ import {useEffect} from "react";
|
||||||
export default function Home() {
|
export default function Home() {
|
||||||
|
|
||||||
const {replace} = useRouter();
|
const {replace} = useRouter();
|
||||||
|
useEffect(()=>{
|
||||||
const pathName = usePathname()
|
const pathName = usePathname()
|
||||||
const searchParams = useSearchParams()
|
const searchParams = useSearchParams()
|
||||||
useEffect(()=>{
|
|
||||||
console.log({pathName},{searchParams})
|
console.log({pathName},{searchParams})
|
||||||
if(localStorage.getItem('platform-security')){
|
if(localStorage.getItem('platform-security')){
|
||||||
if (!pathName){
|
if (!pathName){
|
||||||
|
@ -17,13 +17,11 @@ export default function Home() {
|
||||||
}else {
|
}else {
|
||||||
replace("/task/project")
|
replace("/task/project")
|
||||||
}
|
}
|
||||||
}else if (pathName =="/"){
|
|
||||||
replace("/task/project")
|
|
||||||
}
|
}
|
||||||
}else {
|
}else {
|
||||||
replace("/login")
|
replace("/login")
|
||||||
}
|
}
|
||||||
},)
|
},[])
|
||||||
dayjs.locale('zh-cn')
|
dayjs.locale('zh-cn')
|
||||||
return (
|
return (
|
||||||
<main className="flex min-h-screen flex-col p-6">
|
<main className="flex min-h-screen flex-col p-6">
|
||||||
|
|
|
@ -30,7 +30,7 @@ export default function Layout({children}: { children: React.ReactNode }) {
|
||||||
const [spinning,setSpinning]=useState(false);
|
const [spinning,setSpinning]=useState(false);
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
selectData()
|
selectData()
|
||||||
}, [data,pid])
|
}, [data])
|
||||||
|
|
||||||
function selectData() {
|
function selectData() {
|
||||||
setSpinning(true)
|
setSpinning(true)
|
||||||
|
|
|
@ -66,7 +66,7 @@ export default function Layout({children}: { children: React.ReactNode }) {
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
document.getElementById('tenLeft').style.fontSize = divHeight/6*4 + 'px';
|
document.getElementById('tenLeft').style.fontSize = divHeight/6*4 + 'px';
|
||||||
refreshDate()
|
refreshDate()
|
||||||
}, [data]);
|
}, [useContext(LocalContext)]);
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<div className='firstRow' style={{display: 'flex'}}>
|
<div className='firstRow' style={{display: 'flex'}}>
|
||||||
|
|
|
@ -1,19 +0,0 @@
|
||||||
import React from 'react';
|
|
||||||
import {DateHeaderProps} from "react-big-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;
|
|
|
@ -1,5 +1,5 @@
|
||||||
import {Button, Form, message, Popconfirm} from "antd";
|
import {Button, Form, message, Popconfirm} from "antd";
|
||||||
import React, {useEffect, useRef, useState} from "react";
|
import React, {useEffect, useState} from "react";
|
||||||
import {
|
import {
|
||||||
ModalForm,
|
ModalForm,
|
||||||
ProFormDateTimeRangePicker,
|
ProFormDateTimeRangePicker,
|
||||||
|
@ -17,6 +17,7 @@ import dayjs, {UnitTypeShort} from "dayjs";
|
||||||
import {onceConsumerRead} from "@/utils/codeToReadName";
|
import {onceConsumerRead} from "@/utils/codeToReadName";
|
||||||
import {betweenTime} from "@/utils/timeFormatUtil";
|
import {betweenTime} from "@/utils/timeFormatUtil";
|
||||||
import {QuestionCircleOutlined} from "@ant-design/icons";
|
import {QuestionCircleOutlined} from "@ant-design/icons";
|
||||||
|
import {deleteTask} from "@/lib/task/project/data";
|
||||||
|
|
||||||
interface ClickRecordProps {
|
interface ClickRecordProps {
|
||||||
openClickRecord?: boolean;
|
openClickRecord?: boolean;
|
||||||
|
@ -66,7 +67,6 @@ const ClickRecord: React.FC<ClickRecordProps> = ({
|
||||||
form.setFieldsValue(data)
|
form.setFieldsValue(data)
|
||||||
}
|
}
|
||||||
}, [recordId]);
|
}, [recordId]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|
||||||
<ModalForm<TaskScheduleRecordForm>
|
<ModalForm<TaskScheduleRecordForm>
|
||||||
|
@ -139,11 +139,8 @@ const ClickRecord: React.FC<ClickRecordProps> = ({
|
||||||
} else {
|
} else {
|
||||||
await clickRecordAPI(values);
|
await clickRecordAPI(values);
|
||||||
}
|
}
|
||||||
console.log("before reloadData")
|
|
||||||
reloadData?.();
|
|
||||||
console.log("after reloadData")
|
|
||||||
// 然后在onFinish中使用
|
|
||||||
setOpenClickRecord?.(false)
|
setOpenClickRecord?.(false)
|
||||||
|
reloadData?.()
|
||||||
return true
|
return true
|
||||||
}catch (e){
|
}catch (e){
|
||||||
console.error(e)
|
console.error(e)
|
||||||
|
|
|
@ -159,7 +159,7 @@ const DiaryOption = (props: SelectDiary) => {
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
setDiaryReduceList(returnResult.reverse());
|
setDiaryReduceList(returnResult.reverse());
|
||||||
}, [diaryList, currentIndex,props.taskId]);
|
}, [diaryList, currentIndex]);
|
||||||
|
|
||||||
const listRef = useRef<ListRef>(null);
|
const listRef = useRef<ListRef>(null);
|
||||||
const onScroll = (e: React.UIEvent<HTMLElement, UIEvent>) => {
|
const onScroll = (e: React.UIEvent<HTMLElement, UIEvent>) => {
|
||||||
|
|
|
@ -183,7 +183,7 @@ const CronGenerator: React.FC<CronGeneratorProps> = ({setCronFunction,setExpecte
|
||||||
console.log({fullCronExpression})
|
console.log({fullCronExpression})
|
||||||
setCanReadCron(cronToChinese(fullCronExpression))
|
setCanReadCron(cronToChinese(fullCronExpression))
|
||||||
}
|
}
|
||||||
}, [fullCronExpression,cron]);
|
}, [fullCronExpression]);
|
||||||
|
|
||||||
const onClickConfirmCron = () => {
|
const onClickConfirmCron = () => {
|
||||||
if (fullCronExpression) {
|
if (fullCronExpression) {
|
||||||
|
|
|
@ -1,15 +1,9 @@
|
||||||
import {TaskMessage} from "@/lib/definitions";
|
import {TaskMessage} from "@/lib/definitions";
|
||||||
import React, {Fragment} from "react";
|
import React, {Fragment} from "react";
|
||||||
import {CopyOutlined, SmileOutlined} from "@ant-design/icons";
|
import {SmileOutlined} from "@ant-design/icons";
|
||||||
import {copyToClipboard} from "@/lib/copyToClipboard";
|
|
||||||
|
|
||||||
const TaskNameAndIcon = (props: { task: TaskMessage }) => {
|
const TaskNameAndIcon = (props: {task:TaskMessage}) => {
|
||||||
return (<Fragment>
|
return (<Fragment>
|
||||||
<CopyOutlined onClick={(e) => {
|
|
||||||
e.preventDefault(); // 阻止默认行为(如果有)
|
|
||||||
e.stopPropagation(); // 阻止事件冒泡
|
|
||||||
copyToClipboard(props.task.name)
|
|
||||||
}}/>
|
|
||||||
{props.task.fId &&
|
{props.task.fId &&
|
||||||
<svg className="icon" aria-hidden="true">
|
<svg className="icon" aria-hidden="true">
|
||||||
<use xlinkHref="#icon-tuandui"></use>
|
<use xlinkHref="#icon-tuandui"></use>
|
||||||
|
|
|
@ -206,7 +206,7 @@ const TaskRemindComponent = (props: ITaskRemind) => {
|
||||||
) : (
|
) : (
|
||||||
props.remindTypeList.map((remindType, index) => (
|
props.remindTypeList.map((remindType, index) => (
|
||||||
// <div key={index}>{remindType.split(",").join(", ")}</div>
|
// <div key={index}>{remindType.split(",").join(", ")}</div>
|
||||||
<Fragment key={remindType}>
|
<Fragment>
|
||||||
<ConfigProvider
|
<ConfigProvider
|
||||||
theme={{
|
theme={{
|
||||||
components: {
|
components: {
|
||||||
|
|
|
@ -103,7 +103,7 @@ const TeamMember = (props: { taskId: string, closeOpen?: () => void, reloadData?
|
||||||
return () => {
|
return () => {
|
||||||
isMounted = false;
|
isMounted = false;
|
||||||
};
|
};
|
||||||
}, [open,props.taskId])
|
}, [open])
|
||||||
const removeTeam = (teamMember: TeamMemberVO) => {
|
const removeTeam = (teamMember: TeamMemberVO) => {
|
||||||
removeTeamAPI(teamMember).then(res => {
|
removeTeamAPI(teamMember).then(res => {
|
||||||
if (res.data.status.success) {
|
if (res.data.status.success) {
|
||||||
|
|
|
@ -13,5 +13,5 @@ export const askLoginAPI = (data:{}):Promise<AxiosResponse<ResponseVO<AskLoginRe
|
||||||
}
|
}
|
||||||
|
|
||||||
export const refreshTokenAPI = ():Promise<AxiosResponse<ResponseVO<string>>> =>{
|
export const refreshTokenAPI = ():Promise<AxiosResponse<ResponseVO<string>>> =>{
|
||||||
return httpReq.post(process.env.NEXT_PUBLIC_SECURITY_REQUEST_URL + "/V2/wx/login/refreshToken")
|
return httpReq.get(process.env.NEXT_PUBLIC_SECURITY_REQUEST_URL + "/V2/wx/login/refreshToken")
|
||||||
}
|
}
|
|
@ -5,5 +5,4 @@ export interface TaskEvent extends Event {
|
||||||
state?:any;
|
state?:any;
|
||||||
taskType?:string;
|
taskType?:string;
|
||||||
priority?:any;
|
priority?:any;
|
||||||
description?:string;
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,29 +0,0 @@
|
||||||
declare module 'lunar-calendar' {
|
|
||||||
export interface LunarDate {
|
|
||||||
lunarYear: number;
|
|
||||||
lunarMonth: number;
|
|
||||||
lunarDay: number;
|
|
||||||
zodiac: string;
|
|
||||||
ganZhiYear: string;
|
|
||||||
ganZhiMonth: string;
|
|
||||||
ganZhiDay: string;
|
|
||||||
lunarMonthName: string;
|
|
||||||
lunarDayName: string;
|
|
||||||
solarTerm: string;
|
|
||||||
// 其他农历字段...
|
|
||||||
// 二十四节气
|
|
||||||
term:string;
|
|
||||||
// 农历节日
|
|
||||||
lunarFestival:string;
|
|
||||||
// 公历节日
|
|
||||||
solarFestival:string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function solarToLunar(
|
|
||||||
year: number,
|
|
||||||
month: number,
|
|
||||||
day: number
|
|
||||||
): LunarDate;
|
|
||||||
|
|
||||||
// 其他可能的方法...
|
|
||||||
}
|
|
|
@ -118,7 +118,7 @@ class OperationButton extends React.Component<OperationButtonProps, OperationMod
|
||||||
deleteTask(this.props.itemId).then((response => {
|
deleteTask(this.props.itemId).then((response => {
|
||||||
console.log('response', response)
|
console.log('response', response)
|
||||||
if (response.status.success) {
|
if (response.status.success) {
|
||||||
message.success("删除任务成功")
|
message.success("删除任务成功:" + response.data)
|
||||||
this.props.refreshDate?.()
|
this.props.refreshDate?.()
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
|
|
|
@ -52,7 +52,7 @@ const RightOption: React.FC<OperationButtonProps> = (props) => {
|
||||||
deleteTask(props.itemId).then((response => {
|
deleteTask(props.itemId).then((response => {
|
||||||
console.log('response', response)
|
console.log('response', response)
|
||||||
if (response.status.success) {
|
if (response.status.success) {
|
||||||
message.success("删除任务成功")
|
message.success("删除任务成功:" + response.data)
|
||||||
props.refreshDate?.()
|
props.refreshDate?.()
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
|
|
|
@ -1,16 +1,15 @@
|
||||||
'use client'
|
'use client'
|
||||||
import React, {Fragment, useContext, useEffect, useState} from "react";
|
import React, {Fragment, useContext, useEffect, useState} from "react";
|
||||||
import {Button, Checkbox, CheckboxOptionType, DatePicker, MenuProps, message, Popconfirm, Select, Space} from "antd";
|
import {Button, Checkbox, CheckboxOptionType, DatePicker, MenuProps, message, Select, Space} from "antd";
|
||||||
import {usePathname, useRouter} from "next/navigation";
|
import {usePathname, useRouter} from "next/navigation";
|
||||||
import {DetailModelForm} from "@/ui/task/project/DetailModelForm";
|
import {DetailModelForm} from "@/ui/task/project/DetailModelForm";
|
||||||
import {deleteTask, OPERATION_BUTTON_TYPE, taskStateList} from "@/lib/task/project/data";
|
import {OPERATION_BUTTON_TYPE, taskStateList} from "@/lib/task/project/data";
|
||||||
import style from '@/ui/task/TitleOperation.module.css'
|
import style from '@/ui/task/TitleOperation.module.css'
|
||||||
import LocalContext from "@/ui/LocalContent";
|
import LocalContext from "@/ui/LocalContent";
|
||||||
import {RequestDateType} from "@/ui/task/RequestDateType";
|
import {RequestDateType} from "@/ui/task/RequestDateType";
|
||||||
import dayjs, {Dayjs} from "dayjs";
|
import dayjs, {Dayjs} from "dayjs";
|
||||||
import {useSearchParams} from "next/dist/client/components/navigation";
|
import {useSearchParams} from "next/dist/client/components/navigation";
|
||||||
import Dropdown from "antd/es/dropdown/dropdown";
|
import Dropdown from "antd/es/dropdown/dropdown";
|
||||||
import {QuestionCircleOutlined} from "@ant-design/icons";
|
|
||||||
|
|
||||||
interface TitleOperationProps {
|
interface TitleOperationProps {
|
||||||
setTaskState: (value: string) => void;
|
setTaskState: (value: string) => void;
|
||||||
|
@ -43,7 +42,7 @@ export const TitleOperation: React.FC<TitleOperationProps> = ({
|
||||||
expectStartTimeParseResult[0] && expectStartTimeParseResult[0].value ? dayjs(expectStartTimeParseResult[0].value.toString()) : undefined,
|
expectStartTimeParseResult[0] && expectStartTimeParseResult[0].value ? dayjs(expectStartTimeParseResult[0].value.toString()) : undefined,
|
||||||
expectStartTimeParseResult[1] && expectStartTimeParseResult[1].value ? dayjs(expectStartTimeParseResult[1].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>[] = [
|
const typeList: CheckboxOptionType<string>[] = [
|
||||||
{label: '计划', value: '0,1,2,3'},
|
{label: '计划', value: '0,1,2,3'},
|
||||||
{label: '打卡', value: '4'},
|
{label: '打卡', value: '4'},
|
||||||
|
@ -62,7 +61,7 @@ export const TitleOperation: React.FC<TitleOperationProps> = ({
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
let userMessage = localStorage.getItem('user-message');
|
let userMessage = localStorage.getItem('user-message');
|
||||||
if (userMessage) {
|
if (userMessage){
|
||||||
let parse = JSON.parse(userMessage);
|
let parse = JSON.parse(userMessage);
|
||||||
setNickName(parse.nickname)
|
setNickName(parse.nickname)
|
||||||
}
|
}
|
||||||
|
@ -70,44 +69,24 @@ export const TitleOperation: React.FC<TitleOperationProps> = ({
|
||||||
|
|
||||||
const onClick: MenuProps['onClick'] = ({key}) => {
|
const onClick: MenuProps['onClick'] = ({key}) => {
|
||||||
if (key == "1") {
|
if (key == "1") {
|
||||||
// localStorage.removeItem('platform-security')
|
localStorage.removeItem('platform-security')
|
||||||
// replace(`/login`)
|
replace(`/login`)
|
||||||
} else if (key == "2") {
|
} else if (key == "2") {
|
||||||
replace(pathName)
|
replace(pathName)
|
||||||
setPathParam(undefined)
|
setPathParam(undefined)
|
||||||
// refreshData()
|
refreshData()
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const items: MenuProps['items'] = [
|
const items: MenuProps['items'] = [
|
||||||
{
|
{
|
||||||
label: <Popconfirm
|
label: '退出登录',
|
||||||
title="退出登录"
|
|
||||||
description="确认要退出登录?"
|
|
||||||
icon={<QuestionCircleOutlined style={{color: 'red'}}/>}
|
|
||||||
okText="确认"
|
|
||||||
cancelText="取消"
|
|
||||||
onConfirm={() => {
|
|
||||||
localStorage.removeItem('platform-security')
|
|
||||||
replace(`/login`)
|
|
||||||
}}
|
|
||||||
><a>退出登录</a></Popconfirm>,
|
|
||||||
key: '1',
|
key: '1',
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
const itemsPid: MenuProps['items'] = [
|
const itemsPid: MenuProps['items'] = [
|
||||||
{
|
{
|
||||||
label: <Popconfirm
|
label: '退出登录',
|
||||||
title="退出登录"
|
|
||||||
description="确认要退出登录?"
|
|
||||||
icon={<QuestionCircleOutlined style={{color: 'red'}}/>}
|
|
||||||
okText="确认"
|
|
||||||
cancelText="取消"
|
|
||||||
onConfirm={() => {
|
|
||||||
localStorage.removeItem('platform-security')
|
|
||||||
replace(`/login`)
|
|
||||||
}}
|
|
||||||
><a>退出登录</a></Popconfirm>,
|
|
||||||
key: '1',
|
key: '1',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -163,16 +142,16 @@ export const TitleOperation: React.FC<TitleOperationProps> = ({
|
||||||
allowClear
|
allowClear
|
||||||
style={{minWidth: '100px'}}
|
style={{minWidth: '100px'}}
|
||||||
placeholder="任务状态"
|
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) => {
|
onChange={(value) => {
|
||||||
console.log('onChange', {value})
|
console.log('onChange',{value})
|
||||||
if (value.length == 0) {
|
if(value.length == 0){
|
||||||
setTaskState("")
|
setTaskState("")
|
||||||
} else {
|
}else {
|
||||||
setTaskState(value.join(','))
|
setTaskState(value.join(','))
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
onClear={() => {
|
onClear={()=>{
|
||||||
console.log('onChange,点击了清除无效果')
|
console.log('onChange,点击了清除无效果')
|
||||||
setTaskState("")
|
setTaskState("")
|
||||||
}}
|
}}
|
||||||
|
@ -230,8 +209,8 @@ export const TitleOperation: React.FC<TitleOperationProps> = ({
|
||||||
}
|
}
|
||||||
</Space>
|
</Space>
|
||||||
<Dropdown menu={{items: pathParam ? itemsPid : items, onClick}}>
|
<Dropdown menu={{items: pathParam ? itemsPid : items, onClick}}>
|
||||||
<div style={{display: "flex", height: "32px", alignItems: "center"}}>
|
<div style={{display:"flex", height: "32px", alignItems: "center"}}>
|
||||||
<svg style={{height: "32px", width: "32px", marginRight: "0.5rem"}} className="icon" aria-hidden="true">
|
<svg style={{ height: "32px",width: "32px",marginRight:"0.5rem" }} className="icon" aria-hidden="true">
|
||||||
<use xlinkHref="#icon-user__easyico"></use>
|
<use xlinkHref="#icon-user__easyico"></use>
|
||||||
</svg>
|
</svg>
|
||||||
<span>{nickName}</span>
|
<span>{nickName}</span>
|
||||||
|
|
|
@ -1,15 +1,6 @@
|
||||||
'use client'
|
'use client'
|
||||||
import React, {Fragment, useCallback, useContext, useEffect, useMemo, useRef, useState} from "react";
|
import React, {Fragment, useCallback, useContext, useEffect, useMemo, useRef, useState} from "react";
|
||||||
import {
|
import {Calendar, dateFnsLocalizer, dayjsLocalizer, Event, SlotInfo, View} from 'react-big-calendar'
|
||||||
Calendar,
|
|
||||||
Culture,
|
|
||||||
dateFnsLocalizer,
|
|
||||||
DateLocalizer,
|
|
||||||
dayjsLocalizer,
|
|
||||||
Event,
|
|
||||||
SlotInfo,
|
|
||||||
View
|
|
||||||
} from 'react-big-calendar'
|
|
||||||
import dayjs, {Dayjs} from 'dayjs'
|
import dayjs, {Dayjs} from 'dayjs'
|
||||||
import 'dayjs/locale/zh-cn';
|
import 'dayjs/locale/zh-cn';
|
||||||
import 'react-big-calendar/lib/css/react-big-calendar.css'
|
import 'react-big-calendar/lib/css/react-big-calendar.css'
|
||||||
|
@ -29,11 +20,7 @@ import {TaskWebSelectVO} from "@/lib/task/project/definitions";
|
||||||
import {message, Modal, Spin} from "antd";
|
import {message, Modal, Spin} from "antd";
|
||||||
import ClickRecord from "@/components/ClickRecord";
|
import ClickRecord from "@/components/ClickRecord";
|
||||||
import {editClickRecordRangeAPI} from "@/components/service/ScheduleTask";
|
import {editClickRecordRangeAPI} from "@/components/service/ScheduleTask";
|
||||||
import {CopyOutlined, ExclamationCircleFilled, LoadingOutlined} from "@ant-design/icons";
|
import {ExclamationCircleFilled, LoadingOutlined} from "@ant-design/icons";
|
||||||
import {copyToClipboard} from "@/lib/copyToClipboard";
|
|
||||||
import {solarToLunar} from "lunar-calendar";
|
|
||||||
import CalHeader from "@/components/CalHeader";
|
|
||||||
import {lunarDateShow} from "@/utils/timeFormatUtil";
|
|
||||||
|
|
||||||
const {confirm} = Modal;
|
const {confirm} = Modal;
|
||||||
/**
|
/**
|
||||||
|
@ -41,7 +28,6 @@ const {confirm} = Modal;
|
||||||
* @constructor
|
* @constructor
|
||||||
*/
|
*/
|
||||||
const localizer = dayjsLocalizer(dayjs)
|
const localizer = dayjsLocalizer(dayjs)
|
||||||
|
|
||||||
const DragAndDropCalendar = withDragAndDrop(Calendar)
|
const DragAndDropCalendar = withDragAndDrop(Calendar)
|
||||||
const CalShow: React.FC = () => {
|
const CalShow: React.FC = () => {
|
||||||
dayjs.locale('zh-cn')
|
dayjs.locale('zh-cn')
|
||||||
|
@ -78,9 +64,7 @@ const CalShow: React.FC = () => {
|
||||||
expectedEndTime: range.end
|
expectedEndTime: range.end
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
const dateFormat = (date: Date, culture?: Culture, localizer?: DateLocalizer) => {
|
|
||||||
return `${date.getDate()}/${lunarDateShow(date)}`;
|
|
||||||
};
|
|
||||||
const handleViewChange = (newView: View) => {
|
const handleViewChange = (newView: View) => {
|
||||||
setView(newView);
|
setView(newView);
|
||||||
};
|
};
|
||||||
|
@ -91,23 +75,19 @@ const CalShow: React.FC = () => {
|
||||||
clickRef && typeof clickRef.current === 'number' && !isNaN(clickRef.current) && isFinite(clickRef.current) && window.clearTimeout(clickRef.current)
|
clickRef && typeof clickRef.current === 'number' && !isNaN(clickRef.current) && isFinite(clickRef.current) && window.clearTimeout(clickRef.current)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 会触发范围变化
|
|
||||||
* @param newDate
|
|
||||||
*/
|
|
||||||
const handleNavigate = (newDate: Date) => {
|
const handleNavigate = (newDate: Date) => {
|
||||||
console.log('handleNavigate', newDate)
|
console.log('handleNavigate', newDate)
|
||||||
setDate(newDate);
|
setDate(newDate);
|
||||||
// const searchList: SearchObject[] = []
|
const searchList: SearchObject[] = []
|
||||||
// if (pid != null) {
|
if (pid != null) {
|
||||||
// searchList.push({name: "pid", value: pid, operateType: "="},
|
searchList.push({name: "pid", value: pid, operateType: "="},
|
||||||
// {name: 'ALL-CHILD', value: "true", operateType: "ALL-CHILD"},
|
{name: 'ALL-CHILD', value: "true", operateType: "ALL-CHILD"},
|
||||||
// {name: 'TREE-FILTER', value: "true", operateType: "TREE-FILTER"},
|
{name: 'TREE-FILTER', value: "true", operateType: "TREE-FILTER"},
|
||||||
// );
|
);
|
||||||
// searchObject.data.pid = pid
|
searchObject.data.pid = pid
|
||||||
// setSearchObject({...searchObject})
|
setSearchObject({...searchObject})
|
||||||
// }
|
}
|
||||||
// loadData();
|
loadData(searchList);
|
||||||
};
|
};
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
@ -122,10 +102,6 @@ const CalShow: React.FC = () => {
|
||||||
// );
|
// );
|
||||||
searchObject.data.pid = pid
|
searchObject.data.pid = pid
|
||||||
setSearchObject({...searchObject})
|
setSearchObject({...searchObject})
|
||||||
} else {
|
|
||||||
const {pid, ...search} = searchObject.data
|
|
||||||
searchObject.data = search
|
|
||||||
setSearchObject({...searchObject})
|
|
||||||
}
|
}
|
||||||
// searchListE.push({name: 'expectedStartTime', value: range.start, operateType: ">="})
|
// searchListE.push({name: 'expectedStartTime', value: range.start, operateType: ">="})
|
||||||
// searchListE.push({name: 'expectedStartTime', value: range.end, operateType: "<="})
|
// searchListE.push({name: 'expectedStartTime', value: range.end, operateType: "<="})
|
||||||
|
@ -139,7 +115,7 @@ const CalShow: React.FC = () => {
|
||||||
return () => {
|
return () => {
|
||||||
clearClickTimeout()
|
clearClickTimeout()
|
||||||
}
|
}
|
||||||
}, [state, taskTypeList, refreshData, range, pid]);
|
}, [state, taskTypeList, refreshData, range]);
|
||||||
const calMessages = {
|
const calMessages = {
|
||||||
week: '周',
|
week: '周',
|
||||||
work_week: '工作周',
|
work_week: '工作周',
|
||||||
|
@ -159,7 +135,6 @@ const CalShow: React.FC = () => {
|
||||||
noEventsInRange: '暂无计划',
|
noEventsInRange: '暂无计划',
|
||||||
}
|
}
|
||||||
const loadData = (searchList?: SearchObject[]) => {
|
const loadData = (searchList?: SearchObject[]) => {
|
||||||
console.log("loadData")
|
|
||||||
setSpinning(true)
|
setSpinning(true)
|
||||||
searchObject.data.state = state
|
searchObject.data.state = state
|
||||||
searchObject.data.taskTypeList = taskTypeList
|
searchObject.data.taskTypeList = taskTypeList
|
||||||
|
@ -170,19 +145,10 @@ const CalShow: React.FC = () => {
|
||||||
if (responseD.status.success) {
|
if (responseD.status.success) {
|
||||||
let result: TaskEvent[] = responseD.data.content.map<TaskEvent>(taskState => {
|
let result: TaskEvent[] = responseD.data.content.map<TaskEvent>(taskState => {
|
||||||
return {
|
return {
|
||||||
start: taskState.expectedStartTime ? dayjs(taskState.expectedStartTime).toDate() : dayjs(taskState.expectedEndTime).startOf('day').toDate(),
|
start: dayjs(taskState.expectedStartTime).toDate(),
|
||||||
end: taskState.expectedEndTime ? dayjs(taskState.expectedEndTime).toDate() : dayjs(taskState.expectedStartTime).endOf('day').toDate(),
|
end: dayjs(taskState.expectedEndTime).toDate(),
|
||||||
title: <Fragment>
|
title: <Fragment><TaskNameAndIcon task={taskState}/>
|
||||||
<div>
|
<div>{taskState.description}</div>
|
||||||
<TaskNameAndIcon task={taskState}/>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
{view != 'month' && taskState.description && <CopyOutlined onClick={(e) => {
|
|
||||||
e.preventDefault(); // 阻止默认行为(如果有)
|
|
||||||
e.stopPropagation(); // 阻止事件冒泡
|
|
||||||
copyToClipboard(taskState.description)
|
|
||||||
}}/>} {view != 'month' && taskState.description}
|
|
||||||
</div>
|
|
||||||
</Fragment>,
|
</Fragment>,
|
||||||
// style: {
|
// style: {
|
||||||
// backgroundColor: 'green',
|
// backgroundColor: 'green',
|
||||||
|
@ -193,8 +159,7 @@ const CalShow: React.FC = () => {
|
||||||
id: taskState.id,
|
id: taskState.id,
|
||||||
state: taskState.state,
|
state: taskState.state,
|
||||||
priority: taskState.priority,
|
priority: taskState.priority,
|
||||||
taskType: taskState.taskType,
|
taskType: taskState.taskType
|
||||||
description:taskState.description
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
console.log('responseD.data.content:', result)
|
console.log('responseD.data.content:', result)
|
||||||
|
@ -233,13 +198,9 @@ const CalShow: React.FC = () => {
|
||||||
// }
|
// }
|
||||||
// })
|
// })
|
||||||
}
|
}
|
||||||
/**
|
|
||||||
* from表单使用,打卡记录新建使用
|
|
||||||
*/
|
|
||||||
const reloadData = () => {
|
const reloadData = () => {
|
||||||
setOpen(false)
|
setOpen(false)
|
||||||
loadData();
|
handleNavigate(date)
|
||||||
// handleNavigate(date)
|
|
||||||
}
|
}
|
||||||
const handleSelectSlot = useCallback(
|
const handleSelectSlot = useCallback(
|
||||||
({start, end}: SlotInfo) => {
|
({start, end}: SlotInfo) => {
|
||||||
|
@ -285,7 +246,7 @@ const CalShow: React.FC = () => {
|
||||||
message.error("计划双击完成,非计划双击无效果。")
|
message.error("计划双击完成,非计划双击无效果。")
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (event.state == '7') {
|
if (event.state=='7'){
|
||||||
message.error("任务已经完成")
|
message.error("任务已经完成")
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -315,7 +276,7 @@ const CalShow: React.FC = () => {
|
||||||
if (existing !== undefined && filtered !== undefined) {
|
if (existing !== undefined && filtered !== undefined) {
|
||||||
result = [...filtered, {...existing, state: "7"}];
|
result = [...filtered, {...existing, state: "7"}];
|
||||||
}
|
}
|
||||||
let strings = state == "" ? [] : state.split(",");
|
let strings = state==""?[]:state.split(",");
|
||||||
console.log('result', result, strings)
|
console.log('result', result, strings)
|
||||||
return result.filter((ev: TaskEvent) => !ev.state || strings.length == 0 || strings.indexOf(ev.state.toString()) >= 0);
|
return result.filter((ev: TaskEvent) => !ev.state || strings.length == 0 || strings.indexOf(ev.state.toString()) >= 0);
|
||||||
})
|
})
|
||||||
|
@ -379,49 +340,39 @@ const CalShow: React.FC = () => {
|
||||||
console.log("rangeChange:", rangeLet, (current ? current : view))
|
console.log("rangeChange:", rangeLet, (current ? current : view))
|
||||||
// view 为天的时候类型为数组,index:0为当天
|
// view 为天的时候类型为数组,index:0为当天
|
||||||
if ((current ? current : view) === "day" && Array.isArray(rangeLet)) {
|
if ((current ? current : view) === "day" && Array.isArray(rangeLet)) {
|
||||||
// if (range.start.valueOf() > rangeLet[0].valueOf()) {
|
if (range.start.valueOf() > rangeLet[0].valueOf()) {
|
||||||
range.start = rangeLet[0];
|
// setRange({...range, start: rangeLet[0]})
|
||||||
// }
|
range.start=rangeLet[0];
|
||||||
// if (range.end.valueOf() < rangeLet[0].valueOf()) {
|
} else if (range.end.valueOf() < rangeLet[0].valueOf()) {
|
||||||
range.end = dayjs(rangeLet[0]).add(1, 'd').toDate()
|
// setRange({...range, end: rangeLet[0]})
|
||||||
// }
|
range.end=rangeLet[0]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// 为周的时候类型为数组,周一到周日七天
|
// 为周的时候类型为数组,周一到周日七天
|
||||||
if ((current ? current : view) === "week" && Array.isArray(rangeLet)) {
|
if ((current ? current : view) === "week" && Array.isArray(rangeLet)) {
|
||||||
// if (range.start.valueOf() > rangeLet[0].valueOf()) {
|
if (range.start.valueOf() > rangeLet[0].valueOf()) {
|
||||||
range.start = rangeLet[0];
|
// setRange({...range, start: rangeLet[0]})
|
||||||
// }
|
range.start=rangeLet[0];
|
||||||
// if (range.end.valueOf() < rangeLet[6].valueOf()) {
|
}
|
||||||
range.end = dayjs(rangeLet[6]).add(1, 'd').toDate()
|
if (range.end.valueOf() < rangeLet[6].valueOf()) {
|
||||||
// }
|
// setRange({...range, end: rangeLet[6]})
|
||||||
|
range.end=rangeLet[6]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// 为月的时候类型为对象
|
// 为月的时候类型为对象
|
||||||
if ((current ? current : view) === "month" && rangeLet && !Array.isArray(rangeLet)) {
|
if ((current ? current : view) === "month" && rangeLet && !Array.isArray(rangeLet)) {
|
||||||
// if (range.start.valueOf() > rangeLet.start.valueOf()) {
|
if (range.start.valueOf() > rangeLet.start.valueOf()) {
|
||||||
|
// setRange({...range, start: rangeLet.start})
|
||||||
range.start = rangeLet.start
|
range.start = rangeLet.start
|
||||||
// }
|
}
|
||||||
// if (range.end.valueOf() < rangeLet.end.valueOf()) {
|
if (range.end.valueOf() < rangeLet.end.valueOf()) {
|
||||||
range.end = dayjs(rangeLet.end).add(1, 'd').toDate()
|
// setRange({...range, end: rangeLet.end})
|
||||||
|
range.end = rangeLet.end
|
||||||
|
|
||||||
// }
|
}
|
||||||
}
|
}
|
||||||
setRange({...range})
|
setRange({...range})
|
||||||
}
|
}
|
||||||
|
|
||||||
const toolTipShow = (event:TaskEvent) =>{
|
|
||||||
console.log("toolTipShow", event)
|
|
||||||
let result=""
|
|
||||||
if (view!='month'){
|
|
||||||
result += "\n"
|
|
||||||
}
|
|
||||||
result += "计划:"+event.name
|
|
||||||
if (event.description){
|
|
||||||
result += "\n描述:"+event.description
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
return <div className="App" style={{height: '90vh'}}>
|
return <div className="App" style={{height: '90vh'}}>
|
||||||
{open && <DetailModelForm operationId={operationId}
|
{open && <DetailModelForm operationId={operationId}
|
||||||
description={description}
|
description={description}
|
||||||
|
@ -437,23 +388,9 @@ const CalShow: React.FC = () => {
|
||||||
reloadData={loadData}/>}
|
reloadData={loadData}/>}
|
||||||
<Spin spinning={spinning} indicator={<LoadingOutlined style={{fontSize: 48}} spin/>} fullscreen/>
|
<Spin spinning={spinning} indicator={<LoadingOutlined style={{fontSize: 48}} spin/>} fullscreen/>
|
||||||
<DragAndDropCalendar
|
<DragAndDropCalendar
|
||||||
|
|
||||||
// 本地设置
|
// 本地设置
|
||||||
localizer={localizer}
|
localizer={localizer}
|
||||||
messages={calMessages}
|
messages={calMessages}
|
||||||
formats={{
|
|
||||||
dayFormat: dateFormat,
|
|
||||||
// dateFormat: dateFormat,
|
|
||||||
monthHeaderFormat: (solarDate) => {
|
|
||||||
const lunarDate = solarToLunar(
|
|
||||||
solarDate.getFullYear(),
|
|
||||||
solarDate.getMonth() + 1,
|
|
||||||
1
|
|
||||||
);
|
|
||||||
return `${solarDate.getFullYear()}年${solarDate.getMonth() + 1}月 (农历${lunarDate.lunarMonthName})`;
|
|
||||||
},
|
|
||||||
dayHeaderFormat: dateFormat
|
|
||||||
}}
|
|
||||||
// 修改style
|
// 修改style
|
||||||
eventPropGetter={eventPropGetter}
|
eventPropGetter={eventPropGetter}
|
||||||
events={events}
|
events={events}
|
||||||
|
@ -480,14 +417,6 @@ const CalShow: React.FC = () => {
|
||||||
resizable
|
resizable
|
||||||
onEventResize={moveEvent}
|
onEventResize={moveEvent}
|
||||||
onEventDrop={moveEvent}
|
onEventDrop={moveEvent}
|
||||||
// 组件设置
|
|
||||||
components={
|
|
||||||
{
|
|
||||||
month: {
|
|
||||||
dateHeader: CalHeader
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
tooltipAccessor={toolTipShow}
|
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,26 +18,3 @@
|
||||||
background-color: green !important;
|
background-color: green !important;
|
||||||
color: black !important;
|
color: black !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 修改计划展示,先展示描述后展示时间 start */
|
|
||||||
.rbc-addons-dnd-resizable{
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
}
|
|
||||||
.rbc-event-label{
|
|
||||||
/*设置顺序*/
|
|
||||||
order: 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
.rbc-day-slot .rbc-event-content{
|
|
||||||
flex-grow: 0;
|
|
||||||
min-height:unset;
|
|
||||||
}
|
|
||||||
.rbc-day-slot .rbc-event-content{
|
|
||||||
/* 不自动增长 */
|
|
||||||
flex-grow: 0;
|
|
||||||
/* 移除组件内属性 min-height */
|
|
||||||
min-height:unset;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 修改计划展示,先展示描述后展示时间 end */
|
|
|
@ -123,7 +123,7 @@ export const DetailForm: React.FC<DetailFormProps> = (props) => {
|
||||||
if (props.operationId === OPERATION_BUTTON_TYPE.ADD_CHILD) {
|
if (props.operationId === OPERATION_BUTTON_TYPE.ADD_CHILD) {
|
||||||
addTask(request).then(response => {
|
addTask(request).then(response => {
|
||||||
console.log('response', response)
|
console.log('response', response)
|
||||||
if (response.data.status.success) {
|
if (response.status.success) {
|
||||||
message.success("添加任务成功:" + response.data)
|
message.success("添加任务成功:" + response.data)
|
||||||
props.handleCancel()
|
props.handleCancel()
|
||||||
}
|
}
|
||||||
|
@ -140,11 +140,11 @@ export const DetailForm: React.FC<DetailFormProps> = (props) => {
|
||||||
}
|
}
|
||||||
updateTask(request).then(response => {
|
updateTask(request).then(response => {
|
||||||
console.log('response', response)
|
console.log('response', response)
|
||||||
if (response.data.status.success) {
|
if (response.status.success) {
|
||||||
message.success("修改任务成功:" + response.data)
|
message.success("修改任务成功:" + response.data)
|
||||||
props.handleCancel()
|
props.handleCancel()
|
||||||
}else {
|
}else {
|
||||||
message.error(response.data.status.message)
|
message.error(response.status.message)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
|
@ -10,8 +10,6 @@ import {getTaskState, taskPriorityList, taskStateList} from "@/lib/task/project/
|
||||||
import 'react-virtualized/styles.css';
|
import 'react-virtualized/styles.css';
|
||||||
import RightOption from "@/ui/task/RightOption";
|
import RightOption from "@/ui/task/RightOption";
|
||||||
import TaskNameAndIcon from "@/components/TaskNameAndIcon";
|
import TaskNameAndIcon from "@/components/TaskNameAndIcon";
|
||||||
import {copyToClipboard} from "@/lib/copyToClipboard";
|
|
||||||
import {CopyOutlined} from "@ant-design/icons";
|
|
||||||
|
|
||||||
|
|
||||||
interface DroppableTableProps {
|
interface DroppableTableProps {
|
||||||
|
@ -101,13 +99,9 @@ export const DroppableTable = React.memo((props: DroppableTableProps) => {
|
||||||
<div className='displayFlexRow'> <TaskNameAndIcon task={record}/></div>
|
<div className='displayFlexRow'> <TaskNameAndIcon task={record}/></div>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
</div>
|
</div>
|
||||||
<div style={{width: '45%', boxSizing: 'border-box', minWidth: 0,display: 'flex',justifyContent:"start"}}
|
<div style={{width: '45%', boxSizing: 'border-box', minWidth: 0}}
|
||||||
>
|
className='displayFlexRow'>
|
||||||
<Tooltip placement="topLeft" title={record.description} className="displayFlexRow">
|
<Tooltip placement="topLeft" title={record.description}>
|
||||||
{record.description && <CopyOutlined onClick={(e) => {
|
|
||||||
e.preventDefault();
|
|
||||||
copyToClipboard(record.description)
|
|
||||||
}}/>}
|
|
||||||
<div className='displayFlexRow text-ellipsis'>{record.description}</div>
|
<div className='displayFlexRow text-ellipsis'>{record.description}</div>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -364,7 +364,7 @@ export const DetailModelForm: React.FC<DetailModelFormProps> = (props) => {
|
||||||
deleteTask(props.itemId).then((response => {
|
deleteTask(props.itemId).then((response => {
|
||||||
console.log('response', response)
|
console.log('response', response)
|
||||||
if (response.status.success) {
|
if (response.status.success) {
|
||||||
message.success("删除任务成功")
|
message.success("删除任务成功:" + response.data)
|
||||||
initData()
|
initData()
|
||||||
props.reloadData?.()
|
props.reloadData?.()
|
||||||
}
|
}
|
||||||
|
@ -481,6 +481,8 @@ export const DetailModelForm: React.FC<DetailModelFormProps> = (props) => {
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
|
|
||||||
await addTask(values).then(response => {
|
await addTask(values).then(response => {
|
||||||
console.log('response', response)
|
console.log('response', response)
|
||||||
if (response.data.status.success) {
|
if (response.data.status.success) {
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
'use client'
|
'use client'
|
||||||
import {
|
import {
|
||||||
CheckSquareFilled, CopyOutlined,
|
CheckSquareFilled,
|
||||||
QuestionCircleOutlined
|
QuestionCircleOutlined
|
||||||
} from '@ant-design/icons';
|
} from '@ant-design/icons';
|
||||||
import type {ActionType, FormInstance, ProColumns, ProFormInstance} from '@ant-design/pro-components';
|
import type {ActionType, FormInstance, ProColumns, ProFormInstance} from '@ant-design/pro-components';
|
||||||
|
@ -21,7 +21,6 @@ import '@/ui/task/project/TreeTablePro.modules.css'
|
||||||
import {useSearchParams} from "next/navigation";
|
import {useSearchParams} from "next/navigation";
|
||||||
import {TaskWebSelectVO} from "@/lib/task/project/definitions";
|
import {TaskWebSelectVO} from "@/lib/task/project/definitions";
|
||||||
import TaskNameAndIcon from "@/components/TaskNameAndIcon";
|
import TaskNameAndIcon from "@/components/TaskNameAndIcon";
|
||||||
import {copyToClipboard} from "@/lib/copyToClipboard";
|
|
||||||
|
|
||||||
const TreeTablePro: React.FC = (props: { joinId?: string }) => {
|
const TreeTablePro: React.FC = (props: { joinId?: string }) => {
|
||||||
// 刷新表格
|
// 刷新表格
|
||||||
|
@ -65,15 +64,9 @@ const TreeTablePro: React.FC = (props: { joinId?: string }) => {
|
||||||
title: '任务描述',
|
title: '任务描述',
|
||||||
dataIndex: 'description',
|
dataIndex: 'description',
|
||||||
render: (_, record) => {
|
render: (_, record) => {
|
||||||
return <Fragment>
|
return <Tooltip placement="topLeft" title={record.description}>
|
||||||
|
<div className='text-ellipsis'>{record.description}</div>
|
||||||
<Tooltip placement="topLeft" title={record.description}>
|
|
||||||
<div className='text-ellipsis'>{record.description && <CopyOutlined onClick={(e) => {
|
|
||||||
e.preventDefault();
|
|
||||||
copyToClipboard(record.description)
|
|
||||||
}}/>}{record.description}</div>
|
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
</Fragment>
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -255,14 +248,14 @@ const TreeTablePro: React.FC = (props: { joinId?: string }) => {
|
||||||
}
|
}
|
||||||
// 列表展示
|
// 列表展示
|
||||||
if (!switchChecked) {
|
if (!switchChecked) {
|
||||||
search.treeOrList = false;
|
search.treeOrList=false;
|
||||||
search.treeList = true;
|
search.treeList=true;
|
||||||
search.treeFilter = true;
|
search.treeFilter=true;
|
||||||
} else {
|
}else {
|
||||||
// 树展示
|
// 树展示
|
||||||
search.treeOrList = true;
|
search.treeOrList=true;
|
||||||
search.treeList = true;
|
search.treeList=true;
|
||||||
search.treeFilter = filterChecked;
|
search.treeFilter=filterChecked;
|
||||||
}
|
}
|
||||||
if (params.state) {
|
if (params.state) {
|
||||||
search.state = params.state.join(',');
|
search.state = params.state.join(',');
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import axios, {AxiosInterceptorOptions, CancelTokenSource} from "axios";
|
import axios, {CancelTokenSource} from "axios";
|
||||||
import {message} from "antd";
|
import {message} from "antd";
|
||||||
import {refreshTokenAPI} from "@/lib/login/service";
|
import {refreshTokenAPI} from "@/lib/login/service";
|
||||||
|
|
||||||
|
@ -19,17 +19,11 @@ const cancelTokenSource: CancelTokenSource = axios.CancelToken.source();
|
||||||
httpReq.defaults.headers.common['Accept'] = 'application/json';
|
httpReq.defaults.headers.common['Accept'] = 'application/json';
|
||||||
// 请求前处理
|
// 请求前处理
|
||||||
httpReq.interceptors.request.use((config) => {
|
httpReq.interceptors.request.use((config) => {
|
||||||
console.log("config.url", config.url)
|
|
||||||
// 从本地存储中获取 token
|
// 从本地存储中获取 token
|
||||||
const token = localStorage.getItem('platform-security');
|
const token = localStorage.getItem('platform-security');
|
||||||
if (token) {
|
if (token) {
|
||||||
config.headers.Authorization = `Bearer ${token}`;
|
config.headers.Authorization = `Bearer ${token}`;
|
||||||
if (config.url && config.url.indexOf("refreshToken") == -1 &&
|
reduceToken(token)
|
||||||
config.url.indexOf("/ask/login") == -1 &&
|
|
||||||
config.url.indexOf("/generate/qrcode") == -1
|
|
||||||
) {
|
|
||||||
reduceToken(token);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
config.headers.set("source-client", "web")
|
config.headers.set("source-client", "web")
|
||||||
return config;
|
return config;
|
||||||
|
@ -38,9 +32,6 @@ httpReq.interceptors.request.use((config) => {
|
||||||
console.info("interceptors错误提示.request" + error)
|
console.info("interceptors错误提示.request" + error)
|
||||||
return Promise.reject(error);
|
return Promise.reject(error);
|
||||||
})
|
})
|
||||||
httpReq.interceptors.response.use((onFulfilled) => {
|
|
||||||
return onFulfilled;
|
|
||||||
})
|
|
||||||
|
|
||||||
function reduceToken(token: string) {
|
function reduceToken(token: string) {
|
||||||
if (!token || token.split('.').length !== 3) {
|
if (!token || token.split('.').length !== 3) {
|
||||||
|
@ -71,10 +62,10 @@ function reduceToken(token: string) {
|
||||||
console.log("updateToken:decodedToken:", decodedToken);
|
console.log("updateToken:decodedToken:", decodedToken);
|
||||||
const endTime = decodedToken.exp;
|
const endTime = decodedToken.exp;
|
||||||
console.log('距离过期' + (((endTime as number) - (Date.now() / 1000)) / 60 / 60 + '小时'))
|
console.log('距离过期' + (((endTime as number) - (Date.now() / 1000)) / 60 / 60 + '小时'))
|
||||||
if (((endTime as number) - (Date.now() / 1000)) / 60 / 60 < 3) {
|
if (((endTime as number) - (Date.now() / 1000)) / 60 / 60 / 24 < 3) {
|
||||||
// 小于3小时更新toke3小时或12小时不动过期、内不动
|
// 小于3小时更新toke3小时或12小时不动过期、内不动
|
||||||
refreshTokenAPI().then(res => {
|
refreshTokenAPI().then(res=>{
|
||||||
if (res.data.status.success) {
|
if (res.data.status.success){
|
||||||
localStorage.setItem('platform-security', res.data.data)
|
localStorage.setItem('platform-security', res.data.data)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
import dayjs, { Dayjs, isDayjs } from "dayjs";
|
import dayjs, { Dayjs, isDayjs } from "dayjs";
|
||||||
import utc from "dayjs/plugin/utc";
|
import utc from "dayjs/plugin/utc";
|
||||||
import {solarToLunar} from "lunar-calendar";
|
|
||||||
dayjs.extend(utc)
|
dayjs.extend(utc)
|
||||||
const DATE_FORMAT = "YYYY-MM-DD"
|
const DATE_FORMAT = "YYYY-MM-DD"
|
||||||
// 到秒没啥意义
|
// 到秒没啥意义
|
||||||
|
@ -237,26 +236,8 @@ function dayjsWeek(day: Dayjs): string {
|
||||||
}
|
}
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
function lunarDateShow(date:Date){
|
|
||||||
const lunarDate = solarToLunar(
|
|
||||||
date.getFullYear(),
|
|
||||||
date.getMonth() + 1,
|
|
||||||
date.getDate()
|
|
||||||
);
|
|
||||||
if(lunarDate.term){
|
|
||||||
return lunarDate.term;
|
|
||||||
}
|
|
||||||
if(lunarDate.lunarFestival && lunarDate.lunarMonthName.indexOf("闰")==-1){
|
|
||||||
return lunarDate.lunarFestival;
|
|
||||||
}
|
|
||||||
if(lunarDate.solarFestival){
|
|
||||||
return lunarDate.solarFestival
|
|
||||||
}
|
|
||||||
return lunarDate.lunarMonthName+lunarDate.lunarDayName;
|
|
||||||
}
|
|
||||||
export {
|
export {
|
||||||
DATE_TIME_FORMAT, DATE_FORMAT, DATE_TIME_FORMAT_SIMPLE,
|
DATE_TIME_FORMAT, DATE_FORMAT, DATE_TIME_FORMAT_SIMPLE,
|
||||||
dayStartUtcFormat, nextDayStartUtcFormat, betweenTime,
|
dayStartUtcFormat, nextDayStartUtcFormat, betweenTime,
|
||||||
dateStartUtcFormat, nextDateStartUtcFormat, cronToChinese, dayjsWeek,lunarDateShow
|
dateStartUtcFormat, nextDateStartUtcFormat, cronToChinese, dayjsWeek
|
||||||
}
|
}
|
Loading…
Reference in New Issue