8 changed files with 625 additions and 2 deletions
			
			
		- 
					1package.json
 - 
					441src/pages/app/package/index.tsx
 - 
					26src/pages/app/package/style.ts
 - 
					25src/service/app/package.ts
 - 
					90src/store/app/package.ts
 - 
					25src/types/app/package.d.ts
 - 
					8src/utils/index.ts
 - 
					11vite.config.ts
 
@ -0,0 +1,441 @@ | 
			
		|||||
 | 
				import { useTranslation } from '@/i18n.ts' | 
			
		||||
 | 
				import { Button, Form, Popconfirm, Divider, Space, Tooltip, Badge } from 'antd' | 
			
		||||
 | 
				import { useAtom, useAtomValue } from 'jotai' | 
			
		||||
 | 
				import { | 
			
		||||
 | 
				  deleteAppPackageAtom, | 
			
		||||
 | 
				  saveOrUpdateAppPackageAtom, appPackageAtom, appPackagesAtom, appPackageSearchAtom, | 
			
		||||
 | 
				} from '@/store/app/package' | 
			
		||||
 | 
				import { useEffect, useMemo, useState } from 'react' | 
			
		||||
 | 
				import Action from '@/components/action/Action.tsx' | 
			
		||||
 | 
				import { | 
			
		||||
 | 
				  BetaSchemaForm, | 
			
		||||
 | 
				  ProColumns, | 
			
		||||
 | 
				  ProFormColumnsType, | 
			
		||||
 | 
				} from '@ant-design/pro-components' | 
			
		||||
 | 
				import ListPageLayout from '@/layout/ListPageLayout.tsx' | 
			
		||||
 | 
				import { useStyle } from './style' | 
			
		||||
 | 
				import { FilterOutlined } from '@ant-design/icons' | 
			
		||||
 | 
				import { getValueCount, unSetColumnRules } from '@/utils' | 
			
		||||
 | 
				import { Table as ProTable } from '@/components/table' | 
			
		||||
 | 
				import Switch from '@/components/switch' | 
			
		||||
 | 
				
 | 
			
		||||
 | 
				const i18nPrefix = 'appPackages.list' | 
			
		||||
 | 
				
 | 
			
		||||
 | 
				const AppPackage = () => { | 
			
		||||
 | 
				
 | 
			
		||||
 | 
				  const { styles, cx } = useStyle() | 
			
		||||
 | 
				  const { t } = useTranslation() | 
			
		||||
 | 
				  const [ form ] = Form.useForm() | 
			
		||||
 | 
				  const [ filterForm ] = Form.useForm() | 
			
		||||
 | 
				  const { mutate: saveOrUpdate, isPending: isSubmitting, isSuccess } = useAtomValue(saveOrUpdateAppPackageAtom) | 
			
		||||
 | 
				  const [ search, setSearch ] = useAtom(appPackageSearchAtom) | 
			
		||||
 | 
				  const [ currentAppPackage, setAppPackage ] = useAtom(appPackageAtom) | 
			
		||||
 | 
				  const { data, isFetching, isLoading, refetch } = useAtomValue(appPackagesAtom) | 
			
		||||
 | 
				  const { mutate: deleteAppPackage, isPending: isDeleting } = useAtomValue(deleteAppPackageAtom) | 
			
		||||
 | 
				
 | 
			
		||||
 | 
				  const [ open, setOpen ] = useState(false) | 
			
		||||
 | 
				  const [ openFilter, setFilterOpen ] = useState(false) | 
			
		||||
 | 
				  const [ searchKey, setSearchKey ] = useState(search?.title) | 
			
		||||
 | 
				
 | 
			
		||||
 | 
				  const columns = useMemo(() => { | 
			
		||||
 | 
				    return [ | 
			
		||||
 | 
				      { | 
			
		||||
 | 
				        title: 'ID', | 
			
		||||
 | 
				        dataIndex: 'id', | 
			
		||||
 | 
				        hideInTable: true, | 
			
		||||
 | 
				        hideInSearch: true, | 
			
		||||
 | 
				        formItemProps: { hidden: true } | 
			
		||||
 | 
				      }, | 
			
		||||
 | 
				      { | 
			
		||||
 | 
				        title: t(`${i18nPrefix}.columns.package_name`, '包名'), | 
			
		||||
 | 
				        dataIndex: 'package_name', | 
			
		||||
 | 
				        formItemProps: { | 
			
		||||
 | 
				          rules: [ | 
			
		||||
 | 
				            { | 
			
		||||
 | 
				              required: true, | 
			
		||||
 | 
				              message: t('message.required', '包名必填') | 
			
		||||
 | 
				            } | 
			
		||||
 | 
				          ] | 
			
		||||
 | 
				        } | 
			
		||||
 | 
				      }, | 
			
		||||
 | 
				
 | 
			
		||||
 | 
				      { | 
			
		||||
 | 
				        title: t(`${i18nPrefix}.columns.app_name`, '应用名'), | 
			
		||||
 | 
				        dataIndex: 'app_name', | 
			
		||||
 | 
				        formItemProps: { | 
			
		||||
 | 
				          rules: [ | 
			
		||||
 | 
				            { | 
			
		||||
 | 
				              required: true, | 
			
		||||
 | 
				              message: t('message.required', '应用名必填') | 
			
		||||
 | 
				            } | 
			
		||||
 | 
				          ] | 
			
		||||
 | 
				        } | 
			
		||||
 | 
				      }, | 
			
		||||
 | 
				
 | 
			
		||||
 | 
				      { | 
			
		||||
 | 
				        title: t(`${i18nPrefix}.columns.app_icon`, '应用图标'), | 
			
		||||
 | 
				        dataIndex: 'app_icon', | 
			
		||||
 | 
				        formItemProps: { | 
			
		||||
 | 
				          rules: [ | 
			
		||||
 | 
				            { | 
			
		||||
 | 
				              required: true, | 
			
		||||
 | 
				              message: t('message.required', '应用图标必填') | 
			
		||||
 | 
				            } | 
			
		||||
 | 
				          ] | 
			
		||||
 | 
				        } | 
			
		||||
 | 
				      }, | 
			
		||||
 | 
				
 | 
			
		||||
 | 
				      { | 
			
		||||
 | 
				        title: t(`${i18nPrefix}.columns.web_url`, '主页地址'), | 
			
		||||
 | 
				        dataIndex: 'web_url', | 
			
		||||
 | 
				        formItemProps: { | 
			
		||||
 | 
				          rules: [ | 
			
		||||
 | 
				            { | 
			
		||||
 | 
				              required: true, | 
			
		||||
 | 
				              message: t('message.required', '主页地址必填') | 
			
		||||
 | 
				            } | 
			
		||||
 | 
				          ] | 
			
		||||
 | 
				        } | 
			
		||||
 | 
				      }, | 
			
		||||
 | 
				
 | 
			
		||||
 | 
				      { | 
			
		||||
 | 
				        title: t(`${i18nPrefix}.columns.splash_url`, '启动图'), | 
			
		||||
 | 
				        dataIndex: 'splash_url', | 
			
		||||
 | 
				      }, | 
			
		||||
 | 
				
 | 
			
		||||
 | 
				      { | 
			
		||||
 | 
				        title: t(`${i18nPrefix}.columns.conf`, '配置地址'), | 
			
		||||
 | 
				        dataIndex: 'conf', | 
			
		||||
 | 
				        formItemProps: { | 
			
		||||
 | 
				          rules: [ | 
			
		||||
 | 
				            { | 
			
		||||
 | 
				              required: true, | 
			
		||||
 | 
				              message: t('message.required', '配置地址必填') | 
			
		||||
 | 
				            } | 
			
		||||
 | 
				          ] | 
			
		||||
 | 
				        } | 
			
		||||
 | 
				      }, | 
			
		||||
 | 
				
 | 
			
		||||
 | 
				      { | 
			
		||||
 | 
				        title: t(`${i18nPrefix}.columns.jks_url`, '签名文件地址'), | 
			
		||||
 | 
				        dataIndex: 'jks_url', | 
			
		||||
 | 
				        formItemProps: { | 
			
		||||
 | 
				          rules: [ | 
			
		||||
 | 
				            { | 
			
		||||
 | 
				              required: true, | 
			
		||||
 | 
				              message: t('message.required', '签名文件地址必填') | 
			
		||||
 | 
				            } | 
			
		||||
 | 
				          ] | 
			
		||||
 | 
				        } | 
			
		||||
 | 
				      }, | 
			
		||||
 | 
				
 | 
			
		||||
 | 
				      { | 
			
		||||
 | 
				        title: t(`${i18nPrefix}.columns.app_url`, '应用地址'), | 
			
		||||
 | 
				        dataIndex: 'app_url', | 
			
		||||
 | 
				      }, | 
			
		||||
 | 
				
 | 
			
		||||
 | 
				      { | 
			
		||||
 | 
				        title: t(`${i18nPrefix}.columns.splash_color`, 'App背景色'), | 
			
		||||
 | 
				        dataIndex: 'splash_color', | 
			
		||||
 | 
				      }, | 
			
		||||
 | 
				
 | 
			
		||||
 | 
				      { | 
			
		||||
 | 
				        title: t(`${i18nPrefix}.columns.key_alias`, 'key别名'), | 
			
		||||
 | 
				        dataIndex: 'key_alias', | 
			
		||||
 | 
				        formItemProps: { | 
			
		||||
 | 
				          rules: [ | 
			
		||||
 | 
				            { | 
			
		||||
 | 
				              required: true, | 
			
		||||
 | 
				              message: t('message.required', 'key别名必填') | 
			
		||||
 | 
				            } | 
			
		||||
 | 
				          ] | 
			
		||||
 | 
				        } | 
			
		||||
 | 
				      }, | 
			
		||||
 | 
				
 | 
			
		||||
 | 
				      { | 
			
		||||
 | 
				        title: t(`${i18nPrefix}.columns.store_pwd`, 'jks密码'), | 
			
		||||
 | 
				        dataIndex: 'store_pwd', | 
			
		||||
 | 
				        formItemProps: { | 
			
		||||
 | 
				          rules: [ | 
			
		||||
 | 
				            { | 
			
		||||
 | 
				              required: true, | 
			
		||||
 | 
				              message: t('message.required', 'jks密码必填') | 
			
		||||
 | 
				            } | 
			
		||||
 | 
				          ] | 
			
		||||
 | 
				        } | 
			
		||||
 | 
				      }, | 
			
		||||
 | 
				
 | 
			
		||||
 | 
				      { | 
			
		||||
 | 
				        title: t(`${i18nPrefix}.columns.key_pwd`, 'key密码'), | 
			
		||||
 | 
				        dataIndex: 'key_pwd', | 
			
		||||
 | 
				        formItemProps: { | 
			
		||||
 | 
				          rules: [ | 
			
		||||
 | 
				            { | 
			
		||||
 | 
				              required: true, | 
			
		||||
 | 
				              message: t('message.required', 'key密码必填') | 
			
		||||
 | 
				            } | 
			
		||||
 | 
				          ] | 
			
		||||
 | 
				        } | 
			
		||||
 | 
				      }, | 
			
		||||
 | 
				
 | 
			
		||||
 | 
				      { | 
			
		||||
 | 
				        title: t(`${i18nPrefix}.columns.status`, '状态'), | 
			
		||||
 | 
				        dataIndex: 'status', | 
			
		||||
 | 
				        valueType: 'select', | 
			
		||||
 | 
				        fieldProps: { | 
			
		||||
 | 
				          options: [ | 
			
		||||
 | 
				            { label: '未处理', value: 0 }, | 
			
		||||
 | 
				            { label: '队列中', value: 1 }, | 
			
		||||
 | 
				            { label: '打包中', value: 2 }, | 
			
		||||
 | 
				            { label: '打包成功', value: 3 }, | 
			
		||||
 | 
				            { label: '打包失败', value: 4 }, | 
			
		||||
 | 
				          ] | 
			
		||||
 | 
				        }, | 
			
		||||
 | 
				        render: (_text, record) => { | 
			
		||||
 | 
				          //0未处理  1队列中 2打包中 3打包成功 4打包失败
 | 
			
		||||
 | 
				          return <Badge status={[ 'default', 'processing', 'processing', 'success', 'error' ][record.status]} | 
			
		||||
 | 
				                        text={[ '处理', '队列中', '打包中', '打包成功', '打包失败' ][record.status]}/> | 
			
		||||
 | 
				        } | 
			
		||||
 | 
				      }, | 
			
		||||
 | 
				
 | 
			
		||||
 | 
				      { | 
			
		||||
 | 
				        title: t(`${i18nPrefix}.columns.message`, '打包信息'), | 
			
		||||
 | 
				        dataIndex: 'message', | 
			
		||||
 | 
				      }, | 
			
		||||
 | 
				
 | 
			
		||||
 | 
				      { | 
			
		||||
 | 
				        title: t(`${i18nPrefix}.columns.x_86`, '32位'), | 
			
		||||
 | 
				        dataIndex: 'x_86', | 
			
		||||
 | 
				        valueType: 'switch', | 
			
		||||
 | 
				        render: (_text, record) => { | 
			
		||||
 | 
				          return <Switch checked={record.x_86 === 1} size={'small'}/> | 
			
		||||
 | 
				        } | 
			
		||||
 | 
				      }, | 
			
		||||
 | 
				
 | 
			
		||||
 | 
				      { | 
			
		||||
 | 
				        title: t(`${i18nPrefix}.columns.uid`, 'uid'), | 
			
		||||
 | 
				        dataIndex: 'uid', | 
			
		||||
 | 
				        hideInTable: true, | 
			
		||||
 | 
				        hideInSearch: true, | 
			
		||||
 | 
				        formItemProps: { hidden: true } | 
			
		||||
 | 
				      }, | 
			
		||||
 | 
				
 | 
			
		||||
 | 
				      { | 
			
		||||
 | 
				        title: t(`${i18nPrefix}.columns.option`, '操作'), | 
			
		||||
 | 
				        key: 'option', | 
			
		||||
 | 
				        valueType: 'option', | 
			
		||||
 | 
				        fixed: 'right', | 
			
		||||
 | 
				        render: (_, record) => [ | 
			
		||||
 | 
				          <Action key="edit" | 
			
		||||
 | 
				                  as={'a'} | 
			
		||||
 | 
				                  onClick={() => { | 
			
		||||
 | 
				                    form.setFieldsValue(record) | 
			
		||||
 | 
				                    setOpen(true) | 
			
		||||
 | 
				                  }}>{t('actions.edit')}</Action>, | 
			
		||||
 | 
				          <Popconfirm | 
			
		||||
 | 
				                  key={'del_confirm'} | 
			
		||||
 | 
				                  disabled={isDeleting} | 
			
		||||
 | 
				                  onConfirm={() => { | 
			
		||||
 | 
				                    deleteAppPackage(record.id ) | 
			
		||||
 | 
				                  }} | 
			
		||||
 | 
				                  title={t('message.deleteConfirm')}> | 
			
		||||
 | 
				            <a key="del"> | 
			
		||||
 | 
				              {t('actions.delete', '删除')} | 
			
		||||
 | 
				            </a> | 
			
		||||
 | 
				          </Popconfirm> | 
			
		||||
 | 
				        ] | 
			
		||||
 | 
				      } | 
			
		||||
 | 
				    ] as ProColumns[] | 
			
		||||
 | 
				  }, [ isDeleting, currentAppPackage, search ]) | 
			
		||||
 | 
				
 | 
			
		||||
 | 
				  useEffect(() => { | 
			
		||||
 | 
				
 | 
			
		||||
 | 
				    setSearchKey(search?.title) | 
			
		||||
 | 
				    filterForm.setFieldsValue(search) | 
			
		||||
 | 
				
 | 
			
		||||
 | 
				  }, [ search ]) | 
			
		||||
 | 
				
 | 
			
		||||
 | 
				  useEffect(() => { | 
			
		||||
 | 
				    if (isSuccess) { | 
			
		||||
 | 
				      setOpen(false) | 
			
		||||
 | 
				    } | 
			
		||||
 | 
				  }, [ isSuccess ]) | 
			
		||||
 | 
				
 | 
			
		||||
 | 
				  return ( | 
			
		||||
 | 
				          <ListPageLayout className={styles.container}> | 
			
		||||
 | 
				            <ProTable | 
			
		||||
 | 
				                    rowKey="id" | 
			
		||||
 | 
				                    headerTitle={t(`${i18nPrefix}.title`, '应用打包管理')} | 
			
		||||
 | 
				                    toolbar={{ | 
			
		||||
 | 
				                      search: { | 
			
		||||
 | 
				                        loading: isFetching && !!search?.title, | 
			
		||||
 | 
				                        onSearch: (value: string) => { | 
			
		||||
 | 
				                          setSearch(prev => ({ | 
			
		||||
 | 
				                            ...prev, | 
			
		||||
 | 
				                            title: value | 
			
		||||
 | 
				                          })) | 
			
		||||
 | 
				                        }, | 
			
		||||
 | 
				                        allowClear: true, | 
			
		||||
 | 
				                        onChange: (e) => { | 
			
		||||
 | 
				                          setSearchKey(e.target?.value) | 
			
		||||
 | 
				                        }, | 
			
		||||
 | 
				                        value: searchKey, | 
			
		||||
 | 
				                        placeholder: t(`${i18nPrefix}.placeholder`, '输入应用打包名称') | 
			
		||||
 | 
				                      }, | 
			
		||||
 | 
				                      actions: [ | 
			
		||||
 | 
				                        <Tooltip key={'filter'} title={t(`${i18nPrefix}.filter.tooltip`, '高级查询')}> | 
			
		||||
 | 
				                          <Badge count={getValueCount(search)}> | 
			
		||||
 | 
				                            <Button | 
			
		||||
 | 
				                                    onClick={() => { | 
			
		||||
 | 
				                                      setFilterOpen(true) | 
			
		||||
 | 
				                                    }} | 
			
		||||
 | 
				                                    icon={<FilterOutlined/>} shape={'circle'} size={'small'}/> | 
			
		||||
 | 
				                          </Badge> | 
			
		||||
 | 
				                        </Tooltip>, | 
			
		||||
 | 
				                        <Divider type={'vertical'} key={'divider'}/>, | 
			
		||||
 | 
				                        <Button key={'add'} | 
			
		||||
 | 
				                                onClick={() => { | 
			
		||||
 | 
				                                  form.resetFields() | 
			
		||||
 | 
				                                  form.setFieldsValue({ | 
			
		||||
 | 
				                                    id: 0, | 
			
		||||
 | 
				                                  }) | 
			
		||||
 | 
				                                  setOpen(true) | 
			
		||||
 | 
				                                }} | 
			
		||||
 | 
				                                type={'primary'}>{t(`${i18nPrefix}.add`, '添加')}</Button> | 
			
		||||
 | 
				                      ] | 
			
		||||
 | 
				                    }} | 
			
		||||
 | 
				                    scroll={{ | 
			
		||||
 | 
				                      x: columns.length * 200, | 
			
		||||
 | 
				                      y: 'calc(100vh - 290px)' | 
			
		||||
 | 
				                    }} | 
			
		||||
 | 
				                    search={false} | 
			
		||||
 | 
				                    onRow={(record) => { | 
			
		||||
 | 
				                      return { | 
			
		||||
 | 
				                        className: cx({ | 
			
		||||
 | 
				                          'ant-table-row-selected': currentAppPackage?.id === record.id | 
			
		||||
 | 
				                        }), | 
			
		||||
 | 
				                        onClick: () => { | 
			
		||||
 | 
				                          setAppPackage(record) | 
			
		||||
 | 
				                        } | 
			
		||||
 | 
				                      } | 
			
		||||
 | 
				                    }} | 
			
		||||
 | 
				                    dateFormatter="string" | 
			
		||||
 | 
				                    loading={isLoading || isFetching} | 
			
		||||
 | 
				                    dataSource={data?.rows ?? []} | 
			
		||||
 | 
				                    columns={columns} | 
			
		||||
 | 
				                    options={{ | 
			
		||||
 | 
				                      reload: () => { | 
			
		||||
 | 
				                        refetch() | 
			
		||||
 | 
				                      }, | 
			
		||||
 | 
				                    }} | 
			
		||||
 | 
				                    pagination={{ | 
			
		||||
 | 
				                      total: data?.total, | 
			
		||||
 | 
				                      pageSize: search.pageSize, | 
			
		||||
 | 
				                      current: search.page, | 
			
		||||
 | 
				                      onShowSizeChange: (current: number, size: number) => { | 
			
		||||
 | 
				                        setSearch({ | 
			
		||||
 | 
				                          ...search, | 
			
		||||
 | 
				                          pageSize: size, | 
			
		||||
 | 
				                          page: current | 
			
		||||
 | 
				                        }) | 
			
		||||
 | 
				                      }, | 
			
		||||
 | 
				                      onChange: (current, pageSize) => { | 
			
		||||
 | 
				                        setSearch(prev => { | 
			
		||||
 | 
				                          return { | 
			
		||||
 | 
				                            ...prev, | 
			
		||||
 | 
				                            page: current, | 
			
		||||
 | 
				                            pageSize: pageSize, | 
			
		||||
 | 
				                          } | 
			
		||||
 | 
				                        }) | 
			
		||||
 | 
				                      }, | 
			
		||||
 | 
				                    }} | 
			
		||||
 | 
				            /> | 
			
		||||
 | 
				            <BetaSchemaForm | 
			
		||||
 | 
				                    grid={true} | 
			
		||||
 | 
				                    shouldUpdate={false} | 
			
		||||
 | 
				                    width={1000} | 
			
		||||
 | 
				                    form={form} | 
			
		||||
 | 
				                    layout={'vertical'} | 
			
		||||
 | 
				                    scrollToFirstError={true} | 
			
		||||
 | 
				                    title={t(`${i18nPrefix}.title_${form.getFieldValue('id') !== 0 ? 'edit' : 'add'}`, form.getFieldValue('id') !== 0 ? '应用打包编辑' : '应用打包添加')} | 
			
		||||
 | 
				                    layoutType={'DrawerForm'} | 
			
		||||
 | 
				                    open={open} | 
			
		||||
 | 
				                    drawerProps={{ | 
			
		||||
 | 
				                      maskClosable: false, | 
			
		||||
 | 
				                    }} | 
			
		||||
 | 
				                    onOpenChange={(open) => { | 
			
		||||
 | 
				                      setOpen(open) | 
			
		||||
 | 
				                    }} | 
			
		||||
 | 
				                    loading={isSubmitting} | 
			
		||||
 | 
				                    onValuesChange={(values) => { | 
			
		||||
 | 
				
 | 
			
		||||
 | 
				                    }} | 
			
		||||
 | 
				                    onFinish={async (values) => { | 
			
		||||
 | 
				                      saveOrUpdate(values) | 
			
		||||
 | 
				                    }} | 
			
		||||
 | 
				                    columns={columns as ProFormColumnsType[]}/> | 
			
		||||
 | 
				            <BetaSchemaForm | 
			
		||||
 | 
				                    title={t(`${i18nPrefix}.filter.title`, '应用打包高级查询')} | 
			
		||||
 | 
				                    grid={true} | 
			
		||||
 | 
				                    shouldUpdate={false} | 
			
		||||
 | 
				                    width={500} | 
			
		||||
 | 
				                    form={filterForm} | 
			
		||||
 | 
				                    open={openFilter} | 
			
		||||
 | 
				                    onOpenChange={open => { | 
			
		||||
 | 
				                      setFilterOpen(open) | 
			
		||||
 | 
				                    }} | 
			
		||||
 | 
				                    layout={'vertical'} | 
			
		||||
 | 
				                    scrollToFirstError={true} | 
			
		||||
 | 
				                    layoutType={'DrawerForm'} | 
			
		||||
 | 
				                    drawerProps={{ | 
			
		||||
 | 
				                      maskClosable: false, | 
			
		||||
 | 
				                      mask: false, | 
			
		||||
 | 
				                    }} | 
			
		||||
 | 
				                    submitter={{ | 
			
		||||
 | 
				                      searchConfig: { | 
			
		||||
 | 
				                        resetText: t(`${i18nPrefix}.filter.reset`, '清空'), | 
			
		||||
 | 
				                        submitText: t(`${i18nPrefix}.filter.submit`, '查询'), | 
			
		||||
 | 
				                      }, | 
			
		||||
 | 
				                      onReset: () => { | 
			
		||||
 | 
				                        filterForm.resetFields() | 
			
		||||
 | 
				                      }, | 
			
		||||
 | 
				                      render: (props,) => { | 
			
		||||
 | 
				                        return ( | 
			
		||||
 | 
				                                <div style={{ textAlign: 'right' }}> | 
			
		||||
 | 
				                                  <Space> | 
			
		||||
 | 
				                                    <Button onClick={() => { | 
			
		||||
 | 
				                                      props.reset() | 
			
		||||
 | 
				
 | 
			
		||||
 | 
				                                    }}>{props.searchConfig?.resetText}</Button> | 
			
		||||
 | 
				                                    <Button type="primary" | 
			
		||||
 | 
				                                            onClick={() => { | 
			
		||||
 | 
				                                              props.submit() | 
			
		||||
 | 
				                                            }} | 
			
		||||
 | 
				                                    >{props.searchConfig?.submitText}</Button> | 
			
		||||
 | 
				                                  </Space> | 
			
		||||
 | 
				                                </div> | 
			
		||||
 | 
				                        ) | 
			
		||||
 | 
				                      }, | 
			
		||||
 | 
				
 | 
			
		||||
 | 
				                    }} | 
			
		||||
 | 
				                    onValuesChange={(values) => { | 
			
		||||
 | 
				
 | 
			
		||||
 | 
				                    }} | 
			
		||||
 | 
				
 | 
			
		||||
 | 
				                    onFinish={async (values) => { | 
			
		||||
 | 
				                      //处理,变成数组
 | 
			
		||||
 | 
				                      Object.keys(values).forEach(key => { | 
			
		||||
 | 
				                        if (typeof values[key] === 'string' && values[key].includes(',')) { | 
			
		||||
 | 
				                          values[key] = values[key].split(',') | 
			
		||||
 | 
				                        } | 
			
		||||
 | 
				                      }) | 
			
		||||
 | 
				
 | 
			
		||||
 | 
				                      setSearch(values) | 
			
		||||
 | 
				
 | 
			
		||||
 | 
				                    }} | 
			
		||||
 | 
				                    columns={unSetColumnRules(columns.filter(item => !item.hideInSearch)) as ProFormColumnsType[]}/> | 
			
		||||
 | 
				          </ListPageLayout> | 
			
		||||
 | 
				  ) | 
			
		||||
 | 
				} | 
			
		||||
 | 
				
 | 
			
		||||
 | 
				export default AppPackage | 
			
		||||
