feat:1.主题配置2.网站首页设置3.设置信息持久化

This commit is contained in:
1708-huayu 2025-08-25 18:49:01 +08:00
parent 5eaf84df48
commit 51329f09e8
24 changed files with 324 additions and 89 deletions

View File

@ -57,6 +57,14 @@ http {
add_header 'Access-Control-Allow-Headers' 'User-Agent,Keep-Alive,Content-Type,Authorization,Origin,source-client' always; add_header 'Access-Control-Allow-Headers' 'User-Agent,Keep-Alive,Content-Type,Authorization,Origin,source-client' always;
# 缓存时间 # 缓存时间
add_header 'Access-Control-Max-Age' 1728000 always; add_header 'Access-Control-Max-Age' 1728000 always;
# 安全头部
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;
# 预检请求的处理 # 预检请求的处理
if ($request_method = 'OPTIONS') { if ($request_method = 'OPTIONS') {
return 204; return 204;
@ -83,7 +91,7 @@ http {
index index.html index.htm; index index.html index.htm;
# 正确的文件查找逻辑:所有路由都返回 index.html # 正确的文件查找逻辑:所有路由都返回 index.html
try_files $uri $uri/ /todo/index.html; try_files $uri $uri.html $uri/ /todo/index.html;
# 安全头部 # 安全头部
add_header X-Frame-Options "SAMEORIGIN" always; add_header X-Frame-Options "SAMEORIGIN" always;

BIN
public/static/favicon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

BIN
public/static/pc-Web.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 39 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 868 KiB

View File

@ -40,8 +40,8 @@ export default function Layout({children}: { children: React.ReactNode }) {
data: {state: data.taskState,pid:pid,treeList:true,treeOrList:false,treeFilter:true}, data: {state: data.taskState,pid:pid,treeList:true,treeOrList:false,treeFilter:true},
sortList:[{property:"sort_no",direction:"ASC"}] sortList:[{property:"sort_no",direction:"ASC"}]
} }
if (data.expectedStartTime.length>0){ if (data.expectedStartTime!.length>0){
const parse = JSON.parse(data.expectedStartTime); const parse = JSON.parse(data.expectedStartTime!);
requestParam.data.expectedStartTimeStart=parse[0].value; requestParam.data.expectedStartTimeStart=parse[0].value;
requestParam.data.expectedStartTimeEnd=parse[1].value; requestParam.data.expectedStartTimeEnd=parse[1].value;
} }

View File

@ -30,10 +30,10 @@ export default function Layout({children}: { children: React.ReactNode }) {
{name:'ALL-CHILD',value:"true",operateType: "ALL-CHILD"}, {name:'ALL-CHILD',value:"true",operateType: "ALL-CHILD"},
); );
}else { }else {
if (data.taskState.length>0){ if (data.taskState && data.taskState.length>0){
leftUp.push({name:"state",value:data.taskState,operateType:"IN"}); leftUp.push({name:"state",value:data.taskState,operateType:"IN"});
} }
if (data.expectedStartTime.length>0){ if (data.expectedStartTime && data.expectedStartTime.length>0){
const parse = JSON.parse(data.expectedStartTime); const parse = JSON.parse(data.expectedStartTime);
leftUp.push(...parse); leftUp.push(...parse);
} }

View File

@ -6,24 +6,64 @@ import dayjs from "dayjs";
import 'dayjs/locale/zh-cn'; import 'dayjs/locale/zh-cn';
import {ConfigProvider} from "antd"; import {ConfigProvider} from "antd";
import locale from "antd/locale/zh_CN"; import locale from "antd/locale/zh_CN";
import {BackgroundProvider, useBackground} from "@/ui/BackgroundContext";
import Cookies from "js-cookie";
export default function Layout({children}: { children: React.ReactNode }) { function BodyWithBackground({children}: { children: React.ReactNode }) {
dayjs.locale('zh-cn'); dayjs.locale('zh-cn');
const [taskState, setTaskState] = React.useState<string>('8,9,10') // 背景色 start
const {backgroundColor} = useBackground();
// 背景色 end
// 查询参数获取 start
const {
taskState: taskStateCookies, taskTypeList: taskTypeListCookies,
refreshDataFlag: refreshDataFlagCookies,
expectedStartTime: expectedStartTimeCookies
} = JSON.parse(Cookies.get('platform-setting') || "{}")
console.log(taskStateCookies || '8,9,10',{taskStateCookies})
const [taskState, setTaskState] =
React.useState<string>(taskStateCookies ?? '8,9,10')
let expectStartTimeList = []; let expectStartTimeList = [];
expectStartTimeList.push({'name': "expectedStartTime", 'value': dayjs().subtract(7, 'day'), 'operateType': ">="}); expectStartTimeList.push({'name': "expectedStartTime", 'value': dayjs().subtract(7, 'day'), 'operateType': ">="});
expectStartTimeList.push({'name': "expectedStartTime", 'value': dayjs().add(7, 'day'), 'operateType': "<"}) expectStartTimeList.push({'name': "expectedStartTime", 'value': dayjs().add(7, 'day'), 'operateType': "<"})
const [expectedStartTime, setExpectedStartTime] = React.useState<string>(JSON.stringify(expectStartTimeList)) const [expectedStartTime, setExpectedStartTime] = React.useState<string>(JSON.stringify(expectedStartTimeCookies ?? expectStartTimeList))
const [taskTypeList,setTaskTypeList] = React.useState<string[]>(["0,1,2,3","4"])
const [refreshDataFlag, setRefreshDataFlag] = React.useState<boolean>(true) const [taskTypeList, setTaskTypeList] = React.useState<string[]>(taskTypeListCookies ?? ["0,1,2,3", "4"])
const [refreshDataFlag, setRefreshDataFlag] = React.useState<boolean>(refreshDataFlagCookies || true)
console.log('taskState,expectedStartTime,refreshDataFlag', taskState, expectedStartTime, refreshDataFlag)
// 查询参数获取 end
// 设置参数 start
const updateCookies = (date: {}) => {
try {
const platform = Cookies.get('platform-setting');
const currentSettings = platform ? JSON.parse(platform) : {};
const updatedSettings = {
...currentSettings,
...date
};
Cookies.set('platform-setting', JSON.stringify(updatedSettings), {
expires: 365, // 1年有效期
path: '/',
secure: process.env.NODE_ENV === 'production'
});
} catch (error) {
console.error('获取设置失败:', error);
}
}
// 设置参数 end
function refreshData() { function refreshData() {
setRefreshDataFlag(!refreshDataFlag) setRefreshDataFlag(!refreshDataFlag)
} }
console.log('taskState,expectedStartTime,refreshDataFlag', taskState, expectedStartTime, refreshDataFlag)
return ( return (
<Fragment>
<ConfigProvider <ConfigProvider
locale={locale} locale={locale}
theme={{ theme={{
@ -34,9 +74,11 @@ export default function Layout({children}: { children: React.ReactNode }) {
}, },
}, },
token: { token: {
controlItemBgHover:"#4096ff", colorBgBase: backgroundColor,
controlItemBgActiveHover:"#4096ff", colorPrimaryBg: backgroundColor,
controlItemBgActive:"#4096ff" controlItemBgHover: "#4096ff",
controlItemBgActiveHover: "#4096ff",
controlItemBgActive: "#4096ff"
} }
}} }}
> >
@ -44,17 +86,40 @@ export default function Layout({children}: { children: React.ReactNode }) {
'taskState': taskState, 'taskState': taskState,
'expectedStartTime': expectedStartTime, 'expectedStartTime': expectedStartTime,
'refreshData': refreshDataFlag, 'refreshData': refreshDataFlag,
'taskTypeList':taskTypeList 'taskTypeList': taskTypeList
}} }}
> >
<TitleOperation setTaskState={setTaskState} setExpectedStartTime={setExpectedStartTime} <TitleOperation
setTaskTypeList={setTaskTypeList} setTaskState={(taskState) => {
console.log({taskTypeList})
setTaskState(taskState);
updateCookies({taskState})
}}
setExpectedStartTime={(expectedStartTime) => {
console.log({taskTypeList})
setExpectedStartTime(expectedStartTime);
updateCookies({updateCookies});
}}
setTaskTypeList={(taskTypeList) => {
console.log({taskTypeList})
setTaskTypeList(taskTypeList);
updateCookies({taskTypeList});
}}
refreshData={refreshData}/> refreshData={refreshData}/>
<div style={{height:"calc(100vh - 42px)",overflow:"auto"}}> <div style={{height: "calc(100vh - 42px)", overflow: "auto", background: backgroundColor}}>
{children} {children}
</div> </div>
</LocalContext.Provider> </LocalContext.Provider>
</ConfigProvider> </ConfigProvider>
);
}
export default function Layout({children}: { children: React.ReactNode }) {
return (
<Fragment>
<BackgroundProvider>
<BodyWithBackground> {children}</BodyWithBackground>
</BackgroundProvider>
</Fragment> </Fragment>
); );
} }

