Commit 27942b24 authored by Bill's avatar Bill

feat: 添加app 版本管理

parent aab9b25c
...@@ -11,6 +11,7 @@ import pageCustomized from './pageCustomized' ...@@ -11,6 +11,7 @@ import pageCustomized from './pageCustomized'
//@ts-ignore //@ts-ignore
import asyncRoutes from '../router.config.json'; import asyncRoutes from '../router.config.json';
import refactorRoutes from './refactorRoutes'; import refactorRoutes from './refactorRoutes';
import systemManageRoute from './refactorRoutes/systemManageRoute';
const router = [ const router = [
{ {
...@@ -58,8 +59,9 @@ const router = [ ...@@ -58,8 +59,9 @@ const router = [
// component: '@/pages/home', // component: '@/pages/home',
// // icon: 'BarChartOutlined' // // icon: 'BarChartOutlined'
// }, // },
...asyncRoutes, // ...asyncRoutes,
// ...refactorRoutes, // ...refactorRoutes,
systemManageRoute,
{ {
path: '/noAuth', path: '/noAuth',
hidePageHeader: true, hidePageHeader: true,
......
...@@ -323,6 +323,38 @@ const router = { ...@@ -323,6 +323,38 @@ const router = {
hidePageHeader: true, hidePageHeader: true,
hideInMenu: true, hideInMenu: true,
component: '@/pages/systemManage/platformArg/template', component: '@/pages/systemManage/platformArg/template',
},
{
// APP版本管理
path: '/system/appVersion',
name: 'APP版本管理',
hidePageHeader: true,
// hideInMenu: true,
component: '@/pages/systemManage/appVersion/list',
},
{
// APP版本管理
path: '/system/appVersion/add',
name: '新增APP版本管理',
hidePageHeader: true,
hideInMenu: true,
component: '@/pages/systemManage/appVersion/add',
},
{
// APP版本管理
path: '/system/appVersion/view',
name: '查看APP版本管理',
hidePageHeader: true,
hideInMenu: true,
component: '@/pages/systemManage/appVersion/add',
},
{
// APP版本管理
path: '/system/appVersion/edit',
name: '修改APP版本管理',
hidePageHeader: true,
hideInMenu: true,
component: '@/pages/systemManage/appVersion/add',
} }
] ]
} }
......
...@@ -65,7 +65,7 @@ const FormilyUploadFiles: React.FC<Iprops> = (props: Iprops) => { ...@@ -65,7 +65,7 @@ const FormilyUploadFiles: React.FC<Iprops> = (props: Iprops) => {
return ( return (
<div style={{width: '100%'}}> <div style={{width: '100%'}}>
<UploadFiles fileList={fileList} onChange={onChange} onRemove={onRemove} disable={!editable} {...rest} /> <UploadFiles fileList={fileList} onChange={onChange} onRemove={onRemove} disabled={!editable} {...rest} />
{/* { {/* {
isShowError && errors.length > 0 && ( isShowError && errors.length > 0 && (
<div> <div>
......
...@@ -17,7 +17,7 @@ interface PickUploadProps extends Pick<UploadProps, PickProps> { ...@@ -17,7 +17,7 @@ interface PickUploadProps extends Pick<UploadProps, PickProps> {
*/ */
uploadOrder?: number, uploadOrder?: number,
children?: React.ReactNode, children?: React.ReactNode,
disable?: boolean, disabled?: boolean,
mode?: "text" | "link" | "ghost" | "default" | "primary" | "dashed", mode?: "text" | "link" | "ghost" | "default" | "primary" | "dashed",
buttonText?: string, buttonText?: string,
fileContainerClassName?: string fileContainerClassName?: string
...@@ -47,7 +47,7 @@ const UploadFiles: React.FC<PickUploadProps> = (props: PickUploadProps) => { ...@@ -47,7 +47,7 @@ const UploadFiles: React.FC<PickUploadProps> = (props: PickUploadProps) => {
children, children,
customizeItemRender, customizeItemRender,
onRemove, onRemove,
disable, disabled,
mode, mode,
buttonText, buttonText,
fileContainerClassName, fileContainerClassName,
...@@ -72,7 +72,7 @@ const UploadFiles: React.FC<PickUploadProps> = (props: PickUploadProps) => { ...@@ -72,7 +72,7 @@ const UploadFiles: React.FC<PickUploadProps> = (props: PickUploadProps) => {
}, styles.renderFileContainer, fileContainerClassName); }, styles.renderFileContainer, fileContainerClassName);
const uploadProps = { const uploadProps = {
disabled: disable, disabled: disabled,
name: 'file', name: 'file',
fileList: files, fileList: files,
accept: accept, accept: accept,
...@@ -113,7 +113,7 @@ const UploadFiles: React.FC<PickUploadProps> = (props: PickUploadProps) => { ...@@ -113,7 +113,7 @@ const UploadFiles: React.FC<PickUploadProps> = (props: PickUploadProps) => {
}; };
const handleRemove = (fileItem: UploadFile) => { const handleRemove = (fileItem: UploadFile) => {
if (disable) { if (disabled) {
return; return;
} }
if (onRemove) { if (onRemove) {
...@@ -151,7 +151,7 @@ const UploadFiles: React.FC<PickUploadProps> = (props: PickUploadProps) => { ...@@ -151,7 +151,7 @@ const UploadFiles: React.FC<PickUploadProps> = (props: PickUploadProps) => {
</a> </a>
</div> </div>
{ {
!disable && ( !disabled && (
<DeleteOutlined onClick={() => handleRemove(_item)} /> <DeleteOutlined onClick={() => handleRemove(_item)} />
) )
} }
...@@ -213,7 +213,7 @@ UploadFiles.defaultProps = { ...@@ -213,7 +213,7 @@ UploadFiles.defaultProps = {
onChange: (file: UploadChangeParam) => {}, onChange: (file: UploadChangeParam) => {},
customizeItemRender: null, customizeItemRender: null,
onRemove: null, onRemove: null,
disable: false, disabled: false,
mode: 'default', mode: 'default',
buttonText: '上传文件', buttonText: '上传文件',
fileContainerClassName: '', fileContainerClassName: '',
......
...@@ -151,7 +151,7 @@ const AllQuery = () => { ...@@ -151,7 +151,7 @@ const AllQuery = () => {
</Menu> </Menu>
) )
const controllerBtns = () => ( const ControllerBtns = () => (
<Space> <Space>
<Button <Button
type="primary" type="primary"
...@@ -224,7 +224,7 @@ const AllQuery = () => { ...@@ -224,7 +224,7 @@ const AllQuery = () => {
fetchTableData={(params: any) => fetchData(params)} fetchTableData={(params: any) => fetchData(params)}
controlRender={ controlRender={
<NiceForm <NiceForm
components={{controllerBtns}} components={{ControllerBtns}}
actions={formActions} actions={formActions}
// expressionScope={{controllerBtns: controllerBtns()}} // expressionScope={{controllerBtns: controllerBtns()}}
onSubmit={handleSearch} onSubmit={handleSearch}
......
...@@ -21,7 +21,7 @@ export const schema: ISchema = { ...@@ -21,7 +21,7 @@ export const schema: ISchema = {
// 'x-component-props': { // 'x-component-props': {
// children: '{{controllerBtns}}', // children: '{{controllerBtns}}',
// }, // },
"x-component": 'controllerBtns' "x-component": 'ControllerBtns'
}, },
title: { title: {
type: 'string', type: 'string',
......
import React from 'react';
import BraftEditor from 'braft-editor';
import 'braft-editor/dist/index.css';
interface Iprops {
value: any,
props: {
'x-component-props': any
},
mutators: {
change: (value: any) => void
}
}
const Editor: React.FC<Iprops> & { isFieldComponent: boolean } = (props: Iprops) => {
const { value } = props
const editorProps = props.props['x-component-props'];
const handleChange = (editorState) => {
const isEmpty = editorState.isEmpty();
const value = isEmpty ? null : editorState
props.mutators.change(value)
}
return (
<div >
<BraftEditor {...editorProps} value={value || ''} onChange={handleChange}/>
</div>
)
}
Editor.isFieldComponent = true;
export default Editor;
import React, { useEffect, useState } from 'react';
import NiceForm from '@/components/NiceForm';
import ReutrnEle from '@/components/ReturnEle';
import { usePageStatus } from '@/hooks/usePageStatus';
import { PageHeaderWrapper } from '@ant-design/pro-layout';
import { Button, Card, message } from 'antd';
import { history } from 'umi';
import schema from './schema';
import { Radio } from '@formily/antd-components'
import FormilyUploadFiles from '@/components/UploadFiles/FormilyUploadFiles';
import { createFormActions } from '@formily/antd';
import Editor from './components/Editor';
import moment, { Moment } from 'moment';
import { PublicApi } from '@/services/api';
import { GetManageAppVersionFindResponse } from '@/services/PlatformApi';
import { omit } from '@/utils';
import BraftEditor from 'braft-editor';
const formActions = createFormActions();
type SubmitData = {
content: any,
version: string,
releaseTime: string,
type: 1 | 2,
installPack: {
name: string,
url: string
}[]
}
type InitialValueData = Omit<GetManageAppVersionFindResponse, 'installPack'> & {
installPack: {
name: string,
url: string
}[]
}
function range(start: number, end: number) {
const result: number[] = [];
for (let i = start; i < end; i++) {
result.push(i);
}
return result;
}
const AppVersionAdd = () => {
const { id, preview } = usePageStatus();
console.log(preview);
const isEdit = id && !preview;
const isAdd = !id && !preview;
const isView = id && preview;
const currentDay = moment();
const [initialValue, setInitialValue] = useState<InitialValueData>({ releaseTime: currentDay.format('YYYY-MM-DD HH:mm:ss') } as unknown as InitialValueData);
const lastDay = moment().subtract(1, 'day');
/** 查看或修改时获取数据 */
useEffect(() => {
if (!id) {
return;
}
async function getInitialValue() {
const { data, code } = await PublicApi.getManageAppVersionFind({id});
if (code === 1000) {
const editorState = data.content && BraftEditor.createEditorState(data.content) || '';
setInitialValue({
...data,
content: editorState,
installPack: [{
name: '安卓apk',
url: data.installPack
}],
});
}
}
getInitialValue()
}, [])
const onSubmit = async (values: SubmitData) => {
const conent = values.content.toHTML();
const service = isAdd ? PublicApi.postManageAppVersionAdd : PublicApi.postManageAppVersionUpdate;
const postData = {
content: conent,
...omit(values, ['content', 'installPack']),
installPack: values.installPack.at(0)?.url
}
const { data, code} = await service(postData);
if (code === 1000) {
history.goBack();
return;
}
}
const disabledDate = (current: Moment) => {
return current < lastDay.endOf('day');
}
const disabledTime = () => {
return {
disabledHours: () => range(0, 24).splice(0, currentDay.get('hour')),
disabledMinutes: () => range(0, 60).splice(0, currentDay.get('minute')),
disabledSeconds: () => range(0, 60).splice(0, currentDay.get('second')),
};
}
return (
<PageHeaderWrapper
onBack={() => history.goBack()}
backIcon={<ReutrnEle description="返回" />}
title={isAdd ? '新增版本' : isEdit ? '编辑版本' : '查看版本'}
extra={
!isView && (
<Button onClick={() => formActions.submit()}>保存</Button>
)
}
>
<Card>
<NiceForm
editable={isAdd || isEdit}
value={initialValue}
expressionScope={{
disabledDate,
disabledTime
}}
actions={formActions}
schema={schema}
onSubmit={onSubmit}
components={{
Radio,
RadioGroup: Radio.Group,
Editor,
FormilyUploadFiles
}}
>
</NiceForm>
</Card>
</PageHeaderWrapper>
)
}
export default AppVersionAdd;
import { ISchema } from '@formily/antd';
import { Upload, message } from 'antd';
import { UploadFile } from 'antd/lib/upload/interface';
const schema: ISchema = {
type: 'object',
properties: {
layout: {
type: 'object',
'x-component': 'mega-layout',
"x-component-props": {
"labelWidth": 150,
// "wrapperWidth": 600,
wrapperCol: 8,
labelAlign: 'left',
full: true,
},
properties: {
version: {
title: '版本号',
type: 'string',
'x-rules': [
{
required: true,
message: '请填写版本号,版本号规则为1.0.0'
},
{
pattern: /^V[1-9]\d?(\.(0|[1-9]\d?)){2}$/,
message: '请填写正确的版本规则, 版本号规则为V1.0.0'
}
]
},
releaseTime: {
title: '发布时间',
type: 'date',
'x-component-props': {
format: 'YYYY-MM-DD HH:mm:ss',
style: {
width: '450px'
},
showTime: true,
disabledDate: '{{disabledDate}}',
disabledTime: '{{disabledTime}}'
},
'x-rules': [
{
required: true,
message: '请选择发布时间,发布时间需要大于等于当前时间'
}
]
},
type: {
title: '升级类型',
type: 'string',
'x-component': 'RadioGroup',
enum: [
{ label: '强制更新', value: 1 },
{ label: '非强制更新', value: 2 },
],
'x-rules': [
{
required: true,
message: '请选择升级类型'
}
]
},
contentLayout: {
type: 'object',
'x-component': 'mega-layout',
properties: {
content: {
type: "string",
title: '内容',
"x-component": 'Editor',
"x-rules": {
"required": true,
"message": "请输入内容"
},
"x-props": {
},
"x-component-props": {
contentStyle: {
height: 256,
width: 720,
},
style: {
border: '1px solid #DCDFE6'
},
excludeControls: [
'letter-spacing',
'line-height',
'clear',
'headings',
'list-ol',
'list-ul',
'remove-styles',
'superscript',
'subscript',
'hr',
],
media: {
// 如果要允许上传视频的话,需要重写uploadFn, https://www.yuque.com/braft-editor/be/gz44tn
accepts: {
video: false,
audio: false,
}
}
},
}
}
},
installPack: {
type: 'string',
title: '上传安卓文件',
'x-component': 'FormilyUploadFiles',
'x-component-props': {
maxCount: 1,
beforeUpload: (file: UploadFile) => {
console.log(file);
if (file.type !== 'application/vnd.android.package-archive') {
message.error("上传文件是apk 文件");
return Upload.LIST_IGNORE;
}
return true;
},
},
'x-rules': [
// {
// required: true,
// message: '请上传apk文件'
// }
]
}
}
}
}
}
export default schema
import React, { useRef } from 'react';
import { Card, Button, Space } from 'antd';
import { StandardTable } from 'god';
import { PageHeaderWrapper } from '@ant-design/pro-layout';
import NiceForm from '@/components/NiceForm';
import { PublicApi } from '@/services/api';
import { createFormActions } from '@formily/antd';
import { schema } from './schema';
// import { useStateFilterSearchLinkageEffect, useStateFilterSearchLinkageEffect } from '@/formSchema/effects/useFilterSearch';
import { FORM_FILTER_PATH } from '@/formSchema/const';
import { useStateFilterSearchLinkageEffect } from '@/formSchema/effects/useFilterSearch';
import { PlusOutlined } from '@ant-design/icons';
import { history, Link } from 'umi'
const formActions = createFormActions();
const AppVersionList = () => {
const ref = useRef<any>({});
const columns = [
{ title: '版本号', dataIndex: 'version' },
{ title: '升级类型', dataIndex: 'type' },
{ title: '升级提示语', dataIndex: 'content' },
{ title: '发布时间', dataIndex: 'releaseTime' },
{
title: '操作',
dataIndex: 'action',
render: (text, record, index) => {
return (
<Space>
{
index === 0 && (
<Link to={`/system/appVersion/edit?id=${record.id}`}>修改</Link>
)
}
<Link to={`/system/appVersion/view?id=${record.id}&preview=1`}>查看</Link>
</Space>
)
}
},
]
const fetchData = async (params) => {
const { data, code } = await PublicApi.getManageAppVersionPage(params);
if (code === 1000) {
return data
}
return {
totalCount: 0,
data: []
}
}
const ControllerBtns = () => (
<Space>
<Button
type="primary"
onClick={() => { history.push('/system/appVersion/add') }}
icon={<PlusOutlined />}
>
新建
</Button>
</Space>
);
const handleSearch = (values: {startDate: string, endDate: string}) => {
ref.current.reload(values)
}
return (
<PageHeaderWrapper
title={'APP版本管理'}
>
<Card>
<StandardTable
columns={columns as any}
currentRef={ref}
fetchTableData={(params: any) => fetchData(params)}
controlRender={
<NiceForm
components={{ControllerBtns}}
actions={formActions}
onSubmit={handleSearch}
schema={schema}
effects={($, actions) => {
useStateFilterSearchLinkageEffect($, actions, 'title', FORM_FILTER_PATH);
}}
/>
}
/>
</Card>
</PageHeaderWrapper>
)
}
export default AppVersionList
import { ISchema } from "@formily/antd";
export const schema: ISchema = {
type: 'object',
properties: {
megaLayout: {
type: 'object',
'x-component': 'mega-layout',
properties: {
topLayout: {
type: 'object',
'x-component': 'Mega-Layout',
'x-component-props': {
grid: true,
},
properties: {
ctl: {
type: 'object',
"x-component": 'ControllerBtns'
},
layout: {
type: 'object',
'x-component': 'flex-layout',
'x-component-props': {
colStyle: {
marginLeft: 20,
},
},
properties: {
"[startDate, endDate]": {
type: 'daterange',
'x-component-props': {
placeholder: ["发布开始时间", "发布结束时间"],
allowClear: true,
},
},
submit: {
'x-component': 'Submit',
'x-mega-props': {
span: 1,
},
'x-component-props': {
children: '查询',
},
},
},
}
},
},
},
},
},
};
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment