diff --git a/src/api/iot/device/index.ts b/src/api/iot/device/index.ts index ca15f6fc..5afaad3b 100644 --- a/src/api/iot/device/index.ts +++ b/src/api/iot/device/index.ts @@ -65,6 +65,15 @@ export interface HistoryRecordParams { collectionEndTime?: string } +export interface DeviceContactModelVO { + id: number + attributeCode?: string + attributeName?: string + attributeType?: string + dataType?: string + dataUnit?: string +} + // 物联设备 API export const DeviceApi = { // 查询物联设备分页 @@ -127,6 +136,10 @@ export const DeviceApi = { getDeviceAttributePage: async (params) => { return await request.get({ url: `/iot/device/device-attribute/page`, params }) }, + + getDeviceContactModelPage: async () => { + return await request.get({ url: `/iot/device-contact-model/page` }) + }, // 新增设备属性 createDeviceAttribute: async (data) => { return await request.post({ url: `/iot/device-contact-model/create`, data }) diff --git a/src/api/iot/recipeConfig/index.ts b/src/api/iot/recipeConfig/index.ts index 92189422..90e6a386 100644 --- a/src/api/iot/recipeConfig/index.ts +++ b/src/api/iot/recipeConfig/index.ts @@ -1,23 +1,33 @@ +import request from '@/config/axios' + export interface RecipeConfigVO { id: number recipeCode: string - recipeName: string - recipeType?: string + recipeName?: string + name?: string + recipeType?: string | number productId?: number productName?: string + machineName?: string deviceId?: number deviceName?: string + recipeDesc?: string remark?: string + isEnable?: string | number + dataUnit?: string + createTime?: string } export interface RecipePointDetailVO { id: number - recipeId: number + recipeId: string | number attributeId?: number - pointName: string - pointType: string - dataType: string - dataUnit: string + pointName?: string + pointType?: string + dataType?: string + dataUnit?: string + attributeName?: string + attributeType?: string } export interface RecipePointCandidateVO { @@ -31,7 +41,6 @@ export interface RecipePointCandidateVO { type PageResult = { list: T[]; total: number } const STORAGE_KEYS = { - recipeList: 'mock:recipeConfig:recipes', pointCandidates: 'mock:recipeConfig:pointCandidates', recipePointRelation: 'mock:recipeConfig:recipePointRelation' } as const @@ -54,23 +63,6 @@ const saveToStorage = (key: string, value: any) => { window.localStorage.setItem(key, JSON.stringify(value)) } -const buildMockRecipes = (): RecipeConfigVO[] => { - return Array.from({ length: 18 }).map((_, idx) => { - const no = String(idx + 1).padStart(3, '0') - return { - id: idx + 1, - recipeCode: `RCP-${no}`, - recipeName: `配方-${no}`, - recipeType: idx % 2 === 0 ? '标准' : '自定义', - productId: undefined, - productName: idx % 3 === 0 ? '产品A' : idx % 3 === 1 ? '产品B' : '产品C', - deviceId: undefined, - deviceName: idx % 2 === 0 ? '设备1' : '设备2', - remark: idx % 4 === 0 ? '示例数据' : '' - } - }) -} - const buildMockPointCandidates = (): RecipePointCandidateVO[] => { const pointTypes = ['模拟量', '开关量', '计算量'] const dataTypes = ['int', 'float', 'string', 'bool'] @@ -88,9 +80,6 @@ const buildMockPointCandidates = (): RecipePointCandidateVO[] => { } const ensureMockSeeded = () => { - const recipeList = loadFromStorage(STORAGE_KEYS.recipeList, []) - if (!recipeList.length) saveToStorage(STORAGE_KEYS.recipeList, buildMockRecipes()) - const pointCandidates = loadFromStorage(STORAGE_KEYS.pointCandidates, []) if (!pointCandidates.length) saveToStorage(STORAGE_KEYS.pointCandidates, buildMockPointCandidates()) @@ -119,103 +108,53 @@ const contains = (value: string | undefined, keyword: string | undefined) => { export const RecipeConfigApi = { getRecipeConfigPage: async (params: any) => { - ensureMockSeeded() - await sleep(120) - const recipeCode = params?.recipeCode - const recipeName = params?.recipeName - const productName = params?.productName - const pageNo = params?.pageNo - const pageSize = params?.pageSize - const list = loadFromStorage(STORAGE_KEYS.recipeList, buildMockRecipes()) - const filtered = list.filter((item) => { - return ( - contains(item.recipeCode, recipeCode) && - contains(item.recipeName, recipeName) && - contains(item.productName, productName) - ) - }) - return paginate(filtered, pageNo, pageSize) + const finalParams = { + ...(params ?? {}), + name: params?.name ?? params?.recipeName + } + return await request.get({ url: `/iot/recipe/page`, params: finalParams }) }, createRecipeConfig: async (data: Partial) => { - ensureMockSeeded() - await sleep(120) - const list = loadFromStorage(STORAGE_KEYS.recipeList, buildMockRecipes()) - const maxId = list.reduce((acc, cur) => Math.max(acc, cur.id), 0) - const nextId = maxId + 1 - const newItem: RecipeConfigVO = { - id: nextId, - recipeCode: data.recipeCode ?? '', - recipeName: data.recipeName ?? '', + const finalData = { + id: data.id, + name: data.name ?? data.recipeName, + recipeCode: data.recipeCode, recipeType: data.recipeType, - productId: data.productId, productName: data.productName, - deviceId: data.deviceId, - deviceName: data.deviceName, - remark: data.remark + machineName: data.machineName ?? data.deviceName, + recipeDesc: data.recipeDesc ?? data.remark, + isEnable: data.isEnable, + dataUnit: data.dataUnit } - saveToStorage(STORAGE_KEYS.recipeList, [newItem, ...list]) - return nextId + return await request.post({ url: `/iot/recipe/create`, data: finalData }) }, updateRecipeConfig: async (data: Partial) => { - ensureMockSeeded() - await sleep(120) - if (!data.id) return true - const list = loadFromStorage(STORAGE_KEYS.recipeList, buildMockRecipes()) - const next = list.map((item) => { - if (item.id !== data.id) return item - return { - ...item, - recipeCode: data.recipeCode ?? item.recipeCode, - recipeName: data.recipeName ?? item.recipeName, - recipeType: data.recipeType ?? item.recipeType, - productId: data.productId ?? item.productId, - productName: data.productName ?? item.productName, - deviceId: data.deviceId ?? item.deviceId, - deviceName: data.deviceName ?? item.deviceName, - remark: data.remark ?? item.remark - } - }) - saveToStorage(STORAGE_KEYS.recipeList, next) - return true + const finalData = { + id: data.id, + name: data.name ?? data.recipeName, + recipeCode: data.recipeCode, + recipeType: data.recipeType, + productName: data.productName, + machineName: data.machineName ?? data.deviceName, + recipeDesc: data.recipeDesc ?? data.remark, + isEnable: data.isEnable, + dataUnit: data.dataUnit + } + return await request.put({ url: `/iot/recipe/update`, data: finalData }) }, deleteRecipeConfig: async (id: number) => { - ensureMockSeeded() - await sleep(120) - const list = loadFromStorage(STORAGE_KEYS.recipeList, buildMockRecipes()) - saveToStorage( - STORAGE_KEYS.recipeList, - list.filter((item) => item.id !== id) - ) - - const relation = loadFromStorage>(STORAGE_KEYS.recipePointRelation, {}) - delete relation[String(id)] - saveToStorage(STORAGE_KEYS.recipePointRelation, relation) - return true + return await request.delete({ url: `/iot/recipe/delete?id=` + id }) }, exportRecipeConfig: async (params: any) => { - ensureMockSeeded() - await sleep(120) - const ids = String(params?.ids ?? '') - .split(',') - .map((v) => Number(v)) - .filter((v) => !Number.isNaN(v)) - const list = loadFromStorage(STORAGE_KEYS.recipeList, buildMockRecipes()) - const exportList = ids.length ? list.filter((item) => ids.includes(item.id)) : list - const header = ['配方编码', '配方名称', '配方类型', '关联产品', '关联设备', '备注'] - const rows = exportList.map((item) => [ - item.recipeCode, - item.recipeName, - item.recipeType ?? '', - item.productName ?? '', - item.deviceName ?? '', - item.remark ?? '' - ]) - const csv = [header, ...rows].map((r) => r.map((v) => `"${String(v).replace(/"/g, '""')}"`).join(',')).join('\n') - return new Blob([csv], { type: 'text/csv;charset=utf-8' }) + const finalParams = { + ...(params ?? {}), + name: params?.name ?? params?.recipeName + } + return await request.download({ url: `/iot/recipe/export-excel`, params: finalParams }) }, getPointCandidatePage: async (params: any): Promise> => { @@ -235,39 +174,10 @@ export const RecipeConfigApi = { }, getRecipePointDetailPage: async (params: any) => { - ensureMockSeeded() - await sleep(120) - const recipeId = Number(params?.recipeId) - const pageNo = params?.pageNo - const pageSize = params?.pageSize - if (!recipeId) return { list: [], total: 0 } - - const relation = loadFromStorage>(STORAGE_KEYS.recipePointRelation, {}) - const selectedIds = relation[String(recipeId)] ?? [] - const candidates = loadFromStorage( - STORAGE_KEYS.pointCandidates, - buildMockPointCandidates() - ) - const map = candidates.reduce((acc, cur) => { - acc[cur.id] = cur - return acc - }, {} as Record) - const detailAll: RecipePointDetailVO[] = selectedIds - .map((id) => map[id]) - .filter(Boolean) - .map((item) => ({ - id: item.id, - recipeId, - attributeId: item.id, - pointName: item.pointName, - pointType: item.pointType, - dataType: item.dataType, - dataUnit: item.dataUnit - })) - return paginate(detailAll, pageNo, pageSize) + return await request.get({ url: `/iot/recipe-device-attribute/page`, params }) }, - saveRecipePointConfig: async (data: { recipeId: number; attributeIds: number[] }) => { + saveRecipePointConfig: async (data: { recipeId: string | number; attributeIds: number[] }) => { ensureMockSeeded() await sleep(120) const relation = loadFromStorage>(STORAGE_KEYS.recipePointRelation, {}) diff --git a/src/api/iot/recipePoint/index.ts b/src/api/iot/recipePoint/index.ts new file mode 100644 index 00000000..2185218a --- /dev/null +++ b/src/api/iot/recipePoint/index.ts @@ -0,0 +1,31 @@ +import request from '@/config/axios' + +export interface RecipePointVO { + id: number + recipeId: string | number + name?: string + max?: string | number + min?: string | number + dataType?: string + dataUnit?: string + remark?: string + createTime?: string +} + +export const RecipePointApi = { + getRecipePointPage: async (params: any) => { + return await request.get({ url: `/iot/recipe-point/page`, params }) + }, + + createRecipePoint: async (params: Partial) => { + return await request.post({ url: `/iot/recipe-point/create`, data: params }) + }, + + updateRecipePoint: async (params: Partial) => { + return await request.put({ url: `/iot/recipe-point/update`, data: params }) + }, + + deleteRecipePoint: async (id: number) => { + return await request.delete({ url: `/iot/recipe-point/delete`, params: { id } }) + } +} diff --git a/src/api/mes/deviceledger/index.ts b/src/api/mes/deviceledger/index.ts new file mode 100644 index 00000000..f62231ae --- /dev/null +++ b/src/api/mes/deviceledger/index.ts @@ -0,0 +1,62 @@ +import request from '@/config/axios' + +// 设备类型 VO +export interface DeviceLedgerVO { + id: number // id + deviceCode: string // 设备编号 + deviceName: string // 设备名称 + deviceStatus: number // 设备状态 (0-正常, 1-停用, 2-维修, 3-报废) + deviceBrand: string // 设备品牌 + deviceModel: string // 设备型号 + deviceSpec: string // 设备规格 + deviceType: string | number // 设备类型 + deviceTypeName?: string // 设备类型名称 + supplier: string // 供应商 + workshop: string // 所属车间 + systemOrg: string // 所属系统组织 + deviceLocation: string // 设备位置 + useDept?: string // 使用部门 + deviceManager: string // 设备负责人 + quantity?: number // 数量 + productionDate: Date // 设备生产日期 + factoryEntryDate: Date // 设备入厂日期 + deviceRemark: string // 设备备注 + remark: string // 备注 + creator?: string // 创建人 + createTime?: string | number | Date + updateTime?: string | number | Date + sort: number // 排序 +} + +// 设备类型 API +export const DeviceLedgerApi = { + // 查询设备类型分页 + getDeviceLedgerPage: async (params: any) => { + return await request.get({ url: `/mes/device-ledger/page`, params }) + }, + + // 查询设备类型详情 + getDeviceLedger: async (id: number) => { + return await request.get({ url: `/mes/device-ledger/get?id=` + id }) + }, + + // 新增设备类型 + createDeviceLedger: async (data: DeviceLedgerVO) => { + return await request.post({ url: `/mes/device-ledger/create`, data }) + }, + + // 修改设备类型 + updateDeviceLedger: async (data: DeviceLedgerVO) => { + return await request.put({ url: `/mes/device-ledger/update`, data }) + }, + + // 删除设备类型 + deleteDeviceLedger: async (id: number) => { + return await request.delete({ url: `/mes/device-ledger/delete?id=` + id }) + }, + + // 导出设备类型 Excel + exportDeviceLedger: async (params) => { + return await request.download({ url: `/mes/device-ledger/export-excel`, params }) + } +} diff --git a/src/api/mes/devicetype/index.ts b/src/api/mes/devicetype/index.ts new file mode 100644 index 00000000..0fe53b72 --- /dev/null +++ b/src/api/mes/devicetype/index.ts @@ -0,0 +1,58 @@ +import request from '@/config/axios' + +// 设备类型 VO +export interface DeviceTypeVO { + id: number // id + code: string // 编码 + name: string // 名称 + remark: string // 备注 + sort: number // 排序 + parentId?: number + parentChain?: string + createTime?: string +} + +export interface DeviceTypeTreeVO extends DeviceTypeVO { + parentId?: number + parentChain?: string + createTime?: string + children?: DeviceTypeTreeVO[] + leaf?: boolean +} + +// 设备类型 API +export const DeviceTypeApi = { + // 查询设备类型分页 + getDeviceTypePage: async (params: any) => { + return await request.get({ url: `/mes/device-type/page`, params }) + }, + + getDeviceTypeTree: async (params: any) => { + return await request.get({ url: `/mes/device-type/tree`, params }) + }, + + // 查询设备类型详情 + getDeviceType: async (id: number) => { + return await request.get({ url: `/mes/device-type/get?id=` + id }) + }, + + // 新增设备类型 + createDeviceType: async (data: DeviceTypeVO) => { + return await request.post({ url: `/mes/device-type/create`, data }) + }, + + // 修改设备类型 + updateDeviceType: async (data: DeviceTypeVO) => { + return await request.put({ url: `/mes/device-type/update`, data }) + }, + + // 删除设备类型 + deleteDeviceType: async (id: number) => { + return await request.delete({ url: `/mes/device-type/delete?id=` + id }) + }, + + // 导出设备类型 Excel + exportDeviceType: async (params) => { + return await request.download({ url: `/mes/device-type/export-excel`, params }) + } +} diff --git a/src/components/DiyEditor/components/ComponentContainer.vue b/src/components/DiyEditor/components/ComponentContainer.vue index 48567224..6f2d87c3 100644 --- a/src/components/DiyEditor/components/ComponentContainer.vue +++ b/src/components/DiyEditor/components/ComponentContainer.vue @@ -165,8 +165,8 @@ $toolbar-position: -55px; width: 80px; height: 25px; font-size: 12px; - color: #6a6a6a; line-height: 25px; + color: #6a6a6a; text-align: center; background: #fff; box-shadow: diff --git a/src/components/DiyEditor/components/ComponentLibrary.vue b/src/components/DiyEditor/components/ComponentLibrary.vue index fdb0b1de..fd457e0c 100644 --- a/src/components/DiyEditor/components/ComponentLibrary.vue +++ b/src/components/DiyEditor/components/ComponentLibrary.vue @@ -94,9 +94,9 @@ const handleCloneComponent = (component: DiyComponent) => { diff --git a/src/components/DiyEditor/components/mobile/HotZone/property.vue b/src/components/DiyEditor/components/mobile/HotZone/property.vue index 495cbdce..4f6c3b64 100644 --- a/src/components/DiyEditor/components/mobile/HotZone/property.vue +++ b/src/components/DiyEditor/components/mobile/HotZone/property.vue @@ -42,22 +42,22 @@ const handleOpenEditDialog = () => { diff --git a/src/components/DiyEditor/components/mobile/MenuSwiper/index.vue b/src/components/DiyEditor/components/mobile/MenuSwiper/index.vue index f8e2bbc6..c2319daf 100644 --- a/src/components/DiyEditor/components/mobile/MenuSwiper/index.vue +++ b/src/components/DiyEditor/components/mobile/MenuSwiper/index.vue @@ -103,13 +103,16 @@ watch( .el-carousel__indicator { padding-top: 0; padding-bottom: 0; + .el-carousel__button { --el-carousel-indicator-height: 6px; --el-carousel-indicator-width: 6px; --el-carousel-indicator-out-color: #ff6000; + border-radius: 6px; } } + .el-carousel__indicator.is-active { .el-carousel__button { --el-carousel-indicator-width: 12px; diff --git a/src/components/DiyEditor/components/mobile/NavigationBar/index.vue b/src/components/DiyEditor/components/mobile/NavigationBar/index.vue index c684aee7..ab179cd7 100644 --- a/src/components/DiyEditor/components/mobile/NavigationBar/index.vue +++ b/src/components/DiyEditor/components/mobile/NavigationBar/index.vue @@ -64,10 +64,10 @@ const getSearchProp = (cell: NavigationBarCellProperty) => { .navigation-bar { display: flex; height: 50px; + padding: 0 6px; background: #fff; justify-content: space-between; align-items: center; - padding: 0 6px; /* 左边 */ .left { diff --git a/src/components/DiyEditor/index.vue b/src/components/DiyEditor/index.vue index 700d32bd..355ff156 100644 --- a/src/components/DiyEditor/index.vue +++ b/src/components/DiyEditor/index.vue @@ -545,11 +545,12 @@ $toolbar-height: 42px; gap: 8px; :deep(.el-tag) { - box-shadow: 0 2px 8px 0 rgba(0, 0, 0, 0.1); border: none; + box-shadow: 0 2px 8px 0 rgb(0 0 0 / 10%); + .el-tag__content { - width: 100%; display: flex; + width: 100%; align-items: center; justify-content: flex-start; diff --git a/src/components/InputWithColor/index.vue b/src/components/InputWithColor/index.vue index 2bc53172..e494bcb3 100644 --- a/src/components/InputWithColor/index.vue +++ b/src/components/InputWithColor/index.vue @@ -50,6 +50,7 @@ watch( diff --git a/src/layout/components/UserInfo/src/components/LockDialog.vue b/src/layout/components/UserInfo/src/components/LockDialog.vue index 7257be16..c719c2a9 100644 --- a/src/layout/components/UserInfo/src/components/LockDialog.vue +++ b/src/layout/components/UserInfo/src/components/LockDialog.vue @@ -91,7 +91,7 @@ const handleLock = async () => { + diff --git a/src/views/iot/historyData/HistorySingleDeviceDialog.vue b/src/views/iot/historyData/HistorySingleDeviceDialog.vue index d2d668e3..7e0e7e3e 100644 --- a/src/views/iot/historyData/HistorySingleDeviceDialog.vue +++ b/src/views/iot/historyData/HistorySingleDeviceDialog.vue @@ -3,7 +3,8 @@
- @@ -19,15 +20,18 @@ 采集时间:{{ group.collectTime || '-' }}
-
{{ section.title }}
- -