@ -0,0 +1,26 @@ | 
			
		|||||
 | 
				import { createStyles } from '@/theme' | 
			
		||||
 | 
				
 | 
			
		||||
 | 
				export const useStyle = createStyles(({ token, css, cx, prefixCls }, props: any) => { | 
			
		||||
 | 
				    const prefix = `${prefixCls}-${token?.proPrefix}-appPackage-list-page` | 
			
		||||
 | 
				
 | 
			
		||||
 | 
				    const container = css`
 | 
			
		||||
 | 
				        .ant-table-cell{ | 
			
		||||
 | 
				          .ant-tag{ | 
			
		||||
 | 
				            padding-inline: 3px; | 
			
		||||
 | 
				            margin-inline-end: 3px; | 
			
		||||
 | 
				          } | 
			
		||||
 | 
				        } | 
			
		||||
 | 
				        .ant-table-empty { | 
			
		||||
 | 
				          .ant-table-body{ | 
			
		||||
 | 
				            height: calc(100vh - 350px) | 
			
		||||
 | 
				          } | 
			
		||||
 | 
				        } | 
			
		||||
 | 
				      .ant-pro-table-highlight{ | 
			
		||||
 | 
				
 | 
			
		||||
 | 
				      } | 
			
		||||
 | 
				    `
 | 
			
		||||
 | 
				
 | 
			
		||||
 | 
				    return { | 
			
		||||
 | 
				        container: cx(prefix, props?.className, container), | 
			
		||||
 | 
				    } | 
			
		||||
 | 
				}) | 
			
		||||
