Browse Source

feat: 产品管理页面

main
刘凯 1 year ago
parent
commit
4e344054f9
  1. 8
      src/api/common/index.ts
  2. 17
      src/api/common/types.ts
  3. 41
      src/api/product/index.ts
  4. 45
      src/api/product/types.ts
  5. 6
      src/router/guard/permissionGuard.ts
  6. 57
      src/store/modules/systemEnum.ts
  7. 55
      src/views/product/ProductFormModal.vue
  8. 182
      src/views/product/data.ts
  9. 85
      src/views/product/index.vue

8
src/api/common/index.ts

@ -0,0 +1,8 @@
import type { SystemEnum } from './types'
import { defHttp } from '@/utils/http/axios'
export function getSystemEnumAll() {
return defHttp.get<SystemEnum>({
url: '/system/enum/getAllEnum',
})
}

17
src/api/common/types.ts

@ -0,0 +1,17 @@
interface SystemEnumValue {
val: number
desc: string
}
export type SystemEnumKeys =
| 'eProductSecurityType'
| 'eProductTopicCategory'
| 'eDataType'
| 'eProductTopicType'
| 'eNetworkProtocol'
| 'eNetworkType'
| 'eProductNodeType'
| 'eRoleAlias'
| 'eAuthType'
export type SystemEnum = Record<SystemEnumKeys, SystemEnumValue[]>

41
src/api/product/index.ts

@ -0,0 +1,41 @@
import type { GetProductListParmas, Product } from './types'
import { defHttp } from '@/utils/http/axios'
export function getProductList(params: GetProductListParmas) {
return defHttp.get<PageResult<Product>>({
url: '/product/page',
params,
})
}
export function getProductDetail(id: string) {
return defHttp.get<Product>({
url: `/product/detail?id=${id}`,
})
}
export function createProduct(data: Partial<Product>) {
return defHttp.post({
url: '/product/save',
data,
})
}
export function updateProduct(data: Partial<Product>) {
return defHttp.post({
url: '/product/update',
data,
})
}
export function deleteProduct(id: string) {
return defHttp.post({
url: `/product/remove?id=${id}`,
})
}
export function getAllProducts() {
return defHttp.get({
url: '/product/select',
})
}

45
src/api/product/types.ts

@ -0,0 +1,45 @@
export interface GetProductListParmas extends PageParam {
productName?: string
networkType?: number
networkProtocol?: number
nodeType?: number
securityType?: number
dataType?: number
}
export interface Product {
id: string
tenantId: string
uuid: string
productName: string
productDesc: string
productKey: string
productSecret: string
nodeType: number
networkType: number
networkProtocol: number
authType: number
securityType: number
dataType: number
tsl: string
isRelease: number
}
export enum TopicType {
System = 1,
Custom = 2,
}
export interface GetTopicListPrams {
productId?: string
topicCategory?: TopicType
}
export interface Topic {
id: string
topic: string
topicType: number
enableScript: BooleanFlag
topicDesc: string
productId: string
}

6
src/router/guard/permissionGuard.ts

