diff --git a/apps/web-antd/src/api/device/product/index.ts b/apps/web-antd/src/api/device/product/index.ts index 75515ab..4765ea8 100644 --- a/apps/web-antd/src/api/device/product/index.ts +++ b/apps/web-antd/src/api/device/product/index.ts @@ -52,6 +52,24 @@ export function productUpdate(data: ProductForm) { return requestClient.putWithMsg('/device/product', data); } +/** + * 更新设备产品(部分) + * @param data + * @returns void + */ +export function productUpdateById(id: ID, data: ProductForm) { + return requestClient.putWithMsg(`/device/product/${id}`, data); +} + +/** + * 更新设备产品状态 + * @param data + * @returns void + */ +export function productUpdateStatus(data: ProductForm) { + return requestClient.putWithMsg('/device/product/enable', data); +} + /** * 删除设备产品 * @param id id @@ -60,3 +78,15 @@ export function productUpdate(data: ProductForm) { export function productRemove(id: ID | IDS) { return requestClient.deleteWithMsg(`/device/product/${id}`); } + +/** + * 查询产品存储策略列表 + * @param params + * @returns 产品存储策略列表 + */ +export function getPoliciesList(params?: any) { + return requestClient.get>( + '/device/product/storage/policies', + { params }, + ); +} diff --git a/apps/web-antd/src/api/device/product/model.d.ts b/apps/web-antd/src/api/device/product/model.d.ts index 0cae991..e4a248b 100644 --- a/apps/web-antd/src/api/device/product/model.d.ts +++ b/apps/web-antd/src/api/device/product/model.d.ts @@ -65,6 +65,11 @@ export interface ProductVO { * 存储策略配置 */ storePolicyConf: string; + + /** + * 产品参数 + */ + productParam?: string; } export interface ProductForm extends BaseEntity { @@ -132,6 +137,11 @@ export interface ProductForm extends BaseEntity { * 存储策略配置 */ storePolicyConf?: string; + + /** + * 产品参数 + */ + productParam?: string; } export interface ProductQuery extends PageQuery { diff --git a/apps/web-antd/src/router/access.ts b/apps/web-antd/src/router/access.ts index aea6399..dab9a73 100644 --- a/apps/web-antd/src/router/access.ts +++ b/apps/web-antd/src/router/access.ts @@ -31,6 +31,12 @@ const routeMetaMapping: Record> = { activePath: '/system/role', requireHomeRedirect: true, }, + + '/device/product/detail/:id': { + activePath: '/device/product', + requireHomeRedirect: true, + }, + '/system/oss-config/index': { activePath: '/system/oss', requireHomeRedirect: true, diff --git a/apps/web-antd/src/store/index.ts b/apps/web-antd/src/store/index.ts index 7750334..f52e0db 100644 --- a/apps/web-antd/src/store/index.ts +++ b/apps/web-antd/src/store/index.ts @@ -1,2 +1,3 @@ export * from './auth'; export * from './notify'; +export * from './product'; diff --git a/apps/web-antd/src/store/product.ts b/apps/web-antd/src/store/product.ts new file mode 100644 index 0000000..aa2f409 --- /dev/null +++ b/apps/web-antd/src/store/product.ts @@ -0,0 +1,92 @@ +import type { ProductVO } from '#/api/device/product/model'; + +import { defineStore } from 'pinia'; + +import { productInfo } from '#/api/device/product'; + +export interface ProductDetailState { + current: Partial; + detail: Partial; + tabActiveKey: string; + deviceCount: number; +} + +export const useProductStore = defineStore('product', { + state: (): ProductDetailState => ({ + current: {}, + detail: {}, + tabActiveKey: 'BasicInfo', + deviceCount: 0, + }), + + getters: { + getCurrentProduct: (state) => state.current, + getDetailProduct: (state) => state.detail, + getTabActiveKey: (state) => state.tabActiveKey, + getDeviceCount: (state) => state.deviceCount, + }, + + actions: { + /** + * 设置当前产品信息 + */ + setCurrent(current: Partial) { + this.current = current; + this.detail = current; + }, + + /** + * 获取产品详情 + */ + async getDetail(id: number | string) { + try { + const resp = await productInfo(id); + if (resp) { + this.current = { + ...this.current, + ...resp, + }; + this.detail = resp; + } + } catch (error) { + console.error('获取产品详情失败:', error); + } + }, + + /** + * 刷新产品信息和设备数量 + */ + async refresh(id: number | string) { + await this.getDetail(id); + // TODO: 这里需要添加获取设备数量的 API 调用 + // const res = await getDeviceNumber({ productId: id }); + // if (res) { + // this.deviceCount = res; + // } + }, + + /** + * 设置选中的 tab + */ + setTabActiveKey(key: string) { + this.tabActiveKey = key; + }, + + /** + * 设置设备数量 + */ + setDeviceCount(count: number) { + this.deviceCount = count; + }, + + /** + * 重置状态 + */ + reset() { + this.current = {}; + this.detail = {}; + this.tabActiveKey = 'BasicInfo'; + this.deviceCount = 0; + }, + }, +}); diff --git a/apps/web-antd/src/views/device/product/data.ts b/apps/web-antd/src/views/device/product/data.ts index 271da7b..2794bcd 100644 --- a/apps/web-antd/src/views/device/product/data.ts +++ b/apps/web-antd/src/views/device/product/data.ts @@ -6,6 +6,11 @@ import { h } from 'vue'; import { deviceTypeOptions, enabledOptions } from '#/constants/dicts'; export const querySchema: FormSchemaGetter = () => [ + { + component: 'Input', + fieldName: 'productKey', + label: '产品编码', + }, { component: 'Input', fieldName: 'productName', @@ -53,9 +58,14 @@ export const columns: VxeGridProps['columns'] = [ title: '产品名称', field: 'productName', }, + { + title: '产品分类', + field: 'categoryName', + }, { title: '设备类型', field: 'deviceType', + slots: { default: 'deviceType' }, }, { title: '启用状态', diff --git a/apps/web-antd/src/views/device/product/detail/components/BasicInfo.vue b/apps/web-antd/src/views/device/product/detail/components/BasicInfo.vue new file mode 100644 index 0000000..c0d34c4 --- /dev/null +++ b/apps/web-antd/src/views/device/product/detail/components/BasicInfo.vue @@ -0,0 +1,269 @@ + + + + + diff --git a/apps/web-antd/src/views/device/product/detail/components/ProductParamDrawer.vue b/apps/web-antd/src/views/device/product/detail/components/ProductParamDrawer.vue new file mode 100644 index 0000000..a909769 --- /dev/null +++ b/apps/web-antd/src/views/device/product/detail/components/ProductParamDrawer.vue @@ -0,0 +1,297 @@ + + + + + diff --git a/apps/web-antd/src/views/device/product/detail/index.vue b/apps/web-antd/src/views/device/product/detail/index.vue new file mode 100644 index 0000000..54ec2e7 --- /dev/null +++ b/apps/web-antd/src/views/device/product/detail/index.vue @@ -0,0 +1,219 @@ + + + + + diff --git a/apps/web-antd/src/views/device/product/index.vue b/apps/web-antd/src/views/device/product/index.vue index ec3d1b5..0478286 100644 --- a/apps/web-antd/src/views/device/product/index.vue +++ b/apps/web-antd/src/views/device/product/index.vue @@ -4,6 +4,8 @@ import type { VbenFormProps } from '@vben/common-ui'; import type { VxeGridProps } from '#/adapter/vxe-table'; import type { ProductForm } from '#/api/device/product/model'; +import { useRouter } from 'vue-router'; + import { Page, useVbenDrawer } from '@vben/common-ui'; import { getVxePopupContainer } from '@vben/utils'; @@ -16,6 +18,8 @@ import { productRemove, } from '#/api/device/product'; import { productCategoryTreeList } from '#/api/device/productCategory'; +import { deviceTypeOptions } from '#/constants/dicts'; +import { useProductStore } from '#/store/product'; import { commonDownloadExcel } from '#/utils/file/download'; import { columns, querySchema } from './data'; @@ -40,6 +44,8 @@ const formOptions: VbenFormProps = { // ], // ], }; +const router = useRouter(); +const productStore = useProductStore(); const gridOptions: VxeGridProps = { checkboxConfig: { @@ -111,6 +117,11 @@ function handleAdd() { } async function handleView(row: Required) { + // 保存产品信息到 store + productStore.setCurrent(row); + // 设置默认选中的 tab + productStore.setTabActiveKey('BasicInfo'); + // 跳转到详情页 router.push(`/device/product/detail/${row.id}`); } @@ -179,6 +190,14 @@ function handleDownloadExcel() { +