@ -0,0 +1,25 @@ | 
			
		|||||
 | 
				import { createCURD } from '@/service/base.ts' | 
			
		||||
 | 
				import { APP } from '@/types/app/package' | 
			
		||||
 | 
				import request from '@/request.ts' | 
			
		||||
 | 
				import { IPageResult } from '@/global' | 
			
		||||
 | 
				
 | 
			
		||||
 | 
				const appPackage = { | 
			
		||||
 | 
				  ...createCURD<any, APP.IAppPackage>('/package'), | 
			
		||||
 | 
				  list: async (params: any) => { | 
			
		||||
 | 
				    return await request.get<IPageResult<APP.IAppPackage>>(`/package/list`, { ...params }) | 
			
		||||
 | 
				  }, | 
			
		||||
 | 
				  //http://154.88.7.8:45321/package/v1/create
 | 
			
		||||
 | 
				  add: async (params: any) => { | 
			
		||||
 | 
				    return await request.post<IPageResult<APP.IAppPackage>>(`/package/create`, { ...params }) | 
			
		||||
 | 
				  }, | 
			
		||||
 | 
				  //delete
 | 
			
		||||
 | 
				  delete: async (params: any) => { | 
			
		||||
 | 
				    return await request.post<IPageResult<APP.IAppPackage>>(`/package/delete`, { ...params }) | 
			
		||||
 | 
				  }, | 
			
		||||
 | 
				  //package
 | 
			
		||||
 | 
				  package: async (params: any) => { | 
			
		||||
 | 
				    return await request.post<IPageResult<APP.IAppPackage>>(`/package/package`, { ...params }) | 
			
		||||
 | 
				  }, | 
			
		||||
 | 
				} | 
			
		||||
 | 
				
 | 
			
		||||
 | 
				export default appPackage | 
			
		||||
