feat: 添加i18n,美化界面
This commit is contained in:
@@ -1,30 +1,26 @@
|
||||
import { Input, Modal, Select, Space, Switch } from 'antd';
|
||||
import { Fragment, useEffect, useState } from 'react';
|
||||
import { Input, Modal, Select } from 'antd';
|
||||
import { Fragment, Suspense, useEffect, useState } from 'react';
|
||||
import { TextArea } from '../components/TextArea';
|
||||
import { useContainerStore } from '../store';
|
||||
import { useShallow } from 'zustand/react/shallow';
|
||||
import { Form } from 'antd';
|
||||
import copy from 'copy-to-clipboard';
|
||||
// import copy from 'copy-to-clipboard';
|
||||
import { useNewNavigate } from '@/modules';
|
||||
import { message } from '@/modules/message';
|
||||
import { Dialog, DialogTitle, DialogContent, Tooltip, Button, ButtonGroup } from '@mui/material';
|
||||
import { IconButton } from '@kevisual/center-components/button/index.tsx';
|
||||
import { getDirectoryAndName, toFile, uploadFileChunked } from '@kevisual/resources/index.ts';
|
||||
import {
|
||||
EditOutlined,
|
||||
SettingOutlined,
|
||||
LinkOutlined,
|
||||
SaveOutlined,
|
||||
DeleteOutlined,
|
||||
LeftOutlined,
|
||||
MessageOutlined,
|
||||
PlusOutlined,
|
||||
DashboardOutlined,
|
||||
CloudUploadOutlined,
|
||||
} from '@ant-design/icons';
|
||||
import clsx from 'clsx';
|
||||
import EditOutlined from '@ant-design/icons/EditOutlined';
|
||||
import DeleteOutlined from '@ant-design/icons/DeleteOutlined';
|
||||
import PlusOutlined from '@ant-design/icons/PlusOutlined';
|
||||
import CloudUploadOutlined from '@ant-design/icons/CloudUploadOutlined';
|
||||
|
||||
import { isObjectNull } from '@/utils/is-null';
|
||||
import { CardBlank } from '@/components/card/CardBlank';
|
||||
import { Settings } from 'lucide-react';
|
||||
import React from 'react';
|
||||
|
||||
const DrawEdit = React.lazy(() => import('../module/DrawEdit'));
|
||||
const FormModal = () => {
|
||||
const [form] = Form.useForm();
|
||||
const containerStore = useContainerStore(
|
||||
@@ -81,9 +77,11 @@ const FormModal = () => {
|
||||
<Form.Item name='tags' label='tags'>
|
||||
<Select mode='tags' />
|
||||
</Form.Item>
|
||||
<Form.Item name='code' label='code'>
|
||||
<TextArea />
|
||||
</Form.Item>
|
||||
{!isEdit && (
|
||||
<Form.Item name='code' label='code'>
|
||||
<TextArea />
|
||||
</Form.Item>
|
||||
)}
|
||||
<Form.Item label=' ' colon={false}>
|
||||
<Button variant='contained' type='submit'>
|
||||
提交
|
||||
@@ -122,10 +120,9 @@ const PublishFormModal = () => {
|
||||
}, [containerStore.showEdit]);
|
||||
const onFinish = async () => {
|
||||
const values = form.getFieldsValue();
|
||||
const success = await containerStore.updateData(values, { closePublish: false });
|
||||
if (success) {
|
||||
const formData = containerStore.formData;
|
||||
const code = formData.code;
|
||||
const containerRes = await containerStore.updateData(values, { closePublish: false });
|
||||
if (containerRes.code === 200) {
|
||||
const code = containerRes.data?.code || '-';
|
||||
const fileName = values['publish']?.['fileName'];
|
||||
let directoryAndName: ReturnType<typeof getDirectoryAndName> | null = null;
|
||||
try {
|
||||
@@ -142,7 +139,6 @@ const PublishFormModal = () => {
|
||||
const key = values['publish']['key'];
|
||||
const version = values['publish']['version'];
|
||||
const file = toFile(code, directoryAndName.name);
|
||||
console.log('key', key, version, directoryAndName.directory, directoryAndName.name);
|
||||
const res = await uploadFileChunked(file, {
|
||||
appKey: key,
|
||||
version,
|
||||
@@ -167,15 +163,15 @@ const PublishFormModal = () => {
|
||||
return (
|
||||
<Dialog open={containerStore.showEdit} onClose={() => containerStore.setShowEdit(false)}>
|
||||
<DialogTitle>Publish</DialogTitle>
|
||||
<DialogContent sx={{ padding: '20px', minWidth: '600px' }}>
|
||||
<DialogContent sx={{ padding: '10px', minWidth: '600px' }}>
|
||||
<Form
|
||||
form={form}
|
||||
onFinish={onFinish}
|
||||
labelCol={{
|
||||
span: 4,
|
||||
span: 6,
|
||||
}}
|
||||
wrapperCol={{
|
||||
span: 20,
|
||||
span: 18,
|
||||
}}>
|
||||
<Form.Item name='id' hidden>
|
||||
<Input />
|
||||
@@ -229,12 +225,14 @@ export const ContainerList = () => {
|
||||
setShowPublish: state.setShowPublish,
|
||||
updateData: state.updateData,
|
||||
formData: state.formData,
|
||||
getOne: state.getOne,
|
||||
setOpenDrawEdit: state.setOpenDrawEdit,
|
||||
openDrawEdit: state.openDrawEdit,
|
||||
};
|
||||
}),
|
||||
);
|
||||
|
||||
const [codeEdit, setCodeEdit] = useState(false);
|
||||
const [code, setCode] = useState('');
|
||||
// const [codeEdit, setCodeEdit] = useState(false);
|
||||
useEffect(() => {
|
||||
containerStore.getList();
|
||||
}, []);
|
||||
@@ -248,7 +246,7 @@ export const ContainerList = () => {
|
||||
<div className='w-full h-full flex '>
|
||||
<div className='p-2 flex flex-col gap-2'>
|
||||
<Tooltip title='添加'>
|
||||
<IconButton variant='contained' onClick={onAdd} sx={{ padding: '8px' }}>
|
||||
<IconButton variant='contained' onClick={onAdd}>
|
||||
<PlusOutlined />
|
||||
</IconButton>
|
||||
</Tooltip>
|
||||
@@ -264,56 +262,47 @@ export const ContainerList = () => {
|
||||
className='flex text-sm gap flex-col w-[400px] max-h-[400px] bg-white p-4 rounded-lg'
|
||||
key={item.id}
|
||||
onClick={() => {
|
||||
setCode(item.code);
|
||||
containerStore.setFormData(item);
|
||||
setCodeEdit(true);
|
||||
// containerStore.setFormData(item);
|
||||
}}>
|
||||
<div className='px-4 cursor-pointer'>
|
||||
<div
|
||||
className='font-bold flex items-center'
|
||||
onClick={(e) => {
|
||||
copy(item.code);
|
||||
e.stopPropagation();
|
||||
message.success('copy code success');
|
||||
}}>
|
||||
{item.title || '-'}
|
||||
<div className='font-thin card-key ml-3 text-xs'>{item.tags ? item.tags.join(', ') : ''}</div>
|
||||
<div className='font-thin card-key ml-3'>{item.tags ? item.tags.join(', ') : ''}</div>
|
||||
</div>
|
||||
<div className='font-light text-xs mt-2'>{item.description ? item.description : '-'}</div>
|
||||
</div>
|
||||
<div className='w-full text-xs'>
|
||||
<TextArea className='max-h-[240px] scrollbar' value={item.code} readonly />
|
||||
</div>
|
||||
|
||||
<div className='flex mt-2 '>
|
||||
<ButtonGroup variant='contained' color='primary'>
|
||||
<Button
|
||||
onClick={() => {
|
||||
// containerStore.publishData(item);
|
||||
}}>
|
||||
<SettingOutlined />
|
||||
</Button>
|
||||
<ButtonGroup
|
||||
variant='contained'
|
||||
color='primary'
|
||||
sx={{ color: 'white', '& .MuiButton-root': { color: 'white', minWidth: '32px', width: '32px', height: '32px', padding: '6px' } }}>
|
||||
<Tooltip title='编辑代码'>
|
||||
<Button
|
||||
onClick={(e) => {
|
||||
containerStore.getOne(item.id);
|
||||
containerStore.setFormData(item);
|
||||
containerStore.setOpenDrawEdit(true);
|
||||
e.stopPropagation();
|
||||
}}>
|
||||
<Settings size={16} />
|
||||
</Button>
|
||||
</Tooltip>
|
||||
<Tooltip title='编辑'>
|
||||
<Button
|
||||
onClick={(e) => {
|
||||
containerStore.setFormData(item);
|
||||
containerStore.setShowEdit(true);
|
||||
setCodeEdit(false);
|
||||
e.stopPropagation();
|
||||
}}>
|
||||
<EditOutlined />
|
||||
</Button>
|
||||
</Tooltip>
|
||||
{/* <Tooltip title='预览'>
|
||||
<Button
|
||||
onClick={(e) => {
|
||||
// navicate('/container/preview/' + item.id);
|
||||
window.open('/container/preview/' + item.id);
|
||||
e.stopPropagation();
|
||||
}}>
|
||||
<LinkOutlined />
|
||||
</Button>
|
||||
</Tooltip> */}
|
||||
<Tooltip title='发布到 user app当中'>
|
||||
<Tooltip title='添加到 user app当中'>
|
||||
<Button
|
||||
onClick={(e) => {
|
||||
// containerStore.publishData(item);
|
||||
@@ -355,42 +344,12 @@ export const ContainerList = () => {
|
||||
<CardBlank className='w-[400px]' />
|
||||
</div>
|
||||
</div>
|
||||
<div className={clsx('bg-gray-100 border-l-gray-200 border-bg-slate-300 w-[600px] shark-0', !codeEdit && 'hidden')}>
|
||||
<div className='bg-white p-2'>
|
||||
<div className='mt-2 ml-2 flex gap-2'>
|
||||
<Tooltip title='返回'>
|
||||
<Button
|
||||
onClick={() => {
|
||||
setCodeEdit(false);
|
||||
containerStore.setFormData({});
|
||||
}}>
|
||||
<LeftOutlined />
|
||||
</Button>
|
||||
</Tooltip>
|
||||
<Tooltip title='保存'>
|
||||
<Button
|
||||
onClick={() => {
|
||||
containerStore.updateData({ ...containerStore.formData, code });
|
||||
}}>
|
||||
<SaveOutlined />
|
||||
</Button>
|
||||
</Tooltip>
|
||||
</div>
|
||||
</div>
|
||||
<div className='h-[94%] p-2 rounded-2 shadow-xs'>
|
||||
<TextArea
|
||||
value={code}
|
||||
onChange={(value) => {
|
||||
setCode(value);
|
||||
}}
|
||||
className='h-full max-h-full scrollbar'
|
||||
style={{ overflow: 'auto' }}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<FormModal />
|
||||
<Suspense fallback={<div>Loading...</div>}>
|
||||
<DrawEdit />
|
||||
</Suspense>
|
||||
<PublishFormModal />
|
||||
<FormModal />
|
||||
{contextHolder}
|
||||
</div>
|
||||
);
|
||||
|
||||
103
src/pages/container/module/DrawEdit.tsx
Normal file
103
src/pages/container/module/DrawEdit.tsx
Normal file
@@ -0,0 +1,103 @@
|
||||
import { useEffect, useRef, useState } from 'react';
|
||||
import { BaseEditor } from '@kevisual/codemirror/editor/editor.ts';
|
||||
import { Drawer } from '@mui/material';
|
||||
import { useShallow } from 'zustand/shallow';
|
||||
import { useContainerStore } from '../store';
|
||||
import { Tooltip } from '@mui/material';
|
||||
import { IconButton } from '@kevisual/center-components/button/index.tsx';
|
||||
import { LeftOutlined, SaveOutlined } from '@ant-design/icons';
|
||||
|
||||
export const DrawEdit = () => {
|
||||
const editorElRef = useRef<HTMLDivElement>(null);
|
||||
const editorRef = useRef<BaseEditor>(null);
|
||||
const containerStore = useContainerStore(
|
||||
useShallow((state) => {
|
||||
return {
|
||||
openDrawEdit: state.openDrawEdit,
|
||||
setOpenDrawEdit: state.setOpenDrawEdit,
|
||||
data: state.data,
|
||||
updateData: state.updateData,
|
||||
};
|
||||
}),
|
||||
);
|
||||
const { openDrawEdit, setOpenDrawEdit } = containerStore;
|
||||
const [mount, setMount] = useState(false);
|
||||
useEffect(() => {
|
||||
if (openDrawEdit && editorElRef.current && !mount) {
|
||||
editorRef.current = new BaseEditor();
|
||||
editorRef.current.createEditor(editorElRef.current);
|
||||
setMount(true);
|
||||
}
|
||||
|
||||
return () => {
|
||||
if (editorRef.current) {
|
||||
editorRef.current.destroyEditor();
|
||||
}
|
||||
};
|
||||
}, [openDrawEdit]);
|
||||
|
||||
useEffect(() => {
|
||||
if (openDrawEdit && containerStore.data?.id && mount) {
|
||||
const editor = editorRef.current;
|
||||
const formData = containerStore.data;
|
||||
const fileType = editor?.getFileType(formData.title);
|
||||
const language = editor?.language;
|
||||
if (fileType && fileType !== language) {
|
||||
editor?.setLanguage(fileType, editorElRef.current!);
|
||||
} else {
|
||||
editor?.resetEditor(editorElRef.current!);
|
||||
}
|
||||
editor?.setContent(formData.code || '');
|
||||
}
|
||||
}, [openDrawEdit, containerStore.data?.id, mount]);
|
||||
|
||||
return (
|
||||
<Drawer
|
||||
open={openDrawEdit}
|
||||
ModalProps={{
|
||||
keepMounted: true, // 保持挂载
|
||||
hideBackdrop: true, // 移除mask
|
||||
disableEnforceFocus: true, // 允许操作背景内容
|
||||
disableAutoFocus: true, // 防止自动聚焦
|
||||
}}
|
||||
anchor='right'>
|
||||
<div className='bg-secondary w-[600px] h-[48px]'>
|
||||
<div className='text-white flex p-2'>
|
||||
<div className='ml-2 flex gap-2'>
|
||||
<Tooltip title='返回'>
|
||||
<IconButton
|
||||
sx={{
|
||||
'&:hover': {
|
||||
color: 'primary.main',
|
||||
},
|
||||
}}
|
||||
onClick={() => {
|
||||
setOpenDrawEdit(false);
|
||||
}}>
|
||||
<LeftOutlined />
|
||||
</IconButton>
|
||||
</Tooltip>
|
||||
<Tooltip title='保存'>
|
||||
<IconButton
|
||||
sx={{
|
||||
'&:hover': {
|
||||
color: 'primary.main',
|
||||
},
|
||||
}}
|
||||
onClick={() => {
|
||||
const code = editorRef.current?.getContent();
|
||||
containerStore.updateData({ id: containerStore.data.id, code }, { refresh: false });
|
||||
}}>
|
||||
<SaveOutlined />
|
||||
</IconButton>
|
||||
</Tooltip>
|
||||
</div>
|
||||
<div className='flex-1 ml-2 flex items-center'>{containerStore.data?.title}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className='border-primary' style={{ height: 'calc(100% - 50px)' }} ref={editorElRef}></div>
|
||||
</Drawer>
|
||||
);
|
||||
};
|
||||
|
||||
export default DrawEdit;
|
||||
@@ -12,8 +12,13 @@ type ContainerStore = {
|
||||
setLoading: (loading: boolean) => void;
|
||||
list: any[];
|
||||
getList: () => Promise<void>;
|
||||
updateData: (data: any, opts?: { closePublish?: boolean; closeEdit?: boolean }) => Promise<Boolean>;
|
||||
updateData: (data: any, opts?: { closePublish?: boolean; closeEdit?: boolean, refresh?: boolean }) => Promise<any>;
|
||||
deleteData: (id: string) => Promise<void>;
|
||||
openDrawEdit: boolean;
|
||||
setOpenDrawEdit: (openDrawEdit: boolean) => void;
|
||||
getOne: (id: string) => Promise<void>;
|
||||
data: any;
|
||||
setData: (data: any) => void;
|
||||
};
|
||||
export const useContainerStore = create<ContainerStore>((set, get) => {
|
||||
return {
|
||||
@@ -43,6 +48,7 @@ export const useContainerStore = create<ContainerStore>((set, get) => {
|
||||
const { getList } = get();
|
||||
const closePublish = opts?.closePublish ?? true;
|
||||
const closeEdit = opts?.closeEdit ?? true;
|
||||
const refresh = opts?.refresh ?? true;
|
||||
const res = await query.post({
|
||||
path: 'container',
|
||||
key: 'update',
|
||||
@@ -51,7 +57,9 @@ export const useContainerStore = create<ContainerStore>((set, get) => {
|
||||
if (res.code === 200) {
|
||||
message.success('Success');
|
||||
set({ formData: res.data });
|
||||
getList();
|
||||
if (refresh) {
|
||||
getList();
|
||||
}
|
||||
if (closePublish) {
|
||||
set({ showPublish: false });
|
||||
}
|
||||
@@ -61,7 +69,7 @@ export const useContainerStore = create<ContainerStore>((set, get) => {
|
||||
} else {
|
||||
message.error(res.message || 'Request failed');
|
||||
}
|
||||
return res.code === 200;
|
||||
return res;
|
||||
},
|
||||
deleteData: async (id) => {
|
||||
const { getList } = get();
|
||||
@@ -77,5 +85,23 @@ export const useContainerStore = create<ContainerStore>((set, get) => {
|
||||
message.error(res.message || 'Request failed');
|
||||
}
|
||||
},
|
||||
openDrawEdit: false,
|
||||
setOpenDrawEdit: (openDrawEdit) => set({ openDrawEdit }),
|
||||
getOne: async (id) => {
|
||||
set({ loading: true, data: {} });
|
||||
const res = await query.post({
|
||||
path: 'container',
|
||||
key: 'get',
|
||||
id,
|
||||
});
|
||||
set({ loading: false });
|
||||
if (res.code === 200) {
|
||||
set({ data: res.data });
|
||||
} else {
|
||||
message.error(res.message || 'Request failed');
|
||||
}
|
||||
},
|
||||
data: {},
|
||||
setData: (data) => set({ data }),
|
||||
};
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user