feat:二维码及日志

This commit is contained in:
1708-huayu 2025-07-15 19:04:51 +08:00
parent fdd657a1b3
commit a2eb3d0473
11 changed files with 445 additions and 113 deletions

33
package-lock.json generated
View File

@ -24,7 +24,8 @@
"react-dom": "^18", "react-dom": "^18",
"react-virtualized": "^9.22.6", "react-virtualized": "^9.22.6",
"sass": "^1.77.3", "sass": "^1.77.3",
"tailwindcss": "3.3.3" "tailwindcss": "3.3.3",
"uuid": "^11.1.0"
}, },
"devDependencies": { "devDependencies": {
"@types/js-cookie": "^3.0.6", "@types/js-cookie": "^3.0.6",
@ -33,6 +34,7 @@
"@types/react-big-calendar": "^1.8.9", "@types/react-big-calendar": "^1.8.9",
"@types/react-dom": "^18", "@types/react-dom": "^18",
"@types/react-virtualized": "^9.22.2", "@types/react-virtualized": "^9.22.2",
"@types/uuid": "^10.0.0",
"@vercel/style-guide": "^5.0.1", "@vercel/style-guide": "^5.0.1",
"eslint": "^8", "eslint": "^8",
"eslint-config-next": "14.2.29", "eslint-config-next": "14.2.29",
@ -1670,6 +1672,12 @@
"integrity": "sha512-I8EUhyrgfLrcTkzV3TSsGyl1tSuPrEDzr0yd5m90UgNxQkyDXULk3b6MlQqTCpZpNtWe1K0hzclnZkTcLBe2UQ==", "integrity": "sha512-I8EUhyrgfLrcTkzV3TSsGyl1tSuPrEDzr0yd5m90UgNxQkyDXULk3b6MlQqTCpZpNtWe1K0hzclnZkTcLBe2UQ==",
"dev": true "dev": true
}, },
"node_modules/@types/uuid": {
"version": "10.0.0",
"resolved": "https://registry.npmmirror.com/@types/uuid/-/uuid-10.0.0.tgz",
"integrity": "sha512-7gqG38EyHgyP1S+7+xomFtL+ZNHcKv6DwNaCZmJmo1vgMugyF3TCnXVg4t1uk89mLNwnLtnY3TpOpCOyp1/xHQ==",
"dev": true
},
"node_modules/@types/warning": { "node_modules/@types/warning": {
"version": "3.0.3", "version": "3.0.3",
"resolved": "https://registry.npmmirror.com/@types/warning/-/warning-3.0.3.tgz", "resolved": "https://registry.npmmirror.com/@types/warning/-/warning-3.0.3.tgz",
@ -7534,6 +7542,18 @@
"resolved": "https://registry.npmmirror.com/util-deprecate/-/util-deprecate-1.0.2.tgz", "resolved": "https://registry.npmmirror.com/util-deprecate/-/util-deprecate-1.0.2.tgz",
"integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw=="
}, },
"node_modules/uuid": {
"version": "11.1.0",
"resolved": "https://registry.npmmirror.com/uuid/-/uuid-11.1.0.tgz",
"integrity": "sha512-0/A9rDy9P7cJ+8w1c9WD9V//9Wj15Ce2MPz8Ri6032usz+NfePxx5AcN3bN+r6ZL6jEo066/yNYB3tn4pQEx+A==",
"funding": [
"https://github.com/sponsors/broofa",
"https://github.com/sponsors/ctavan"
],
"bin": {
"uuid": "dist/esm/bin/uuid"
}
},
"node_modules/validate-npm-package-license": { "node_modules/validate-npm-package-license": {
"version": "3.0.4", "version": "3.0.4",
"resolved": "https://registry.npmmirror.com/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", "resolved": "https://registry.npmmirror.com/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz",
@ -8969,6 +8989,12 @@
"integrity": "sha512-I8EUhyrgfLrcTkzV3TSsGyl1tSuPrEDzr0yd5m90UgNxQkyDXULk3b6MlQqTCpZpNtWe1K0hzclnZkTcLBe2UQ==", "integrity": "sha512-I8EUhyrgfLrcTkzV3TSsGyl1tSuPrEDzr0yd5m90UgNxQkyDXULk3b6MlQqTCpZpNtWe1K0hzclnZkTcLBe2UQ==",
"dev": true "dev": true
}, },
"@types/uuid": {
"version": "10.0.0",
"resolved": "https://registry.npmmirror.com/@types/uuid/-/uuid-10.0.0.tgz",
"integrity": "sha512-7gqG38EyHgyP1S+7+xomFtL+ZNHcKv6DwNaCZmJmo1vgMugyF3TCnXVg4t1uk89mLNwnLtnY3TpOpCOyp1/xHQ==",
"dev": true
},
"@types/warning": { "@types/warning": {
"version": "3.0.3", "version": "3.0.3",
"resolved": "https://registry.npmmirror.com/@types/warning/-/warning-3.0.3.tgz", "resolved": "https://registry.npmmirror.com/@types/warning/-/warning-3.0.3.tgz",
@ -13420,6 +13446,11 @@
"resolved": "https://registry.npmmirror.com/util-deprecate/-/util-deprecate-1.0.2.tgz", "resolved": "https://registry.npmmirror.com/util-deprecate/-/util-deprecate-1.0.2.tgz",
"integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw=="
}, },
"uuid": {
"version": "11.1.0",
"resolved": "https://registry.npmmirror.com/uuid/-/uuid-11.1.0.tgz",
"integrity": "sha512-0/A9rDy9P7cJ+8w1c9WD9V//9Wj15Ce2MPz8Ri6032usz+NfePxx5AcN3bN+r6ZL6jEo066/yNYB3tn4pQEx+A=="
},
"validate-npm-package-license": { "validate-npm-package-license": {
"version": "3.0.4", "version": "3.0.4",
"resolved": "https://registry.npmmirror.com/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", "resolved": "https://registry.npmmirror.com/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz",

View File

@ -25,7 +25,8 @@
"react-dom": "^18", "react-dom": "^18",
"react-virtualized": "^9.22.6", "react-virtualized": "^9.22.6",
"sass": "^1.77.3", "sass": "^1.77.3",
"tailwindcss": "3.3.3" "tailwindcss": "3.3.3",
"uuid": "^11.1.0"
}, },
"devDependencies": { "devDependencies": {
"@types/js-cookie": "^3.0.6", "@types/js-cookie": "^3.0.6",
@ -34,6 +35,7 @@
"@types/react-big-calendar": "^1.8.9", "@types/react-big-calendar": "^1.8.9",
"@types/react-dom": "^18", "@types/react-dom": "^18",
"@types/react-virtualized": "^9.22.2", "@types/react-virtualized": "^9.22.2",
"@types/uuid": "^10.0.0",
"@vercel/style-guide": "^5.0.1", "@vercel/style-guide": "^5.0.1",
"eslint": "^8", "eslint": "^8",
"eslint-config-next": "14.2.29", "eslint-config-next": "14.2.29",

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 103 KiB

View File

@ -1,15 +1,14 @@
'use client' 'use client'
import {ProConfigProvider} from "@ant-design/pro-components"; import {ProConfigProvider} from "@ant-design/pro-components";
import React, {lazy, Suspense} from "react"; import React, {lazy, Suspense} from "react";
import Page from "@/ui/login/Page";
import Loading from "@/app/loading"; import Loading from "@/app/loading";
// const Page = lazy(() => import('@/ui/login/Page')); import XcxLoginPage from "@/ui/login/XcxLoginPage";
export default function Login() { export default function Login() {
return ( return (
<Suspense fallback={<Loading/>}> <Suspense fallback={<Loading/>}>
<ProConfigProvider dark> <ProConfigProvider dark>
<Page/> <XcxLoginPage/>
</ProConfigProvider> </ProConfigProvider>
</Suspense> </Suspense>
); );

View File

@ -0,0 +1,100 @@
import React, {useEffect, useState} from 'react';
import { Avatar, List, message } from 'antd';
import VirtualList from 'rc-virtual-list';
import { Button, Drawer } from 'antd';
interface UserItem {
email: string;
gender: string;
name: string;
avatar: string;
}
const CONTAINER_HEIGHT = 400;
const PAGE_SIZE = 20;
const DiaryOption = () => {
// 抽屉 start
const [open, setOpen] = useState(false);
const showDrawer = () => {
setOpen(true);
};
const onClose = () => {
setOpen(false);
};
// 抽屉 end
// 数据 start
const [data, setData] = useState<UserItem[]>([]);
const [page, setPage] = useState(1);
const appendData = (showMessage = true) => {
const fakeDataUrl = `https://660d2bd96ddfa2943b33731c.mockapi.io/api/users/?page=${page}&limit=${PAGE_SIZE}`;
fetch(fakeDataUrl)
.then((res) => res.json())
.then((body) => {
const results = Array.isArray(body) ? body : [];
setData(data.concat(results));
setPage(page + 1);
showMessage && message.success(`${results.length} more items loaded!`);
});
};
useEffect(() => {
appendData(false);
}, []);
const onScroll = (e: React.UIEvent<HTMLElement, UIEvent>) => {
// Refer to: https://developer.mozilla.org/en-US/docs/Web/API/Element/scrollHeight#problems_and_solutions
if (
Math.abs(e.currentTarget.scrollHeight - e.currentTarget.scrollTop - CONTAINER_HEIGHT) <= 1
) {
appendData();
}
};
// 数据 end
return (
<>
<Button type="primary" onClick={showDrawer}>
</Button>
<Drawer
mask={false}
title="Basic Drawer"
closable={{ 'aria-label': 'Close Button' }}
onClose={onClose}
open={open}
>
<div className="displayFlexRow">
<Button type="primary"></Button>
<Button type="primary"></Button>
<Button type="primary"></Button>
</div>
<div>
<List>
<VirtualList
data={data}
height={CONTAINER_HEIGHT}
itemHeight={47}
itemKey="email"
onScroll={onScroll}
>
{item => (
<List.Item key={item.email}>
<List.Item.Meta
avatar={<Avatar src={item.avatar} />}
title={<a href="https://ant.design">{item.name}</a>}
description={item.email}
/>
<div>Content</div>
</List.Item>
)}
</VirtualList>
</List>
</div>
</Drawer>
</>
);
};
export default DiaryOption;

View File

@ -0,0 +1,55 @@
/**
*
* // 使用示例
* copyToClipboard('要复制的文本')
* .then(() => console.log('复制成功'))
* .catch(() => console.error('复制失败'));
* @param text
* @returns Promise resolve(true) reject(false)
*/
export const copyToClipboard = (text: string): Promise<boolean> => {
return new Promise((resolve, reject) => {
// 方案1: 使用现代 Clipboard API
if (navigator.clipboard && window.isSecureContext) {
navigator.clipboard.writeText(text)
.then(() => resolve(true))
.catch(() => {
// 现代 API 失败时回退到传统方法
fallbackCopy(text) ? resolve(true) : reject(false);
});
}
// 方案2: 传统 document.execCommand 方法
else {
fallbackCopy(text) ? resolve(true) : reject(false);
}
});
};
// 传统复制方法兼容方案
const fallbackCopy = (text: string): boolean => {
try {
// 创建临时文本域
const textArea = document.createElement('textarea');
textArea.value = text;
// 隐藏文本域(不在视口中显示)
textArea.style.position = 'fixed';
textArea.style.top = '-9999px';
textArea.style.left = '-9999px';
textArea.style.opacity = '0';
document.body.appendChild(textArea);
// 选择并复制
textArea.select();
const successful = document.execCommand('copy');
// 清理DOM
document.body.removeChild(textArea);
return successful;
} catch (err) {
console.error('复制失败:', err);
return false;
}
};

6
src/lib/login/service.ts Normal file
View File

@ -0,0 +1,6 @@
import {httpReq} from "@/utils/axiosReq";
export const generateQrcodeAPI = (data:{}) => {
return httpReq.post(process.env.NEXT_PUBLIC_SECURITY_REQUEST_URL + "/V2/wx/login/generate/qrcode",
data)
}

View File

@ -0,0 +1,111 @@
'use client'
import {
LoginFormPage,
} from '@ant-design/pro-components';
import {message, theme, Modal, Button, Skeleton, Image, QRCode} from 'antd';
import React, {useLayoutEffect} from 'react';
import {useState} from 'react';
import {CaptchaLoginSuccess, LoginObject} from "@/lib/login/definitions";
import {useRouter} from 'next/navigation'
import { v4 as uuidv4 } from 'uuid';
import {generateQrcodeAPI} from "@/lib/login/service";
export default function XcxLoginPage() {
const [loaded, setLoaded] = useState(false);
useLayoutEffect(() => {
setLoaded(true);
})
// 二维码 start
const [qrCodeShow, setQrCodeShow] = useState<boolean>(false);
const [qrCodeStatus, setQrCodeStatus] = useState<'active' | 'expired' | 'loading' | 'scanned'>();
const [qrCodeValue, setQrCodeValue] = useState<string>("-");
const generateQrcode = () => {
// 不在二维码页面直接返回
if (!qrCodeShow) {
return;
}
if (qrCodeStatus=='loading') {
message.info({content:"请耐心等待"})
}else if (qrCodeStatus=='expired') {
generateQrCode()
}else if (qrCodeStatus=='active') {
}else if (qrCodeStatus=='scanned') {
}else {
generateQrCode()
}
}
function generateQrCode(){
// 生成唯一id
const clientId: string = uuidv4();
generateQrcodeAPI({clientId}).then(res=>{
setQrCodeValue(JSON.stringify({
clientId,serverId:res.data.data
}))
})
}
// 二维码 end
const {token} = theme.useToken();
const router = useRouter()
const [messageApi, contextHolder] = message.useMessage();
const [loading, setLoading] = useState(false);
const [open, setOpen] = useState(false);
const [captchaLoginSuccessList, setCaptchaLoginSuccessList] = useState([]);
const captchaUserNameConfirm = (captchaLoginSuccess: CaptchaLoginSuccess) => {
messageApi.open({
type: 'info',
content: "使用帐号" + captchaLoginSuccess.username + "登录成功"
})
localStorage.setItem('platform-security', captchaLoginSuccess.token)
router.push('/task/project')
setOpen(false)
setLoading(false)
}
return (
<div
style={{
backgroundColor: 'white',
height: '100vh',
}}
>
{contextHolder}
<Modal
open={open}
title="发现您注册有多个帐号,请选择需要登录的账号"
footer={
captchaLoginSuccessList.map((label: CaptchaLoginSuccess, index) => (
<Button key={label.username} onClick={() => captchaUserNameConfirm(label)}>
{label.username}
</Button>
))
}
>
</Modal>
{loaded ? <LoginFormPage
backgroundImageUrl="/20-1733751222585.jpg"
title="马上行计划管理"
containerStyle={{
backgroundColor: 'rgba(0, 0, 0,0.65)',
backdropFilter: 'blur(4px)',
}}
onFinish={(formData: LoginObject) => {
// 二维码和小程序扫码来回切换
setQrCodeShow(!qrCodeShow)
// 生成二维码
generateQrcode()
}}
submitter={{ searchConfig: { submitText: qrCodeShow?"在我的-PC扫码登录或者返回":"已打开微信小程序,生成登录码。",resetText: '重置2'}}}
>
<div className="displayFlexColumn" style={{margin:'20px'}}>
{
qrCodeShow?<QRCode value={qrCodeValue} size={300} status={qrCodeStatus} onRefresh={() => console.log('refresh')} />:
<Image width={300} src="/static/pc-Web.png"/>
}
</div>
</LoginFormPage> : <Skeleton/>}
</div>
);
};

View File

@ -9,6 +9,7 @@ import dayjs from "dayjs";
import {getTaskState, taskPriorityList} from "@/lib/task/project/data"; import {getTaskState, taskPriorityList} from "@/lib/task/project/data";
import 'react-virtualized/styles.css'; import 'react-virtualized/styles.css';
import RightOption from "@/ui/task/RightOption"; import RightOption from "@/ui/task/RightOption";
import {CopyOutlined} from "@ant-design/icons";
interface DroppableTableProps { interface DroppableTableProps {
tableCode: string, tableCode: string,
@ -70,7 +71,7 @@ export const DroppableTable = React.memo((props: DroppableTableProps) => {
<ConfigProvider> <ConfigProvider>
{/* 表头 */} {/* 表头 */}
<div style={headerStyle} className='displayFlexRow'> <div style={headerStyle} className='displayFlexRow'>
<div style={{width: '20%'}} className='displayFlexRow'>{stateName}</div> <div style={{width: '20%',paddingLeft:"1rem"}} className='displayFlexRow'>{stateName}</div>
<div style={{width: '45%'}} className='displayFlexRow'></div> <div style={{width: '45%'}} className='displayFlexRow'></div>
<div style={{width: '15%'}} className='displayFlexRow'></div> <div style={{width: '15%'}} className='displayFlexRow'></div>
<div style={{width: '20%'}} className='displayFlexRow'></div> <div style={{width: '20%'}} className='displayFlexRow'></div>
@ -89,7 +90,7 @@ export const DroppableTable = React.memo((props: DroppableTableProps) => {
style={getItemStyle(snapshot.isDragging, {...provided.draggableProps.style})} style={getItemStyle(snapshot.isDragging, {...provided.draggableProps.style})}
className="virtualized-row displayFlexRow" className="virtualized-row displayFlexRow"
> >
<div style={{width: '20%'}} className='displayFlexRow'> <div style={{width: '20%',paddingLeft:"1rem"}} className='displayFlexRow'>
<Tooltip placement="topLeft" title={record.name} <Tooltip placement="topLeft" title={record.name}
className='displayFlexRow'> className='displayFlexRow'>
<div className='displayFlexRow'>{record.name}</div> <div className='displayFlexRow'>{record.name}</div>

View File

@ -17,37 +17,38 @@ import {
} from "@/lib/task/project/data"; } from "@/lib/task/project/data";
import {DataType} from "@/lib/definitions"; import {DataType} from "@/lib/definitions";
import dayjs, {Dayjs} from "dayjs"; import dayjs, {Dayjs} from "dayjs";
import DiaryOption from "@/components/DiaryOption";
export type DetailModelFormProps={ export type DetailModelFormProps = {
// 当前内容id // 当前内容id
itemId?: string, itemId?: string,
pid?:string, pid?: string,
// 祖宗任务id // 祖宗任务id
pPid?:string, pPid?: string,
// 操作id // 操作id
operationId: OPERATION_BUTTON_TYPE, operationId: OPERATION_BUTTON_TYPE,
// 标题描述 // 标题描述
description:string, description: string,
// 是否打开界面,用于非按钮操作 // 是否打开界面,用于非按钮操作
open:boolean, open: boolean,
// 使用按钮操作 // 使用按钮操作
haveButton:boolean, haveButton: boolean,
expectedStartTime?:Dayjs, expectedStartTime?: Dayjs,
expectedEndTime?:Dayjs, expectedEndTime?: Dayjs,
// 重新加载数据 // 重新加载数据
reloadData?: () => void reloadData?: () => void
} }
export type PidSelectTree= { label: string; value: string;pid:string; children?: PidSelectTree[] } export type PidSelectTree = { label: string; value: string; pid: string; children?: PidSelectTree[] }
export const DetailModelForm: React.FC<DetailModelFormProps> = (props) => { export const DetailModelForm: React.FC<DetailModelFormProps> = (props) => {
console.log("DetailModelForm:props:",props) console.log("DetailModelForm:props:", props)
const [form] = Form.useForm<DataType>(); const [form] = Form.useForm<DataType>();
const [pid, setPid] = useState<string>(props.pid?props.pid:'0'); const [pid, setPid] = useState<string>(props.pid ? props.pid : '0');
const [editFormDisable, setEditFormDisable] = useState(props.operationId === OPERATION_BUTTON_TYPE.DETAIL) const [editFormDisable, setEditFormDisable] = useState(props.operationId === OPERATION_BUTTON_TYPE.DETAIL)
// 团队第一层 pid必须为0 // 团队第一层 pid必须为0
const [taskType, setTaskType] = useState('0') const [taskType, setTaskType] = useState('0')
useEffect(() => { useEffect(() => {
if (props.itemId!=undefined&&( if (props.itemId != undefined && (
props.operationId === OPERATION_BUTTON_TYPE.DETAIL || props.operationId === OPERATION_BUTTON_TYPE.UPDATE)) { props.operationId === OPERATION_BUTTON_TYPE.DETAIL || props.operationId === OPERATION_BUTTON_TYPE.UPDATE)) {
getTask(props.itemId).then(task => { getTask(props.itemId).then(task => {
console.log('DetailModelForm:getTask(props.itemId)', props.itemId, task); console.log('DetailModelForm:getTask(props.itemId)', props.itemId, task);
@ -60,38 +61,43 @@ export const DetailModelForm: React.FC<DetailModelFormProps> = (props) => {
task.data.expectedTimeRange = [task.data.expectedStartTime ? dayjs(task.data.expectedStartTime) : undefined, task.data.expectedTimeRange = [task.data.expectedStartTime ? dayjs(task.data.expectedStartTime) : undefined,
task.data.expectedEndTime ? dayjs(task.data.expectedEndTime) : undefined]; task.data.expectedEndTime ? dayjs(task.data.expectedEndTime) : undefined];
form.setFieldsValue(task.data) form.setFieldsValue(task.data)
console.log("form.setFieldsValue(task.data)"+JSON.stringify(task.data)) console.log("form.setFieldsValue(task.data)" + JSON.stringify(task.data))
} else { } else {
message.error(task.status.message); message.error(task.status.message);
props.reloadData?.() props.reloadData?.()
} }
}) })
}else if(props.operationId === OPERATION_BUTTON_TYPE.ADD|| props.operationId === OPERATION_BUTTON_TYPE.ADD_CHILD){ } else if (props.operationId === OPERATION_BUTTON_TYPE.ADD || props.operationId === OPERATION_BUTTON_TYPE.ADD_CHILD) {
let data={'expectedTimeRange':[props.expectedStartTime?props.expectedStartTime:dayjs(), props.expectedEndTime],'pid':props.pid}; let data = {
'expectedTimeRange': [props.expectedStartTime ? props.expectedStartTime : dayjs(), props.expectedEndTime],
'pid': props.pid
};
form.setFieldsValue(data) form.setFieldsValue(data)
} }
}, [props]) }, [props])
function childReduce(child:DataType[]):PidSelectTree[]{
const result:PidSelectTree[] = []; function childReduce(child: DataType[]): PidSelectTree[] {
child.map(data=> { const result: PidSelectTree[] = [];
const resultData:PidSelectTree = {label:data.name,value:data.id,pid:data.pid}; child.map(data => {
if (data.children){ const resultData: PidSelectTree = {label: data.name, value: data.id, pid: data.pid};
resultData.children=childReduce(data.children); if (data.children) {
resultData.children = childReduce(data.children);
} }
result.push(resultData); result.push(resultData);
}) })
return result; return result;
} }
// 如果不是添加任务需要回显 // 如果不是添加任务需要回显
return ( return (
<ModalForm<DataType> <ModalForm<DataType>
title={props.description} title={props.description}
open={props.open&&!props.haveButton} open={props.open && !props.haveButton}
trigger={props.haveButton? trigger={props.haveButton ?
<Button type="primary"> <Button type="primary">
<PlusOutlined /> <PlusOutlined/>
{props.description} {props.description}
</Button>:undefined </Button> : undefined
} }
form={form} form={form}
autoFocusFirstInput autoFocusFirstInput
@ -102,10 +108,10 @@ export const DetailModelForm: React.FC<DetailModelFormProps> = (props) => {
props.reloadData?.(); props.reloadData?.();
}, },
}} }}
submitter={props.itemId!==undefined&&props.itemId!=='-1'?{ submitter={props.itemId !== undefined && props.itemId !== '-1' ? {
render: (prop, defaultDoms) => { render: (prop, defaultDoms) => {
return [ return [
editFormDisable?<Button editFormDisable ? <Button
key="edit" key="edit"
onClick={() => { onClick={() => {
// props.submit(); // props.submit();
@ -113,52 +119,55 @@ export const DetailModelForm: React.FC<DetailModelFormProps> = (props) => {
}} }}
> >
</Button>:undefined, </Button> : undefined,
props.operationId === OPERATION_BUTTON_TYPE.DETAIL||props.operationId === OPERATION_BUTTON_TYPE.UPDATE?<Popconfirm props.operationId === OPERATION_BUTTON_TYPE.DETAIL || props.operationId === OPERATION_BUTTON_TYPE.UPDATE ?
key ='delete' <Popconfirm
title="删除任务" key='delete'
description="确认要删除任务?" title="删除任务"
icon={<QuestionCircleOutlined style={{color: 'red'}}/>} description="确认要删除任务?"
okText="确认" icon={<QuestionCircleOutlined style={{color: 'red'}}/>}
cancelText="取消" okText="确认"
onConfirm={() => { cancelText="取消"
if (props.itemId!==undefined) { onConfirm={() => {
deleteTask(props.itemId).then((response => { if (props.itemId !== undefined) {
console.log('response', response) deleteTask(props.itemId).then((response => {
if (response.status.success) { console.log('response', response)
message.success("删除任务成功:" + response.data) if (response.status.success) {
props.reloadData?.() message.success("删除任务成功:" + response.data)
} props.reloadData?.()
})); }
} }));
}} }
><Button type="primary" danger> }}
>
</Button> <Button type="primary" danger>
</Popconfirm>:undefined
</Button>
</Popconfirm> : undefined
, ,
<DiaryOption/>,
...defaultDoms ...defaultDoms
]; ];
}, },
}:undefined} } : undefined}
onFinish={async (values) => { onFinish={async (values) => {
console.log('Received values of form: ', values); console.log('Received values of form: ', values);
if (values.pid===undefined){ if (values.pid === undefined) {
values.pid='0' values.pid = '0'
} }
if (values.expectedTimeRange?.[0]!=undefined) { if (values.expectedTimeRange?.[0] != undefined) {
values.expectedStartTime=dayjs(values.expectedTimeRange[0]).format() values.expectedStartTime = dayjs(values.expectedTimeRange[0]).format()
} }
if (values.expectedTimeRange?.[1]!=undefined) { if (values.expectedTimeRange?.[1] != undefined) {
values.expectedEndTime=dayjs(values.expectedTimeRange[1]).format() values.expectedEndTime = dayjs(values.expectedTimeRange[1]).format()
} }
if (values.actualTimeRange?.[0]!=undefined) { if (values.actualTimeRange?.[0] != undefined) {
values.actualStartTime=dayjs(values.actualTimeRange[0]).toDate() values.actualStartTime = dayjs(values.actualTimeRange[0]).toDate()
} }
if (values.actualTimeRange?.[1]!=undefined) { if (values.actualTimeRange?.[1] != undefined) {
values.actualEndTime=dayjs(values.actualTimeRange[1]).toDate() values.actualEndTime = dayjs(values.actualTimeRange[1]).toDate()
} }
var result:boolean=false; var result: boolean = false;
let state = taskStateList.find(taskState => taskState.name === values.state?.toString()); let state = taskStateList.find(taskState => taskState.name === values.state?.toString());
if (state) { if (state) {
@ -169,7 +178,7 @@ export const DetailModelForm: React.FC<DetailModelFormProps> = (props) => {
values.priority = priority.code values.priority = priority.code
} }
// todo 修改 // todo 修改
if (props.operationId === OPERATION_BUTTON_TYPE.UPDATE||(props.operationId === OPERATION_BUTTON_TYPE.DETAIL&&!editFormDisable)) { if (props.operationId === OPERATION_BUTTON_TYPE.UPDATE || (props.operationId === OPERATION_BUTTON_TYPE.DETAIL && !editFormDisable)) {
await updateTask(values).then(response => { await updateTask(values).then(response => {
console.log('response', response) console.log('response', response)
if (response.status.success) { if (response.status.success) {
@ -177,16 +186,16 @@ export const DetailModelForm: React.FC<DetailModelFormProps> = (props) => {
// 树任务重新刷新 // 树任务重新刷新
// 四象限任务重新刷新 // 四象限任务重新刷新
// 如果可以直接更新列表而不请求。。。。。。 // 如果可以直接更新列表而不请求。。。。。。
console.log('props.reloadData?.()',props.reloadData) console.log('props.reloadData?.()', props.reloadData)
props.reloadData?.() props.reloadData?.()
result= true result = true
}else { } else {
message.error(response.status.message) message.error(response.status.message)
result= false result = false
} }
} }
); );
}else { } else {
await addTask(values).then(response => { await addTask(values).then(response => {
console.log('response', response) console.log('response', response)
if (response.status.success) { if (response.status.success) {
@ -194,12 +203,12 @@ export const DetailModelForm: React.FC<DetailModelFormProps> = (props) => {
// 树任务重新刷新 // 树任务重新刷新
// 四象限任务重新刷新 // 四象限任务重新刷新
// 如果可以直接更新列表而不请求。。。。。。 // 如果可以直接更新列表而不请求。。。。。。
console.log('props.reloadData?.()',props.reloadData) console.log('props.reloadData?.()', props.reloadData)
props.reloadData?.() props.reloadData?.()
result= true result = true
}else { } else {
message.error(response.status.message) message.error(response.status.message)
result= false result = false
} }
} }
); );
@ -207,9 +216,9 @@ export const DetailModelForm: React.FC<DetailModelFormProps> = (props) => {
return result; return result;
}} }}
> >
<ProFormText width="sm" name="id" hidden={true} label="主键" /> <ProFormText width="sm" name="id" hidden={true} label="主键"/>
<ProFormText width="sm" name="code" initialValue={props.itemId} hidden={true} label="任务编码" /> <ProFormText width="sm" name="code" initialValue={props.itemId} hidden={true} label="任务编码"/>
<ProFormText width="sm" name="pPid" initialValue={props.pPid} hidden={true} label="祖宗id" /> <ProFormText width="sm" name="pPid" initialValue={props.pPid} hidden={true} label="祖宗id"/>
<ProForm.Group> <ProForm.Group>
<ProFormSelect <ProFormSelect
required={true} required={true}
@ -218,38 +227,52 @@ export const DetailModelForm: React.FC<DetailModelFormProps> = (props) => {
name="taskType" name="taskType"
label="任务类型" label="任务类型"
initialValue='0' initialValue='0'
disabled ={editFormDisable} disabled={editFormDisable}
onChange={(value:string, option)=>{ onChange={(value: string, option) => {
setTaskType(value) setTaskType(value)
}} }}
rules={[ rules={[
{required:true, {
message:"请输入计划类型" required: true,
message: "请输入计划类型"
} }
]} ]}
/> />
<ProFormText <ProFormText
required={true} required={true}
hidden={taskType!='1'} hidden={taskType != '1'}
width="sm" width="sm"
name="fName" name="fName"
label="团队名称" label="团队名称"
tooltip="最长为 10 位" tooltip="最长为 10 位"
placeholder="请输入团队名称" placeholder="请输入团队名称"
disabled ={editFormDisable} disabled={editFormDisable}
/> />
<ProFormTreeSelect <ProFormTreeSelect
hidden={taskType=='1'} hidden={taskType == '1'}
width="sm" width="sm"
request={() =>{ request={() => {
return getTaskTreeResult(JSON.stringify( return getTaskTreeResult(JSON.stringify(
{pageSize:1000,pageNumber:1,data:[{code:'pid',value:'0',operateType:'='},{code:'state',value:'8,9',operateType:'IN'},{code:'',value:true,operateType: "TREE"}]} {
)).then(result=> childReduce(result.data.content)) pageSize: 1000,
pageNumber: 1,
data: [{code: 'pid', value: '0', operateType: '='}, {
code: 'state',
value: '8,9',
operateType: 'IN'
}, {code: '', value: true, operateType: "TREE"}]
}
)).then(result => childReduce(result.data.content))
}} }}
name="pid" name="pid"
label="父级任务" label="父级任务"
fieldProps={{onSelect: (e,node) => {console.log('onSelect',e,node);setPid(e)}}} fieldProps={{
disabled ={editFormDisable} onSelect: (e, node) => {
console.log('onSelect', e, node);
setPid(e)
}
}}
disabled={editFormDisable}
/> />
<ProFormText <ProFormText
required={true} required={true}
@ -258,13 +281,14 @@ export const DetailModelForm: React.FC<DetailModelFormProps> = (props) => {
label="任务名称" label="任务名称"
tooltip="最长为 10 位" tooltip="最长为 10 位"
placeholder="请输入任务名称" placeholder="请输入任务名称"
disabled ={editFormDisable} disabled={editFormDisable}
rules={[ rules={[
{required:true, {
message:"请输入计划名称" required: true,
},{ message: "请输入计划名称"
max:10, }, {
message:"名称长度不易超过10个字" max: 10,
message: "名称长度不易超过10个字"
} }
]} ]}
/> />
@ -275,7 +299,7 @@ export const DetailModelForm: React.FC<DetailModelFormProps> = (props) => {
label="任务描述" label="任务描述"
// tooltip="最长为 24 位" // tooltip="最长为 24 位"
placeholder="请输入任务描述" placeholder="请输入任务描述"
disabled ={editFormDisable} disabled={editFormDisable}
/> />
<ProForm.Group> <ProForm.Group>
@ -290,10 +314,11 @@ export const DetailModelForm: React.FC<DetailModelFormProps> = (props) => {
name="priority" name="priority"
label="任务优先级" label="任务优先级"
initialValue='3' initialValue='3'
disabled ={editFormDisable} disabled={editFormDisable}
rules={[ rules={[
{required:true, {
message:"请选择计划优先级" required: true,
message: "请选择计划优先级"
} }
]} ]}
/> />
@ -308,10 +333,11 @@ export const DetailModelForm: React.FC<DetailModelFormProps> = (props) => {
name="state" name="state"
label="任务状态" label="任务状态"
initialValue='8' initialValue='8'
disabled ={editFormDisable} disabled={editFormDisable}
rules={[ rules={[
{required:true, {
message:"请选择计划状态" required: true,
message: "请选择计划状态"
} }
]} ]}
/> />
@ -322,16 +348,16 @@ export const DetailModelForm: React.FC<DetailModelFormProps> = (props) => {
initialValue={[dayjs(), undefined]} initialValue={[dayjs(), undefined]}
name="expectedTimeRange" name="expectedTimeRange"
label="期望时间" label="期望时间"
fieldProps={{allowEmpty:[true, true],showTime:true,needConfirm:true}} fieldProps={{allowEmpty: [true, true], showTime: true, needConfirm: true}}
placeholder={['开始时间','结束时间']} placeholder={['开始时间', '结束时间']}
disabled ={editFormDisable} disabled={editFormDisable}
/> />
<ProFormDateTimeRangePicker <ProFormDateTimeRangePicker
name="actualTimeRange" name="actualTimeRange"
label="实际时间" label="实际时间"
fieldProps={ {allowEmpty:[true, true],showTime:true,needConfirm:true}} fieldProps={{allowEmpty: [true, true], showTime: true, needConfirm: true}}
placeholder={['开始时间','结束时间']} placeholder={['开始时间', '结束时间']}
disabled ={editFormDisable} disabled={editFormDisable}
/> />
</ProForm.Group> </ProForm.Group>

View File

@ -23,6 +23,7 @@ httpReq.interceptors.request.use((config) => {
if (token) { if (token) {
config.headers.Authorization = `Bearer ${token}`; config.headers.Authorization = `Bearer ${token}`;
} }
config.headers.set("source-client","web")
return config; return config;
}, },
(error) => { (error) => {