0
点赞
收藏
分享

微信扫一扫

React - 11 TASK demo

1.server.js

const express = require('express'),
	bodyparser = require('body-parser'),
	fs = require('fs').promises,
	path = require('path');
const pathdb = path.resolve(__dirname, 'database'),
	config = require('./package.json').config,
	server = config.server,
	{ open, safeList } = config.cros,
	{ filter, responsePublic, nowTimeFn } = require('./utils');

/*-创建&启动服务-*/
const app = express();
app.listen(server, () => {
	console.log(`THE WEB SERVICE SUCCESSFULLY AND LISTENING TO THE PORT:${server}!`);
});

/*-中间件-*/
if (open) {
	app.use((req, res, next) => {
		let origin = req.headers.origin || req.headers.referer || "";
		console.log(21, origin)
		origin = origin.replace(/\/$/g, '');
		origin = !safeList.includes(origin) ? '' : origin;
		console.log(24, origin)
		res.header("Access-Control-Allow-Origin", origin);
		res.header("Access-Control-Allow-Methods", 'GET,POST,DELETE,HEAD,OPTIONS,PATCH,PUT');
		res.header("Access-Control-Allow-Headers", 'DNT,authorzation,web-token,app-token,Authorization,Accept,Origin,Keep-Alive,User-Agent,X-Mx-ReqToken,X-Data-Type,X-Auth-Token,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range,x-token');
		res.header("Access-Control-Allow-Credentials", true);
		req.method === 'OPTIONS' ? res.send() : next();
	});
}
app.use(bodyparser.urlencoded({ extended: false }));
app.use(async (req, _, next) => {
	req.$taskDATA = filter(await fs.readFile(`${pathdb}/task.json`, 'utf-8'));
	next();
});

/*-接口管理-*/
app.get('/getTaskList', async (req, res) => {
	let $taskDATA = req.$taskDATA;
	let { limit = 100, page = 1, state = 0 } = req.query;
	$taskDATA.reverse();
	if (+state !== 0) $taskDATA = $taskDATA.filter(item => +item['state'] === +state);
	let total = $taskDATA.length,
		pageNum = Math.ceil(total / limit),
		list = [];
	if (page <= pageNum) {
		for (let i = (page - 1) * limit; i <= (page * limit - 1); i++) {
			let item = $taskDATA[i];
			if (!item) break;
			list.push({
				id: +item['id'],
				task: item['task'],
				state: item['state'],
				time: item['time'],
				complete: item['complete']
			});
		}
	}
	responsePublic(res, true, {
		page,
		pageNum,
		total,
		limit,
		list
	});
});

app.post('/addTask', async (req, res) => {
	let $taskDATA = req.$taskDATA,
		len = $taskDATA.length,
		body = req.body,
		nowTime = nowTimeFn();
	body = {
		id: len === 0 ? 1 : +($taskDATA[len - 1]['id']) + 1,
		task: '',
		state: 1,
		time: nowTime,
		complete: nowTime,
		...body,
	};
	body.complete = body.time;
	$taskDATA.push(body);
	try {
		await fs.writeFile(`${pathdb}/task.json`, JSON.stringify($taskDATA), 'utf-8');
		responsePublic(res, true);
	} catch (_) {
		responsePublic(res, false);
	}
});

app.get('/removeTask', async (req, res) => {
	let $taskDATA = req.$taskDATA,
		{ id = 0 } = req.query,
		flag = false;
	$taskDATA = $taskDATA.filter(item => {
		if (+item.id === +id) {
			flag = true;
			return false;
		}
		return true;
	});
	if (!flag) {
		responsePublic(res, false);
		return;
	}
	try {
		await fs.writeFile(`${pathdb}/task.json`, JSON.stringify($taskDATA), 'utf-8');
		responsePublic(res, true);
	} catch (_) {
		responsePublic(res, false);
	}
});

app.get('/completeTask', async (req, res) => {
	let $taskDATA = req.$taskDATA,
		{ id = 0 } = req.query,
		flag = false;
	$taskDATA = $taskDATA.map(item => {
		if (+item.id === +id) {
			flag = true;
			item.state = 2;
			item.complete = nowTimeFn();
		}
		return item;
	});
	if (!flag) {
		responsePublic(res, false);
		return;
	}
	try {
		await fs.writeFile(`${pathdb}/task.json`, JSON.stringify($taskDATA), 'utf-8');
		responsePublic(res, true);
	} catch (_) {
		responsePublic(res, false);
	}
});

/*-静态页面&404-*/
app.use(express.static('./static'));
app.use((_, res) => {
	res.status(404);
	res.send();
});

React - 11 TASK demo_react

2.antd组件库

antd组件库,自带按需导入,不用额外配置(用到了哪些组件,最后打包的时候就打包哪些组件),但是使用的时候还是得用到哪个解构哪个

React - 11 TASK demo_react_02

配置汉化,引入全局样式index.less

React - 11 TASK demo_react_03

index.lss中引入reset

React - 11 TASK demo_react_04