View File

@ -2,9 +2,7 @@ import TreeTablePro from "@/ui/task/project/TreeTablePro";
const Page: React.FC = () => { const Page: React.FC = () => {
return ( return (
<>
<TreeTablePro/> <TreeTablePro/>
</>
); );
}; };

View File

@ -102,9 +102,9 @@ const ShareOption = (props: { taskId: string }) => {
{buttonIndex == 1 && <div className="displayFlexRow"> {buttonIndex == 1 && <div className="displayFlexRow">
<div className="displayFlexColumn"> <div className="displayFlexColumn">
<div className="title"></div> <div className="title"></div>
<Image width={300} src="/static/pc-Web.png"/> <Image width={300} src="/static/pc-Web.jpg"/>
<Button <Button
onClick={() => doDownload("/static/pc-Web.png", '微信小程序马上行计划管理.png')}></Button> onClick={() => doDownload("/static/pc-Web.jpg", '微信小程序马上行计划管理.png')}></Button>
</div> </div>
<div className="displayFlexColumn" id="myqrcode"> <div className="displayFlexColumn" id="myqrcode">
<div className="title">1</div> <div className="title">1</div>

View File

@ -12,6 +12,7 @@ import {
quitTeamAPI, quitTeamAPI,
removeTeamAPI removeTeamAPI
} from "@/components/service/Share"; } from "@/components/service/Share";
import Cookies from "js-cookie";
const TeamMember = (props: { taskId: string, closeOpen?: () => void, reloadData?: () => void }) => { const TeamMember = (props: { taskId: string, closeOpen?: () => void, reloadData?: () => void }) => {
const [open, setOpen] = useState(false); const [open, setOpen] = useState(false);
@ -54,7 +55,10 @@ const TeamMember = (props: { taskId: string, closeOpen?: () => void, reloadData?
// 处理管理员数据 // 处理管理员数据
if (adminRes.data?.status?.success) { if (adminRes.data?.status?.success) {
const message = localStorage.getItem('user-message'); let message = localStorage.getItem('user-message');
if (!message){
message = Cookies.get('user-message')||""
}
if (message) { if (message) {
try { try {
const { username } = JSON.parse(message); const { username } = JSON.parse(message);

7
src/lib/PlatformSettingModel.d.ts vendored Normal file
View File

@ -0,0 +1,7 @@
export interface PlatformSettingModel {
colorBgBase?:string,
taskState?:string,
expectedStartTime?:string,
refreshData?:boolean,
taskTypeList?:string[]
}

View File

@ -0,0 +1,72 @@
// contexts/BackgroundContext.tsx
'use client';
import React, {createContext, useContext, useState, ReactNode} from 'react';
import Cookies from "js-cookie";
interface BackgroundContextType {
backgroundColor: string;
setBackgroundColor: (color: string) => void;
}
const BackgroundContext = createContext<BackgroundContextType | undefined>(undefined);
// 导出 hook
export const useBackground = () => {
const context = useContext(BackgroundContext);
if (context === undefined) {
throw new Error('useBackground must be used within a BackgroundProvider');
}
return context;
};
// 导出 Provider
interface BackgroundProviderProps {
children: ReactNode;
}
export const BackgroundProvider: React.FC<BackgroundProviderProps> = ({children}) => {
const [backgroundColor, setBackgroundColor] = useState<string>(() => {
try {
const platform = Cookies.get('platform-setting');
if (!platform) return '#fff';
const settings = JSON.parse(platform);
return settings?.colorBgBase || '#fff';
} catch (error) {
console.error('获取设置失败:', error);
return '#fff'; // 确保有默认值
}
});
const setBackgroundColorCookies = (color: string) => {
setBackgroundColor(color)
try {
const platform = Cookies.get('platform-setting');
const currentSettings = platform ? JSON.parse(platform) : {};
const updatedSettings = {
...currentSettings,
colorBgBase: color
};
Cookies.set('platform-setting', JSON.stringify(updatedSettings), {
expires: 365, // 1年有效期
path: '/',
secure: process.env.NODE_ENV === 'production'
});
} catch (error) {
console.error('获取设置失败:', error);
}
}
return (
<BackgroundContext.Provider value={{backgroundColor, setBackgroundColor: setBackgroundColorCookies}}>
{children}
</BackgroundContext.Provider>
);
};

View File

@ -1,6 +1,6 @@
import React from 'react'; import React from 'react';
import {PlatformSettingModel} from "@/lib/PlatformSettingModel";
const LocalContext = React.createContext({'taskState':'','expectedStartTime':'','refreshData':true, const LocalContext = React.createContext<PlatformSettingModel>({});
'taskTypeList':[""]});
export default LocalContext; export default LocalContext;

View File

@ -10,6 +10,7 @@ import {LoginObject} from "@/lib/login/definitions";
import {useRouter} from 'next/navigation' import {useRouter} from 'next/navigation'
import {v4 as uuidv4} from 'uuid'; import {v4 as uuidv4} from 'uuid';
import {askLoginAPI, generateQrcodeAPI} from "@/lib/login/service"; import {askLoginAPI, generateQrcodeAPI} from "@/lib/login/service";
import Cookies from "js-cookie";
// import Cookies from "js-cookie"; // import Cookies from "js-cookie";
export default function XcxLoginPage() { export default function XcxLoginPage() {
@ -81,6 +82,11 @@ export default function XcxLoginPage() {
localStorage.setItem('user-message', JSON.stringify(res.data.data[0],(key, value) => { localStorage.setItem('user-message', JSON.stringify(res.data.data[0],(key, value) => {
return key === 'password' ? undefined : value; return key === 'password' ? undefined : value;
})) }))
Cookies.set('platform-security', res.data.data[0].token,{
expires: 365, // 1年有效期
path: '/',
secure: process.env.NODE_ENV === 'production'
})
// 删除名为 'platform-security' 的Cookie // 删除名为 'platform-security' 的Cookie
// Cookies.remove('platform-security'); // Cookies.remove('platform-security');
// 设置一个有效期为7天的Cookie // 设置一个有效期为7天的Cookie
@ -148,7 +154,7 @@ export default function XcxLoginPage() {
{ {
qrCodeShow ? qrCodeShow ?
<QRCode value={qrCodeValue} size={300} status={qrCodeStatus} onRefresh={generateQrcode}/> : <QRCode value={qrCodeValue} size={300} status={qrCodeStatus} onRefresh={generateQrcode}/> :
<Image width={300} src="/static/pc-Web.png"/> <Image width={300} src="/static/pc-Web.jpg"/>
} }
</div> </div>
</LoginFormPage> : <Skeleton/>} </LoginFormPage> : <Skeleton/>}

View File

@ -1,6 +1,17 @@
'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,
ColorPicker,
DatePicker,
MenuProps,
message,
Popconfirm,
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 {deleteTask, OPERATION_BUTTON_TYPE, taskStateList} from "@/lib/task/project/data";
@ -11,7 +22,12 @@ 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"; import {QuestionCircleOutlined} from "@ant-design/icons";
import { theme } from 'antd';
import type {Color} from "antd/es/color-picker/color";
import {useBackground} from "@/ui/BackgroundContext";
import Cookies from "js-cookie";
const { useToken } = theme;
interface TitleOperationProps { interface TitleOperationProps {
setTaskState: (value: string) => void; setTaskState: (value: string) => void;
setTaskTypeList: (value: string[]) => void; setTaskTypeList: (value: string[]) => void;
@ -28,16 +44,16 @@ export const TitleOperation: React.FC<TitleOperationProps> = ({
const {replace} = useRouter(); const {replace} = useRouter();
const searchParams = useSearchParams(); const searchParams = useSearchParams();
const pathname = usePathname(); const pathname = usePathname();
const { token } = useToken();
const [pathParam, setPathParam] = useState<string | undefined>(searchParams.toString()); const [pathParam, setPathParam] = useState<string | undefined>(searchParams.toString());
const [pathName, setPathName] = useState(pathname); const [pathName, setPathName] = useState(pathname);
const { backgroundColor, setBackgroundColor } = useBackground();
console.log('usePathname()', pathname); console.log('usePathname()', pathname);
console.log('useSearchParams()', searchParams.toString(), searchParams.get('pName'), searchParams.get('pid')); console.log('useSearchParams()', searchParams.toString(), searchParams.get('pName'), searchParams.get('pid'));
const data = useContext(LocalContext); const data = useContext(LocalContext);
const {RangePicker} = DatePicker; const {RangePicker} = DatePicker;
const expectStartTimeParseResult: RequestDateType[] = data.expectedStartTime.length > 0 ? JSON.parse(data.expectedStartTime) : [undefined, undefined] const expectStartTimeParseResult: RequestDateType[] = data.expectedStartTime!.length > 0 ? JSON.parse(data.expectedStartTime!) : [undefined, undefined]
expectStartTimeParseResult.map(item => item && item.value ? dayjs(item.value.toString()) : undefined) expectStartTimeParseResult.map(item => item && item.value ? dayjs(item.value.toString()) : undefined)
const defaultExpectStartTime: [start: Dayjs | null | undefined, end: Dayjs | null | undefined] = [ const defaultExpectStartTime: [start: Dayjs | null | undefined, end: Dayjs | null | undefined] = [
expectStartTimeParseResult[0] && expectStartTimeParseResult[0].value ? dayjs(expectStartTimeParseResult[0].value.toString()) : undefined, expectStartTimeParseResult[0] && expectStartTimeParseResult[0].value ? dayjs(expectStartTimeParseResult[0].value.toString()) : undefined,
@ -62,6 +78,9 @@ export const TitleOperation: React.FC<TitleOperationProps> = ({
useEffect(() => { useEffect(() => {
let userMessage = localStorage.getItem('user-message'); let userMessage = localStorage.getItem('user-message');
if (!userMessage){
userMessage = Cookies.get('user-message')||""
}
if (userMessage) { if (userMessage) {
let parse = JSON.parse(userMessage); let parse = JSON.parse(userMessage);
setNickName(parse.nickname) setNickName(parse.nickname)
@ -79,6 +98,16 @@ export const TitleOperation: React.FC<TitleOperationProps> = ({
} }
}; };
const changeBackGroundColor = (value: Color, hex: string) =>{
console.log({value},{hex},value.toHexString())
// setBackgroundColor(typeof value === 'string' ? value : value!.toHexString())
setBackgroundColor(value.toHexString())
}
const clearBackGroundColor = ()=>{
setBackgroundColor("#fff")
}
const items: MenuProps['items'] = [ const items: MenuProps['items'] = [
{ {
label: <Popconfirm label: <Popconfirm
@ -94,6 +123,14 @@ export const TitleOperation: React.FC<TitleOperationProps> = ({
><a>退</a></Popconfirm>, ><a>退</a></Popconfirm>,
key: '1', key: '1',
}, },
{
label: <ColorPicker trigger="hover" allowClear onClear={clearBackGroundColor}
value={backgroundColor}
onChange={changeBackGroundColor}>
<a></a>
</ColorPicker>,
key:3
},
]; ];
const itemsPid: MenuProps['items'] = [ const itemsPid: MenuProps['items'] = [
{ {
@ -110,14 +147,23 @@ export const TitleOperation: React.FC<TitleOperationProps> = ({
><a>退</a></Popconfirm>, ><a>退</a></Popconfirm>,
key: '1', key: '1',
}, },
{
label: <ColorPicker trigger="hover"
allowClear onClear={clearBackGroundColor}
value={backgroundColor}
onChange={changeBackGroundColor}>
<a></a>
</ColorPicker>,
key:3
},
{ {
label: '从顶级任务查看', label: '从顶级任务查看',
key: '2', key: '2',
}, },
]; ];
return <div className={style.container}> return <div className={style.container} style={{background: token.colorBgBase,}}>
<Space style={{marginTop: 0, "height": "42px", "alignContent": "center"}}> <Space style={{marginTop: 0, height: "42px", alignContent: "center", }}>
<DetailModelForm haveButton={true} open={false} operationId={OPERATION_BUTTON_TYPE.ADD} <DetailModelForm haveButton={true} open={false} operationId={OPERATION_BUTTON_TYPE.ADD}
description='添加主线任务' reloadData={refreshData}/> description='添加主线任务' reloadData={refreshData}/>
{ {
@ -163,7 +209,7 @@ 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) {

View File

@ -315,7 +315,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 == "" ? [] : 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);
}) })

View File

@ -2,7 +2,7 @@
import React, {CSSProperties} from "react"; import React, {CSSProperties} from "react";
import {Draggable, Droppable} from "react-beautiful-dnd"; import {Draggable, Droppable} from "react-beautiful-dnd";
import {ConfigProvider, Tooltip} from "antd"; import {ConfigProvider, theme, Tooltip} from "antd";
import {DataType} from "@/lib/definitions"; import {DataType} from "@/lib/definitions";
import './index.modules.css' import './index.modules.css'
import dayjs from "dayjs"; import dayjs from "dayjs";
@ -21,6 +21,8 @@ interface DroppableTableProps {
} }
export const DroppableTable = React.memo((props: DroppableTableProps) => { export const DroppableTable = React.memo((props: DroppableTableProps) => {
const { useToken } = theme;
const { token } = useToken();
const stateName = React.useMemo(() => { const stateName = React.useMemo(() => {
switch (props.tableCode) { switch (props.tableCode) {
case '0': case '0':
@ -38,7 +40,7 @@ export const DroppableTable = React.memo((props: DroppableTableProps) => {
const getItemStyle = React.useCallback((isDragging: boolean, draggableStyle: any): CSSProperties => ({ const getItemStyle = React.useCallback((isDragging: boolean, draggableStyle: any): CSSProperties => ({
userSelect: "none", userSelect: "none",
background: isDragging ? "lightgreen" : "white", background: isDragging ? "lightgreen" : token.colorBgBase,
position: 'relative', position: 'relative',
zIndex: isDragging ? 2147483647 : 'auto', zIndex: isDragging ? 2147483647 : 'auto',
...draggableStyle, ...draggableStyle,
@ -47,13 +49,13 @@ export const DroppableTable = React.memo((props: DroppableTableProps) => {
verticalAlign: 'middle', verticalAlign: 'middle',
textAlign: 'center', textAlign: 'center',
borderColor:taskPriorityList.find((item) => item.code === props.tableCode)?.color borderColor:taskPriorityList.find((item) => item.code === props.tableCode)?.color
}), []); }), [token]);
const getListStyle = React.useCallback((isDraggingOver: boolean) => ({ const getListStyle = React.useCallback((isDraggingOver: boolean) => ({
background: isDraggingOver ? "lightblue" : "white", background: isDraggingOver ? "lightblue" : token.colorBgBase,
height: 'calc((100vh - 42px)/2)', height: 'calc((100vh - 42px)/2)',
width: '50vw' width: '50vw'
}), []); }), [token]);
const headerStyle = React.useMemo(() => ({ const headerStyle = React.useMemo(() => ({
backgroundColor: taskPriorityList.find((item) => item.code === props.tableCode)?.color, backgroundColor: taskPriorityList.find((item) => item.code === props.tableCode)?.color,

View File

@ -61,16 +61,16 @@ const TreeTable: React.FC<TableSearchType> = (props) => {
dataIndex: 'state', dataIndex: 'state',
width: '10%', width: '10%',
key: 'state', key: 'state',
filtered: checkLocal&&dataLocalContext.taskState.length > 0, filtered: checkLocal&&dataLocalContext.taskState!.length > 0,
defaultFilteredValue: dataLocalContext.taskState.split(','), defaultFilteredValue: dataLocalContext.taskState!.split(','),
onFilter: (text, record) => { onFilter: (text, record) => {
// console.log('&record.priority.toString()===props.priority',record.priority,text,props.priority) // console.log('&record.priority.toString()===props.priority',record.priority,text,props.priority)
// &record.priority.toString()===props.priority 不重要紧急 0 0 // &record.priority.toString()===props.priority 不重要紧急 0 0
if (dataLocalContext.taskState.length === 0) { if (dataLocalContext.taskState!.length === 0) {
return true; return true;
} }
var dataLocalContextTaskStateList = dataLocalContext.taskState.split(","); var dataLocalContextTaskStateList = dataLocalContext.taskState!.split(",");
console.log('dataLocalContextTaskStateList', dataLocalContext.taskState.length > 0, dataLocalContextTaskStateList); console.log('dataLocalContextTaskStateList', dataLocalContext.taskState!.length > 0, dataLocalContextTaskStateList);
return taskStateList.filter(taskState => dataLocalContextTaskStateList.includes(taskState.code)) return taskStateList.filter(taskState => dataLocalContextTaskStateList.includes(taskState.code))
.find(taskState => taskState.name === record.state) != undefined; .find(taskState => taskState.name === record.state) != undefined;
} }
@ -100,14 +100,14 @@ const TreeTable: React.FC<TableSearchType> = (props) => {
dataIndex: 'expectedStartTime', dataIndex: 'expectedStartTime',
width: '10%', width: '10%',
key: 'expectedStartTime', key: 'expectedStartTime',
filtered: checkLocal&&dataLocalContext.expectedStartTime.length > 0, filtered: checkLocal&&dataLocalContext.expectedStartTime!.length > 0,
// defaultFilteredValue: JSON.parse(dataLocalContext.expectedStartTime), // defaultFilteredValue: JSON.parse(dataLocalContext.expectedStartTime),
onFilter: (text, record) => { onFilter: (text, record) => {
console.log('dataLocalContext.expectedStartTime',dataLocalContext.expectedStartTime) console.log('dataLocalContext.expectedStartTime',dataLocalContext.expectedStartTime)
if (dataLocalContext.expectedStartTime.length === 0) { if (dataLocalContext.expectedStartTime!.length === 0) {
return true; return true;
} }
const expectStartTimeParseResult:RequestDateType[] = JSON.parse(dataLocalContext.expectedStartTime); const expectStartTimeParseResult:RequestDateType[] = JSON.parse(dataLocalContext.expectedStartTime!);
console.log('expectStartTimeParseResult',expectStartTimeParseResult) console.log('expectStartTimeParseResult',expectStartTimeParseResult)
if (expectStartTimeParseResult[0]!=undefined){ if (expectStartTimeParseResult[0]!=undefined){
let le:boolean; let le:boolean;
@ -155,10 +155,10 @@ const TreeTable: React.FC<TableSearchType> = (props) => {
resultDataType.action= <OperationButton itemId={resultDataType.id} itemName={resultDataType.name} resultDataType.action= <OperationButton itemId={resultDataType.id} itemName={resultDataType.name}
fId={resultDataType.fId} fName={resultDataType.fName} fId={resultDataType.fId} fName={resultDataType.fName}
pid={resultDataType.pid} pPid={resultDataType.pPid} refreshDate={props.refreshDate}/> pid={resultDataType.pid} pPid={resultDataType.pPid} refreshDate={props.refreshDate}/>
if (dataLocalContext.expectedStartTime.length === 0) { if (dataLocalContext.expectedStartTime!.length === 0) {
return true; return true;
} }
const expectStartTimeParseResult:RequestDateType[] = JSON.parse(dataLocalContext.expectedStartTime); const expectStartTimeParseResult:RequestDateType[] = JSON.parse(dataLocalContext.expectedStartTime!);
if (expectStartTimeParseResult[0]!=undefined){ if (expectStartTimeParseResult[0]!=undefined){
let le:boolean; let le:boolean;
if (expectStartTimeParseResult[0].operateType==='<='){ if (expectStartTimeParseResult[0].operateType==='<='){

View File

@ -62,16 +62,16 @@ const TreeTable: React.FC<TableSearchType> = (props) => {
dataIndex: 'state', dataIndex: 'state',
width: '10%', width: '10%',
key: 'state', key: 'state',
filtered: checkLocal&&dataLocalContext.taskState.length > 0, filtered: checkLocal&&dataLocalContext.taskState!.length > 0,
defaultFilteredValue: dataLocalContext.taskState.split(','), defaultFilteredValue: dataLocalContext.taskState!.split(','),
onFilter: (text, record) => { onFilter: (text, record) => {
// console.log('&record.priority.toString()===props.priority',record.priority,text,props.priority) // console.log('&record.priority.toString()===props.priority',record.priority,text,props.priority)
// &record.priority.toString()===props.priority 不重要紧急 0 0 // &record.priority.toString()===props.priority 不重要紧急 0 0
if (dataLocalContext.taskState.length === 0) { if (dataLocalContext.taskState!.length === 0) {
return true; return true;
} }
var dataLocalContextTaskStateList = dataLocalContext.taskState.split(","); var dataLocalContextTaskStateList = dataLocalContext.taskState!.split(",");
console.log('dataLocalContextTaskStateList', dataLocalContext.taskState.length > 0, dataLocalContextTaskStateList); console.log('dataLocalContextTaskStateList', dataLocalContext.taskState!.length > 0, dataLocalContextTaskStateList);
return taskStateList.filter(taskState => dataLocalContextTaskStateList.includes(taskState.code)) return taskStateList.filter(taskState => dataLocalContextTaskStateList.includes(taskState.code))
.find(taskState => taskState.name === record.state) != undefined; .find(taskState => taskState.name === record.state) != undefined;
}, },
@ -101,14 +101,14 @@ const TreeTable: React.FC<TableSearchType> = (props) => {
dataIndex: 'expectedStartTime', dataIndex: 'expectedStartTime',
width: '13%', width: '13%',
key: 'expectedStartTime', key: 'expectedStartTime',
filtered: checkLocal&&dataLocalContext.expectedStartTime.length > 0, filtered: checkLocal&&dataLocalContext.expectedStartTime!.length > 0,
// defaultFilteredValue: JSON.parse(dataLocalContext.expectedStartTime), // defaultFilteredValue: JSON.parse(dataLocalContext.expectedStartTime),
onFilter: (text, record) => { onFilter: (text, record) => {
console.log('dataLocalContext.expectedStartTime',dataLocalContext.expectedStartTime) console.log('dataLocalContext.expectedStartTime',dataLocalContext.expectedStartTime)
if (dataLocalContext.expectedStartTime.length === 0) { if (dataLocalContext.expectedStartTime!.length === 0) {
return true; return true;
} }
const expectStartTimeParseResult:RequestDateType[] = JSON.parse(dataLocalContext.expectedStartTime); const expectStartTimeParseResult:RequestDateType[] = JSON.parse(dataLocalContext.expectedStartTime!);
console.log('expectStartTimeParseResult',expectStartTimeParseResult) console.log('expectStartTimeParseResult',expectStartTimeParseResult)
if (expectStartTimeParseResult[0]!=undefined){ if (expectStartTimeParseResult[0]!=undefined){
let le:boolean; let le:boolean;
@ -169,10 +169,10 @@ const TreeTable: React.FC<TableSearchType> = (props) => {
resultDataType.action= <OperationButton itemId={resultDataType.id} itemName={resultDataType.name} resultDataType.action= <OperationButton itemId={resultDataType.id} itemName={resultDataType.name}
fId={resultDataType.fId} fName={resultDataType.fName} fId={resultDataType.fId} fName={resultDataType.fName}
priority={resultDataType.priority} pid={resultDataType.pid} pPid={resultDataType.pPid} refreshDate={props.refreshDate}/> priority={resultDataType.priority} pid={resultDataType.pid} pPid={resultDataType.pPid} refreshDate={props.refreshDate}/>
if (dataLocalContext.expectedStartTime.length === 0) { if (dataLocalContext.expectedStartTime!.length === 0) {
return true; return true;
} }
const expectStartTimeParseResult:RequestDateType[] = JSON.parse(dataLocalContext.expectedStartTime); const expectStartTimeParseResult:RequestDateType[] = JSON.parse(dataLocalContext.expectedStartTime!);
if (expectStartTimeParseResult[0]!=undefined){ if (expectStartTimeParseResult[0]!=undefined){
let le:boolean; let le:boolean;
if (expectStartTimeParseResult[0].operateType==='<='){ if (expectStartTimeParseResult[0].operateType==='<='){

View File

@ -22,6 +22,7 @@ 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"; import {copyToClipboard} from "@/lib/copyToClipboard";
import LocalContext from "@/ui/LocalContent";
const TreeTablePro: React.FC = (props: { joinId?: string }) => { const TreeTablePro: React.FC = (props: { joinId?: string }) => {
// 刷新表格 // 刷新表格
@ -33,6 +34,7 @@ const TreeTablePro: React.FC = (props: { joinId?: string }) => {
// 页码信息 // 页码信息
const [current, setCurrent] = React.useState(1); const [current, setCurrent] = React.useState(1);
const [pageSize, setPageSize] = React.useState(10); const [pageSize, setPageSize] = React.useState(10);
const {taskState: state} = useContext(LocalContext);
// 获取路径参数pid // 获取路径参数pid
const pathPid = useSearchParams().get('pid'); const pathPid = useSearchParams().get('pid');
const pid = pathPid ? pathPid : '0'; const pid = pathPid ? pathPid : '0';
@ -111,9 +113,9 @@ const TreeTablePro: React.FC = (props: { joinId?: string }) => {
dataIndex: 'state', dataIndex: 'state',
valueType: 'select', valueType: 'select',
order: 3, order: 3,
initialValue: ['8', '9'], initialValue: state =="" ?undefined:state!.split(','),
fieldProps: { fieldProps: {
defaultValue: ['8', '9'], defaultValue: state =="" ?undefined:state!.split(','),
mode: "tags", mode: "tags",
options: taskStateList.map(item => { options: taskStateList.map(item => {
return {label: item.name, value: item.code} return {label: item.name, value: item.code}

View File

@ -1,6 +1,7 @@
import axios, {AxiosInterceptorOptions, CancelTokenSource} from "axios"; import axios, {AxiosInterceptorOptions, CancelTokenSource} from "axios";
import {message} from "antd"; import {message} from "antd";
import {refreshTokenAPI} from "@/lib/login/service"; import {refreshTokenAPI} from "@/lib/login/service";
import Cookies from "js-cookie";
export const httpReq = axios.create({ export const httpReq = axios.create({
@ -21,7 +22,10 @@ httpReq.defaults.headers.common['Accept'] = 'application/json';
httpReq.interceptors.request.use((config) => { httpReq.interceptors.request.use((config) => {
console.log("config.url", config.url) console.log("config.url", config.url)
// 从本地存储中获取 token // 从本地存储中获取 token
const token = localStorage.getItem('platform-security'); let token = localStorage.getItem('platform-security');
if (!token){
token=Cookies.get("platform-security")||""
}
if (token) { if (token) {
config.headers.Authorization = `Bearer ${token}`; config.headers.Authorization = `Bearer ${token}`;
if (config.url && config.url.indexOf("refreshToken") == -1 && if (config.url && config.url.indexOf("refreshToken") == -1 &&
@ -76,6 +80,11 @@ function reduceToken(token: string) {
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)
Cookies.set('platform-security', res.data.data,{
expires: 365, // 1年有效期
path: '/',
secure: process.env.NODE_ENV === 'production'
})
} }
}) })
} }

View File

@ -32,7 +32,8 @@
"**/*.ts", "**/*.ts",
"**/*.tsx", "**/*.tsx",
".next/types/**/*.ts", ".next/types/**/*.ts",
"docker/out/types/**/*.ts" "docker/out/types/**/*.ts",
"docker/outd/types/**/*.ts"
], ],
"exclude": [ "exclude": [
"node_modules" "node_modules"

View File

@ -1,6 +1,4 @@
# 可能用到的技术栈 # 可能用到的技术栈
## Next
https://nextjs.org/docs/app/api-reference/cli/next#next-build-options
## 面向开发者的 Web 技术 ## 面向开发者的 Web 技术
https://developer.mozilla.org/zh-CN/docs/Web/API/Window/scrollX https://developer.mozilla.org/zh-CN/docs/Web/API/Window/scrollX
## 富文本 ## 富文本

View File

@ -0,0 +1,17 @@
## next
https://nextjs.org/docs/app/guides/static-exports
## ant定制主题
https://ant.design/docs/react/customize-theme-cn
https://ant.design/theme-editor-cn#Color
## react-big-calendar
演示
https://jquense.github.io/react-big-calendar/examples/index.html?path=/docs/about-big-calendar--page
github
https://github.com/jquense/react-big-calendar
## LunarCalendar
https://www.npmjs.com/package/lunar-calendar
https://github.com/zzyss86/LunarCalendar
## umi
https://umijs.org/docs/introduce/faq