|
@@ -1,143 +1,191 @@
|
|
|
-import React, { useState } from 'react';
|
|
|
-import { Button, Form, Input, message, Modal, Radio, Upload } from 'antd';
|
|
|
-import { TableListItem } from '../data.d';
|
|
|
-import { UploadOutlined } from '@ant-design/icons';
|
|
|
+import React, { useEffect, useState } from 'react';
|
|
|
+import { Button, message, Modal } from 'antd';
|
|
|
+import Quill from '@/pages/Memory/components/Quill';
|
|
|
+import service from '@/pages/Memory/service';
|
|
|
+import { useSingleState } from 'nice-hooks';
|
|
|
+import { getTextFromHtml } from '@/utils/utils';
|
|
|
+import { TableListItem } from '../../MemoryList/data.d';
|
|
|
|
|
|
// 表单特殊字段
|
|
|
export interface FormValueType extends Partial<TableListItem> {}
|
|
|
|
|
|
export interface UpdateFormProps {
|
|
|
- onCancel: (flag?: boolean, formVals?: FormValueType) => void;
|
|
|
- onSubmit: (values: FormValueType) => void;
|
|
|
- updateModalVisible: boolean;
|
|
|
+ onCancel: (fresh?: boolean) => void;
|
|
|
+ modalVisible: boolean;
|
|
|
values: Partial<TableListItem>;
|
|
|
}
|
|
|
|
|
|
-const FormItem = Form.Item;
|
|
|
+const dealImage = (base64: string, targetWidth: number, targetSize: number, callback: Function) => {
|
|
|
+ const newImage = new Image();
|
|
|
+ let quality = 0.8;
|
|
|
+ newImage.src = base64;
|
|
|
+ // url为外域时需要
|
|
|
+ newImage.setAttribute('crossOrigin', 'Anonymous');
|
|
|
+ let imgWidth;
|
|
|
+ let imgHeight;
|
|
|
+ newImage.onload = function () {
|
|
|
+ imgWidth = newImage.width;
|
|
|
+ imgHeight = newImage.height;
|
|
|
+ const canvas = document.createElement('canvas');
|
|
|
+ const ctx = canvas.getContext('2d');
|
|
|
+ if (Math.max(imgWidth, imgHeight) > targetWidth) {
|
|
|
+ if (imgWidth > imgHeight) {
|
|
|
+ canvas.width = targetWidth;
|
|
|
+ canvas.height = (targetWidth * imgHeight) / imgWidth;
|
|
|
+ } else {
|
|
|
+ canvas.height = targetWidth;
|
|
|
+ canvas.width = (targetWidth * imgWidth) / imgHeight;
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ canvas.width = imgWidth;
|
|
|
+ canvas.height = imgHeight;
|
|
|
+ }
|
|
|
+ // @ts-ignore
|
|
|
+ ctx.clearRect(0, 0, canvas.width, canvas.height);
|
|
|
+ // @ts-ignore
|
|
|
+ ctx.drawImage(newImage, 0, 0, canvas.width, canvas.height);
|
|
|
+ // 如想确保图片压缩到自己想要的尺寸,如要求在50-150kb之间,请加以下语句,quality初始值根据情况自定
|
|
|
+ while (base64.length / 1024 > targetSize) {
|
|
|
+ quality -= 0.01;
|
|
|
+ // eslint-disable-next-line no-param-reassign
|
|
|
+ base64 = canvas.toDataURL('image/jpeg', quality);
|
|
|
+ }
|
|
|
+ // 防止最后一次压缩低于最低尺寸,只要quality递减合理,无需考虑
|
|
|
+ // while (base64.length / 1024 < 50) {
|
|
|
+ // quality += 0.001;
|
|
|
+ // base64 = canvas.toDataURL("image/jpeg", quality);
|
|
|
+ // }
|
|
|
+ callback(base64); // 必须通过回调函数返回,否则无法及时拿到该值
|
|
|
+ };
|
|
|
+};
|
|
|
|
|
|
-const formLayout = {
|
|
|
- labelCol: { span: 7 },
|
|
|
- wrapperCol: { span: 13 },
|
|
|
+/**
|
|
|
+ * 压缩html中的base64
|
|
|
+ */
|
|
|
+const dealHtml = (html: string, callBack: Function) => {
|
|
|
+ callBack(html);
|
|
|
+ const htmlDoc = new DOMParser().parseFromString(html, 'text/html');
|
|
|
+ const imgs = htmlDoc.querySelectorAll('img');
|
|
|
+ for (let i = 0; i < imgs.length; i += 1) {
|
|
|
+ const { src } = imgs[i];
|
|
|
+ if (src.startsWith('data')) {
|
|
|
+ dealImage(src, 500, 150, (base64: string) => {
|
|
|
+ imgs[i].src = base64;
|
|
|
+ callBack(htmlDoc.body.innerHTML);
|
|
|
+ console.log(`压缩图片${i}`);
|
|
|
+ });
|
|
|
+ }
|
|
|
+ }
|
|
|
};
|
|
|
|
|
|
const UpdateForm: React.FC<UpdateFormProps> = (props) => {
|
|
|
- const [formVals, setFormVals] = useState<FormValueType>(props.values);
|
|
|
+ const [btnDisable, setBtnDisable] = useState(false);
|
|
|
|
|
|
- const [form] = Form.useForm();
|
|
|
+ const [formValues, setFormValues] = useSingleState<TableListItem>({
|
|
|
+ back: '',
|
|
|
+ front: '',
|
|
|
+ id: undefined,
|
|
|
+ period: 0,
|
|
|
+ remindTime: new Date(),
|
|
|
+ tag: '',
|
|
|
+ updateTime: '',
|
|
|
+ userId: 0,
|
|
|
+ ...props.values,
|
|
|
+ });
|
|
|
|
|
|
- const {
|
|
|
- onSubmit: handleUpdate,
|
|
|
- onCancel: handleUpdateModalVisible,
|
|
|
- updateModalVisible,
|
|
|
- values,
|
|
|
- } = props;
|
|
|
+ const { onCancel: hideModal, modalVisible } = props;
|
|
|
|
|
|
- const submit = async () => {
|
|
|
- const fieldsValue = await form.validateFields();
|
|
|
- const newValue = { ...formVals, ...fieldsValue };
|
|
|
- setFormVals(newValue);
|
|
|
- handleUpdate(newValue);
|
|
|
- };
|
|
|
-
|
|
|
- const modelFileProps = {
|
|
|
- action: 'https://www.mocky.io/v2/5cc8019d300000980a055e76',
|
|
|
- // @ts-ignore
|
|
|
- onChange(info) {
|
|
|
- if (info.file.status === 'done') {
|
|
|
- setFormVals({ ...formVals, ...{ modelFile: info.file.response.url } });
|
|
|
- message.success(`file uploaded successfully`);
|
|
|
- } else if (info.file.status === 'error') {
|
|
|
- message.error(`file upload failed.`);
|
|
|
- }
|
|
|
- },
|
|
|
- };
|
|
|
- const vocabFileProps = {
|
|
|
- action: 'https://www.mocky.io/v2/5cc8019d300000980a055e76',
|
|
|
- // @ts-ignore
|
|
|
- onChange(info) {
|
|
|
- if (info.file.status === 'done') {
|
|
|
- setFormVals({ ...formVals, ...{ vocabFile: info.file.response.url } });
|
|
|
- message.success(`file uploaded successfully`);
|
|
|
- } else if (info.file.status === 'error') {
|
|
|
- message.error(`file upload failed.`);
|
|
|
+ const addHandle = async () => {
|
|
|
+ /**
|
|
|
+ * 判断
|
|
|
+ */
|
|
|
+ console.log(formValues);
|
|
|
+ if (getTextFromHtml(formValues.front + formValues.back).length <= 1) {
|
|
|
+ message.info('你是不是没有输入文字?');
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ if (formValues.front.length >= 300000 || formValues.back.length >= 300000) {
|
|
|
+ message.info('文字太长了,减少一些吧!');
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ setBtnDisable(true); // 禁用按钮
|
|
|
+ let res;
|
|
|
+ if (formValues.id !== undefined) {
|
|
|
+ res = await service.update(formValues);
|
|
|
+ } else {
|
|
|
+ res = await service.insert(formValues);
|
|
|
+ }
|
|
|
+ setBtnDisable(false); // 释放按钮
|
|
|
+ if (res.success) {
|
|
|
+ message.info('操作成功');
|
|
|
+ if (formValues.id !== undefined) {
|
|
|
+ hideModal(true);
|
|
|
+ } else {
|
|
|
+ setFormValues({ front: '', back: '' });
|
|
|
}
|
|
|
- },
|
|
|
- };
|
|
|
- const labelFileProps = {
|
|
|
- action: 'https://www.mocky.io/v2/5cc8019d300000980a055e76',
|
|
|
- // @ts-ignore
|
|
|
- onChange(info) {
|
|
|
- if (info.file.status === 'done') {
|
|
|
- setFormVals({ ...formVals, ...{ labelFile: info.file.response.url } });
|
|
|
- message.success(`file uploaded successfully`);
|
|
|
- } else if (info.file.status === 'error') {
|
|
|
- message.error(`file upload failed.`);
|
|
|
- }
|
|
|
- },
|
|
|
+ } else {
|
|
|
+ message.info(`操作失败: ${res.message}`);
|
|
|
+ }
|
|
|
};
|
|
|
|
|
|
- const renderFooter = () => {
|
|
|
- return (
|
|
|
- <>
|
|
|
- <Button onClick={() => handleUpdateModalVisible(false, values)}>取消</Button>
|
|
|
- <Button type="primary" onClick={() => submit()}>
|
|
|
- 提交
|
|
|
- </Button>
|
|
|
- </>
|
|
|
- );
|
|
|
- };
|
|
|
+ useEffect(() => {
|
|
|
+ console.log(props);
|
|
|
+ document.onkeydown = (ev) => {
|
|
|
+ if (ev.ctrlKey && ev.key.toLowerCase() === 'enter') {
|
|
|
+ addHandle();
|
|
|
+ } else if (ev.key.toLowerCase() === 'escape') {
|
|
|
+ hideModal(false);
|
|
|
+ }
|
|
|
+ };
|
|
|
+ }, []);
|
|
|
|
|
|
return (
|
|
|
<Modal
|
|
|
width={640}
|
|
|
- bodyStyle={{ padding: '32px 40px 48px' }}
|
|
|
+ bodyStyle={{ padding: '15px 15px 15px' }}
|
|
|
destroyOnClose
|
|
|
title="配置模型"
|
|
|
- visible={updateModalVisible}
|
|
|
- footer={renderFooter()}
|
|
|
- onCancel={() => handleUpdateModalVisible()}
|
|
|
+ visible={modalVisible}
|
|
|
+ onCancel={() => hideModal(false)}
|
|
|
+ footer={null}
|
|
|
>
|
|
|
- <Form {...formLayout} form={form} initialValues={formVals}>
|
|
|
- <FormItem
|
|
|
- name="modelName"
|
|
|
- label="模型名称"
|
|
|
- rules={[{ required: true, message: '请输入规则名称!' }]}
|
|
|
- >
|
|
|
- <Input placeholder="请输入" />
|
|
|
- </FormItem>
|
|
|
+ <div>
|
|
|
+ <h4>正面</h4>
|
|
|
+ <Quill
|
|
|
+ readonly={false}
|
|
|
+ onChange={(value) => {
|
|
|
+ dealHtml(value, (html: string) => {
|
|
|
+ setFormValues({ front: html });
|
|
|
+ });
|
|
|
+ }}
|
|
|
+ value={formValues.front}
|
|
|
+ />
|
|
|
|
|
|
- <FormItem
|
|
|
- name="modelType"
|
|
|
- label="模型类型"
|
|
|
- rules={[{ required: true, message: '请选择模型类型!' }]}
|
|
|
+ <p />
|
|
|
+ <h4>反面</h4>
|
|
|
+ <Quill
|
|
|
+ readonly={false}
|
|
|
+ onChange={(value) => {
|
|
|
+ dealHtml(value, (html: string) => {
|
|
|
+ setFormValues({ back: html });
|
|
|
+ });
|
|
|
+ }}
|
|
|
+ value={formValues.back}
|
|
|
+ />
|
|
|
+ <p />
|
|
|
+ <Button type="primary" disabled={btnDisable} onClick={addHandle}>
|
|
|
+ 确定
|
|
|
+ </Button>
|
|
|
+ <span> </span>
|
|
|
+ <Button
|
|
|
+ type="primary"
|
|
|
+ onClick={() => {
|
|
|
+ hideModal(false);
|
|
|
+ }}
|
|
|
>
|
|
|
- <Radio.Group>
|
|
|
- <Radio.Button value="0">aubert</Radio.Button>
|
|
|
- <Radio.Button value="1">blstm</Radio.Button>
|
|
|
- </Radio.Group>
|
|
|
- </FormItem>
|
|
|
- <FormItem label="模型文件">
|
|
|
- <Upload {...modelFileProps}>
|
|
|
- <Button>
|
|
|
- <UploadOutlined /> Upload
|
|
|
- </Button>
|
|
|
- </Upload>
|
|
|
- </FormItem>
|
|
|
- <FormItem label="词向量文件">
|
|
|
- <Upload {...vocabFileProps}>
|
|
|
- <Button>
|
|
|
- <UploadOutlined /> Upload
|
|
|
- </Button>
|
|
|
- </Upload>
|
|
|
- </FormItem>
|
|
|
- <FormItem label="标签文件">
|
|
|
- <Upload {...labelFileProps}>
|
|
|
- <Button>
|
|
|
- <UploadOutlined /> Upload
|
|
|
- </Button>
|
|
|
- </Upload>
|
|
|
- </FormItem>
|
|
|
- </Form>
|
|
|
+ 关闭
|
|
|
+ </Button>
|
|
|
+ </div>
|
|
|
</Modal>
|
|
|
);
|
|
|
};
|