@ -0,0 +1,90 @@ | 
			
		|||||
 | 
				import { atom } from 'jotai' | 
			
		||||
 | 
				import { IApiResult, IPage } from '@/global' | 
			
		||||
 | 
				import { atomWithMutation, atomWithQuery, queryClientAtom } from 'jotai-tanstack-query' | 
			
		||||
 | 
				import { message } from 'antd' | 
			
		||||
 | 
				import { t } from 'i18next' | 
			
		||||
 | 
				import { APP } from '@/types/app/package' | 
			
		||||
 | 
				import aPPServ from '@/service/app/package' | 
			
		||||
 | 
				
 | 
			
		||||
 | 
				type SearchParams = IPage & { | 
			
		||||
 | 
				  key?: string | 
			
		||||
 | 
				
 | 
			
		||||
 | 
				  [key: string]: any | 
			
		||||
 | 
				} | 
			
		||||
 | 
				
 | 
			
		||||
 | 
				export const appPackageIdAtom = atom(0) | 
			
		||||
 | 
				
 | 
			
		||||
 | 
				export const appPackageIdsAtom = atom<number[]>([]) | 
			
		||||
 | 
				
 | 
			
		||||
 | 
				export const appPackageAtom = atom<APP.IAppPackage>(undefined as unknown as APP.IAppPackage ) | 
			
		||||
 | 
				
 | 
			
		||||
 | 
				export const appPackageSearchAtom = atom<SearchParams>({ | 
			
		||||
 | 
				  key: '', | 
			
		||||
 | 
				  pageSize: 10, | 
			
		||||
 | 
				  page: 1, | 
			
		||||
 | 
				} as SearchParams) | 
			
		||||
 | 
				
 | 
			
		||||
 | 
				export const appPackagePageAtom = atom<IPage>({ | 
			
		||||
 | 
				  pageSize: 10, | 
			
		||||
 | 
				  page: 1, | 
			
		||||
 | 
				}) | 
			
		||||
 | 
				
 | 
			
		||||
 | 
				export const appPackagesAtom = atomWithQuery((get) => { | 
			
		||||
 | 
				  return { | 
			
		||||
 | 
				    queryKey: [ 'appPackages', get(appPackageSearchAtom) ], | 
			
		||||
 | 
				    queryFn: async ({ queryKey: [ , params ] }) => { | 
			
		||||
 | 
				      return await aPPServ.list(params as SearchParams) | 
			
		||||
 | 
				    }, | 
			
		||||
 | 
				    select: res => { | 
			
		||||
 | 
				      const data = res.data | 
			
		||||
 | 
				      data.rows = data.rows?.map(row => { | 
			
		||||
 | 
				        return { | 
			
		||||
 | 
				          ...row, | 
			
		||||
 | 
				          //status: convertToBool(row.status)
 | 
			
		||||
 | 
				        } | 
			
		||||
 | 
				      }) | 
			
		||||
 | 
				      return data | 
			
		||||
 | 
				    } | 
			
		||||
 | 
				  } | 
			
		||||
 | 
				}) | 
			
		||||
 | 
				
 | 
			
		||||
 | 
				//saveOrUpdateAtom
 | 
			
		||||
 | 
				export const saveOrUpdateAppPackageAtom = atomWithMutation<IApiResult, APP.IAppPackage>((get) => { | 
			
		||||
 | 
				
 | 
			
		||||
 | 
				  return { | 
			
		||||
 | 
				    mutationKey: [ 'updateAppPackage' ], | 
			
		||||
 | 
				    mutationFn: async (data) => { | 
			
		||||
 | 
				      //data.status = data.status ? '1' : '0'
 | 
			
		||||
 | 
				      if (data.id === 0) { | 
			
		||||
 | 
				        return await aPPServ.add(data) | 
			
		||||
 | 
				      } | 
			
		||||
 | 
				      return await aPPServ.update(data) | 
			
		||||
 | 
				    }, | 
			
		||||
 | 
				    onSuccess: (res) => { | 
			
		||||
 | 
				      const isAdd = !!res.data?.id | 
			
		||||
 | 
				      message.success(t(isAdd ? 'message.saveSuccess' : 'message.editSuccess', '保存成功')) | 
			
		||||
 | 
				
 | 
			
		||||
 | 
				      //更新列表
 | 
			
		||||
 | 
				      // eslint-disable-next-line @typescript-eslint/ban-ts-comment
 | 
			
		||||
 | 
				      // @ts-ignore fix
 | 
			
		||||
 | 
				      get(queryClientAtom).invalidateQueries({ queryKey: [ 'appPackages', get(appPackageSearchAtom) ] }) | 
			
		||||
 | 
				
 | 
			
		||||
 | 
				      return res | 
			
		||||
 | 
				    } | 
			
		||||
 | 
				  } | 
			
		||||
 | 
				}) | 
			
		||||
 | 
				
 | 
			
		||||
 | 
				export const deleteAppPackageAtom = atomWithMutation((get) => { | 
			
		||||
 | 
				  return { | 
			
		||||
 | 
				    mutationKey: [ 'deleteAppPackage' ], | 
			
		||||
 | 
				    mutationFn: async (ids: number) => { | 
			
		||||
 | 
				      return await aPPServ.delete({ id: ids } ?? get(appPackageIdsAtom)) | 
			
		||||
 | 
				    }, | 
			
		||||
 | 
				    onSuccess: (res) => { | 
			
		||||
 | 
				      message.success('message.deleteSuccess') | 
			
		||||
 | 
				      //更新列表
 | 
			
		||||
 | 
				      get(queryClientAtom).invalidateQueries({ queryKey: [ 'appPackages', get(appPackageSearchAtom) ] }) | 
			
		||||
 | 
				      return res | 
			
		||||
 | 
				    } | 
			
		||||
 | 
				  } | 
			
		||||
 | 
				}) | 
			
		||||
