feat: 修复Container界面和File App 和 User App
User App 添加permission
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
import { Button, Input, Modal, Select, Space, Switch, Table, Tooltip } from 'antd';
|
||||
import { Input, Modal, Select, Space, Switch } from 'antd';
|
||||
import { Fragment, useEffect, useState } from 'react';
|
||||
import { TextArea } from '../components/TextArea';
|
||||
import { useContainerStore } from '../store';
|
||||
@@ -7,6 +7,9 @@ import { Form } from 'antd';
|
||||
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,
|
||||
@@ -54,48 +57,44 @@ const FormModal = () => {
|
||||
};
|
||||
const isEdit = containerStore.formData.id;
|
||||
return (
|
||||
<Modal
|
||||
title={isEdit ? 'Edit' : 'Add'}
|
||||
open={containerStore.showEdit}
|
||||
onClose={() => containerStore.setShowEdit(false)}
|
||||
destroyOnClose
|
||||
footer={false}
|
||||
width={800}
|
||||
onCancel={onClose}>
|
||||
<Form
|
||||
form={form}
|
||||
onFinish={onFinish}
|
||||
labelCol={{
|
||||
span: 4,
|
||||
}}
|
||||
wrapperCol={{
|
||||
span: 20,
|
||||
}}>
|
||||
<Form.Item name='id' hidden>
|
||||
<Input />
|
||||
</Form.Item>
|
||||
<Form.Item name='title' label='title'>
|
||||
<Input />
|
||||
</Form.Item>
|
||||
<Form.Item name='description' label='description'>
|
||||
<Input.TextArea rows={4} />
|
||||
</Form.Item>
|
||||
<Form.Item name='tags' label='tags'>
|
||||
<Select mode='tags' />
|
||||
</Form.Item>
|
||||
<Form.Item name='code' label='code'>
|
||||
<TextArea />
|
||||
</Form.Item>
|
||||
<Form.Item label=' ' colon={false}>
|
||||
<Button type='primary' htmlType='submit'>
|
||||
Submit
|
||||
</Button>
|
||||
<Button className='ml-2' htmlType='reset' onClick={onClose}>
|
||||
Cancel
|
||||
</Button>
|
||||
</Form.Item>
|
||||
</Form>
|
||||
</Modal>
|
||||
<Dialog open={containerStore.showEdit} onClose={() => containerStore.setShowEdit(false)}>
|
||||
<DialogTitle>{isEdit ? 'Edit' : 'Add'}</DialogTitle>
|
||||
<DialogContent sx={{ padding: '20px', minWidth: '600px' }}>
|
||||
<Form
|
||||
form={form}
|
||||
onFinish={onFinish}
|
||||
labelCol={{
|
||||
span: 4,
|
||||
}}
|
||||
wrapperCol={{
|
||||
span: 20,
|
||||
}}>
|
||||
<Form.Item name='id' hidden>
|
||||
<Input />
|
||||
</Form.Item>
|
||||
<Form.Item name='title' label='title'>
|
||||
<Input />
|
||||
</Form.Item>
|
||||
<Form.Item name='description' label='description'>
|
||||
<Input.TextArea rows={4} />
|
||||
</Form.Item>
|
||||
<Form.Item name='tags' label='tags'>
|
||||
<Select mode='tags' />
|
||||
</Form.Item>
|
||||
<Form.Item name='code' label='code'>
|
||||
<TextArea />
|
||||
</Form.Item>
|
||||
<Form.Item label=' ' colon={false}>
|
||||
<Button variant='contained' type='submit'>
|
||||
提交
|
||||
</Button>
|
||||
<Button className='ml-2' onClick={onClose}>
|
||||
取消
|
||||
</Button>
|
||||
</Form.Item>
|
||||
</Form>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
);
|
||||
};
|
||||
const PublishFormModal = () => {
|
||||
@@ -106,7 +105,6 @@ const PublishFormModal = () => {
|
||||
showEdit: state.showPublish,
|
||||
setShowEdit: state.setShowPublish,
|
||||
formData: state.formData,
|
||||
publishData: state.publishData,
|
||||
updateData: state.updateData,
|
||||
};
|
||||
}),
|
||||
@@ -122,8 +120,41 @@ const PublishFormModal = () => {
|
||||
}
|
||||
}
|
||||
}, [containerStore.showEdit]);
|
||||
const onFinish = async (values: any) => {
|
||||
containerStore.publishData(values);
|
||||
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 fileName = values['publish']?.['fileName'];
|
||||
let directoryAndName: ReturnType<typeof getDirectoryAndName> | null = null;
|
||||
try {
|
||||
directoryAndName = getDirectoryAndName(fileName);
|
||||
if (!directoryAndName) {
|
||||
message.error('Invalid filename');
|
||||
return;
|
||||
}
|
||||
} catch (error) {
|
||||
message.error('Invalid filename');
|
||||
return;
|
||||
}
|
||||
|
||||
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,
|
||||
directory: directoryAndName.directory,
|
||||
});
|
||||
// @ts-ignore
|
||||
if (res.code === 200) {
|
||||
message.success('upload success');
|
||||
} else {
|
||||
message.error('upload failed');
|
||||
}
|
||||
}
|
||||
};
|
||||
const onUpdate = async () => {
|
||||
const values = form.getFieldsValue();
|
||||
@@ -133,57 +164,53 @@ const PublishFormModal = () => {
|
||||
containerStore.setShowEdit(false);
|
||||
form.resetFields();
|
||||
};
|
||||
const isEdit = containerStore.formData.id;
|
||||
return (
|
||||
<Modal
|
||||
title={'Publish'}
|
||||
open={containerStore.showEdit}
|
||||
onClose={() => containerStore.setShowEdit(false)}
|
||||
destroyOnClose
|
||||
footer={false}
|
||||
width={800}
|
||||
onCancel={onClose}>
|
||||
<Form
|
||||
form={form}
|
||||
onFinish={onFinish}
|
||||
labelCol={{
|
||||
span: 4,
|
||||
}}
|
||||
wrapperCol={{
|
||||
span: 20,
|
||||
}}>
|
||||
<Form.Item name='id' hidden>
|
||||
<Input />
|
||||
</Form.Item>
|
||||
<Form.Item name={['publish', 'title']} label='title'>
|
||||
<Input />
|
||||
</Form.Item>
|
||||
<Form.Item name={['publish', 'description']} label='description'>
|
||||
<Input.TextArea rows={4} />
|
||||
</Form.Item>
|
||||
<Form.Item name={['publish', 'version']} label='version' required>
|
||||
<Input />
|
||||
</Form.Item>
|
||||
<Form.Item name={['publish', 'key']} label='key' required>
|
||||
<Input />
|
||||
</Form.Item>
|
||||
<Form.Item name={['publish', 'fileName']} label='file name' required>
|
||||
<Input />
|
||||
</Form.Item>
|
||||
<Form.Item name={['publish', 'saveHTML']} label='save html'>
|
||||
<Switch />
|
||||
</Form.Item>
|
||||
<Form.Item label=' ' colon={false}>
|
||||
<div className='flex gap-3'>
|
||||
<Button type='primary' htmlType='submit'>
|
||||
Save And Publish
|
||||
</Button>
|
||||
<Button onClick={onUpdate}> Save</Button>
|
||||
<Button onClick={onClose}>Cancel</Button>
|
||||
</div>
|
||||
</Form.Item>
|
||||
</Form>
|
||||
</Modal>
|
||||
<Dialog open={containerStore.showEdit} onClose={() => containerStore.setShowEdit(false)}>
|
||||
<DialogTitle>Publish</DialogTitle>
|
||||
<DialogContent sx={{ padding: '20px', minWidth: '600px' }}>
|
||||
<Form
|
||||
form={form}
|
||||
onFinish={onFinish}
|
||||
labelCol={{
|
||||
span: 4,
|
||||
}}
|
||||
wrapperCol={{
|
||||
span: 20,
|
||||
}}>
|
||||
<Form.Item name='id' hidden>
|
||||
<Input />
|
||||
</Form.Item>
|
||||
<Form.Item name={['publish', 'key']} label='App key' required>
|
||||
<Input />
|
||||
</Form.Item>
|
||||
<Form.Item name={['publish', 'version']} label='App Version' required>
|
||||
<Input />
|
||||
</Form.Item>
|
||||
<Form.Item name={['publish', 'fileName']} label='Filename' tooltip='可以是文件夹格式,比如(directory/a.name)' required>
|
||||
<Input />
|
||||
</Form.Item>
|
||||
<Form.Item name={['publish', 'description']} label='Description'>
|
||||
<Input.TextArea rows={4} />
|
||||
</Form.Item>
|
||||
<Form.Item label=' ' colon={false}>
|
||||
<div className='flex gap-3'>
|
||||
<Tooltip
|
||||
placement='top'
|
||||
title='根据文件名和code的字符串的内容,自动生成文件。并保存。如果是其他文件类型,转成base64上传。比如图片以类似data:image/jpeg;开头'>
|
||||
<Button variant='contained' color='primary' type='submit'>
|
||||
上传
|
||||
</Button>
|
||||
</Tooltip>
|
||||
|
||||
<Button variant='contained' onClick={onUpdate}>
|
||||
保存
|
||||
</Button>
|
||||
<Button onClick={onClose}>取消</Button>
|
||||
</div>
|
||||
</Form.Item>
|
||||
</Form>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
);
|
||||
};
|
||||
export const ContainerList = () => {
|
||||
@@ -216,11 +243,14 @@ export const ContainerList = () => {
|
||||
containerStore.setFormData({});
|
||||
containerStore.setShowEdit(true);
|
||||
};
|
||||
|
||||
return (
|
||||
<div className='w-full h-full flex '>
|
||||
<div className='p-2 flex flex-col gap-2'>
|
||||
<Tooltip title='add'>
|
||||
<Button onClick={onAdd} icon={<PlusOutlined />}></Button>
|
||||
<Tooltip title='添加'>
|
||||
<IconButton variant='contained' onClick={onAdd} sx={{ padding: '8px' }}>
|
||||
<PlusOutlined />
|
||||
</IconButton>
|
||||
</Tooltip>
|
||||
</div>
|
||||
<div className='flex grow overflow-hidden h-full'>
|
||||
@@ -255,41 +285,48 @@ export const ContainerList = () => {
|
||||
<TextArea className='max-h-[240px] scrollbar' value={item.code} readonly />
|
||||
</div>
|
||||
<div className='flex mt-2 '>
|
||||
<Space.Compact>
|
||||
<ButtonGroup variant='contained' color='primary'>
|
||||
<Button
|
||||
onClick={() => {
|
||||
// containerStore.publishData(item);
|
||||
}}
|
||||
icon={<SettingOutlined />}></Button>
|
||||
<Button
|
||||
onClick={(e) => {
|
||||
containerStore.setFormData(item);
|
||||
containerStore.setShowEdit(true);
|
||||
setCodeEdit(false);
|
||||
e.stopPropagation();
|
||||
}}
|
||||
icon={<EditOutlined />}></Button>
|
||||
<Tooltip title='预览'>
|
||||
}}>
|
||||
<SettingOutlined />
|
||||
</Button>
|
||||
<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();
|
||||
}}
|
||||
icon={<LinkOutlined />}></Button>
|
||||
</Tooltip>
|
||||
<Tooltip title='publish'>
|
||||
}}>
|
||||
<LinkOutlined />
|
||||
</Button>
|
||||
</Tooltip> */}
|
||||
<Tooltip title='发布到 user app当中'>
|
||||
<Button
|
||||
onClick={(e) => {
|
||||
// containerStore.publishData(item);
|
||||
containerStore.setFormData(item);
|
||||
containerStore.setShowPublish(true);
|
||||
e.stopPropagation();
|
||||
}}
|
||||
icon={<CloudUploadOutlined />}></Button>
|
||||
}}>
|
||||
<CloudUploadOutlined />
|
||||
</Button>
|
||||
</Tooltip>
|
||||
<Tooltip title='删除'>
|
||||
<Button
|
||||
// color='error'
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
modal.confirm({
|
||||
@@ -300,10 +337,11 @@ export const ContainerList = () => {
|
||||
},
|
||||
});
|
||||
e.stopPropagation();
|
||||
}}
|
||||
icon={<DeleteOutlined />}></Button>
|
||||
}}>
|
||||
<DeleteOutlined />
|
||||
</Button>
|
||||
</Tooltip>
|
||||
</Space.Compact>
|
||||
</ButtonGroup>
|
||||
</div>
|
||||
</div>
|
||||
</Fragment>
|
||||
@@ -325,24 +363,17 @@ export const ContainerList = () => {
|
||||
onClick={() => {
|
||||
setCodeEdit(false);
|
||||
containerStore.setFormData({});
|
||||
}}
|
||||
icon={<LeftOutlined />}></Button>
|
||||
}}>
|
||||
<LeftOutlined />
|
||||
</Button>
|
||||
</Tooltip>
|
||||
<Tooltip title='保存'>
|
||||
<Button
|
||||
onClick={() => {
|
||||
console.log('save', containerStore.formData);
|
||||
containerStore.updateData({ ...containerStore.formData, code });
|
||||
}}
|
||||
icon={<SaveOutlined />}></Button>
|
||||
</Tooltip>
|
||||
<Tooltip title='预览'>
|
||||
<Button
|
||||
onClick={(e) => {
|
||||
// navicate('/container/preview/' + item.id);
|
||||
e.stopPropagation();
|
||||
}}
|
||||
icon={<LinkOutlined />}></Button>
|
||||
}}>
|
||||
<SaveOutlined />
|
||||
</Button>
|
||||
</Tooltip>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -12,9 +12,8 @@ type ContainerStore = {
|
||||
setLoading: (loading: boolean) => void;
|
||||
list: any[];
|
||||
getList: () => Promise<void>;
|
||||
updateData: (data: any) => Promise<void>;
|
||||
updateData: (data: any, opts?: { closePublish?: boolean; closeEdit?: boolean }) => Promise<Boolean>;
|
||||
deleteData: (id: string) => Promise<void>;
|
||||
publishData: (data: any) => Promise<void>;
|
||||
};
|
||||
export const useContainerStore = create<ContainerStore>((set, get) => {
|
||||
return {
|
||||
@@ -40,8 +39,10 @@ export const useContainerStore = create<ContainerStore>((set, get) => {
|
||||
message.error(res.message || 'Request failed');
|
||||
}
|
||||
},
|
||||
updateData: async (data) => {
|
||||
updateData: async (data, opts) => {
|
||||
const { getList } = get();
|
||||
const closePublish = opts?.closePublish ?? true;
|
||||
const closeEdit = opts?.closeEdit ?? true;
|
||||
const res = await query.post({
|
||||
path: 'container',
|
||||
key: 'update',
|
||||
@@ -49,11 +50,18 @@ export const useContainerStore = create<ContainerStore>((set, get) => {
|
||||
});
|
||||
if (res.code === 200) {
|
||||
message.success('Success');
|
||||
set({ showEdit: false, showPublish: false, formData: res.data });
|
||||
set({ formData: res.data });
|
||||
getList();
|
||||
if (closePublish) {
|
||||
set({ showPublish: false });
|
||||
}
|
||||
if (closeEdit) {
|
||||
set({ showEdit: false });
|
||||
}
|
||||
} else {
|
||||
message.error(res.message || 'Request failed');
|
||||
}
|
||||
return res.code === 200;
|
||||
},
|
||||
deleteData: async (id) => {
|
||||
const { getList } = get();
|
||||
@@ -69,17 +77,5 @@ export const useContainerStore = create<ContainerStore>((set, get) => {
|
||||
message.error(res.message || 'Request failed');
|
||||
}
|
||||
},
|
||||
publishData: async (data) => {
|
||||
const res = await query.post({
|
||||
path: 'container',
|
||||
key: 'publish',
|
||||
data,
|
||||
});
|
||||
if (res.code === 200) {
|
||||
message.success('Success');
|
||||
} else {
|
||||
message.error(res.message || 'Request failed');
|
||||
}
|
||||
},
|
||||
};
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user