ant design 中 form表单

React - 11 TASK demo_react_05

momentjs 和 dayjs

React - 11 TASK demo_react_06

await 成功才会往下走;使用ref获取表单实例,拿到表单对象;form表单验证

React - 11 TASK demo_react_07

React - 11 TASK demo_react_08

给form设置ref

React - 11 TASK demo_react_09

3.关于请求

向服务器发送数据请求失败

  • 请求失败:向服务器发送请求,服务器没有响应对应的信息HTTP状态码不是2开始的,或者压根就没有返回任何的信息1
  • 服务器返回信息了状态码也是200] ,但是返回的内容不是我们想要 周味天 网络层失败 && 业务层失败

基于post请求向服务器发送请求,需要基于请求主体把信息传递给服务器

普通对象 >变为"Tobject Object]”字符串传递给服务器 [不对的]

Axios库对其做了处理,我们写的是普通对象,Axios内部会默认把其变为JSON字符串,传递给服务器!!

格式要求:

  • 字符串 + json字符串 application/json

'{x:10,name:”珠峰"}'

    + urlencoded格式字符串 application/www-urlencoded

"X-10&name=珠峰"

+普通字符串 text/plain

  • FormData对象「用于文件上传」 multipart/form-data

let im new FormData();

fm.append(‘file', file)

切换标签发送请求

React - 11 TASK demo_react_10

请求数据

try catch后面的代码,相当于finally(与下图setTimeout无关,setTimeout用来模拟接口时间让loading效果展示出来)

React - 11 TASK demo_react_11

在真实项目中,继承React.Component或者React.PureComponent差别不大

React - 11 TASK demo_react_12

4.Task.jsx 完整代码

import React from "react";
import './Task.less';
import { Button, DatePicker, Form, Input, Modal, Popconfirm, Table, Tag, message } from 'antd';
import { getTaskList, addTask, removeTask, completeTask } from '@/api';
import { flushSync } from 'react-dom';
// 日期补0方法
const zero = function zero(str) {
    str = String(str)
    return str.length < 2 ? '0' + str : str
}
// 对日期处理的方法
const formatTime = function formatTime(time) {
    let arr = time.match(/\d+/g),
        [, month, day, hours = '00', minutes = '00'] = arr;
    return `${zero(month)}-${zero(day)} ${zero(hours)}:${zero(minutes)}`
}

class Task extends React.PureComponent {
    // 定义表格列的数据
    columns = [
        {
          title: '编号',
          dataIndex: 'id',
          id: '1',
          align: 'center',
          width: '8%'
        },
        {
          title: '任务描述',
          dataIndex: 'task',
          id: '2',
          ellipsis: true,
          width: '50%'
        },
        {
          title: '状态',
          dataIndex: 'state',
          id: '3',
          align: 'center',
          width: '10%',
          render: (text, record, index) => {
            let res
            switch (text) {
                case 1:
                    res = '未完成'
                    break;
                case 2:
                    res = '已完成'
                    break;
                default:
                    res = ''
                    break;
            }
            return res
          }
        },
        {
          title: '完成时间',
          dataIndex: 'time',
          id: '4',
          align: 'center',
          width: '15%',
          render: (_, record) => {
            let { state, time, complete } = record
            if (+state === 2) time = complete
            return formatTime(time)
          }
        },
        {
          title: '操作',
          render: (_, record) => {
            const { id, state } = record
            return <>
                <Popconfirm title="您确定要删除吗" onConfirm={this.handleDelete.bind(null, id)}>
                    <Button type="link">删除</Button>
                </Popconfirm>
                { +state !== 2 ? <Popconfirm title="您确定要完成吗" onConfirm={this.handleUpdate.bind(null, id)}>
                    <Button type="link">完成</Button>
                </Popconfirm> : null }
            </>
          },
        },
    ]
    // 初始组件的状态
    state = {
        tableData: [
            {
                id: '1',
                task: '今天天气很不错,今夜阳光灿烂,今天天气很不错,今夜阳光灿烂,今天天气很不错,今夜阳光灿烂,今天天气很不错,今夜阳光灿烂,今天天气很不错,今夜阳光灿烂',
                time: '1999-01-11 01:01:45',
                complete: '2023-05-12 19:10:32',
                address: '西湖区湖底公园1号',
                state: 1,
            },
            {
                id: '2',
                task: 'react知识哦',
                time: '1999-01-101 01:01:45',
                complete: '2023-05-12 19:38:57',
                address: '西湖区湖底公园1号',
                state: 2
            },
        ],
        tableLoading: false,
        modalVisible: false,
        confirmLoading: false,
        selectedIndex: 0
    }
    // 对话框和表单处理
    closeModal = () => {
        this.setState({
            modalVisible: false,
            confirmLoading: false
        })
        this.formIns.resetFields()
    }
    // 提交
    submit = async () => {
        try {
            // 表单校验 await 这里成功才会往下走,失败就不走了
            await this.formIns.validateFields()
            message.success('表单校验通过')
            let { task, time } = this.formIns.getFieldsValue()
            time = time.format('YYY-MM-DD HH:mm:ss')
            console.log(126, task, time)
            this.setState({ confirmLoading: true })
            // 向服务器发送请求
            let { code } = await addTask(task, time)
            if (+code !== 0) {
                message.error('很遗憾,当前操作失败,请稍后重试')
            } else {
                this.closeModal() // 关闭弹窗,取消loading,清除表单数据
                this.queryData()
                message.success('恭喜您,当前操作成功!')
            }
        } catch (_) {}
        this.setState({ confirmLoading: false })
    }
    // 删除
    handleDelete = async (id) => {
        try {
            let { code } = await removeTask(id)
            if (+code !== 0) {
                message.error('很遗憾,当前操作失败,请稍后重试')
            } else {
                this.queryData()
                message.success('删除成功!')
            }
        } catch (_) {}
    }
    // 完成
    handleUpdate = async (id) => {
        try {
            let { code } = await completeTask(id)
            if (+code !== 0) {
                message.error('很遗憾,当前操作失败,请稍后重试')
            } else {
                this.queryData()
                message.success('更新成功!')
            }
        } catch (_) {}
    }
    // 切换全部/已完成/未完成标签
    changeIndex =  (index) => {
        console.log(index)
        if (this.state.selectedIndex === index) return
        // this.setState({ selectedIndex: index })
        // // 由于setState是异步,这里拿不到最新的selectedIndex
        // this.queryData()

        // // 方法一 在setState回调中取拿数据
        // this.setState({ selectedIndex: index }, () => {
        //     this.queryData()
        // })
        // 方法二 flushSync()
        // flushSync(this.setState({ selectedIndex: index }))
        // this.queryData()
        // 或者这样写
        this.setState({ selectedIndex: index })
        flushSync()
        this.queryData()
    }
    // 从服务器获取指定状态的任务
    queryData = async () => {
        let { selectedIndex } = this.state
        try {
            this.setState({ tableLoading: true })
            let { code, list } = await getTaskList(selectedIndex)
            if (+code !== 0) list = [];
            setTimeout(() => {
                this.setState({ tableData: list })
            }, 3000);
        } catch (_) {}
        // 此处相当于finally
        setTimeout(() => {
            this.setState({ tableLoading: false })
        }, 3000);
    }
    // 周期函数
    componentDidMount () {
        // 第一次渲染完成后立即发送请求
        this.queryData()
        // tableLoading初始值就是false,在这里再改成false,还是会触发渲染,解决办法可以把class Task extends React.Component改成继承React.PureComponent,因为PureComponent中自动加了shouldComponentUpdate,对新老状态做了浅比较,缺点是 像这种操作,如果list中的数据没有变,执行this.setState({ tableData: list })还是会渲染,因为这里每次的list是引用 类型,地址是不一样的,最优方案是自己去做深比较
        setTimeout(() => {
            this.setState({ tableLoading: false })
        }, 5000);
    }
    render () {
        console.log('render')
        let { tableData, tableLoading, modalVisible, confirmLoading, selectedIndex } = this.state
        return <div className="task-box">
            {/* 头部 */}
            <div className="header">
                <h2 className="title">Task OA管理系统</h2>
                <Button type="primary" onClick={() => {
                    this.setState({
                        modalVisible: true
                    })
                }}>新增任务</Button>

            </div>
            {/* 标签 */}
            <div className="tag-box">
                {['全部', '未完成', '已完成'].map((item, index) => {
                    return <Tag key={index} color={selectedIndex === index ? '#1677ff' : ''}
                    onClick={this.changeIndex.bind(null, index)}
                    >{item}</Tag>
                })}
                {/* <Tag color="#1677ff">全部</Tag>
                <Tag>未完成</Tag>
                <Tag>已完成</Tag> */}
            </div>
            {/* 表格 */}
            <Table
                dataSource={tableData}
                columns={this.columns}
                loading={tableLoading}
                rowKey="id" />

            {/* 对话框 & 表单 */}
            <Modal open={modalVisible} title="新增任务弹窗" confirmLoading={confirmLoading} onOk={this.submit} onCancel={this.closeModal}>
                <Form ref={ x => this.formIns = x } initialValues={{ task: '', time: '' }} layout="vertical"
                    style={{
                        maxWidth: 600,
                    }}>
                    <Form.Item name="task" label="任务描述" validateTrigger="onBlur" rules={[
                        { required: true, message: '任务描述必填' },
                        { min: 6, message: '至少输入6位' }
                    ]}>
                        <Input.TextArea rows={4} allowClear />
                    </Form.Item>
                    <Form.Item name="time" label="完成时间" validateTrigger="onBlur" rules={[
                        { required: true }
                    ]}>
                        <DatePicker showTime format="YYYY/MM/DD HH:mm:ss" />
                    </Form.Item>
                </Form>
            </Modal>
        </div>
    }
}

export default Task;




举报

相关推荐

0 条评论