@ -0,0 +1,25 @@ | 
			
		|||||
 | 
				export namespace APP { | 
			
		||||
 | 
				  export interface IAppPackage { | 
			
		||||
 | 
				    id: number; | 
			
		||||
 | 
				    package_name: string; | 
			
		||||
 | 
				    app_name: string; | 
			
		||||
 | 
				    app_icon: string; | 
			
		||||
 | 
				    web_url: string; | 
			
		||||
 | 
				    splash_url: string; | 
			
		||||
 | 
				    conf: string; | 
			
		||||
 | 
				    jks_url: string; | 
			
		||||
 | 
				    app_url: string; | 
			
		||||
 | 
				    splash_color: string; | 
			
		||||
 | 
				    key_alias: string; | 
			
		||||
 | 
				    store_pwd: string; | 
			
		||||
 | 
				    key_pwd: string; | 
			
		||||
 | 
				    created_by: number; | 
			
		||||
 | 
				    created_at: string; | 
			
		||||
 | 
				    updated_at: string; | 
			
		||||
 | 
				    updated_by: number; | 
			
		||||
 | 
				    status: number; | 
			
		||||
 | 
				    message: string; | 
			
		||||
 | 
				    x_86: number; | 
			
		||||
 | 
				    uid: number; | 
			
		||||
 | 
				  } | 
			
		||||
 | 
				} | 
			
		||||
						Write
						Preview
					
					
					Loading…
					
					Cancel
						Save
					
		Reference in new issue