@ -6,6 +6,7 @@ import { PageEnum } from '@/enums/pageEnum'
import { useUserStoreWithOut } from '@/store/modules/user'
import { PAGE_NOT_FOUND_ROUTE } from '@/router/routes/basic'
import { useSystemEnumStoreWithOut } from '@/store/modules/systemEnum'
// import { RootRoute } from '@/router/routes'
@ -18,6 +19,8 @@ const whitePathList: PageEnum[] = [LOGIN_PATH]
export function createPermissionGuard(router: Router) {
const userStore = useUserStoreWithOut()
const permissionStore = usePermissionStoreWithOut()
const systemEnumStore = useSystemEnumStoreWithOut()
router.beforeEach(async (to, from, next) => {
// if (
// from.path === ROOT_PATH &&
@ -77,6 +80,9 @@ export function createPermissionGuard(router: Router) {
return
}
if (!systemEnumStore.initialized)
systemEnumStore.initialize()
// get userinfo while last fetch time is empty
if (userStore.getLastUpdateTime === 0) {
try {

57
src/store/modules/systemEnum.ts

@ -0,0 +1,57 @@
import { defineStore } from 'pinia'
import { ref, shallowRef } from 'vue'
import { store } from '@/store'
import { noop } from '@/utils'
import { getSystemEnumAll } from '@/api/common'
import type { SystemEnum, SystemEnumKeys } from '@/api/common/types'
export const useSystemEnumStore = defineStore('systemEnum', () => {
const systemEnumAll = shallowRef<SystemEnum>()
function setSystemEnumAll() {
getSystemEnumAll()
.then((res) => {
systemEnumAll.value = res
})
.catch(noop)
}
function getSystemEnumLabel(enumType: SystemEnumKeys, value: number) {
if (!systemEnumAll.value)
return
const ret = systemEnumAll.value[enumType].find(item => item.val === value)
return ret && ret.desc
}
function getSystemEnums(enumType: SystemEnumKeys, options?: { labelField: string, valueField: string }) {
if (!systemEnumAll.value)
return []
const enums = systemEnumAll.value[enumType] || []
const { labelField, valueField } = options || { labelField: 'label', valueField: 'value' }
return enums.map((item) => {
return {
[labelField]: item.desc,
[valueField]: item.val,
}
})
}
const initialized = ref(false)
function initialize() {
initialized.value = true
setSystemEnumAll()
}
return {
initialized,
initialize,
getSystemEnumLabel,
getSystemEnums,
}
})
export function useSystemEnumStoreWithOut() {
return useSystemEnumStore(store)
}

55
src/views/product/ProductFormModal.vue

@ -0,0 +1,55 @@
<script lang="ts" setup>
import { ref } from 'vue'
import { getFormSchema } from './data'
import { useMessage } from '@/hooks/web/useMessage'
import { BasicForm, useForm } from '@/components/Form'
import { BasicModal, useModalInner } from '@/components/Modal'
import { createProduct, updateProduct } from '@/api/product'
import type { Product } from '@/api/product/types'
defineOptions({ name: 'ProductFormModal' })
const emit = defineEmits(['success', 'register'])
const isUpdate = ref(false)
const [registerForm, { setFieldsValue, validate }] = useForm({
labelWidth: 100,
baseColProps: { span: 24 },
schemas: getFormSchema(isUpdate),
showActionButtonGroup: false,
actionColOptions: { span: 23 },
})
const [registerModal, { setModalProps, closeModal }] = useModalInner(async (data: Product) => {
isUpdate.value = true
setFieldsValue({ ...data })
})
async function handleSubmit() {
try {
const values = await validate<Product>()
setModalProps({ confirmLoading: true })
await (isUpdate.value ? updateProduct(values) : createProduct(values))
closeModal()
emit('success')
useMessage().createMessage.success('保存成功')
}
finally {
setModalProps({ confirmLoading: false })
}
}
</script>
<template>
<BasicModal
v-bind="$attrs"
width="30%"
:min-height="100"
:title="isUpdate ? '编辑' : '新增'"
:after-close="() => isUpdate = false"
@register="registerModal"
@ok="handleSubmit"
>
<BasicForm @register="registerForm" />
</BasicModal>
</template>

182
src/views/product/data.ts

@ -0,0 +1,182 @@
import type { Ref } from 'vue'
import type { BasicColumn, FormSchema } from '@/components/Table'
import { useSystemEnumStoreWithOut } from '@/store/modules/systemEnum'
const { getSystemEnumLabel, getSystemEnums } = useSystemEnumStoreWithOut()
export const columns: BasicColumn[] = [
{
title: '产品名称',
dataIndex: 'productName',
},
{
title: '产品标识',
dataIndex: 'productKey',
},
{
title: '节点类型',
dataIndex: 'nodeType',
customRender: ({ value }) => getSystemEnumLabel('eProductNodeType', value),
},
{
title: '联网方式',
dataIndex: 'networkType',
customRender: ({ value }) => getSystemEnumLabel('eNetworkType', value),
},
{
title: '鉴权方式',
dataIndex: 'authType',
customRender: ({ value }) => getSystemEnumLabel('eAuthType', value),
},
{
title: '安全类型',
dataIndex: 'securityType',
customRender: ({ value }) => getSystemEnumLabel('eProductSecurityType', value),
},
{
title: '通信协议',
dataIndex: 'networkProtocol',
customRender: ({ value }) => getSystemEnumLabel('eNetworkProtocol', value),
},
{
title: '数据格式',
dataIndex: 'dataType',
customRender: ({ value }) => getSystemEnumLabel('eDataType', value),
},
{
title: '创建时间',
dataIndex: 'createTime',
width: 200,
},
]
export const searchFormSchemas: FormSchema[] = [
{
label: '产品名称',
field: 'productName',
component: 'Input',
colProps: { span: 6 },
},
{
label: '联网方式',
field: 'networkType',
component: 'Select',
componentProps: {
options: getSystemEnums('eNetworkType'),
},
colProps: { span: 6 },
},
{
label: '通信协议',
field: 'networkProtocol',
component: 'Select',
componentProps: {
options: getSystemEnums('eNetworkProtocol'),
},
colProps: { span: 6 },
},
{
label: '节点类型',
field: 'nodeType',
component: 'Select',
componentProps: {
options: getSystemEnums('eProductNodeType'),
},
colProps: { span: 6 },
},
{
label: '安全类型',
field: 'securityType',
component: 'Select',
componentProps: {
options: getSystemEnums('eProductSecurityType'),
},
colProps: { span: 6 },
},
{
label: '数据格式',
field: 'dataType',
component: 'Select',
componentProps: {
options: getSystemEnums('eDataType'),
},
colProps: { span: 6 },
},
]
export function getFormSchema(isUpdate: Ref<boolean>): FormSchema[] {
return [
{
field: 'id',
show: false,
component: 'Input',
},
{
label: '产品名称',
field: 'productName',
required: true,
component: 'Input',
},
{
label: '联网方式',
field: 'networkType',
component: 'Select',
componentProps: {
options: getSystemEnums('eNetworkType'),
},
},
{
label: '通信协议',
field: 'networkProtocol',
component: 'Select',
componentProps: {
options: getSystemEnums('eNetworkProtocol'),
},
ifShow: () => !isUpdate.value,
},
{
label: '节点类型',
field: 'nodeType',
required: true,
component: 'Select',
componentProps: {
options: getSystemEnums('eProductNodeType'),
},
ifShow: () => !isUpdate.value,
},
{
label: '安全类型',
field: 'securityType',
component: 'Select',
componentProps: {
options: getSystemEnums('eProductSecurityType'),
},
ifShow: () => !isUpdate.value,
},
{
label: '鉴权方式',
field: 'authType',
required: true,
component: 'Select',
componentProps: {
options: getSystemEnums('eAuthType'),
},
ifShow: () => !isUpdate.value,
},
{
label: '数据格式',
field: 'dataType',
required: true,
component: 'Select',
componentProps: {
options: getSystemEnums('eDataType'),
},
ifShow: () => !isUpdate.value,
},
{
label: '产品描述',
field: 'productDesc',
component: 'InputTextArea',
},
]
}

85
src/views/product/index.vue

@ -0,0 +1,85 @@
<script setup lang="ts">
import { PlusOutlined } from '@ant-design/icons-vue'
import { columns, searchFormSchemas } from './data'
import ProductFormModal from './ProductFormModal.vue'
import { BasicTable, TableAction, useTable } from '@/components/Table'
import { deleteProduct, getProductList } from '@/api/product'
import { useModal } from '@/components/Modal'
import type { Product } from '@/api/product/types'
import { useMessage } from '@/hooks/web/useMessage'
defineOptions({ name: 'Product' })
const [registerModal, { openModal }] = useModal<Product>()
const [register, { reload }] = useTable({
api: getProductList,
columns,
formConfig: {
schemas: searchFormSchemas,
labelWidth: 80,
},
bordered: true,
canResize: false,
useSearchForm: true,
actionColumn: {
width: 220,
title: '操作',
dataIndex: 'action',
fixed: 'right',
},
})
async function handleDelete(id: string) {
try {
await deleteProduct(id)
useMessage().createMessage.success('删除成功')
reload()
}
catch {}
}
</script>
<template>
<div>
<BasicTable :api="async () => ([] as Product[])" @register="register">
<template #tableTitle>
<a-button type="primary" @click="openModal">
<PlusOutlined />
新建
</a-button>
</template>
<template #bodyCell="{ column, record }">
<template v-if="column.key === 'action'">
<TableAction
:actions="[
{
icon: 'i-ant-design:file-search-outlined',
label: '详情',
onClick: () => $router.push(`/product/detail/${record.id}`),
},
{
icon: 'i-ant-design:edit-outlined',
label: '编辑',
onClick: () => openModal(true, record),
},
{
icon: 'i-ant-design:delete-outlined',
danger: true,
label: '删除',
popConfirm: {
title: '是否要删除数据?',
placement: 'left',
confirm: () => handleDelete(record.id),
},
},
]"
/>
</template>
</template>
</BasicTable>
<ProductFormModal @register="registerModal" @success="reload" />
</div>
</template>
Loading…
Cancel
Save