import request from '@/config/axios' export interface RecipeConfigVO { id: number recipeCode: string recipeName?: string name?: string recipeType?: string | number recipeTypeId?: string | number productId?: number productName?: string machineName?: string machineId?: number deviceId?: number deviceName?: string recipeDesc?: string remark?: string isEnable?: string | number dataUnit?: string createTime?: string } export interface RecipePointDetailVO { id: number recipeId: string | number attributeId?: number pointName?: string pointType?: string dataType?: string dataUnit?: string attributeName?: string attributeType?: string } export interface RecipePointCandidateVO { id: number pointName: string pointType: string dataType: string dataUnit: string } type PageResult = { list: T[]; total: number } const STORAGE_KEYS = { pointCandidates: 'mock:recipeConfig:pointCandidates', recipePointRelation: 'mock:recipeConfig:recipePointRelation' } as const const safeParseJson = (value: string | null): T | undefined => { if (!value) return undefined try { return JSON.parse(value) as T } catch { return undefined } } const loadFromStorage = (key: string, fallback: T): T => { const parsed = safeParseJson(window.localStorage.getItem(key)) return parsed ?? fallback } const saveToStorage = (key: string, value: any) => { window.localStorage.setItem(key, JSON.stringify(value)) } const buildMockPointCandidates = (): RecipePointCandidateVO[] => { const pointTypes = ['模拟量', '开关量', '计算量'] const dataTypes = ['int', 'float', 'string', 'bool'] const units = ['kg', 'm³', '℃', 'A', 'V', ''] return Array.from({ length: 60 }).map((_, idx) => { const no = String(idx + 1).padStart(3, '0') return { id: idx + 1, pointName: `点位-${no}`, pointType: pointTypes[idx % pointTypes.length], dataType: dataTypes[idx % dataTypes.length], dataUnit: units[idx % units.length] } }) } const ensureMockSeeded = () => { const pointCandidates = loadFromStorage(STORAGE_KEYS.pointCandidates, []) if (!pointCandidates.length) saveToStorage(STORAGE_KEYS.pointCandidates, buildMockPointCandidates()) const relation = loadFromStorage>(STORAGE_KEYS.recipePointRelation, {}) if (!Object.keys(relation).length) saveToStorage(STORAGE_KEYS.recipePointRelation, {}) } const sleep = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms)) const paginate = (items: T[], pageNo: number, pageSize: number): PageResult => { const safePageNo = Math.max(1, Number(pageNo) || 1) const safePageSize = Math.max(1, Number(pageSize) || 10) const start = (safePageNo - 1) * safePageSize return { total: items.length, list: items.slice(start, start + safePageSize) } } const contains = (value: string | undefined, keyword: string | undefined) => { const v = (value ?? '').toLowerCase() const k = (keyword ?? '').trim().toLowerCase() if (!k) return true return v.includes(k) } export const RecipeConfigApi = { getRecipeConfigPage: async (params: any) => { const finalParams = { ...(params ?? {}), name: params?.name ?? params?.recipeName } return await request.get({ url: `/iot/recipe/page`, params: finalParams }) }, createRecipeConfig: async (data: Partial) => { const finalData = { id: data.id, name: data.name ?? data.recipeName, recipeCode: data.recipeCode, recipeTypeId: (data as any).recipeTypeId ?? data.recipeType, productId: data.productId, machineId: (data as any).machineId ?? data.deviceId, recipeDesc: data.recipeDesc ?? data.remark, isEnable: data.isEnable, dataUnit: data.dataUnit } return await request.post({ url: `/iot/recipe/create`, data: finalData }) }, updateRecipeConfig: async (data: Partial) => { const finalData = { id: data.id, name: data.name ?? data.recipeName, recipeCode: data.recipeCode, recipeTypeId: (data as any).recipeTypeId ?? data.recipeType, productId: data.productId, machineId: (data as any).machineId ?? data.deviceId, 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) => { return await request.delete({ url: `/iot/recipe/delete?id=` + id }) }, exportRecipeConfig: async (params: any) => { const finalParams = { ...(params ?? {}), name: params?.name ?? params?.recipeName } return await request.download({ url: `/iot/recipe/export-excel`, params: finalParams }) }, getPointCandidatePage: async (params: any): Promise> => { ensureMockSeeded() await sleep(80) const keyword = params?.keyword const pageNo = params?.pageNo const pageSize = params?.pageSize const list = loadFromStorage( STORAGE_KEYS.pointCandidates, buildMockPointCandidates() ) const filtered = keyword ? list.filter((item) => contains(item.pointName, keyword)) : list return paginate(filtered, pageNo, pageSize) }, getRecipePointDetailPage: async (params: any) => { return await request.get({ url: `/iot/recipe-device-attribute/page`, params }) }, updateRecipeDeviceAttribute: async (data: { recipeId: string | number; ids: number[] }) => { return await request.put({ url: `/iot/recipe-device-attribute/update`, data }) }, saveRecipePointConfig: async (data: { recipeId: string | number; attributeIds: number[] }) => { ensureMockSeeded() await sleep(120) const relation = loadFromStorage>(STORAGE_KEYS.recipePointRelation, {}) relation[String(data.recipeId)] = Array.from(new Set(data.attributeIds ?? [])).filter((v) => { return typeof v === 'number' && !Number.isNaN(v) }) saveToStorage(STORAGE_KEYS.recipePointRelation, relation) return true } }