From 185cd91d7c835085c5bf5ff1bd8ec948d859f076 Mon Sep 17 00:00:00 2001 From: houzhongjian <houzhongyi@126.com> Date: 星期五, 13 九月 2024 16:28:13 +0800 Subject: [PATCH] Merge remote-tracking branch 'origin/master' --- src/api/data/channel/http/index.ts | 43 src/views/data/ind/data/index.vue | 161 + src/utils/dateUtil.ts | 5 public/template/模型参数导入模板.xlsx | 0 src/views/model/pre/predict/index.vue | 173 + src/views/mpk/mpk.vue | 210 + src/api/model/sche/scheme/index.ts | 46 src/api/model/pre/dm/index.ts | 37 src/api/data/channel/kio/index.ts | 40 src/api/mpk/project.ts | 33 src/api/data/ind/data/data.set.ts | 40 src/views/mpk/MpkForm.vue | 278 ++ src/views/data/channel/opcda/OpcDaDeviceForm.vue | 138 + src/views/data/channel/opcda/index.vue | 152 + src/views/model/pre/predict/MmPredictItemForm.vue | 209 + src/views/model/pre/result/index.vue | 149 + src/views/model/mcs/sche/scheme/index.vue | 178 + src/api/model/pre/predict/index.ts | 50 src/api/data/ind/data/data.field.ts | 35 src/router/modules/remaining.ts | 46 src/views/model/pre/dm/DmModuleForm.vue | 136 + src/views/data/ind/data/field/DataSetFieldForm.vue | 124 + src/views/data/channel/opcua/OpcUaDeviceForm.vue | 167 + src/views/data/ind/category/CategoryForm.vue | 141 + src/views/data/channel/modbus/index.vue | 9 src/api/model/pre/item/index.ts | 37 src/views/data/channel/opcua/index.vue | 157 + src/api/data/channel/opcda/index.ts | 40 src/views/model/mcs/sche/model/index.vue | 172 + src/views/data/channel/modbus/ModBusDeviceForm.vue | 6 src/views/data/ind/category/index.vue | 159 + src/views/data/channel/http/index.vue | 156 + src/utils/dict.ts | 12 src/views/model/mcs/sche/scheme/ScheduleSchemeForm.vue | 215 + src/api/model/sche/model/index.ts | 66 src/views/mpk/MpkGenerator.vue | 49 src/api/mpk/mpkHistory.ts | 10 src/views/mpk/ProjectForm.vue | 153 + src/views/mpk/ProjectPackageModelDialog.vue | 119 + src/api/data/channel/opcua/index.ts | 44 src/views/mpk/MpkGeneratorHistory.vue | 109 src/views/model/mcs/sche/model/ScheduleModelForm.vue | 400 +++ src/views/mpk/ProjectPackage.vue | 96 src/api/data/ind/category/index.ts | 42 src/views/data/channel/kio/index.vue | 152 + src/views/mpk/MpkRun.vue | 243 ++ src/views/data/ind/data/field/index.vue | 155 + src/views/mpk/project.vue | 228 + src/views/model/pre/result/MmResultTableForm.vue | 96 src/views/model/pre/item/index.vue | 151 + src/api/mpk/mpk.ts | 46 src/api/data/da/point/index.ts | 49 src/api/model/pre/result/index.ts | 35 src/views/mpk/ProjectPackageHistory.vue | 155 + src/views/model/pre/item/ItemTypeForm.vue | 115 src/api/mpk/projectPackageHistory.ts | 13 src/views/data/ind/data/DataSetForm.vue | 129 + src/views/data/channel/http/HttpApiForm.vue | 155 + src/views/model/pre/dm/index.vue | 154 + src/views/data/da/point/index.vue | 172 + src/views/data/da/point/DaPointForm.vue | 202 + src/views/data/channel/kio/KioDeviceForm.vue | 132 + 62 files changed, 7,013 insertions(+), 11 deletions(-) diff --git "a/public/template/\346\250\241\345\236\213\345\217\202\346\225\260\345\257\274\345\205\245\346\250\241\346\235\277.xlsx" "b/public/template/\346\250\241\345\236\213\345\217\202\346\225\260\345\257\274\345\205\245\346\250\241\346\235\277.xlsx" new file mode 100644 index 0000000..cfe9487 --- /dev/null +++ "b/public/template/\346\250\241\345\236\213\345\217\202\346\225\260\345\257\274\345\205\245\346\250\241\346\235\277.xlsx" Binary files differ diff --git a/src/api/data/channel/http/index.ts b/src/api/data/channel/http/index.ts new file mode 100644 index 0000000..0280b5b --- /dev/null +++ b/src/api/data/channel/http/index.ts @@ -0,0 +1,43 @@ +import request from '@/config/axios' + +export interface HttpApiVO { + id: string + name: string, + code: string, + url: string, + method: string, + collectType: string, + param: string, + descp: string, + status: number +} + +export interface HttpApiPageReqVO extends PageParam { + name?: string, + code?: string +} + +// 查询HttpApi列表 +export const getHttpApiPage = (params: HttpApiPageReqVO) => { + return request.get({ url: '/data/channel/http/api/page', params }) +} + +// 查询HttpApi详情 +export const getHttpApi = (id: number) => { + return request.get({ url: `/data/channel/http/api/info/${id}`}) +} + +// 新增HttpApi +export const createHttpApi = (data: HttpApiVO) => { + return request.post({ url: '/data/channel/http/api/add', data }) +} + +// 修改HttpApi +export const updateHttpApi = (data: HttpApiVO) => { + return request.put({ url: '/data/channel/http/api/update', data }) +} + +// 删除HttpApi +export const deleteHttpApi = (id: number) => { + return request.delete({ url: '/data/channel/http/api/delete?id=' + id }) +} diff --git a/src/api/data/channel/kio/index.ts b/src/api/data/channel/kio/index.ts new file mode 100644 index 0000000..5025234 --- /dev/null +++ b/src/api/data/channel/kio/index.ts @@ -0,0 +1,40 @@ +import request from '@/config/axios' + +export interface KioDeviceVO { + id: string + instanceName: string + address: string + port: number + username: string + password: string +} + +export interface KioDevicePageReqVO extends PageParam { + instanceName?: string + address?: string +} + +// 查询KioDevice列表 +export const getKioDevicePage = (params: KioDevicePageReqVO) => { + return request.get({ url: '/data/channel/kio/device/page', params }) +} + +// 查询KioDevice详情 +export const getKioDevice = (id: number) => { + return request.get({ url: `/data/channel/kio/device/info/${id}`}) +} + +// 新增KioDevice +export const createKioDevice = (data: KioDeviceVO) => { + return request.post({ url: '/data/channel/kio/device/add', data }) +} + +// 修改KioDevice +export const updateKioDevice = (data: KioDeviceVO) => { + return request.put({ url: '/data/channel/kio/device/update', data }) +} + +// 删除KioDevice +export const deleteKioDevice = (id: number) => { + return request.delete({ url: '/data/channel/kio/device/delete?id=' + id }) +} diff --git a/src/api/data/channel/opcda/index.ts b/src/api/data/channel/opcda/index.ts new file mode 100644 index 0000000..2347d4a --- /dev/null +++ b/src/api/data/channel/opcda/index.ts @@ -0,0 +1,40 @@ +import request from '@/config/axios' + +export interface OpcDaDeviceVO { + id: string + serverName: string + host: string + user: string + password: string + progId: string + clsId: string +} + +export interface OpcDaDevicePageReqVO extends PageParam { + serverName?: string +} + +// 查询OpcDaDevice列表 +export const getOpcDaDevicePage = (params: OpcDaDevicePageReqVO) => { + return request.get({ url: '/data/channel/opcda/device/page', params }) +} + +// 查询OpcDaDevice详情 +export const getOpcDaDevice = (id: number) => { + return request.get({ url: `/data/channel/opcda/device/info/${id}`}) +} + +// 新增OpcDaDevice +export const createOpcDaDevice = (data: OpcDaDeviceVO) => { + return request.post({ url: '/data/channel/opcda/device/add', data }) +} + +// 修改OpcDaDevice +export const updateOpcDaDevice = (data: OpcDaDeviceVO) => { + return request.put({ url: '/data/channel/opcda/device/update', data }) +} + +// 删除OpcDaDevice +export const deleteOpcDaDevice = (id: number) => { + return request.delete({ url: '/data/channel/opcda/device/delete?id=' + id }) +} diff --git a/src/api/data/channel/opcua/index.ts b/src/api/data/channel/opcua/index.ts new file mode 100644 index 0000000..f553a41 --- /dev/null +++ b/src/api/data/channel/opcua/index.ts @@ -0,0 +1,44 @@ +import request from '@/config/axios' + +export interface OpcUaDeviceVO { + id: string + serverName: string + endpointUrl: string + securityPolicy: string + securityMode: string + connectionType: string + userName: string + password: string + certificatePath: string + connectInactivityTimeout: number + reconnectInterval: number +} + +export interface OpcUaDevicePageReqVO extends PageParam { + serverName?: string +} + +// 查询OpcUaDevice列表 +export const getOpcUaDevicePage = (params: OpcUaDevicePageReqVO) => { + return request.get({ url: '/data/channel/opcua/device/page', params }) +} + +// 查询OpcUaDevice详情 +export const getOpcUaDevice = (id: number) => { + return request.get({ url: `/data/channel/opcua/device/info/${id}`}) +} + +// 新增OpcUaDevice +export const createOpcUaDevice = (data: OpcUaDeviceVO) => { + return request.post({ url: '/data/channel/opcua/device/add', data }) +} + +// 修改OpcUaDevice +export const updateOpcUaDevice = (data: OpcUaDeviceVO) => { + return request.put({ url: '/data/channel/opcua/device/update', data }) +} + +// 删除OpcUaDevice +export const deleteOpcUaDevice = (id: number) => { + return request.delete({ url: '/data/channel/opcua/device/delete?id=' + id }) +} diff --git a/src/api/data/da/point/index.ts b/src/api/data/da/point/index.ts new file mode 100644 index 0000000..0b55b99 --- /dev/null +++ b/src/api/data/da/point/index.ts @@ -0,0 +1,49 @@ +import request from '@/config/axios' + +export interface DaPointVO { + id: string + pointNo: string, + pointName: string, + pointType: string, + dataType: string, + valueType: string, + storeType: string, + unit: string, + unittransfactor: number, + defaultValue: number, + maxValue: number, + minValue: number, + minfreqid: string, + remark: string, + isEnable: number, +} + +export interface DaPointPageReqVO extends PageParam { + pointNo?: string, + pointName?: string +} + +// 查询DaPoint列表 +export const getDaPointPage = (params: DaPointPageReqVO) => { + return request.get({ url: '/data/da/point/page', params }) +} + +// 查询DaPoint详情 +export const getDaPoint = (id: number) => { + return request.get({ url: `/data/da/point/info/${id}`}) +} + +// 新增DaPoint +export const createDaPoint = (data: DaPointVO) => { + return request.post({ url: '/data/da/point/add', data }) +} + +// 修改DaPoint +export const updateDaPoint = (data: DaPointVO) => { + return request.put({ url: '/data/da/point/update', data }) +} + +// 删除DaPoint +export const deleteDaPoint = (id: number) => { + return request.delete({ url: '/data/da/point/delete?id=' + id }) +} diff --git a/src/api/data/ind/category/index.ts b/src/api/data/ind/category/index.ts new file mode 100644 index 0000000..5b2b7bf --- /dev/null +++ b/src/api/data/ind/category/index.ts @@ -0,0 +1,42 @@ +import request from '@/config/axios' + +export interface IndItemCategoryVO { + id: string + label: string + pid: string + sort: number +} + +export interface IndItemCategoryReqVO { + label?: string +} + +// 查询列表 +export const getCategoryList = (params) => { + return request.get({ url: '/data/ind/category/list', params}) +} + +// 查询列表 +export const getCategoryListAllSimple = () => { + return request.get({ url: '/data/ind/category/list-all-simple'}) +} + +// 查询详情 +export const getCategory = (id: number) => { + return request.get({ url: '/data/ind/category/get?id=' + id}) +} + +// 新增 +export const createCategory = (data: ScheduleModelVO) => { + return request.post({ url: '/data/ind/category/create', data }) +} + +// 修改 +export const updateCategory = (data: ScheduleModelVO) => { + return request.put({ url: '/data/ind/category/update', data }) +} + +// 删除 +export const deleteCategory = (id: number) => { + return request.delete({ url: '/data/ind/category/delete?id=' + id }) +} diff --git a/src/api/data/ind/data/data.field.ts b/src/api/data/ind/data/data.field.ts new file mode 100644 index 0000000..ae4e230 --- /dev/null +++ b/src/api/data/ind/data/data.field.ts @@ -0,0 +1,35 @@ +import request from '@/config/axios' + +export type DataSetFieldVO = { + id: number | undefined + dataSetId: string + fieldCode: string + fieldName: string + fieldType: string + sort: number +} + +// 查询列表 +export const getDataSetFieldPage = (params: PageParam) => { + return request.get({ url: '/data/ind/data-set-field/page', params }) +} + +// 查询详情 +export const getDataSetField = (id: number) => { + return request.get({ url: '/data/ind/data-set-field/get?id=' + id }) +} + +// 新增 +export const createDataSetField = (data: DataSetFieldVO) => { + return request.post({ url: '/data/ind/data-set-field/create', data }) +} + +// 修改 +export const updateDataSetField = (data: DataSetFieldVO) => { + return request.put({ url: '/data/ind/data-set-field/update', data }) +} + +// 删除 +export const deleteDataSetField = (id: number) => { + return request.delete({ url: '/data/ind/data-set-field/delete?id=' + id }) +} diff --git a/src/api/data/ind/data/data.set.ts b/src/api/data/ind/data/data.set.ts new file mode 100644 index 0000000..371f9db --- /dev/null +++ b/src/api/data/ind/data/data.set.ts @@ -0,0 +1,40 @@ +import request from '@/config/axios' + +export type DataSetVO = { + id: number | undefined + name: string + dataSource: string + querySql: string + remark: string + sort: number +} + +// 查询列表 +export const getDataSetList = () => { + return request.get({ url: '/data/ind/data-set/list-all-simple' }) +} + +// 查询列表 +export const getDataSetPage = (params: PageParam) => { + return request.get({ url: '/data/ind/data-set/page', params }) +} + +// 查询详情 +export const getDataSet = (id: number) => { + return request.get({ url: '/data/ind/data-set/get?id=' + id }) +} + +// 新增 +export const createDataSet = (data: DataSetVO) => { + return request.post({ url: '/data/ind/data-set/create', data }) +} + +// 修改 +export const updateDataSet = (data: DataSetVO) => { + return request.put({ url: '/data/ind/data-set/update', data }) +} + +// 删除 +export const deleteDataSet = (id: number) => { + return request.delete({ url: '/data/ind/data-set/delete?id=' + id }) +} diff --git a/src/api/model/pre/dm/index.ts b/src/api/model/pre/dm/index.ts new file mode 100644 index 0000000..db9638a --- /dev/null +++ b/src/api/model/pre/dm/index.ts @@ -0,0 +1,37 @@ +import request from '@/config/axios' + +export interface MmItemTypeVO { + id: string + itemtypename: string, + itemclasstype: string, + assemblyname: string +} + +export interface MmItemTypePageReqVO extends PageParam { + modulename?: string +} + +// 查询MmItemType列表 +export const getMmItemTypePage = (params: MmItemTypePageReqVO) => { + return request.get({ url: '/pre/item-type/page', params }) +} + +// 查询MmItemType详情 +export const getMmItemType = (id: number) => { + return request.get({ url: `/pre/item-type/get/${id}`}) +} + +// 新增MmItemType +export const createMmItemType = (data: MmItemTypeVO) => { + return request.post({ url: '/pre/item-type/create', data }) +} + +// 修改MmItemType +export const updateMmItemType = (data: MmItemTypeVO) => { + return request.put({ url: '/pre/item-type/update', data }) +} + +// 删除MmItemType +export const deleteMmItemType = (id: number) => { + return request.delete({ url: '/pre/item-type/delete?id=' + id }) +} diff --git a/src/api/model/pre/item/index.ts b/src/api/model/pre/item/index.ts new file mode 100644 index 0000000..30a9017 --- /dev/null +++ b/src/api/model/pre/item/index.ts @@ -0,0 +1,37 @@ +import request from '@/config/axios' + +export interface MmItemTypeVO { + id: string + itemtypename: string, + itemclasstype: string, + assemblyname: string +} + +export interface MmItemTypePageReqVO extends PageParam { + itemtypename?: string +} + +// 查询MmItemType列表 +export const getMmItemTypePage = (params: MmItemTypePageReqVO) => { + return request.get({ url: '/pre/item-type/page', params }) +} + +// 查询MmItemType详情 +export const getMmItemType = (id: number) => { + return request.get({ url: `/pre/item-type/get/${id}`}) +} + +// 新增MmItemType +export const createMmItemType = (data: MmItemTypeVO) => { + return request.post({ url: '/pre/item-type/create', data }) +} + +// 修改MmItemType +export const updateMmItemType = (data: MmItemTypeVO) => { + return request.put({ url: '/pre/item-type/update', data }) +} + +// 删除MmItemType +export const deleteMmItemType = (id: number) => { + return request.delete({ url: '/pre/item-type/delete?id=' + id }) +} diff --git a/src/api/model/pre/predict/index.ts b/src/api/model/pre/predict/index.ts new file mode 100644 index 0000000..3b0798e --- /dev/null +++ b/src/api/model/pre/predict/index.ts @@ -0,0 +1,50 @@ +import request from '@/config/axios' + +export interface MmPredictItemVO { + id: string + itemno: string, + itemname: string, + itemtypeid: string, + itemtypename: string, + granularity: number, + isfuse: number, + workchecked: number, + moduleid: string, + itemorder: number, + status: number, + categoryid: string, + pointid: string, + tagname: string, + resulttableid: string, + tablename: string, +} + +export interface MmPredictItemPageReqVO extends PageParam { + itemno?: string, + itemname?: string, +} + +// 查询MmPredictItem列表 +export const getMmPredictItemPage = (params: MmPredictItemPageReqVO) => { + return request.get({ url: '/pre/result-table/page', params }) +} + +// 查询MmPredictItem详情 +export const getMmPredictItem = (id: number) => { + return request.get({ url: `/pre/result-table/get/${id}`}) +} + +// 新增MmPredictItem +export const createMmPredictItem = (data: MmPredictItemVO) => { + return request.post({ url: '/pre/result-table/create', data }) +} + +// 修改MmPredictItem +export const updateMmPredictItem = (data: MmPredictItemVO) => { + return request.put({ url: '/pre/result-table/update', data }) +} + +// 删除MmPredictItem +export const deleteMmPredictItem = (id: number) => { + return request.delete({ url: '/pre/result-table/delete?id=' + id }) +} diff --git a/src/api/model/pre/result/index.ts b/src/api/model/pre/result/index.ts new file mode 100644 index 0000000..04ad0fb --- /dev/null +++ b/src/api/model/pre/result/index.ts @@ -0,0 +1,35 @@ +import request from '@/config/axios' + +export interface MmResultTableVO { + id: string + tablename: string, +} + +export interface MmResultTablePageReqVO extends PageParam { + tablename?: string +} + +// 查询MmResultTable列表 +export const getMmResultTablePage = (params: MmResultTablePageReqVO) => { + return request.get({ url: '/pre/predict-item/page', params }) +} + +// 查询MmResultTable详情 +export const getMmResultTable = (id: number) => { + return request.get({ url: `/pre/predict-item/get/${id}`}) +} + +// 新增MmResultTable +export const createMmResultTable = (data: MmResultTableVO) => { + return request.post({ url: '/pre/predict-item/create', data }) +} + +// 修改MmResultTable +export const updateMmResultTable = (data: MmResultTableVO) => { + return request.put({ url: '/pre/predict-item/update', data }) +} + +// 删除MmResultTable +export const deleteMmResultTable = (id: number) => { + return request.delete({ url: '/pre/predict-item/delete?id=' + id }) +} diff --git a/src/api/model/sche/model/index.ts b/src/api/model/sche/model/index.ts new file mode 100644 index 0000000..cece2cf --- /dev/null +++ b/src/api/model/sche/model/index.ts @@ -0,0 +1,66 @@ +import request from '@/config/axios' + +export interface ScheduleModelVO { + id: string + modelCode: string + modelName: string + modelType: string + className: string + methodName: string + portLength: number + paramStructure: string + modelPath: string + resultStrId: string + invocation: string + status: number, + paramList: null, + settingList: null +} + +export interface ModelParamVO { + modelparamportorder: number + modelparamorder: number + modelparamtype: string + modelparamid: string + datalength: number +} + +export interface ScheduleModelPageReqVO extends PageParam { + modelCode?: string + modelName?: string +} + +// 查询ScheduleModel列表 +export const getScheduleModelPage = (params: ScheduleModelPageReqVO) => { + return request.get({ url: '/model/sche/model/page', params }) +} + +// 查询ScheduleModel详情 +export const getScheduleModel = (id: number) => { + return request.get({ url: '/model/sche/model/get?id=' + id}) +} + +// 新增ScheduleModel +export const createScheduleModel = (data: ScheduleModelVO) => { + return request.post({ url: '/model/sche/model/create', data }) +} + +// 修改ScheduleModel +export const updateScheduleModel = (data: ScheduleModelVO) => { + return request.put({ url: '/model/sche/model/update', data }) +} + +// 删除ScheduleModel +export const deleteScheduleModel = (id: number) => { + return request.delete({ url: '/model/sche/model/delete?id=' + id }) +} + +// 查询ScheduleModel列表 +export const getScheduleModelList = () => { + return request.get({ url: '/model/sche/model/list'}) +} + +// 查询模型参数列表 +export const getModelParamList = (modelparamListMap) => { + modelparamListMap['point'] = [] +} diff --git a/src/api/model/sche/scheme/index.ts b/src/api/model/sche/scheme/index.ts new file mode 100644 index 0000000..3d3971f --- /dev/null +++ b/src/api/model/sche/scheme/index.ts @@ -0,0 +1,46 @@ +import request from '@/config/axios' + +export interface ScheduleSchemeVO { + id: string + code: string + name: string + triggerMethod: string + triggerCondition: string + scheduleObj: string + scheduleType: string + scheduleStrategy: string + modelId: string + scheduleTime: string + remark: string + status: number +} + +export interface ScheduleSchemePageReqVO extends PageParam { + modelCode?: string + modelName?: string +} + +// 查询ScheduleScheme列表 +export const getScheduleSchemePage = (params: ScheduleSchemePageReqVO) => { + return request.get({ url: '/model/sche/scheme/page', params }) +} + +// 查询ScheduleScheme详情 +export const getScheduleScheme = (id: number) => { + return request.get({ url: '/model/sche/scheme/get?id=' + id}) +} + +// 新增ScheduleScheme +export const createScheduleScheme = (data: ScheduleSchemeVO) => { + return request.post({ url: '/model/sche/scheme/create', data }) +} + +// 修改ScheduleScheme +export const updateScheduleScheme = (data: ScheduleSchemeVO) => { + return request.put({ url: '/model/sche/scheme/update', data }) +} + +// 删除ScheduleScheme +export const deleteScheduleScheme = (id: number) => { + return request.delete({ url: '/model/sche/scheme/delete?id=' + id }) +} diff --git a/src/api/mpk/mpk.ts b/src/api/mpk/mpk.ts new file mode 100644 index 0000000..44800d0 --- /dev/null +++ b/src/api/mpk/mpk.ts @@ -0,0 +1,46 @@ +import request from '@/config/axios' + +export interface MpkVO { + id?: string + pyName: string + pkgName: string + pyType: string + className: string + dataLength: number + pyModule: string + remark?: string + modelMethods: object + filePath: string +} + +export const getPage = async (params: PageParam) => { + return await request.get({ url: '/model/mpk/file/page', params }) +} + +export const getMpk = async (id: number) => { + return await request.get({ url: '/model/mpk/file/' + id }) +} + +export const createMpk = async (data: MpkVO) => { + return await request.post({ url: '/model/mpk/file', data: data }) +} + +export const updateMpk = async (params: MpkVO) => { + return await request.put({ url: '/model/mpk/file', data: params }) +} + +export const deleteMpk = async (id: number) => { + return await request.delete({ url: '/model/mpk/file?id=' + id }) +} + +export const generatorCode = (params) => { + return request.download({ url: '/model/mpk/file/generat', params }) +} + +export const modelRun = (params) => { + return request.post({ url: '/model/mpk/api/run', data: params }) +} + +export const list = () => { + return request.get({ url: '/model/mpk/file/list'}) +} diff --git a/src/api/mpk/mpkHistory.ts b/src/api/mpk/mpkHistory.ts new file mode 100644 index 0000000..a026f4e --- /dev/null +++ b/src/api/mpk/mpkHistory.ts @@ -0,0 +1,10 @@ +import request from '@/config/axios' + + +export const getPage = async (params: PageParam) => { + return await request.get({ url: '/model/mpk/generatorCodeHistory/page', params }) +} + +export const download = (params) => { + return request.download({ url: '/model/mpk/generatorCodeHistory/download', params }) +} diff --git a/src/api/mpk/project.ts b/src/api/mpk/project.ts new file mode 100644 index 0000000..514b05b --- /dev/null +++ b/src/api/mpk/project.ts @@ -0,0 +1,33 @@ +import request from '@/config/axios' + +export const getPage = async (params: PageParam) => { + return await request.get({ url: '/model/mpk/project/page', params }) +} + +export const getProject = async (id: number) => { + return await request.get({ url: '/model/mpk/project/' + id }) +} + +export const createProject = async (data) => { + return await request.post({ url: '/model/mpk/project', data: data }) +} + +export const updateProject = async (params) => { + return await request.put({ url: '/model/mpk/project', data: params }) +} + +export const deleteProject = async (id: number) => { + return await request.delete({ url: '/model/mpk/project?id=' + id }) +} + +export const packageProject = (params) => { + return request.download({ url: '/model/mpk/file/packageModel', params }) +} + +export const list = () => { + return request.get({ url: '/model/mpk/project/list'}) +} + +export const getProjectModel = async (params: PageParam) => { + return await request.get({ url: '/model/mpk/project/getProjectModel', params }) +} diff --git a/src/api/mpk/projectPackageHistory.ts b/src/api/mpk/projectPackageHistory.ts new file mode 100644 index 0000000..aff5c30 --- /dev/null +++ b/src/api/mpk/projectPackageHistory.ts @@ -0,0 +1,13 @@ +import request from '@/config/axios' + +export const getPage = async (params: PageParam) => { + return await request.get({ url: '/model/mpk/projectPackageHistory/page', params }) +} + +export const download = (params) => { + return request.download({ url: '/model/mpk/projectPackageHistory/download', params }) +} + +export const getPackageModel = async (params: PageParam) => { + return await request.get({ url: '/model/mpk/projectPackageHistory/getPackageModel', params }) +} diff --git a/src/router/modules/remaining.ts b/src/router/modules/remaining.ts index 90fa84b..b889036 100644 --- a/src/router/modules/remaining.ts +++ b/src/router/modules/remaining.ts @@ -328,6 +328,52 @@ } ] }, + { + path: '/project', + component: Layout, + name: 'project', + meta: { + hidden: true + }, + children: [ + { + path: 'package/history/:projectId', + component: () => import('@/views/mpk/ProjectPackageHistory.vue'), + name: 'ProjectPackageHistory', + meta: { + title: '打包历史', + noCache: true, + hidden: true, + canTo: true, + icon: '', + activeMenu: '/model/project' + } + } + ] + }, + { + path: '/ind/data', + component: Layout, + name: 'dataSet', + meta: { + hidden: true + }, + children: [ + { + path: 'field/:dataSetId', + component: () => import('@/views/data/ind/data/field/index.vue'), + name: 'IndDataSetField', + meta: { + title: '数据集字段', + noCache: true, + hidden: true, + canTo: true, + icon: '', + activeMenu: '/data/ind/data' + } + } + ] + }, ] export default remainingRouter diff --git a/src/utils/dateUtil.ts b/src/utils/dateUtil.ts index 316b870..b83c3a5 100644 --- a/src/utils/dateUtil.ts +++ b/src/utils/dateUtil.ts @@ -6,6 +6,7 @@ const DATE_TIME_FORMAT = 'YYYY-MM-DD HH:mm:ss' const DATE_FORMAT = 'YYYY-MM-DD' +const DATE_TIME_PATTERN_STRING = 'YYYYMMDDHHmmss' export function formatToDateTime(date?: dayjs.ConfigType, format = DATE_TIME_FORMAT): string { return dayjs(date).format(format) @@ -15,4 +16,8 @@ return dayjs(date).format(format) } +export function formatToDateString(date?: dayjs.ConfigType, format = DATE_TIME_PATTERN_STRING): string { + return dayjs(date).format(format) +} + export const dateUtil = dayjs diff --git a/src/utils/dict.ts b/src/utils/dict.ts index 7fbcfeb..03ed2fd 100644 --- a/src/utils/dict.ts +++ b/src/utils/dict.ts @@ -226,5 +226,15 @@ AI_WRITE_LENGTH = 'ai_write_length', // AI 写作长度 AI_WRITE_FORMAT = 'ai_write_format', // AI 写作格式 AI_WRITE_TONE = 'ai_write_tone', // AI 写作语气 - AI_WRITE_LANGUAGE = 'ai_write_language' // AI 写作语言 + AI_WRITE_LANGUAGE = 'ai_write_language', // AI 写作语言 + + // ========== MODEL - 模型管理模块 ========== + SCHE_MODEL_TYPE = 'sche_model_type', + SCHE_MODEL_INVOCATION = 'sche_model_invocation', + SCHE_TRIGGER_METHOD = 'sche_trigger_method', + MODEL_PARAM_TYPE = 'model_param_type', + MODEL_METHOD = 'model_method', + + // ========== DATA - 数据平台模块 ========== + DATA_FIELD_TYPE = 'data_field_type', } diff --git a/src/views/data/channel/http/HttpApiForm.vue b/src/views/data/channel/http/HttpApiForm.vue new file mode 100644 index 0000000..92fb9c5 --- /dev/null +++ b/src/views/data/channel/http/HttpApiForm.vue @@ -0,0 +1,155 @@ +<template> + <Dialog v-model="dialogVisible" :title="dialogTitle" width="50%"> + <el-form + ref="formRef" + v-loading="formLoading" + :model="formData" + :rules="formRules" + label-width="120px" + > + <el-row> + <el-col :span="12"> + <el-form-item label="名称" prop="name"> + <el-input v-model="formData.name" placeholder="请输入名称" /> + </el-form-item> + </el-col> + </el-row> + <el-row> + <el-col :span="12"> + <el-form-item label="编码" prop="code"> + <el-input v-model="formData.code" placeholder="请输入编码" /> + </el-form-item> + </el-col> + <el-col :span="12"> + <el-form-item label="url" prop="url"> + <el-input v-model="formData.url" placeholder="请输入url" /> + </el-form-item> + </el-col> + </el-row> + <el-row> + <el-col :span="12"> + <el-form-item label="方法" prop="method"> + <el-input v-model="formData.method" placeholder="请输入方法" /> + </el-form-item> + </el-col> + <el-col :span="12"> + <el-form-item label="采集类型" prop="collectType"> + <el-input v-model="formData.collectType" placeholder="请输入采集类型" /> + </el-form-item> + </el-col> + </el-row> + <el-row> + <el-col :span="12"> + <el-form-item label="参数" prop="param"> + <el-input v-model="formData.param" placeholder="请输入参数" /> + </el-form-item> + </el-col> + <el-col :span="12"> + <el-form-item label="描述" prop="descp"> + <el-input v-model="formData.descp" placeholder="请输入描述" /> + </el-form-item> + </el-col> + </el-row> + <el-row> + <el-col :span="12"> + <el-form-item label="状态" prop="status"> + <el-input v-model="formData.status" placeholder="请输入状态" /> + </el-form-item> + </el-col> + </el-row> + </el-form> + <template #footer> + <el-button :disabled="formLoading" type="primary" @click="submitForm">确 定</el-button> + <el-button @click="dialogVisible = false">取 消</el-button> + </template> + </Dialog> +</template> +<script lang="ts" setup> +import * as HttpApi from '@/api/data/channel/http' + +defineOptions({ name: 'DataHttpApiForm' }) + + const { t } = useI18n() // 国际化 + const message = useMessage() // 消息弹窗 + const dialogVisible = ref(false) // 弹窗的是否展示 + const dialogTitle = ref('') // 弹窗的标题 + const formLoading = ref(false) // 表单的加载中:1)修改时的数据加载;2)提交的按钮禁用 + const formType = ref('') // 表单的类型:create - 新增;update - 修改 + const formData = ref({ + id: undefined, + name: undefined, + code: undefined, + url: undefined, + method: undefined, + collectType: undefined, + param: undefined, + descp: undefined, + status: undefined + }) + const formRules = reactive({ + name: [{ required: true, message: '名称不能为空', trigger: 'blur' }], + code: [{ required: true, message: '编码不能为空', trigger: 'blur' }], + url: [{ required: true, message: 'url不能为空', trigger: 'blur' }], + }) + const formRef = ref() // 表单 Ref + + /** 打开弹窗 */ + const open = async (type: string, id?: number) => { + dialogVisible.value = true + dialogTitle.value = t('action.' + type) + formType.value = type + resetForm() + // 修改时,设置数据 + if (id) { + formLoading.value = true + try { + formData.value = await HttpApi.getHttpApi(id) + } finally { + formLoading.value = false + } + } + } + defineExpose({ open }) // 提供 open 方法,用于打开弹窗 + + /** 提交表单 */ + const emit = defineEmits(['success']) // 定义 success 事件,用于操作成功后的回调 + const submitForm = async () => { + // 校验表单 + if (!formRef) return + const valid = await formRef.value.validate() + if (!valid) return + // 提交请求 + formLoading.value = true + try { + const data = formData.value as unknown as HttpApi.HttpApiVO + if (formType.value === 'create') { + await HttpApi.createHttpApi(data) + message.success(t('common.createSuccess')) + } else { + await HttpApi.updateHttpApi(data) + message.success(t('common.updateSuccess')) + } + dialogVisible.value = false + // 发送操作成功的事件 + emit('success') + } finally { + formLoading.value = false + } + } + + /** 重置表单 */ + const resetForm = () => { + formData.value = { + id: undefined, + name: undefined, + code: undefined, + url: undefined, + method: undefined, + collectType: undefined, + param: undefined, + descp: undefined, + status: undefined + } + formRef.value?.resetFields() + } +</script> diff --git a/src/views/data/channel/http/index.vue b/src/views/data/channel/http/index.vue new file mode 100644 index 0000000..80bbf40 --- /dev/null +++ b/src/views/data/channel/http/index.vue @@ -0,0 +1,156 @@ +<template> + <!-- 搜索 --> + <ContentWrap> + <el-form + class="-mb-15px" + :model="queryParams" + ref="queryFormRef" + :inline="true" + label-width="68px" + > + <el-form-item label="名称" prop="name"> + <el-input + v-model="queryParams.name" + placeholder="请输入名称" + clearable + @keyup.enter="handleQuery" + class="!w-240px" + /> + </el-form-item> + <el-form-item> + <el-button @click="handleQuery"> + <Icon icon="ep:search" class="mr-5px" /> + 搜索 + </el-button> + <el-button @click="resetQuery"> + <Icon icon="ep:refresh" class="mr-5px" /> + 重置 + </el-button> + <el-button + type="primary" + plain + @click="openForm('create')" + v-hasPermi="['system:tenant:create']" + > + <Icon icon="ep:plus" class="mr-5px" /> + 新增 + </el-button> + </el-form-item> + </el-form> + </ContentWrap> + + <!-- 列表 --> + <ContentWrap> + <el-table v-loading="loading" :data="list"> + <el-table-column label="名称" align="center" prop="name" /> + <el-table-column label="编码" align="center" prop="code" /> + <el-table-column label="url" align="center" prop="url" /> + <el-table-column label="方法" align="center" prop="method" /> + <el-table-column label="采集类型" align="center" prop="collectType" /> + <el-table-column label="参数" align="center" prop="param" /> + <el-table-column label="描述" align="center" prop="descp" /> + <el-table-column label="状态" align="center" prop="status" /> + + <el-table-column label="操作" align="center" min-width="110" fixed="right"> + <template #default="scope"> + <el-button + link + type="primary" + @click="openForm('update', scope.row.id)" + v-hasPermi="['system:tenant:update']" + > + 编辑 + </el-button> + <el-button + link + type="danger" + @click="handleDelete(scope.row.id)" + v-hasPermi="['system:tenant:delete']" + > + 删除 + </el-button> + </template> + </el-table-column> + </el-table> + <!-- 分页 --> + <Pagination + :total="total" + v-model:page="queryParams.pageNo" + v-model:limit="queryParams.pageSize" + @pagination="getList" + /> + </ContentWrap> + + <!-- 表单弹窗:添加/修改 --> + <HttpApiForm ref="formRef" @success="getList" /> + +</template> +<script lang="ts" setup> +import * as HttpApi from '@/api/data/channel/http' +import HttpApiForm from './HttpApiForm.vue' + +defineOptions({name: 'DataHttp'}) + + const message = useMessage() // 消息弹窗 + const {t} = useI18n() // 国际化 + + const loading = ref(true) // 列表的加载中 + const total = ref(0) // 列表的总页数 + const list = ref([]) // 列表的数据 + const queryParams = reactive({ + pageNo: 1, + pageSize: 10, + name: undefined + }) + const queryFormRef = ref() // 搜索的表单 + const exportLoading = ref(false) // 导出的加载中 + + /** 查询列表 */ + const getList = async () => { + loading.value = true + try { + const page = await HttpApi.getHttpApiPage(queryParams) + list.value = page.list + total.value = page.total + } finally { + loading.value = false + } + } + + /** 搜索按钮操作 */ + const handleQuery = () => { + queryParams.pageNo = 1 + getList() + } + + /** 重置按钮操作 */ + const resetQuery = () => { + queryFormRef.value.resetFields() + handleQuery() + } + + /** 添加/修改操作 */ + const formRef = ref() + const openForm = (type: string, id?: number) => { + formRef.value.open(type, id) + } + + /** 删除按钮操作 */ + const handleDelete = async (id: number) => { + try { + // 删除的二次确认 + await message.delConfirm() + // 发起删除 + await HttpApi.deleteHttpApi(id) + message.success(t('common.delSuccess')) + // 刷新列表 + await getList() + } catch { + } + } + + /** 初始化 **/ + onMounted(async () => { + await getList() + }) +</script> diff --git a/src/views/data/channel/kio/KioDeviceForm.vue b/src/views/data/channel/kio/KioDeviceForm.vue new file mode 100644 index 0000000..c475a54 --- /dev/null +++ b/src/views/data/channel/kio/KioDeviceForm.vue @@ -0,0 +1,132 @@ +<template> + <Dialog v-model="dialogVisible" :title="dialogTitle" width="50%"> + <el-form + ref="formRef" + v-loading="formLoading" + :model="formData" + :rules="formRules" + label-width="120px" + > + <el-row> + <el-col :span="12"> + <el-form-item label="实例名称" prop="instanceName"> + <el-input v-model="formData.instanceName" placeholder="请输入实例名称" /> + </el-form-item> + </el-col> + </el-row> + <el-row> + <el-col :span="12"> + <el-form-item label="IP地址" prop="address"> + <el-input v-model="formData.address" placeholder="请输入IP地址" /> + </el-form-item> + </el-col> + <el-col :span="12"> + <el-form-item label="端口" prop="port"> + <el-input v-model="formData.port" placeholder="请输入端口" /> + </el-form-item> + </el-col> + </el-row> + <el-row> + <el-col :span="12"> + <el-form-item label="用户名" prop="username"> + <el-input v-model="formData.username" placeholder="请输入用户名" /> + </el-form-item> + </el-col> + <el-col :span="12"> + <el-form-item label="密码" prop="password"> + <el-input type = "password" v-model="formData.password" placeholder="请输入密码" /> + </el-form-item> + </el-col> + </el-row> + </el-form> + <template #footer> + <el-button :disabled="formLoading" type="primary" @click="submitForm">确 定</el-button> + <el-button @click="dialogVisible = false">取 消</el-button> + </template> + </Dialog> +</template> +<script lang="ts" setup> +import * as KioApi from '@/api/data/channel/kio' + +defineOptions({ name: 'DataKioDeviceForm' }) + + const { t } = useI18n() // 国际化 + const message = useMessage() // 消息弹窗 + const dialogVisible = ref(false) // 弹窗的是否展示 + const dialogTitle = ref('') // 弹窗的标题 + const formLoading = ref(false) // 表单的加载中:1)修改时的数据加载;2)提交的按钮禁用 + const formType = ref('') // 表单的类型:create - 新增;update - 修改 + const formData = ref({ + id: undefined, + instanceName: undefined, + address: undefined, + port: undefined, + username: undefined, + password: undefined, + }) + const formRules = reactive({ + instanceName: [{ required: true, message: '设备名称不能为空', trigger: 'blur' }], + address: [{ required: true, message: 'IP地址不能为空', trigger: 'blur' }], + port: [{ required: true, message: '端口不能为空', trigger: 'blur' }], + username: [{ required: true, message: '用户名不能为空', trigger: 'blur' }], + password: [{ required: true, message: '密码不能为空', trigger: 'blur' }] + }) + const formRef = ref() // 表单 Ref + + /** 打开弹窗 */ + const open = async (type: string, id?: number) => { + dialogVisible.value = true + dialogTitle.value = t('action.' + type) + formType.value = type + resetForm() + // 修改时,设置数据 + if (id) { + formLoading.value = true + try { + formData.value = await KioApi.getKioDevice(id) + } finally { + formLoading.value = false + } + } + } + defineExpose({ open }) // 提供 open 方法,用于打开弹窗 + + /** 提交表单 */ + const emit = defineEmits(['success']) // 定义 success 事件,用于操作成功后的回调 + const submitForm = async () => { + // 校验表单 + if (!formRef) return + const valid = await formRef.value.validate() + if (!valid) return + // 提交请求 + formLoading.value = true + try { + const data = formData.value as unknown as KioApi.KioDeviceVO + if (formType.value === 'create') { + await KioApi.createKioDevice(data) + message.success(t('common.createSuccess')) + } else { + await KioApi.updateKioDevice(data) + message.success(t('common.updateSuccess')) + } + dialogVisible.value = false + // 发送操作成功的事件 + emit('success') + } finally { + formLoading.value = false + } + } + + /** 重置表单 */ + const resetForm = () => { + formData.value = { + id: undefined, + instanceName: undefined, + address: undefined, + port: undefined, + username: undefined, + password: undefined + } + formRef.value?.resetFields() + } +</script> diff --git a/src/views/data/channel/kio/index.vue b/src/views/data/channel/kio/index.vue new file mode 100644 index 0000000..36cea40 --- /dev/null +++ b/src/views/data/channel/kio/index.vue @@ -0,0 +1,152 @@ +<template> + <!-- 搜索 --> + <ContentWrap> + <el-form + class="-mb-15px" + :model="queryParams" + ref="queryFormRef" + :inline="true" + label-width="68px" + > + <el-form-item label="实例名称" prop="instanceName"> + <el-input + v-model="queryParams.instanceName" + placeholder="请输入实例名称" + clearable + @keyup.enter="handleQuery" + class="!w-240px" + /> + </el-form-item> + <el-form-item> + <el-button @click="handleQuery"> + <Icon icon="ep:search" class="mr-5px" /> + 搜索 + </el-button> + <el-button @click="resetQuery"> + <Icon icon="ep:refresh" class="mr-5px" /> + 重置 + </el-button> + <el-button + type="primary" + plain + @click="openForm('create')" + v-hasPermi="['system:tenant:create']" + > + <Icon icon="ep:plus" class="mr-5px" /> + 新增 + </el-button> + </el-form-item> + </el-form> + </ContentWrap> + + <!-- 列表 --> + <ContentWrap> + <el-table v-loading="loading" :data="list"> + <el-table-column label="实例名称" align="center" prop="instanceName" /> + <el-table-column label="IP地址" align="center" prop="address" /> + <el-table-column label="端口" align="center" prop="port" /> + <el-table-column label="用户名" align="center" prop="username" /> + <el-table-column label="操作" align="center" min-width="110" fixed="right"> + <template #default="scope"> + <el-button + link + type="primary" + @click="openForm('update', scope.row.id)" + v-hasPermi="['system:tenant:update']" + > + 编辑 + </el-button> + <el-button + link + type="danger" + @click="handleDelete(scope.row.id)" + v-hasPermi="['system:tenant:delete']" + > + 删除 + </el-button> + </template> + </el-table-column> + </el-table> + <!-- 分页 --> + <Pagination + :total="total" + v-model:page="queryParams.pageNo" + v-model:limit="queryParams.pageSize" + @pagination="getList" + /> + </ContentWrap> + + <!-- 表单弹窗:添加/修改 --> + <KioDeviceForm ref="formRef" @success="getList" /> + +</template> +<script lang="ts" setup> +import * as KioApi from '@/api/data/channel/kio' +import KioDeviceForm from './KioDeviceForm.vue' + +defineOptions({name: 'DataKio'}) + + const message = useMessage() // 消息弹窗 + const {t} = useI18n() // 国际化 + + const loading = ref(true) // 列表的加载中 + const total = ref(0) // 列表的总页数 + const list = ref([]) // 列表的数据 + const queryParams = reactive({ + pageNo: 1, + pageSize: 10, + instanceName: undefined, + address: undefined + }) + const queryFormRef = ref() // 搜索的表单 + const exportLoading = ref(false) // 导出的加载中 + + /** 查询列表 */ + const getList = async () => { + loading.value = true + try { + const page = await KioApi.getKioDevicePage(queryParams) + list.value = page.list + total.value = page.total + } finally { + loading.value = false + } + } + + /** 搜索按钮操作 */ + const handleQuery = () => { + queryParams.pageNo = 1 + getList() + } + + /** 重置按钮操作 */ + const resetQuery = () => { + queryFormRef.value.resetFields() + handleQuery() + } + + /** 添加/修改操作 */ + const formRef = ref() + const openForm = (type: string, id?: number) => { + formRef.value.open(type, id) + } + + /** 删除按钮操作 */ + const handleDelete = async (id: number) => { + try { + // 删除的二次确认 + await message.delConfirm() + // 发起删除 + await KioApi.deleteKioDevice(id) + message.success(t('common.delSuccess')) + // 刷新列表 + await getList() + } catch { + } + } + + /** 初始化 **/ + onMounted(async () => { + await getList() + }) +</script> diff --git a/src/views/data/channel/modbus/ModBusDeviceForm.vue b/src/views/data/channel/modbus/ModBusDeviceForm.vue index ad17a36..5ab02f1 100644 --- a/src/views/data/channel/modbus/ModBusDeviceForm.vue +++ b/src/views/data/channel/modbus/ModBusDeviceForm.vue @@ -77,11 +77,9 @@ </Dialog> </template> <script lang="ts" setup> - import { DICT_TYPE, getIntDictOptions } from '@/utils/dict' - import * as ModBusApi from '@/api/data/channel/modbus' - import { CommonStatusEnum } from '@/utils/constants' +import * as ModBusApi from '@/api/data/channel/modbus' - defineOptions({ name: 'DataModBusDeviceForm' }) +defineOptions({ name: 'DataModBusDeviceForm' }) const { t } = useI18n() // 国际化 const message = useMessage() // 消息弹窗 diff --git a/src/views/data/channel/modbus/index.vue b/src/views/data/channel/modbus/index.vue index c7247c0..27b491f 100644 --- a/src/views/data/channel/modbus/index.vue +++ b/src/views/data/channel/modbus/index.vue @@ -97,13 +97,10 @@ </template> <script lang="ts" setup> - import {DICT_TYPE, getIntDictOptions} from '@/utils/dict' - import {dateFormatter} from '@/utils/formatTime' - import download from '@/utils/download' - import * as ModbusApi from '@/api/data/channel/modbus' - import ModBusDeviceForm from './ModBusDeviceForm.vue' +import * as ModbusApi from '@/api/data/channel/modbus' +import ModBusDeviceForm from './ModBusDeviceForm.vue' - defineOptions({name: 'DataModbus'}) +defineOptions({name: 'DataModBus'}) const message = useMessage() // 消息弹窗 const {t} = useI18n() // 国际化 diff --git a/src/views/data/channel/opcda/OpcDaDeviceForm.vue b/src/views/data/channel/opcda/OpcDaDeviceForm.vue new file mode 100644 index 0000000..74de79c --- /dev/null +++ b/src/views/data/channel/opcda/OpcDaDeviceForm.vue @@ -0,0 +1,138 @@ +<template> + <Dialog v-model="dialogVisible" :title="dialogTitle" width="50%"> + <el-form + ref="formRef" + v-loading="formLoading" + :model="formData" + :rules="formRules" + label-width="120px" + > + <el-row> + <el-col :span="12"> + <el-form-item label="服务名" prop="serverName"> + <el-input v-model="formData.serverName" placeholder="请输入服务名"/> + </el-form-item> + </el-col> + <el-col :span="12"> + <el-form-item label="IP" prop="host"> + <el-input v-model="formData.host" placeholder="请输入IP"/> + </el-form-item> + </el-col> + </el-row> + <el-row> + <el-col :span="12"> + <el-form-item label="用户名" prop="user"> + <el-input v-model="formData.user" placeholder="请输入用户名"/> + </el-form-item> + </el-col> + <el-col :span="12"> + <el-form-item label="密码" prop="password"> + <el-input type = "password" v-model="formData.password" placeholder="请输入密码" /> + </el-form-item> + </el-col> + </el-row> + <el-row> + <el-col :span="12"> + <el-form-item label="设备名" prop="progId"> + <el-input v-model="formData.progId" placeholder="请输入设备名"/> + </el-form-item> + </el-col> + <el-col :span="12"> + <el-form-item label="设备注册表ID" prop="clsId"> + <el-input type="password" v-model="formData.clsId" placeholder="请输入设备注册表ID"/> + </el-form-item> + </el-col> + </el-row> + </el-form> + <template #footer> + <el-button :disabled="formLoading" type="primary" @click="submitForm">确 定</el-button> + <el-button @click="dialogVisible = false">取 消</el-button> + </template> + </Dialog> +</template> +<script lang="ts" setup> +import * as OpcDaApi from '@/api/data/channel/opcda' + +defineOptions({name: 'DataOpcDaDeviceForm'}) + +const {t} = useI18n() // 国际化 +const message = useMessage() // 消息弹窗 +const dialogVisible = ref(false) // 弹窗的是否展示 +const dialogTitle = ref('') // 弹窗的标题 +const formLoading = ref(false) // 表单的加载中:1)修改时的数据加载;2)提交的按钮禁用 +const formType = ref('') // 表单的类型:create - 新增;update - 修改 +const formData = ref({ + id: undefined, + serverName: undefined, + host: undefined, + user: undefined, + password: undefined, + progId: undefined, + clsId: undefined +}) +const formRules = reactive({ + serverName: [{required: true, message: '服务名不能为空', trigger: 'blur'}], + host: [{required: true, message: 'IP不能为空', trigger: 'blur'}], + user: [{required: true, message: '用户名不能为空', trigger: 'blur'}], + password: [{required: true, message: '密码不能为空', trigger: 'blur'}] +}) +const formRef = ref() // 表单 Ref + +/** 打开弹窗 */ +const open = async (type: string, id?: number) => { + dialogVisible.value = true + dialogTitle.value = t('action.' + type) + formType.value = type + resetForm() + // 修改时,设置数据 + if (id) { + formLoading.value = true + try { + formData.value = await OpcDaApi.getOpcDaDevice(id) + } finally { + formLoading.value = false + } + } +} +defineExpose({open}) // 提供 open 方法,用于打开弹窗 + +/** 提交表单 */ +const emit = defineEmits(['success']) // 定义 success 事件,用于操作成功后的回调 +const submitForm = async () => { + // 校验表单 + if (!formRef) return + const valid = await formRef.value.validate() + if (!valid) return + // 提交请求 + formLoading.value = true + try { + const data = formData.value as unknown as OpcDaApi.OpcDaDeviceVO + if (formType.value === 'create') { + await OpcDaApi.createOpcDaDevice(data) + message.success(t('common.createSuccess')) + } else { + await OpcDaApi.updateOpcDaDevice(data) + message.success(t('common.updateSuccess')) + } + dialogVisible.value = false + // 发送操作成功的事件 + emit('success') + } finally { + formLoading.value = false + } +} + +/** 重置表单 */ +const resetForm = () => { + formData.value = { + id: undefined, + serverName: undefined, + host: undefined, + user: undefined, + password: undefined, + progId: undefined, + clsId: undefined + } + formRef.value?.resetFields() +} +</script> diff --git a/src/views/data/channel/opcda/index.vue b/src/views/data/channel/opcda/index.vue new file mode 100644 index 0000000..d9b62fb --- /dev/null +++ b/src/views/data/channel/opcda/index.vue @@ -0,0 +1,152 @@ +<template> + <!-- 搜索 --> + <ContentWrap> + <el-form + class="-mb-15px" + :model="queryParams" + ref="queryFormRef" + :inline="true" + label-width="68px" + > + <el-form-item label="服务名" prop="serverName"> + <el-input + v-model="queryParams.serverName" + placeholder="请输入服务名" + clearable + @keyup.enter="handleQuery" + class="!w-240px" + /> + </el-form-item> + <el-form-item> + <el-button @click="handleQuery"> + <Icon icon="ep:search" class="mr-5px" /> + 搜索 + </el-button> + <el-button @click="resetQuery"> + <Icon icon="ep:refresh" class="mr-5px" /> + 重置 + </el-button> + <el-button + type="primary" + plain + @click="openForm('create')" + v-hasPermi="['system:tenant:create']" + > + <Icon icon="ep:plus" class="mr-5px" /> + 新增 + </el-button> + </el-form-item> + </el-form> + </ContentWrap> + + <!-- 列表 --> + <ContentWrap> + <el-table v-loading="loading" :data="list"> + <el-table-column label="服务名" align="center" prop="serverName" /> + <el-table-column label="IP" align="center" prop="host" /> + <el-table-column label="用户名" align="center" prop="user" /> + <el-table-column label="设备名" align="center" prop="progId" /> + <el-table-column label="设备注册表ID" align="center" prop="clsId" /> + <el-table-column label="操作" align="center" min-width="110" fixed="right"> + <template #default="scope"> + <el-button + link + type="primary" + @click="openForm('update', scope.row.id)" + v-hasPermi="['system:tenant:update']" + > + 编辑 + </el-button> + <el-button + link + type="danger" + @click="handleDelete(scope.row.id)" + v-hasPermi="['system:tenant:delete']" + > + 删除 + </el-button> + </template> + </el-table-column> + </el-table> + <!-- 分页 --> + <Pagination + :total="total" + v-model:page="queryParams.pageNo" + v-model:limit="queryParams.pageSize" + @pagination="getList" + /> + </ContentWrap> + + <!-- 表单弹窗:添加/修改 --> + <OpcDaDeviceForm ref="formRef" @success="getList" /> + +</template> +<script lang="ts" setup> +import * as OpcDaApi from '@/api/data/channel/opcda' +import OpcDaDeviceForm from './OpcDaDeviceForm.vue' + +defineOptions({name: 'DataOpcDa'}) + + const message = useMessage() // 消息弹窗 + const {t} = useI18n() // 国际化 + + const loading = ref(true) // 列表的加载中 + const total = ref(0) // 列表的总页数 + const list = ref([]) // 列表的数据 + const queryParams = reactive({ + pageNo: 1, + pageSize: 10, + serverName: undefined + }) + const queryFormRef = ref() // 搜索的表单 + const exportLoading = ref(false) // 导出的加载中 + + /** 查询列表 */ + const getList = async () => { + loading.value = true + try { + const page = await OpcDaApi.getOpcDaDevicePage(queryParams) + list.value = page.list + total.value = page.total + } finally { + loading.value = false + } + } + + /** 搜索按钮操作 */ + const handleQuery = () => { + queryParams.pageNo = 1 + getList() + } + + /** 重置按钮操作 */ + const resetQuery = () => { + queryFormRef.value.resetFields() + handleQuery() + } + + /** 添加/修改操作 */ + const formRef = ref() + const openForm = (type: string, id?: number) => { + formRef.value.open(type, id) + } + + /** 删除按钮操作 */ + const handleDelete = async (id: number) => { + try { + // 删除的二次确认 + await message.delConfirm() + // 发起删除 + await OpcDaApi.deleteOpcDaDevice(id) + message.success(t('common.delSuccess')) + // 刷新列表 + await getList() + } catch { + } + } + + /** 初始化 **/ + onMounted(async () => { + await getList() + }) +</script> diff --git a/src/views/data/channel/opcua/OpcUaDeviceForm.vue b/src/views/data/channel/opcua/OpcUaDeviceForm.vue new file mode 100644 index 0000000..981a395 --- /dev/null +++ b/src/views/data/channel/opcua/OpcUaDeviceForm.vue @@ -0,0 +1,167 @@ +<template> + <Dialog v-model="dialogVisible" :title="dialogTitle" width="50%"> + <el-form + ref="formRef" + v-loading="formLoading" + :model="formData" + :rules="formRules" + label-width="120px" + > + <el-row> + <el-col :span="12"> + <el-form-item label="服务名" prop="serverName"> + <el-input v-model="formData.serverName" placeholder="请输入服务名"/> + </el-form-item> + </el-col> + <el-col :span="12"> + <el-form-item label="端点URL" prop="endpointUrl"> + <el-input v-model="formData.endpointUrl" placeholder="请输入端点URL"/> + </el-form-item> + </el-col> + </el-row> + <el-row> + <el-col :span="12"> + <el-form-item label="安全策略" prop="securityPolicy"> + <el-input v-model="formData.securityPolicy" placeholder="请输入安全策略"/> + </el-form-item> + </el-col> + <el-col :span="12"> + <el-form-item label="安全模式" prop="securityMode"> + <el-input v-model="formData.securityMode" placeholder="请输入安全模式"/> + </el-form-item> + </el-col> + </el-row> + <el-row> + <el-col :span="12"> + <el-form-item label="连接方式" prop="connectionType"> + <el-input v-model="formData.connectionType" placeholder="请输入连接方式"/> + </el-form-item> + </el-col> + <el-col :span="12"> + <el-form-item label="用户名" prop="userName"> + <el-input v-model="formData.userName" placeholder="请输入用户名"/> + </el-form-item> + </el-col> + </el-row> + <el-row> + <el-col :span="12"> + <el-form-item label="密码" prop="password"> + <el-input type="password" v-model="formData.password" placeholder="请输入密码"/> + </el-form-item> + </el-col> + <el-col :span="12"> + <el-form-item label="安全证书路径" prop="certificatePath"> + <el-input v-model="formData.certificatePath" placeholder="请输入安全证书路径"/> + </el-form-item> + </el-col> + </el-row> + <el-row> + <el-col :span="12"> + <el-form-item label="连接方式" prop="connectInactivityTimeout"> + <el-input v-model="formData.connectInactivityTimeout" placeholder="请输入连接方式"/> + </el-form-item> + </el-col> + <el-col :span="12"> + <el-form-item label="重连超时" prop="reconnectInterval"> + <el-input v-model="formData.reconnectInterval" placeholder="请输入重连超时"/> + </el-form-item> + </el-col> + </el-row> + </el-form> + <template #footer> + <el-button :disabled="formLoading" type="primary" @click="submitForm">确 定</el-button> + <el-button @click="dialogVisible = false">取 消</el-button> + </template> + </Dialog> +</template> +<script lang="ts" setup> +import * as OpcUaApi from '@/api/data/channel/opcua' + +defineOptions({name: 'DataOpcUaDeviceForm'}) + +const {t} = useI18n() // 国际化 +const message = useMessage() // 消息弹窗 +const dialogVisible = ref(false) // 弹窗的是否展示 +const dialogTitle = ref('') // 弹窗的标题 +const formLoading = ref(false) // 表单的加载中:1)修改时的数据加载;2)提交的按钮禁用 +const formType = ref('') // 表单的类型:create - 新增;update - 修改 +const formData = ref({ + id: undefined, + serverName: undefined, + endpointUrl: undefined, + securityPolicy: undefined, + securityMode: undefined, + connectionType: undefined, + userName: undefined, + password: undefined, + certificatePath: undefined, + connectInactivityTimeout: undefined, + reconnectInterval: undefined, +}) +const formRules = reactive({ + serverName: [{required: true, message: '服务名不能为空', trigger: 'blur'}], +}) +const formRef = ref() // 表单 Ref + +/** 打开弹窗 */ +const open = async (type: string, id?: number) => { + dialogVisible.value = true + dialogTitle.value = t('action.' + type) + formType.value = type + resetForm() + // 修改时,设置数据 + if (id) { + formLoading.value = true + try { + formData.value = await OpcUaApi.getOpcUaDevice(id) + } finally { + formLoading.value = false + } + } +} +defineExpose({open}) // 提供 open 方法,用于打开弹窗 + +/** 提交表单 */ +const emit = defineEmits(['success']) // 定义 success 事件,用于操作成功后的回调 +const submitForm = async () => { + // 校验表单 + if (!formRef) return + const valid = await formRef.value.validate() + if (!valid) return + // 提交请求 + formLoading.value = true + try { + const data = formData.value as unknown as OpcUaApi.OpcUaDeviceVO + if (formType.value === 'create') { + await OpcUaApi.createOpcUaDevice(data) + message.success(t('common.createSuccess')) + } else { + await OpcUaApi.updateOpcUaDevice(data) + message.success(t('common.updateSuccess')) + } + dialogVisible.value = false + // 发送操作成功的事件 + emit('success') + } finally { + formLoading.value = false + } +} + +/** 重置表单 */ +const resetForm = () => { + formData.value = { + id: undefined, + serverName: undefined, + endpointUrl: undefined, + securityPolicy: undefined, + securityMode: undefined, + connectionType: undefined, + userName: undefined, + password: undefined, + certificatePath: undefined, + connectInactivityTimeout: undefined, + reconnectInterval: undefined, + } + formRef.value?.resetFields() +} +</script> diff --git a/src/views/data/channel/opcua/index.vue b/src/views/data/channel/opcua/index.vue new file mode 100644 index 0000000..a30307a --- /dev/null +++ b/src/views/data/channel/opcua/index.vue @@ -0,0 +1,157 @@ +<template> + <!-- 搜索 --> + <ContentWrap> + <el-form + class="-mb-15px" + :model="queryParams" + ref="queryFormRef" + :inline="true" + label-width="68px" + > + <el-form-item label="服务名" prop="serverName"> + <el-input + v-model="queryParams.serverName" + placeholder="请输入服务名" + clearable + @keyup.enter="handleQuery" + class="!w-240px" + /> + </el-form-item> + <el-form-item> + <el-button @click="handleQuery"> + <Icon icon="ep:search" class="mr-5px" /> + 搜索 + </el-button> + <el-button @click="resetQuery"> + <Icon icon="ep:refresh" class="mr-5px" /> + 重置 + </el-button> + <el-button + type="primary" + plain + @click="openForm('create')" + v-hasPermi="['system:tenant:create']" + > + <Icon icon="ep:plus" class="mr-5px" /> + 新增 + </el-button> + </el-form-item> + </el-form> + </ContentWrap> + + <!-- 列表 --> + <ContentWrap> + <el-table v-loading="loading" :data="list"> + <el-table-column label="服务名" align="center" prop="serverName" /> + <el-table-column label="端点URL" align="center" prop="endpointUrl" /> + <el-table-column label="安全策略" align="center" prop="securityPolicy" /> + <el-table-column label="安全模式" align="center" prop="securityMode" /> + <el-table-column label="连接方式" align="center" prop="connectionType" /> + <el-table-column label="用户名" align="center" prop="userName" /> + <el-table-column label="密码" align="center" prop="password" /> + <el-table-column label="安全证书路径" align="center" prop="certificatePath" /> + <el-table-column label="设备不活动超时时间" align="center" prop="connectInactivityTimeout" /> + <el-table-column label="重连超时" align="center" prop="reconnectInterval" /> + <el-table-column label="操作" align="center" min-width="110" fixed="right"> + <template #default="scope"> + <el-button + link + type="primary" + @click="openForm('update', scope.row.id)" + v-hasPermi="['system:tenant:update']" + > + 编辑 + </el-button> + <el-button + link + type="danger" + @click="handleDelete(scope.row.id)" + v-hasPermi="['system:tenant:delete']" + > + 删除 + </el-button> + </template> + </el-table-column> + </el-table> + <!-- 分页 --> + <Pagination + :total="total" + v-model:page="queryParams.pageNo" + v-model:limit="queryParams.pageSize" + @pagination="getList" + /> + </ContentWrap> + + <!-- 表单弹窗:添加/修改 --> + <OpcUaDeviceForm ref="formRef" @success="getList" /> + +</template> +<script lang="ts" setup> +import * as OpcUaApi from '@/api/data/channel/opcua' +import OpcUaDeviceForm from './OpcUaDeviceForm.vue' + +defineOptions({name: 'DataOpcUa'}) + + const message = useMessage() // 消息弹窗 + const {t} = useI18n() // 国际化 + + const loading = ref(true) // 列表的加载中 + const total = ref(0) // 列表的总页数 + const list = ref([]) // 列表的数据 + const queryParams = reactive({ + pageNo: 1, + pageSize: 10, + serverName: undefined + }) + const queryFormRef = ref() // 搜索的表单 + const exportLoading = ref(false) // 导出的加载中 + + /** 查询列表 */ + const getList = async () => { + loading.value = true + try { + const page = await OpcUaApi.getOpcUaDevicePage(queryParams) + list.value = page.list + total.value = page.total + } finally { + loading.value = false + } + } + + /** 搜索按钮操作 */ + const handleQuery = () => { + queryParams.pageNo = 1 + getList() + } + + /** 重置按钮操作 */ + const resetQuery = () => { + queryFormRef.value.resetFields() + handleQuery() + } + + /** 添加/修改操作 */ + const formRef = ref() + const openForm = (type: string, id?: number) => { + formRef.value.open(type, id) + } + + /** 删除按钮操作 */ + const handleDelete = async (id: number) => { + try { + // 删除的二次确认 + await message.delConfirm() + // 发起删除 + await OpcUaApi.deleteOpcUaDevice(id) + message.success(t('common.delSuccess')) + // 刷新列表 + await getList() + } catch { + } + } + + /** 初始化 **/ + onMounted(async () => { + await getList() + }) +</script> diff --git a/src/views/data/da/point/DaPointForm.vue b/src/views/data/da/point/DaPointForm.vue new file mode 100644 index 0000000..82282f2 --- /dev/null +++ b/src/views/data/da/point/DaPointForm.vue @@ -0,0 +1,202 @@ +<template> + <Dialog v-model="dialogVisible" :title="dialogTitle" width="50%"> + <el-form + ref="formRef" + v-loading="formLoading" + :model="formData" + :rules="formRules" + label-width="120px" + > + <el-row> + <el-col :span="12"> + <el-form-item label="测点编码" prop="pointNo"> + <el-input v-model="formData.pointNo" placeholder="请输入测点编码" /> + </el-form-item> + </el-col> + </el-row> + <el-row> + <el-col :span="12"> + <el-form-item label="测点名称" prop="pointName"> + <el-input v-model="formData.pointName" placeholder="请输入测点名称" /> + </el-form-item> + </el-col> + <el-col :span="12"> + <el-form-item label="测点类型" prop="pointType"> + <el-input v-model="formData.pointType" placeholder="请输入测点类型" /> + </el-form-item> + </el-col> + </el-row> + <el-row> + <el-col :span="12"> + <el-form-item label="数据类型" prop="dataType"> + <el-input v-model="formData.dataType" placeholder="请输入数据类型" /> + </el-form-item> + </el-col> + <el-col :span="12"> + <el-form-item label="值类型" prop="valueType"> + <el-input v-model="formData.valueType" placeholder="请输入值类型" /> + </el-form-item> + </el-col> + </el-row> + <el-row> + <el-col :span="12"> + <el-form-item label="存储类型" prop="storeType"> + <el-input v-model="formData.storeType" placeholder="请输入存储类型" /> + </el-form-item> + </el-col> + <el-col :span="12"> + <el-form-item label="测量单位" prop="unit"> + <el-input v-model="formData.unit" placeholder="请输入测量单位" /> + </el-form-item> + </el-col> + </el-row> + <el-row> + <el-col :span="12"> + <el-form-item label="单位转换" prop="unittransfactor"> + <el-input v-model="formData.unittransfactor" placeholder="请输入单位转换" /> + </el-form-item> + </el-col> + <el-col :span="12"> + <el-form-item label="默认值" prop="defaultValue"> + <el-input v-model="formData.defaultValue" placeholder="请输入默认值" /> + </el-form-item> + </el-col> + </el-row> + <el-row> + <el-col :span="12"> + <el-form-item label="最大值" prop="maxValue"> + <el-input v-model="formData.maxValue" placeholder="请输入最大值" /> + </el-form-item> + </el-col> + <el-col :span="12"> + <el-form-item label="最小值" prop="minValue"> + <el-input v-model="formData.minValue" placeholder="请输入最小值" /> + </el-form-item> + </el-col> + </el-row> + <el-row> + <el-col :span="12"> + <el-form-item label="采集频率" prop="minfreqid"> + <el-input v-model="formData.minfreqid" placeholder="请输入采集频率" /> + </el-form-item> + </el-col> + <el-col :span="12"> + <el-form-item label="备注" prop="remark"> + <el-input v-model="formData.remark" placeholder="请输入备注" /> + </el-form-item> + </el-col> + </el-row> + <el-row> + <el-col :span="12"> + <el-form-item label="是否启用" prop="isEnable"> + <el-input v-model="formData.isEnable" placeholder="请输入是否启用" /> + </el-form-item> + </el-col> + </el-row> + </el-form> + <template #footer> + <el-button :disabled="formLoading" type="primary" @click="submitForm">确 定</el-button> + <el-button @click="dialogVisible = false">取 消</el-button> + </template> + </Dialog> +</template> +<script lang="ts" setup> +import * as DaPoint from '@/api/data/da/point' + +defineOptions({ name: 'DataDaPointForm' }) + + const { t } = useI18n() // 国际化 + const message = useMessage() // 消息弹窗 + const dialogVisible = ref(false) // 弹窗的是否展示 + const dialogTitle = ref('') // 弹窗的标题 + const formLoading = ref(false) // 表单的加载中:1)修改时的数据加载;2)提交的按钮禁用 + const formType = ref('') // 表单的类型:create - 新增;update - 修改 + const formData = ref({ + id: undefined, + pointNo: undefined, + pointName: undefined, + pointType: undefined, + dataType: undefined, + valueType: undefined, + storeType: undefined, + unit: undefined, + unittransfactor: undefined, + defaultValue: undefined, + maxValue: undefined, + minValue: undefined, + minfreqid: undefined, + remark: undefined, + isEnable: undefined, + }) + const formRules = reactive({ + pointNo: [{ required: true, message: '测点编码不能为空', trigger: 'blur' }], + pointName: [{ required: true, message: '测点名称不能为空', trigger: 'blur' }], + }) + const formRef = ref() // 表单 Ref + + /** 打开弹窗 */ + const open = async (type: string, id?: number) => { + dialogVisible.value = true + dialogTitle.value = t('action.' + type) + formType.value = type + resetForm() + // 修改时,设置数据 + if (id) { + formLoading.value = true + try { + formData.value = await DaPoint.getDaPoint(id) + } finally { + formLoading.value = false + } + } + } + defineExpose({ open }) // 提供 open 方法,用于打开弹窗 + + /** 提交表单 */ + const emit = defineEmits(['success']) // 定义 success 事件,用于操作成功后的回调 + const submitForm = async () => { + // 校验表单 + if (!formRef) return + const valid = await formRef.value.validate() + if (!valid) return + // 提交请求 + formLoading.value = true + try { + const data = formData.value as unknown as DaPoint.DaPointVO + if (formType.value === 'create') { + await DaPoint.createDaPoint(data) + message.success(t('common.createSuccess')) + } else { + await DaPoint.updateDaPoint(data) + message.success(t('common.updateSuccess')) + } + dialogVisible.value = false + // 发送操作成功的事件 + emit('success') + } finally { + formLoading.value = false + } + } + + /** 重置表单 */ + const resetForm = () => { + formData.value = { + id: undefined, + pointNo: undefined, + pointName: undefined, + pointType: undefined, + dataType: undefined, + valueType: undefined, + storeType: undefined, + unit: undefined, + unittransfactor: undefined, + defaultValue: undefined, + maxValue: undefined, + minValue: undefined, + minfreqid: undefined, + remark: undefined, + isEnable: undefined, + } + formRef.value?.resetFields() + } +</script> diff --git a/src/views/data/da/point/index.vue b/src/views/data/da/point/index.vue new file mode 100644 index 0000000..42304ce --- /dev/null +++ b/src/views/data/da/point/index.vue @@ -0,0 +1,172 @@ +<template> + <!-- 搜索 --> + <ContentWrap> + <el-form + class="-mb-15px" + :model="queryParams" + ref="queryFormRef" + :inline="true" + label-width="68px" + > + <el-form-item label="测点编码" prop="pointNo"> + <el-input + v-model="queryParams.pointNo" + placeholder="请输入测点编码" + clearable + @keyup.enter="handleQuery" + class="!w-240px" + /> + </el-form-item> + <el-form-item label="测点名称" prop="pointName"> + <el-input + v-model="queryParams.pointName" + placeholder="请输入测点名称" + clearable + @keyup.enter="handleQuery" + class="!w-240px" + /> + </el-form-item> + <el-form-item> + <el-button @click="handleQuery"> + <Icon icon="ep:search" class="mr-5px" /> + 搜索 + </el-button> + <el-button @click="resetQuery"> + <Icon icon="ep:refresh" class="mr-5px" /> + 重置 + </el-button> + <el-button + type="primary" + plain + @click="openForm('create')" + v-hasPermi="['system:tenant:create']" + > + <Icon icon="ep:plus" class="mr-5px" /> + 新增 + </el-button> + </el-form-item> + </el-form> + </ContentWrap> + + <!-- 列表 --> + <ContentWrap> + <el-table v-loading="loading" :data="list"> + <el-table-column label="测点编码" align="center" prop="pointNo" /> + <el-table-column label="测点名称" align="center" prop="pointName" /> + <el-table-column label="测点类型" align="center" prop="pointType" /> + <el-table-column label="数据类型" align="center" prop="dataType" /> + <el-table-column label="值类型" align="center" prop="valueType" /> + <el-table-column label="存储类型" align="center" prop="storeType" /> + <el-table-column label="测量单位" align="center" prop="unit" /> + <el-table-column label="单位转换" align="center" prop="unittransfactor" /> + <el-table-column label="默认值" align="center" prop="defaultValue" /> + <el-table-column label="最大值" align="center" prop="maxValue" /> + <el-table-column label="最小值" align="center" prop="minValue" /> + <el-table-column label="采集频率" align="center" prop="minfreqid" /> + <el-table-column label="备注" align="center" prop="remark" /> + <el-table-column label="是否启用" align="center" prop="isEnable" /> + + <el-table-column label="操作" align="center" min-width="110" fixed="right"> + <template #default="scope"> + <el-button + link + type="primary" + @click="openForm('update', scope.row.id)" + v-hasPermi="['system:tenant:update']" + > + 编辑 + </el-button> + <el-button + link + type="danger" + @click="handleDelete(scope.row.id)" + v-hasPermi="['system:tenant:delete']" + > + 删除 + </el-button> + </template> + </el-table-column> + </el-table> + <!-- 分页 --> + <Pagination + :total="total" + v-model:page="queryParams.pageNo" + v-model:limit="queryParams.pageSize" + @pagination="getList" + /> + </ContentWrap> + + <!-- 表单弹窗:添加/修改 --> + <DaPointForm ref="formRef" @success="getList" /> + +</template> +<script lang="ts" setup> +import DaPointForm from './DaPointForm.vue' +import * as DaPoint from '@/api/data/da/point' + +defineOptions({name: 'DataDaPoint'}) + + const message = useMessage() // 消息弹窗 + const {t} = useI18n() // 国际化 + + const loading = ref(true) // 列表的加载中 + const total = ref(0) // 列表的总页数 + const list = ref([]) // 列表的数据 + const queryParams = reactive({ + pageNo: 1, + pageSize: 10, + pointNo: undefined, + pointName: undefined, + }) + const queryFormRef = ref() // 搜索的表单 + const exportLoading = ref(false) // 导出的加载中 + + /** 查询列表 */ + const getList = async () => { + loading.value = true + try { + const page = await DaPoint.getDaPointPage(queryParams) + list.value = page.list + total.value = page.total + } finally { + loading.value = false + } + } + + /** 搜索按钮操作 */ + const handleQuery = () => { + queryParams.pageNo = 1 + getList() + } + + /** 重置按钮操作 */ + const resetQuery = () => { + queryFormRef.value.resetFields() + handleQuery() + } + + /** 添加/修改操作 */ + const formRef = ref() + const openForm = (type: string, id?: number) => { + formRef.value.open(type, id) + } + + /** 删除按钮操作 */ + const handleDelete = async (id: number) => { + try { + // 删除的二次确认 + await message.delConfirm() + // 发起删除 + await DaPoint.deleteDaPoint(id) + message.success(t('common.delSuccess')) + // 刷新列表 + await getList() + } catch { + } + } + + /** 初始化 **/ + onMounted(async () => { + await getList() + }) +</script> diff --git a/src/views/data/ind/category/CategoryForm.vue b/src/views/data/ind/category/CategoryForm.vue new file mode 100644 index 0000000..d4bd86c --- /dev/null +++ b/src/views/data/ind/category/CategoryForm.vue @@ -0,0 +1,141 @@ +<template> + <Dialog v-model="dialogVisible" :title="dialogTitle"> + <el-form + ref="formRef" + v-loading="formLoading" + :model="formData" + :rules="formRules" + label-width="100px" + > + <el-form-item label="上级菜单"> + <el-tree-select + v-model="formData.pid" + :data="categoryTree" + :default-expanded-keys="[0]" + :props="categoryTreeProps" + check-strictly + node-key="id" + /> + </el-form-item> + <el-form-item label="分类名称" prop="label"> + <el-input v-model="formData.label" clearable placeholder="请输入分类名称" /> + </el-form-item> + <el-form-item label="显示排序" prop="sort"> + <el-input-number v-model="formData.sort" :min="0" clearable controls-position="right" /> + </el-form-item> + </el-form> + <template #footer> + <el-button :disabled="formLoading" type="primary" @click="submitForm">确 定</el-button> + <el-button @click="dialogVisible = false">取 消</el-button> + </template> + </Dialog> +</template> +<script lang="ts" setup> + import { DICT_TYPE, getIntDictOptions } from '@/utils/dict' + import * as CategoryApi from '@/api/data/ind/category' + import { CACHE_KEY, useCache } from '@/hooks/web/useCache' + import { CommonStatusEnum, SystemMenuTypeEnum } from '@/utils/constants' + import { defaultProps, handleTree } from '@/utils/tree' + + defineOptions({ name: 'IndItemCategoryForm' }) + + const { wsCache } = useCache() + const { t } = useI18n() // 国际化 + const message = useMessage() // 消息弹窗 + + const categoryTreeProps = ref({ + children: 'children', + label: 'label', + value: 'id', + isLeaf: 'leaf', + emitPath: false + }) + + const dialogVisible = ref(false) // 弹窗的是否展示 + const dialogTitle = ref('') // 弹窗的标题 + const formLoading = ref(false) // 表单的加载中:1)修改时的数据加载;2)提交的按钮禁用 + const formType = ref('') // 表单的类型:create - 新增;update - 修改 + const formData = ref({ + id: undefined, + label: '', + pid: '0', + sort: Number(undefined) + }) + const formRules = reactive({ + label: [{ required: true, message: '分类名称不能为空', trigger: 'blur' }], + sort: [{ required: true, message: '分类顺序不能为空', trigger: 'blur' }] + }) + const formRef = ref() // 表单 Ref + + /** 打开弹窗 */ + const open = async (type: string, id?: number, parentId?: number) => { + dialogVisible.value = true + dialogTitle.value = t('action.' + type) + formType.value = type + resetForm() + if (parentId) { + formData.value.parentId = parentId + } + // 修改时,设置数据 + if (id) { + formLoading.value = true + try { + formData.value = await CategoryApi.getCategory(id) + } finally { + formLoading.value = false + } + } + // 获得菜单列表 + await getTree() + } + defineExpose({ open }) // 提供 open 方法,用于打开弹窗 + + /** 提交表单 */ + const emit = defineEmits(['success']) // 定义 success 事件,用于操作成功后的回调 + const submitForm = async () => { + // 校验表单 + if (!formRef) return + const valid = await formRef.value.validate() + if (!valid) return + // 提交请求 + formLoading.value = true + try { + const data = formData.value as unknown as CategoryApi.IndItemCategoryVO + if (formType.value === 'create') { + await CategoryApi.createCategory(data) + message.success(t('common.createSuccess')) + } else { + await CategoryApi.updateCategory(data) + message.success(t('common.updateSuccess')) + } + dialogVisible.value = false + // 发送操作成功的事件 + emit('success') + } finally { + formLoading.value = false + // 清空,从而触发刷新 + wsCache.delete(CACHE_KEY.ROLE_ROUTERS) + } + } + + /** 获取下拉框[上级菜单]的数据 */ + const categoryTree = ref<Tree[]>([]) // 树形结构 + const getTree = async () => { + categoryTree.value = [] + const res = await CategoryApi.getCategoryListAllSimple() + let menu: Tree = { id: '0', label: '主类目', children: [] } + menu.children = handleTree(res, 'id', 'pid') + categoryTree.value.push(menu) + } + + /** 重置表单 */ + const resetForm = () => { + formData.value = { + id: undefined, + label: '', + pid: '0', + sort: Number(undefined) + } + formRef.value?.resetFields() + } +</script> diff --git a/src/views/data/ind/category/index.vue b/src/views/data/ind/category/index.vue new file mode 100644 index 0000000..951250c --- /dev/null +++ b/src/views/data/ind/category/index.vue @@ -0,0 +1,159 @@ +<template> + <!-- 搜索工作栏 --> + <ContentWrap> + <el-form + ref="queryFormRef" + :inline="true" + :model="queryParams" + class="-mb-15px" + label-width="68px" + > + <el-form-item label="分类名称" prop="name"> + <el-input + v-model="queryParams.label" + class="!w-240px" + clearable + placeholder="请输入分类名称" + @keyup.enter="handleQuery" + /> + </el-form-item> + <el-form-item> + <el-button @click="handleQuery"> + <Icon class="mr-5px" icon="ep:search" /> + 搜索 + </el-button> + <el-button @click="resetQuery"> + <Icon class="mr-5px" icon="ep:refresh" /> + 重置 + </el-button> + <el-button + v-hasPermi="['data:ind-item-category:create']" + plain + type="primary" + @click="openForm('create')" + > + <Icon class="mr-5px" icon="ep:plus" /> + 新增 + </el-button> + <el-button plain type="danger" @click="toggleExpandAll"> + <Icon class="mr-5px" icon="ep:sort" /> + 展开/折叠 + </el-button> + </el-form-item> + </el-form> + </ContentWrap> + + <!-- 列表 --> + <ContentWrap> + <el-table + v-if="refreshTable" + v-loading="loading" + :data="list" + :default-expand-all="isExpandAll" + row-key="id" + > + <el-table-column :show-overflow-tooltip="true" label="分类名称" prop="label" width="300" /> + <el-table-column label="排序" prop="sort" width="60" /> + <el-table-column align="center" label="操作"> + <template #default="scope"> + <el-button + v-hasPermi="['data:ind-item-category:update']" + link + type="primary" + @click="openForm('update', scope.row.id)" + > + 修改 + </el-button> + <el-button + v-hasPermi="['data:ind-item-category:delete']" + link + type="danger" + @click="handleDelete(scope.row.id)" + > + 删除 + </el-button> + </template> + </el-table-column> + </el-table> + </ContentWrap> + + <!-- 表单弹窗:添加/修改 --> + <CategoryForm ref="formRef" @success="getList" /> +</template> +<script lang="ts" setup> + import { DICT_TYPE, getIntDictOptions } from '@/utils/dict' + import { handleTree } from '@/utils/tree' + import * as CategoryApi from '@/api/data/ind/category' + import CategoryForm from './CategoryForm.vue' + import { CACHE_KEY, useCache } from '@/hooks/web/useCache' + + defineOptions({ name: 'IndItemCategory' }) + + const { wsCache } = useCache() + const { t } = useI18n() // 国际化 + const message = useMessage() // 消息弹窗 + + const loading = ref(true) // 列表的加载中 + const list = ref<any>([]) // 列表的数据 + const queryParams = reactive({ + label: undefined + }) + const queryFormRef = ref() // 搜索的表单 + const isExpandAll = ref(false) // 是否展开,默认全部折叠 + const refreshTable = ref(true) // 重新渲染表格状态 + + /** 查询列表 */ + const getList = async () => { + loading.value = true + try { + const data = await CategoryApi.getCategoryList(queryParams) + list.value = handleTree(data, 'id', 'pid') + } finally { + loading.value = false + } + } + + /** 搜索按钮操作 */ + const handleQuery = () => { + getList() + } + + /** 重置按钮操作 */ + const resetQuery = () => { + queryFormRef.value.resetFields() + handleQuery() + } + + /** 添加/修改操作 */ + const formRef = ref() + const openForm = (type: string, id?: number, parentId?: number) => { + formRef.value.open(type, id, parentId) + } + + /** 展开/折叠操作 */ + const toggleExpandAll = () => { + refreshTable.value = false + isExpandAll.value = !isExpandAll.value + nextTick(() => { + refreshTable.value = true + }) + } + + /** 删除按钮操作 */ + const handleDelete = async (id: number) => { + try { + // 删除的二次确认 + await message.delConfirm() + // 发起删除 + await CategoryApi.deleteCategory(id) + message.success(t('common.delSuccess')) + // 刷新列表 + await getList() + } catch {} + } + + /** 初始化 **/ + onMounted(() => { + getList() + }) +</script> diff --git a/src/views/data/ind/data/DataSetForm.vue b/src/views/data/ind/data/DataSetForm.vue new file mode 100644 index 0000000..132e25c --- /dev/null +++ b/src/views/data/ind/data/DataSetForm.vue @@ -0,0 +1,129 @@ +<template> + <Dialog v-model="dialogVisible" :title="dialogTitle"> + <el-form + ref="formRef" + v-loading="formLoading" + :model="formData" + :rules="formRules" + label-width="80px" + > + <el-form-item label="名称" prop="name"> + <el-input v-model="formData.name" placeholder="请输入名称" /> + </el-form-item> + <el-form-item label="数据源" prop="dataSource"> + <el-select v-model="formData.dataSource" clearable placeholder="请选择数据源"> + <el-option + v-for="item in dataSourceList" + :key="item.id" + :label="item.name" + :value="item.id + ''" + /> + </el-select> + </el-form-item> + <el-form-item label="查询语句" prop="querySql"> + <el-input v-model="formData.querySql" placeholder="请输入内容" type="textarea" maxlength="200" + show-word-limit spellcheck="false"/> + </el-form-item> + <el-form-item label="备注" prop="remark"> + <el-input v-model="formData.remark" placeholder="请输入内容" type="textarea" maxlength="100" + show-word-limit/> + </el-form-item> + </el-form> + <template #footer> + <el-button :disabled="formLoading" type="primary" @click="submitForm">确 定</el-button> + <el-button @click="dialogVisible = false">取 消</el-button> + </template> + </Dialog> +</template> +<script lang="ts" setup> + import { DICT_TYPE, getIntDictOptions } from '@/utils/dict' + import * as DataSetApi from '@/api/data/ind/data/data.set' + import { CommonStatusEnum } from '@/utils/constants' + import * as DataSourceConfigApi from "@/api/infra/dataSourceConfig"; + + defineOptions({ name: 'IndDataSetForm' }) + + const { t } = useI18n() // 国际化 + const message = useMessage() // 消息弹窗 + + const dialogVisible = ref(false) // 弹窗的是否展示 + const dialogTitle = ref('') // 弹窗的标题 + const formLoading = ref(false) // 表单的加载中:1)修改时的数据加载;2)提交的按钮禁用 + const formType = ref('') // 表单的类型:create - 新增;update - 修改 + const formData = ref({ + id: undefined, + name: '', + dataSource: '', + querySql: '', + remark: '' + }) + const formRules = reactive({ + name: [{ required: true, message: '名称不能为空', trigger: 'blur' }], + dataSource: [{ required: true, message: '数据源不能为空', trigger: 'blur' }], + querySql: [{ required: true, message: '查询语句不能为空', trigger: 'change' }] + }) + const formRef = ref() // 表单 Ref + const dataSourceList = ref([] as DataSourceConfigApi.DataSourceConfigVO[]) + + /** 打开弹窗 */ + const open = async (type: string, id?: number) => { + dialogVisible.value = true + dialogTitle.value = t('action.' + type) + formType.value = type + resetForm() + + // 加载数据源列表 + dataSourceList.value = await DataSourceConfigApi.getDataSourceConfigList() + + // 修改时,设置数据 + if (id) { + formLoading.value = true + try { + formData.value = await DataSetApi.getDataSet(id) + } finally { + formLoading.value = false + } + } + + + } + defineExpose({ open }) // 提供 open 方法,用于打开弹窗 + + /** 提交表单 */ + const emit = defineEmits(['success']) // 定义 success 事件,用于操作成功后的回调 + const submitForm = async () => { + // 校验表单 + if (!formRef) return + const valid = await formRef.value.validate() + if (!valid) return + // 提交请求 + formLoading.value = true + try { + const data = formData.value as DataSetApi.DataSetVO + if (formType.value === 'create') { + await DataSetApi.createDataSet(data) + message.success(t('common.createSuccess')) + } else { + await DataSetApi.updateDataSet(data) + message.success(t('common.updateSuccess')) + } + dialogVisible.value = false + // 发送操作成功的事件 + emit('success') + } finally { + formLoading.value = false + } + } + + /** 重置表单 */ + const resetForm = () => { + formData.value = { + id: undefined, + name: '', + dataSource: '', + querySql: '', + remark: '' + } + formRef.value?.resetFields() + } +</script> diff --git a/src/views/data/ind/data/field/DataSetFieldForm.vue b/src/views/data/ind/data/field/DataSetFieldForm.vue new file mode 100644 index 0000000..f2be8a6 --- /dev/null +++ b/src/views/data/ind/data/field/DataSetFieldForm.vue @@ -0,0 +1,124 @@ +<template> + <Dialog v-model="dialogVisible" :title="dialogTitle"> + <el-form + ref="formRef" + v-loading="formLoading" + :model="formData" + :rules="formRules" + label-width="80px" + > + <el-form-item label="英文名" prop="fieldCode"> + <el-input v-model="formData.fieldCode" placeholder="请输入英文名" /> + </el-form-item> + <el-form-item label="中文名" prop="fieldName"> + <el-input v-model="formData.fieldName" placeholder="请输入中文名" /> + </el-form-item> + <el-form-item label="数据类型" prop="fieldType"> + <el-select v-model="formData.fieldType" placeholder="请选择"> + <el-option + v-for="dict in getStrDictOptions(DICT_TYPE.DATA_FIELD_TYPE)" + :key="dict.value" + :label="dict.label" + :value="dict.value" + /> + </el-select> + </el-form-item> + <el-form-item label="显示排序" prop="sort"> + <el-input-number v-model="formData.sort" :min="0" controls-position="right" /> + </el-form-item> + </el-form> + <template #footer> + <el-button :disabled="formLoading" type="primary" @click="submitForm">确 定</el-button> + <el-button @click="dialogVisible = false">取 消</el-button> + </template> + </Dialog> +</template> +<script lang="ts" setup> + import { DICT_TYPE, getStrDictOptions } from '@/utils/dict' + import * as DataSetFieldApi from '@/api/data/ind/data/data.field' + import { CommonStatusEnum } from '@/utils/constants' + + defineOptions({ name: 'IndDataSetFieldForm' }) + + const { t } = useI18n() // 国际化 + const message = useMessage() // 消息弹窗 + + const dialogVisible = ref(false) // 弹窗的是否展示 + const dialogTitle = ref('') // 弹窗的标题 + const formLoading = ref(false) // 表单的加载中:1)修改时的数据加载;2)提交的按钮禁用 + const formType = ref('') // 表单的类型:create - 新增;update - 修改 + const formData = ref({ + id: undefined, + dataSetId: '', + fieldCode: '', + fieldName: '', + fieldType: '', + sort: undefined + }) + const formRules = reactive({ + fieldCode: [{ required: true, message: '数据标签不能为空', trigger: 'blur' }], + fieldName: [{ required: true, message: '数据键值不能为空', trigger: 'blur' }], + sort: [{ required: true, message: '数据顺序不能为空', trigger: 'blur' }] + }) + const formRef = ref() // 表单 Ref + + /** 打开弹窗 */ + const open = async (type: string, id?: number, dataSetId?: string) => { + dialogVisible.value = true + dialogTitle.value = t('action.' + type) + formType.value = type + resetForm() + if (dataSetId) { + formData.value.dataSetId = dataSetId + } + // 修改时,设置数据 + if (id) { + formLoading.value = true + try { + formData.value = await DataSetFieldApi.getDataSetField(id) + } finally { + formLoading.value = false + } + } + } + defineExpose({ open }) // 提供 open 方法,用于打开弹窗 + + /** 提交表单 */ + const emit = defineEmits(['success']) // 定义 success 事件,用于操作成功后的回调 + const submitForm = async () => { + // 校验表单 + if (!formRef) return + const valid = await formRef.value.validate() + if (!valid) return + // 提交请求 + formLoading.value = true + try { + const data = formData.value as DataSetFieldApi.DataSetFieldVO + if (formType.value === 'create') { + await DataSetFieldApi.createDataSetField(data) + message.success(t('common.createSuccess')) + } else { + await DataSetFieldApi.updateDataSetField(data) + message.success(t('common.updateSuccess')) + } + dialogVisible.value = false + // 发送操作成功的事件 + emit('success') + } finally { + formLoading.value = false + } + } + + /** 重置表单 */ + const resetForm = () => { + formData.value = { + id: undefined, + dataSetId: '', + fieldCode: '', + fieldName: '', + fieldType: '', + sort: undefined + } + formRef.value?.resetFields() + } +</script> diff --git a/src/views/data/ind/data/field/index.vue b/src/views/data/ind/data/field/index.vue new file mode 100644 index 0000000..429d0b8 --- /dev/null +++ b/src/views/data/ind/data/field/index.vue @@ -0,0 +1,155 @@ +<template> + <ContentWrap> + <el-form + class="-mb-15px" + :model="queryParams" + ref="queryFormRef" + :inline="true" + label-width="68px" + > + <el-form-item label="字典名称" prop="dataSetId"> + <el-select v-model="queryParams.dataSetId" class="!w-240px"> + <el-option + v-for="item in dictSetList" + :key="item.id" + :label="item.name" + :value="item.id" + /> + </el-select> + </el-form-item> + <el-form-item> + <el-button @click="handleQuery"><Icon icon="ep:search" class="mr-5px" /> 搜索</el-button> + <el-button @click="resetQuery"><Icon icon="ep:refresh" class="mr-5px" /> 重置</el-button> + <el-button + type="primary" + plain + @click="openForm('create')" + v-hasPermi="['data:ind-data-set:create']" + > + <Icon icon="ep:plus" class="mr-5px" /> 新增 + </el-button> + </el-form-item> + </el-form> + </ContentWrap> + + <!-- 列表 --> + <ContentWrap> + <el-table v-loading="loading" :data="list"> + <el-table-column label="英文名" header-align="center" align="left" prop="fieldCode" /> + <el-table-column label="中文名" header-align="center" align="left" prop="fieldName" /> + <el-table-column label="数据类型" align="center" prop="fieldType"> + <template #default="scope"> + <dict-tag :type="DICT_TYPE.DATA_FIELD_TYPE" :value="scope.row.fieldType" /> + </template> + </el-table-column> + <el-table-column label="排序" align="center" prop="sort" /> + <el-table-column label="操作" align="center"> + <template #default="scope"> + <el-button + link + type="primary" + @click="openForm('update', scope.row.id)" + v-hasPermi="['data:ind-data-set:update']" + > + 修改 + </el-button> + <el-button + link + type="danger" + @click="handleDelete(scope.row.id)" + v-hasPermi="['data:ind-data-set:delete']" + > + 删除 + </el-button> + </template> + </el-table-column> + </el-table> + <!-- 分页 --> + <Pagination + :total="total" + v-model:page="queryParams.pageNo" + v-model:limit="queryParams.pageSize" + @pagination="getList" + /> + </ContentWrap> + + <!-- 表单弹窗:添加/修改 --> + <DataSetFieldForm ref="formRef" @success="getList" /> +</template> +<script lang="ts" setup> +import { getIntDictOptions, DICT_TYPE } from '@/utils/dict' +import { dateFormatter } from '@/utils/formatTime' +import download from '@/utils/download' +import * as DataSetApi from '@/api/data/ind/data/data.set' +import * as DataSetFieldApi from '@/api/data/ind/data/data.field' +import DataSetFieldForm from './DataSetFieldForm.vue' + +defineOptions({ name: 'IndDataSetField' }) + +const message = useMessage() // 消息弹窗 +const { t } = useI18n() // 国际化 +const route = useRoute() // 路由 + +const loading = ref(true) // 列表的加载中 +const total = ref(0) // 列表的总页数 +const list = ref([]) // 列表的数据 +const queryParams = reactive({ + pageNo: 1, + pageSize: 10, + label: '', + dataSetId: route.params.dataSetId +}) +const queryFormRef = ref() // 搜索的表单 +const exportLoading = ref(false) // 导出的加载中 +const dictSetList = ref<DataSetApi.DataSetVO[]>() // 字典类型的列表 + +/** 查询列表 */ +const getList = async () => { + loading.value = true + try { + const data = await DataSetFieldApi.getDataSetFieldPage(queryParams) + list.value = data.list + total.value = data.total + } finally { + loading.value = false + } +} + +/** 搜索按钮操作 */ +const handleQuery = () => { + queryParams.pageNo = 1 + getList() +} + +/** 重置按钮操作 */ +const resetQuery = () => { + queryFormRef.value.resetFields() + handleQuery() +} + +/** 添加/修改操作 */ +const formRef = ref() +const openForm = (type: string, id?: number) => { + formRef.value.open(type, id, queryParams.dataSetId) +} + +/** 删除按钮操作 */ +const handleDelete = async (id: number) => { + try { + // 删除的二次确认 + await message.delConfirm() + // 发起删除 + await DataSetFieldApi.deleteDataSetField(id) + message.success(t('common.delSuccess')) + // 刷新列表 + await getList() + } catch {} +} + +/** 初始化 **/ +onMounted(async () => { + await getList() + // 查询字典(精简)列表 + dictSetList.value = await DataSetApi.getDataSetList() +}) +</script> diff --git a/src/views/data/ind/data/index.vue b/src/views/data/ind/data/index.vue new file mode 100644 index 0000000..3421ae4 --- /dev/null +++ b/src/views/data/ind/data/index.vue @@ -0,0 +1,161 @@ +<template> + <!-- 搜索工作栏 --> + <ContentWrap> + <el-form + ref="queryFormRef" + :inline="true" + :model="queryParams" + class="-mb-15px" + label-width="68px" + > + <el-form-item label="名称" prop="name"> + <el-input + v-model="queryParams.name" + class="!w-240px" + clearable + placeholder="请输入名称" + @keyup.enter="handleQuery" + /> + </el-form-item> + <el-form-item> + <el-button @click="handleQuery"> + <Icon class="mr-5px" icon="ep:search" /> + 搜索 + </el-button> + <el-button @click="resetQuery"> + <Icon class="mr-5px" icon="ep:refresh" /> + 重置 + </el-button> + <el-button + v-hasPermi="['data:ind-data-set:create']" + plain + type="primary" + @click="openForm('create')" + > + <Icon class="mr-5px" icon="ep:plus" /> + 新增 + </el-button> + </el-form-item> + </el-form> + </ContentWrap> + + <!-- 列表 --> + <ContentWrap> + <el-table v-loading="loading" :data="list"> + <el-table-column align="center" label="名称" prop="name" show-overflow-tooltip /> + <el-table-column align="center" label="备注" prop="remark" /> + <el-table-column + :formatter="dateFormatter" + align="center" + label="创建时间" + prop="createTime" + width="180" + /> + <el-table-column align="center" label="操作"> + <template #default="scope"> + <el-button + v-hasPermi="['data:ind-data-set:update']" + link + type="primary" + @click="openForm('update', scope.row.id)" + > + 修改 + </el-button> + <router-link :to="'/ind/data/field/' + scope.row.id"> + <el-button link type="primary">字段</el-button> + </router-link> + <el-button + v-hasPermi="['data:ind-data-set:delete']" + link + type="danger" + @click="handleDelete(scope.row.id)" + > + 删除 + </el-button> + </template> + </el-table-column> + </el-table> + <!-- 分页 --> + <Pagination + v-model:limit="queryParams.pageSize" + v-model:page="queryParams.pageNo" + :total="total" + @pagination="getList" + /> + </ContentWrap> + + <!-- 表单弹窗:添加/修改 --> + <DataSetForm ref="formRef" @success="getList" /> +</template> + +<script lang="ts" setup> + import { DICT_TYPE, getIntDictOptions } from '@/utils/dict' + import { dateFormatter } from '@/utils/formatTime' + import * as DataSetApi from '@/api/data/ind/data/data.set' + import DataSetForm from './DataSetForm.vue' + import download from '@/utils/download' + + defineOptions({ name: 'IndDataSet' }) + + const message = useMessage() // 消息弹窗 + const { t } = useI18n() // 国际化 + + const loading = ref(true) // 列表的加载中 + const total = ref(0) // 列表的总页数 + const list = ref([]) // 字典表格数据 + const queryParams = reactive({ + pageNo: 1, + pageSize: 10, + name: '' + }) + const queryFormRef = ref() // 搜索的表单 + const exportLoading = ref(false) // 导出的加载中 + + /** 查询字典类型列表 */ + const getList = async () => { + loading.value = true + try { + const data = await DataSetApi.getDataSetPage(queryParams) + list.value = data.list + total.value = data.total + } finally { + loading.value = false + } + } + + /** 搜索按钮操作 */ + const handleQuery = () => { + queryParams.pageNo = 1 + getList() + } + + /** 重置按钮操作 */ + const resetQuery = () => { + queryFormRef.value.resetFields() + handleQuery() + } + + /** 添加/修改操作 */ + const formRef = ref() + const openForm = (type: string, id?: number) => { + formRef.value.open(type, id) + } + + /** 删除按钮操作 */ + const handleDelete = async (id: number) => { + try { + // 删除的二次确认 + await message.delConfirm() + // 发起删除 + await DataSetApi.deleteDataSet(id) + message.success(t('common.delSuccess')) + // 刷新列表 + await getList() + } catch {} + } + + /** 初始化 **/ + onMounted(() => { + getList() + }) +</script> diff --git a/src/views/model/mcs/sche/model/ScheduleModelForm.vue b/src/views/model/mcs/sche/model/ScheduleModelForm.vue new file mode 100644 index 0000000..19518d5 --- /dev/null +++ b/src/views/model/mcs/sche/model/ScheduleModelForm.vue @@ -0,0 +1,400 @@ +<template> + <Dialog v-model="dialogVisible" :title="dialogTitle" width="60%"> + <el-form + ref="formRef" + v-loading="formLoading" + :model="formData" + :rules="formRules" + label-width="120px" + > + <el-row> + <el-col :span="12"> + <el-form-item label="模型编号" prop="modelCode"> + <el-input v-model="formData.modelCode" placeholder="请输入模型编号" /> + </el-form-item> + </el-col> + <el-col :span="12"> + <el-form-item label="模型名称" prop="modelName"> + <el-input v-model="formData.modelName" placeholder="请输入模型名称" /> + </el-form-item> + </el-col> + </el-row> + <el-row> + <el-col :span="12"> + <el-form-item label="模型类型" prop="modelType"> + <el-select v-model="formData.modelType" placeholder="请选择"> + <el-option + v-for="dict in getStrDictOptions(DICT_TYPE.SCHE_MODEL_TYPE)" + :key="dict.value" + :label="dict.label" + :value="dict.value" + /> + </el-select> + </el-form-item> + </el-col> + <el-col :span="12"> + <el-form-item label="调用方式" prop="invocation"> + <el-select v-model="formData.invocation" placeholder="请选择"> + <el-option + v-for="dict in getStrDictOptions(DICT_TYPE.SCHE_MODEL_INVOCATION)" + :key="dict.value" + :label="dict.label" + :value="dict.value" + /> + </el-select> + </el-form-item> + </el-col> + </el-row> + <el-row> + <el-col :span="24"> + <el-form-item label="类名" prop="className"> + <el-input v-model="formData.className" placeholder="请输入类名 " /> + </el-form-item> + </el-col> + </el-row> + <el-row> + <el-col :span="12"> + <el-form-item label="方法名" prop="methodName"> + <el-input v-model="formData.methodName" placeholder="请输入方法名 " /> + </el-form-item> + </el-col> + <el-col :span="12"> + <el-form-item label="参数数量" prop="portLength"> + <el-input-number v-model="formData.portLength" :min="0" controls-position="right" /> + </el-form-item> + </el-col> + </el-row> + <el-row> + <el-col :span="24"> + <el-form-item label="参数构造" prop="paramStructure"> + <el-input v-model="formData.paramStructure" placeholder="请输入参数构造 " /> + </el-form-item> + </el-col> + </el-row> + <el-row> + <el-col :span="24"> + <el-form-item label="模型路径" prop="modelPath"> + <el-input v-model="formData.modelPath" placeholder="模型路径" /> + </el-form-item> + </el-col> + </el-row> + <el-divider content-position="left">输入参数</el-divider> + <el-table + :data="formData.paramList" + border + style="width: 100%; margin-top: 5px;"> + <el-table-column + prop="" + label="端口" + width="100" + align="center"> + <template #default="scope"> + <el-input size="mini" v-model="scope.row.modelparamportorder" maxlength="5" clearable + style="width:100%; hight:100%"/> + </template> + </el-table-column> + <el-table-column + prop="" + label="序号" + width="100" + align="center"> + <template #default="scope"> + <el-input size="mini" v-model="scope.row.modelparamorder" maxlength="5" clearable + style="width:100%;hight:100%"/> + </template> + </el-table-column> + <el-table-column + prop="" + label="类型" + width="150" + align="center"> + <template #default="scope"> + <el-select v-model="scope.row.modelparamtype" placeholder="请选择"> + <el-option + v-for="dict in getStrDictOptions(DICT_TYPE.MODEL_PARAM_TYPE)" + :key="dict.value" + :label="dict.label" + :value="dict.value" + /> + </el-select> + </template> + </el-table-column> + <el-table-column + prop="" + label="参数名称" + align="center"> + <template #default="scope"> + <el-select + size="mini" + v-model="scope.row.modelparamid" + filterable + placeholder="请选择"> + <el-option + v-for="(item, index) in modelparamListMap['k']" + :key="index" + :label="item.name" + :value="item.id" + :disabled="!(item.type === scope.row.modelparamtype)"/> + </el-select> + </template> + </el-table-column> + <el-table-column + prop="" + label="参数长度" + width="120" + align="center"> + <template #default="scope"> + <el-input size="mini" v-model="scope.row.datalength" maxlength="50" clearable + style="width:100%;hight:100%"/> + </template> + </el-table-column> + <el-table-column + prop="" + label="操作" + width="100" + align="center"> + <template #default="scope"> + <el-button + link + @click.prevent="addRow(scope.$index, formData.paramList)" + type="primary" + size="small"> + 添加 + </el-button> + <el-button + link + @click.prevent="deleteRow(scope.$index, formData.paramList)" + type="primary" + size="small"> + 删除 + </el-button> + </template> + </el-table-column> + </el-table> + + <el-divider content-position="left">设置参数</el-divider> + <el-table + :data="formData.settingList" + border + style="width: 100%; margin-top: 5px;"> + <el-table-column + prop="" + label="键" + align="center"> + <template #default="scope"> + <el-input size="mini" v-model="scope.row.key" maxlength="256" clearable + style="width:100%;hight:100%"/> + </template> + </el-table-column> + <el-table-column + prop="" + label="名称" + align="center"> + <template #default="scope"> + <el-input size="mini" v-model="scope.row.name" maxlength="256" clearable + style="width:100%;hight:100%"/> + </template> + </el-table-column> + <el-table-column + prop="" + label="类型" + align="center"> + <template #default="scope"> + <el-input size="mini" v-model="scope.row.valuetype" maxlength="256" clearable + style="width:100%;hight:100%"/> + </template> + </el-table-column> + <el-table-column + prop="" + label="值" + align="center"> + <template #default="scope"> + <el-input size="mini" v-model="scope.row.value" maxlength="256" clearable + style="width:100%;hight:100%"/> + </template> + </el-table-column> + <el-table-column + prop="" + label="操作" + width="100" + align="center"> + <template #default="scope"> + <el-button + @click.prevent="addRow(scope.$index, formData.settingList)" + link + type="primary" + size="small"> + 添加 + </el-button> + <el-button + @click.prevent="deleteRow(scope.$index, formData.settingList)" + link + type="primary" + size="small"> + 删除 + </el-button> + </template> + </el-table-column> + </el-table> + </el-form> + <template #footer> + <el-button :disabled="formLoading" type="primary" @click="submitForm">确 定</el-button> + <el-button @click="dialogVisible = false">取 消</el-button> + </template> + </Dialog> +</template> +<script lang="ts" setup> + import { DICT_TYPE, getStrDictOptions } from '@/utils/dict' + import * as ScheduleModelApi from '@/api/model/sche/model' + import { CommonStatusEnum } from '@/utils/constants' + + defineOptions({ name: 'ScheduleModelForm' }) + + const { t } = useI18n() // 国际化 + const message = useMessage() // 消息弹窗 + const dialogVisible = ref(false) // 弹窗的是否展示 + const dialogTitle = ref('') // 弹窗的标题 + const formLoading = ref(false) // 表单的加载中:1)修改时的数据加载;2)提交的按钮禁用 + const formType = ref('') // 表单的类型:create - 新增;update - 修改 + const formData = ref({ + id: undefined, + modelCode: undefined, + modelName: undefined, + modelType: undefined, + className: undefined, + methodName: undefined, + portLength: undefined, + paramStructure: undefined, + modelPath: undefined, + resultStrId: undefined, + invocation: undefined, + status: CommonStatusEnum.ENABLE, + paramList: [{ + modelparamportorder: '1', + modelparamorder: '1', + modelparamtype: '', + modelparamid: '', + datalength: '' + }], + settingList: [{ + key: '', + value: '', + valuetype: '', + name: '' + }] + }) + const formRules = reactive({ + modelCode: [{ required: true, message: '模型编号不能为空', trigger: 'blur' }], + modelName: [{ required: true, message: '模型名称不能为空', trigger: 'blur' }], + modelType: [{ required: true, message: '模型类型不能为空', trigger: 'blur' }] + }) + const formRef = ref() // 表单 Ref + const modelparamListMap = ref({}) + + const addRow = function (index, rows) { + let row = JSON.parse(JSON.stringify(rows[index])) + rows.splice(index, 0, row) + this.orderRow(rows) + } + + const deleteRow = function (index, rows) { + if (!rows || rows.length === 1) { + message.error('不能全部删除!') + return + } + rows.splice(index, 1) + this.orderRow(rows) + } + + const orderRow = function (rows) { + let modelparamorder = 0 + let modelparamportorder = 0 + rows.forEach(function (value) { + if (value.modelparamportorder !== modelparamportorder) { + modelparamportorder = value.modelparamportorder + modelparamorder = 1 + } + value.modelparamorder = modelparamorder + modelparamorder++ + }) + } + + /** 打开弹窗 */ + const open = async (type: string, id?: number) => { + dialogVisible.value = true + dialogTitle.value = t('action.' + type) + formType.value = type + resetForm() + // 修改时,设置数据 + if (id) { + formLoading.value = true + try { + formData.value = await ScheduleModelApi.getScheduleModel(id) + } finally { + formLoading.value = false + } + + // 加载数据源列表 + await ScheduleModelApi.getModelParamList(modelparamListMap) + } + } + defineExpose({ open }) // 提供 open 方法,用于打开弹窗 + + /** 提交表单 */ + const emit = defineEmits(['success']) // 定义 success 事件,用于操作成功后的回调 + const submitForm = async () => { + // 校验表单 + if (!formRef) return + const valid = await formRef.value.validate() + if (!valid) return + // 提交请求 + formLoading.value = true + try { + const data = formData.value as unknown as ScheduleModelApi.ScheduleModelVO + if (formType.value === 'create') { + await ScheduleModelApi.createScheduleModel(data) + message.success(t('common.createSuccess')) + } else { + await ScheduleModelApi.updateScheduleModel(data) + message.success(t('common.updateSuccess')) + } + dialogVisible.value = false + // 发送操作成功的事件 + emit('success') + } finally { + formLoading.value = false + } + } + + /** 重置表单 */ + const resetForm = () => { + formData.value = { + id: undefined, + modelCode: undefined, + modelName: undefined, + modelType: undefined, + className: undefined, + methodName: undefined, + portLength: undefined, + paramStructure: undefined, + modelPath: undefined, + resultStrId: undefined, + invocation: undefined, + status: CommonStatusEnum.ENABLE, + paramList: [{ + modelparamportorder: '1', + modelparamorder: '1', + modelparamtype: '', + modelparamid: '', + datalength: '' + }], + settingList: [{ + key: '', + value: '', + valuetype: '', + name: '' + }] + } + formRef.value?.resetFields() + } +</script> diff --git a/src/views/model/mcs/sche/model/index.vue b/src/views/model/mcs/sche/model/index.vue new file mode 100644 index 0000000..8d888a6 --- /dev/null +++ b/src/views/model/mcs/sche/model/index.vue @@ -0,0 +1,172 @@ +<template> + <!-- 搜索 --> + <ContentWrap> + <el-form + class="-mb-15px" + :model="queryParams" + ref="queryFormRef" + :inline="true" + label-width="68px" + > + <el-form-item label="模型编号" prop="modelCode"> + <el-input + v-model="queryParams.modelCode" + placeholder="请输入模型编号" + clearable + @keyup.enter="handleQuery" + class="!w-240px" + /> + </el-form-item> + <el-form-item label="模型名称" prop="modelName"> + <el-input + v-model="queryParams.modelName" + placeholder="请输入模型名称" + clearable + @keyup.enter="handleQuery" + class="!w-240px" + /> + </el-form-item> + <el-form-item> + <el-button @click="handleQuery"> + <Icon icon="ep:search" class="mr-5px" /> + 搜索 + </el-button> + <el-button @click="resetQuery"> + <Icon icon="ep:refresh" class="mr-5px" /> + 重置 + </el-button> + <el-button + type="primary" + plain + @click="openForm('create')" + v-hasPermi="['sche:model:create']" + > + <Icon icon="ep:plus" class="mr-5px" /> + 新增 + </el-button> + </el-form-item> + </el-form> + </ContentWrap> + + <!-- 列表 --> + <ContentWrap> + <el-table v-loading="loading" :data="list"> + <el-table-column label="模型编号" align="center" prop="modelCode" min-width="100"/> + <el-table-column label="模型名称" align="center" prop="modelName" min-width="100"/> + <el-table-column label="模型类型" align="center" prop="modelType" min-width="100"/> + <el-table-column label="类名" align="center" prop="className" min-width="200"/> + <el-table-column label="方法名" align="center" prop="methodName" min-width="100"/> + <el-table-column label="参数数量" align="center" prop="portLength" min-width="100"/> + <el-table-column label="参数构造" align="center" prop="paramStructure" min-width="200" /> + <el-table-column label="调用方式" align="center" prop="invocation" min-width="100"> + <template #default="scope"> + <dict-tag :type="DICT_TYPE.SCHE_MODEL_INVOCATION" :value="scope.row.invocation" /> + </template> + </el-table-column> + <el-table-column label="操作" align="center" min-width="100" fixed="right"> + <template #default="scope"> + <el-button + link + type="primary" + @click="openForm('update', scope.row.id)" + v-hasPermi="['sche:model:update']" + > + 编辑 + </el-button> + <el-button + link + type="danger" + @click="handleDelete(scope.row.id)" + v-hasPermi="['sche:model:delete']" + > + 删除 + </el-button> + </template> + </el-table-column> + </el-table> + <!-- 分页 --> + <Pagination + :total="total" + v-model:page="queryParams.pageNo" + v-model:limit="queryParams.pageSize" + @pagination="getList" + /> + </ContentWrap> + + <!-- 表单弹窗:添加/修改 --> + <ScheduleModelForm ref="formRef" @success="getList" /> + +</template> +<script lang="ts" setup> + import {DICT_TYPE, getIntDictOptions} from '@/utils/dict' + import {dateFormatter} from '@/utils/formatTime' + import download from '@/utils/download' + import * as ScheduleModelApi from '@/api/model/sche/model' + import ScheduleModelForm from './ScheduleModelForm.vue' + + defineOptions({name: 'ScheduleModel'}) + + const message = useMessage() // 消息弹窗 + const {t} = useI18n() // 国际化 + + const loading = ref(true) // 列表的加载中 + const total = ref(0) // 列表的总页数 + const list = ref([]) // 列表的数据 + const queryParams = reactive({ + pageNo: 1, + pageSize: 10, + modelCode: undefined, + modelName: undefined + }) + const queryFormRef = ref() // 搜索的表单 + const exportLoading = ref(false) // 导出的加载中 + + /** 查询列表 */ + const getList = async () => { + loading.value = true + try { + const page = await ScheduleModelApi.getScheduleModelPage(queryParams) + list.value = page.list + total.value = page.total + } finally { + loading.value = false + } + } + + /** 搜索按钮操作 */ + const handleQuery = () => { + queryParams.pageNo = 1 + getList() + } + + /** 重置按钮操作 */ + const resetQuery = () => { + queryFormRef.value.resetFields() + handleQuery() + } + + /** 添加/修改操作 */ + const formRef = ref() + const openForm = (type: string, id?: number) => { + formRef.value.open(type, id) + } + + /** 删除按钮操作 */ + const handleDelete = async (id: number) => { + try { + // 删除的二次确认 + await message.delConfirm() + // 发起删除 + await ScheduleModelApi.deleteScheduleModel(id) + message.success(t('common.delSuccess')) + // 刷新列表 + await getList() + } catch { + } + } + + /** 初始化 **/ + onMounted(async () => { + await getList() + }) +</script> diff --git a/src/views/model/mcs/sche/scheme/ScheduleSchemeForm.vue b/src/views/model/mcs/sche/scheme/ScheduleSchemeForm.vue new file mode 100644 index 0000000..f7c0b44 --- /dev/null +++ b/src/views/model/mcs/sche/scheme/ScheduleSchemeForm.vue @@ -0,0 +1,215 @@ +<template> + <Dialog v-model="dialogVisible" :title="dialogTitle" width="50%"> + <el-form + ref="formRef" + v-loading="formLoading" + :model="formData" + :rules="formRules" + label-width="120px" + > + <el-row> + <el-col :span="12"> + <el-form-item label="方案编号" prop="code"> + <el-input v-model="formData.code" placeholder="请输入方案编号" /> + </el-form-item> + </el-col> + <el-col :span="12"> + <el-form-item label="方案名称" prop="name"> + <el-input v-model="formData.name" placeholder="请输入方案名称" /> + </el-form-item> + </el-col> + </el-row> + <el-row> + <el-col :span="12"> + <el-form-item label="触发方式" prop="triggerMethod"> + <el-select v-model="formData.triggerMethod" placeholder="请选择"> + <el-option + v-for="dict in getIntDictOptions(DICT_TYPE.SCHE_TRIGGER_METHOD)" + :key="dict.value" + :label="dict.label" + :value="dict.value" + /> + </el-select> + </el-form-item> + </el-col> + <el-col :span="12"> + <el-form-item label="触发条件" prop="triggerCondition"> + <el-input v-model="formData.triggerCondition" placeholder="请输入触发条件" /> + </el-form-item> + </el-col> + </el-row> + <el-row> + <el-col :span="12"> + <el-form-item label="调整对象" prop="scheduleObj"> + <el-input v-model="formData.scheduleObj" placeholder="请输入调整对象" /> + </el-form-item> + </el-col> + <el-col :span="12"> + <el-form-item label="调整类型" prop="scheduleType"> + <el-input v-model="formData.scheduleType" placeholder="请输入调整类型" /> + </el-form-item> + </el-col> + </el-row> + <el-row> + <el-col :span="12"> + <el-form-item label="调整策略" prop="scheduleStrategy"> + <el-input v-model="formData.scheduleStrategy" placeholder="请输入调整策略 " /> + </el-form-item> + </el-col> + <el-col :span="12"> + <el-form-item label="调度模型" prop="modelId"> + <el-select v-model="formData.modelId" clearable placeholder="请选择调度模型"> + <el-option + v-for="item in scheduleModelList" + :key="item.id" + :label="item.modelName" + :value="item.id" + /> + </el-select> + + </el-form-item> + </el-col> + </el-row> + <el-row> + <el-col :span="24"> + <el-form-item label="备注" prop="remark"> + <el-input v-model="formData.remark" placeholder="请输入备注" type="textarea" maxlength="100" + show-word-limit/> + </el-form-item> + </el-col> + </el-row> + </el-form> + <template #footer> + <el-button :disabled="formLoading" type="primary" @click="submitForm">确 定</el-button> + <el-button @click="dialogVisible = false">取 消</el-button> + </template> + </Dialog> +</template> +<script lang="ts" setup> + import { DICT_TYPE, getIntDictOptions } from '@/utils/dict' + import * as ScheduleSchemeApi from '@/api/model/sche/scheme' + import { CommonStatusEnum } from '@/utils/constants' + import * as ScheduleModelApi from "@/api/model/sche/model"; + + defineOptions({ name: 'ScheduleSchemeForm' }) + + const { t } = useI18n() // 国际化 + const message = useMessage() // 消息弹窗 + const dialogVisible = ref(false) // 弹窗的是否展示 + const dialogTitle = ref('') // 弹窗的标题 + const formLoading = ref(false) // 表单的加载中:1)修改时的数据加载;2)提交的按钮禁用 + const formType = ref('') // 表单的类型:create - 新增;update - 修改 + const formData = ref({ + id: undefined, + code: undefined, + name: undefined, + triggerMethod: undefined, + triggerCondition: undefined, + scheduleObj: undefined, + scheduleType: undefined, + scheduleStrategy: undefined, + modelId: undefined, + scheduleTime: undefined, + remark: undefined, + status: 0 + }) + const formRules = reactive({ + code: [{ required: true, message: '编号不能为空', trigger: 'blur' }], + name: [{ required: true, message: '名称不能为空', trigger: 'blur' }] + }) + const formRef = ref() // 表单 Ref + const scheduleModelList = ref([] as ScheduleModelApi.ScheduleModelVO[]) + + const addRow = function (index, rows) { + let row = JSON.parse(JSON.stringify(rows[index])) + rows.splice(index, 0, row) + this.orderRow(rows) + } + + const deleteRow = function (index, rows) { + if (!rows || rows.length === 1) { + message.error('不能全部删除!') + return + } + rows.splice(index, 1) + this.orderRow(rows) + } + + const orderRow = function (rows) { + let modelparamorder = 0 + let modelparamportorder = 0 + rows.forEach(function (value) { + if (value.modelparamportorder !== modelparamportorder) { + modelparamportorder = value.modelparamportorder + modelparamorder = 1 + } + value.modelparamorder = modelparamorder + modelparamorder++ + }) + } + + /** 打开弹窗 */ + const open = async (type: string, id?: number) => { + dialogVisible.value = true + dialogTitle.value = t('action.' + type) + formType.value = type + resetForm() + // 修改时,设置数据 + if (id) { + formLoading.value = true + try { + formData.value = await ScheduleSchemeApi.getScheduleScheme(id) + } finally { + formLoading.value = false + } + } + // 加载调度模型列表 + scheduleModelList.value = await ScheduleModelApi.getScheduleModelList() + } + defineExpose({ open }) // 提供 open 方法,用于打开弹窗 + + /** 提交表单 */ + const emit = defineEmits(['success']) // 定义 success 事件,用于操作成功后的回调 + const submitForm = async () => { + // 校验表单 + if (!formRef) return + const valid = await formRef.value.validate() + if (!valid) return + // 提交请求 + formLoading.value = true + try { + const data = formData.value as unknown as ScheduleSchemeApi.ScheduleSchemeVO + if (formType.value === 'create') { + await ScheduleSchemeApi.createScheduleScheme(data) + message.success(t('common.createSuccess')) + } else { + await ScheduleSchemeApi.updateScheduleScheme(data) + message.success(t('common.updateSuccess')) + } + dialogVisible.value = false + // 发送操作成功的事件 + emit('success') + } finally { + formLoading.value = false + } + } + + /** 重置表单 */ + const resetForm = () => { + formData.value = { + id: undefined, + code: undefined, + name: undefined, + triggerMethod: undefined, + triggerCondition: undefined, + scheduleObj: undefined, + scheduleType: undefined, + scheduleStrategy: undefined, + modelId: undefined, + scheduleTime: undefined, + remark: undefined, + status: CommonStatusEnum.ENABLE + } + formRef.value?.resetFields() + } +</script> diff --git a/src/views/model/mcs/sche/scheme/index.vue b/src/views/model/mcs/sche/scheme/index.vue new file mode 100644 index 0000000..6212a90 --- /dev/null +++ b/src/views/model/mcs/sche/scheme/index.vue @@ -0,0 +1,178 @@ +<template> + <!-- 搜索 --> + <ContentWrap> + <el-form + class="-mb-15px" + :model="queryParams" + ref="queryFormRef" + :inline="true" + label-width="68px" + > + <el-form-item label="方案编号" prop="code"> + <el-input + v-model="queryParams.code" + placeholder="请输入方案编号" + clearable + @keyup.enter="handleQuery" + class="!w-240px" + /> + </el-form-item> + <el-form-item label="方案名称" prop="name"> + <el-input + v-model="queryParams.name" + placeholder="请输入方案名称" + clearable + @keyup.enter="handleQuery" + class="!w-240px" + /> + </el-form-item> + <el-form-item> + <el-button @click="handleQuery"> + <Icon icon="ep:search" class="mr-5px" /> + 搜索 + </el-button> + <el-button @click="resetQuery"> + <Icon icon="ep:refresh" class="mr-5px" /> + 重置 + </el-button> + <el-button + type="primary" + plain + @click="openForm('create')" + v-hasPermi="['sche:scheme:create']" + > + <Icon icon="ep:plus" class="mr-5px" /> + 新增 + </el-button> + </el-form-item> + </el-form> + </ContentWrap> + + <!-- 列表 --> + <ContentWrap> + <el-table v-loading="loading" :data="list"> + <el-table-column label="方案编号" align="center" prop="code" min-width="100"/> + <el-table-column label="方案名称" align="center" prop="name" min-width="100"/> + <el-table-column label="触发方式" align="center" prop="triggerMethod" min-width="100"> + <template #default="scope"> + <dict-tag :type="DICT_TYPE.SCHE_TRIGGER_METHOD" :value="scope.row.triggerMethod" /> + </template> + </el-table-column> + <el-table-column label="触发条件" align="center" prop="triggerCondition" min-width="100"/> + <el-table-column label="调整对象" align="center" prop="scheduleObj" min-width="100"/> + <el-table-column label="调整类型" align="center" prop="scheduleType" min-width="100"/> + <el-table-column label=" 调整策略" align="center" prop="scheduleStrategy" min-width="100"/> + <el-table-column label="调度时间" align="center" prop="scheduleTime" min-width="160" /> + <el-table-column label="备注" align="center" prop="remark" min-width="100" /> + <el-table-column label="状态" align="center" prop="status" min-width="100"> + <template #default="scope"> + <dict-tag :type="DICT_TYPE.COMMON_STATUS" :value="scope.row.status" /> + </template> + </el-table-column> + <el-table-column label="操作" align="center" min-width="110" fixed="right"> + <template #default="scope"> + <el-button + link + type="primary" + @click="openForm('update', scope.row.id)" + v-hasPermi="['sche:scheme:update']" + > + 编辑 + </el-button> + <el-button + link + type="danger" + @click="handleDelete(scope.row.id)" + v-hasPermi="['sche:scheme:delete']" + > + 删除 + </el-button> + </template> + </el-table-column> + </el-table> + <!-- 分页 --> + <Pagination + :total="total" + v-model:page="queryParams.pageNo" + v-model:limit="queryParams.pageSize" + @pagination="getList" + /> + </ContentWrap> + + <!-- 表单弹窗:添加/修改 --> + <ScheduleSchemeForm ref="formRef" @success="getList" /> + +</template> +<script lang="ts" setup> + import {DICT_TYPE, getIntDictOptions} from '@/utils/dict' + import {dateFormatter} from '@/utils/formatTime' + import download from '@/utils/download' + import * as ScheduleSchemeApi from '@/api/model/sche/scheme' + import ScheduleSchemeForm from './ScheduleSchemeForm.vue' + + defineOptions({name: 'ScheduleScheme'}) + + const message = useMessage() // 消息弹窗 + const {t} = useI18n() // 国际化 + + const loading = ref(true) // 列表的加载中 + const total = ref(0) // 列表的总页数 + const list = ref([]) // 列表的数据 + const queryParams = reactive({ + pageNo: 1, + pageSize: 10, + code: undefined, + name: undefined + }) + const queryFormRef = ref() // 搜索的表单 + const exportLoading = ref(false) // 导出的加载中 + + /** 查询列表 */ + const getList = async () => { + loading.value = true + try { + const page = await ScheduleSchemeApi.getScheduleSchemePage(queryParams) + list.value = page.list + total.value = page.total + } finally { + loading.value = false + } + } + + /** 搜索按钮操作 */ + const handleQuery = () => { + queryParams.pageNo = 1 + getList() + } + + /** 重置按钮操作 */ + const resetQuery = () => { + queryFormRef.value.resetFields() + handleQuery() + } + + /** 添加/修改操作 */ + const formRef = ref() + const openForm = (type: string, id?: number) => { + formRef.value.open(type, id) + } + + /** 删除按钮操作 */ + const handleDelete = async (id: number) => { + try { + // 删除的二次确认 + await message.delConfirm() + // 发起删除 + await ScheduleSchemeApi.deleteScheduleScheme(id) + message.success(t('common.delSuccess')) + // 刷新列表 + await getList() + } catch { + } + } + + /** 初始化 **/ + onMounted(async () => { + await getList() + }) +</script> diff --git a/src/views/model/pre/dm/DmModuleForm.vue b/src/views/model/pre/dm/DmModuleForm.vue new file mode 100644 index 0000000..93dcd9e --- /dev/null +++ b/src/views/model/pre/dm/DmModuleForm.vue @@ -0,0 +1,136 @@ +<template> + <Dialog v-model="dialogVisible" :title="dialogTitle" width="50%"> + <el-form + ref="formRef" + v-loading="formLoading" + :model="formData" + :rules="formRules" + label-width="120px" + > + <el-row> + <el-col :span="12"> + <el-form-item label="名称" prop="modulename"> + <el-input v-model="formData.modulename" placeholder="请输入名称"/> + </el-form-item> + </el-col> + <el-col :span="12"> + <el-form-item label="类型" prop="moduletype"> + <el-input v-model="formData.moduletype" placeholder="请输入类型"/> + </el-form-item> + </el-col> + </el-row> + <el-row> + <el-col :span="12"> + <el-form-item label="周期" prop="cycle"> + <el-input v-model="formData.cycle" placeholder="请输入周期"/> + </el-form-item> + </el-col> + <el-col :span="12"> + <el-form-item label="模块配置" prop="modulenavconfig"> + <el-input v-model="formData.modulenavconfig" placeholder="请输入模块配置"/> + </el-form-item> + </el-col> + </el-row> + <el-row> + <el-col :span="12"> + <el-form-item label="预测时间" prop="predicttime"> + <el-input v-model="formData.predicttime" placeholder="请输入预测时间"/> + </el-form-item> + </el-col> + <el-col :span="12"> + <el-form-item label="采集时间" prop="collecttime"> + <el-input v-model="formData.collecttime" placeholder="请输入采集时间"/> + </el-form-item> + </el-col> + </el-row> + </el-form> + <template #footer> + <el-button :disabled="formLoading" type="primary" @click="submitForm">确 定</el-button> + <el-button @click="dialogVisible = false">取 消</el-button> + </template> + </Dialog> +</template> +<script lang="ts" setup> +import * as DmModule from '@/api/model/pre/dm' + +defineOptions({name: 'DataDmModuleForm'}) + +const {t} = useI18n() // 国际化 +const message = useMessage() // 消息弹窗 +const dialogVisible = ref(false) // 弹窗的是否展示 +const dialogTitle = ref('') // 弹窗的标题 +const formLoading = ref(false) // 表单的加载中:1)修改时的数据加载;2)提交的按钮禁用 +const formType = ref('') // 表单的类型:create - 新增;update - 修改 +const formData = ref({ + id: undefined, + modulename: undefined, + moduletype: undefined, + cycle: undefined, + modulenavconfig: undefined, + predicttime: undefined, + collecttime: undefined +}) +const formRules = reactive({ + modulename: [{required: true, message: '名称不能为空', trigger: 'blur'}], + moduletype: [{required: true, message: '类型不能为空', trigger: 'blur'}], +}) +const formRef = ref() // 表单 Ref + +/** 打开弹窗 */ +const open = async (type: string, id?: number) => { + dialogVisible.value = true + dialogTitle.value = t('action.' + type) + formType.value = type + resetForm() + // 修改时,设置数据 + if (id) { + formLoading.value = true + try { + formData.value = await DmModule.getDmModule(id) + } finally { + formLoading.value = false + } + } +} +defineExpose({open}) // 提供 open 方法,用于打开弹窗 + +/** 提交表单 */ +const emit = defineEmits(['success']) // 定义 success 事件,用于操作成功后的回调 +const submitForm = async () => { + // 校验表单 + if (!formRef) return + const valid = await formRef.value.validate() + if (!valid) return + // 提交请求 + formLoading.value = true + try { + const data = formData.value as unknown as DmModule.DmModuleVO + if (formType.value === 'create') { + await DmModule.createDmModule(data) + message.success(t('common.createSuccess')) + } else { + await DmModule.updateDmModule(data) + message.success(t('common.updateSuccess')) + } + dialogVisible.value = false + // 发送操作成功的事件 + emit('success') + } finally { + formLoading.value = false + } +} + +/** 重置表单 */ +const resetForm = () => { + formData.value = { + id: undefined, + modulename: undefined, + moduletype: undefined, + cycle: undefined, + modulenavconfig: undefined, + predicttime: undefined, + collecttime: undefined + } + formRef.value?.resetFields() +} +</script> diff --git a/src/views/model/pre/dm/index.vue b/src/views/model/pre/dm/index.vue new file mode 100644 index 0000000..dd14eee --- /dev/null +++ b/src/views/model/pre/dm/index.vue @@ -0,0 +1,154 @@ +<template> + <!-- 搜索 --> + <ContentWrap> + <el-form + class="-mb-15px" + :model="queryParams" + ref="queryFormRef" + :inline="true" + label-width="68px" + > + <el-form-item label="名称" prop="modulename"> + <el-input + v-model="queryParams.modulename" + placeholder="请输入名称" + clearable + @keyup.enter="handleQuery" + class="!w-240px" + /> + </el-form-item> + <el-form-item> + <el-button @click="handleQuery"> + <Icon icon="ep:search" class="mr-5px" /> + 搜索 + </el-button> + <el-button @click="resetQuery"> + <Icon icon="ep:refresh" class="mr-5px" /> + 重置 + </el-button> + <el-button + type="primary" + plain + @click="openForm('create')" + v-hasPermi="['system:tenant:create']" + > + <Icon icon="ep:plus" class="mr-5px" /> + 新增 + </el-button> + </el-form-item> + </el-form> + </ContentWrap> + + <!-- 列表 --> + <ContentWrap> + <el-table v-loading="loading" :data="list"> + <el-table-column label="名称" align="center" prop="modulename" /> + <el-table-column label="类型" align="center" prop="moduletype" /> + <el-table-column label="周期" align="center" prop="cycle" /> + <el-table-column label="模块配置" align="center" prop="modulenavconfig" /> + <el-table-column label="预测时间" align="center" prop="predicttime" /> + <el-table-column label="采集时间" align="center" prop="collecttime" /> + + <el-table-column label="操作" align="center" min-width="110" fixed="right"> + <template #default="scope"> + <el-button + link + type="primary" + @click="openForm('update', scope.row.id)" + v-hasPermi="['system:tenant:update']" + > + 编辑 + </el-button> + <el-button + link + type="danger" + @click="handleDelete(scope.row.id)" + v-hasPermi="['system:tenant:delete']" + > + 删除 + </el-button> + </template> + </el-table-column> + </el-table> + <!-- 分页 --> + <Pagination + :total="total" + v-model:page="queryParams.pageNo" + v-model:limit="queryParams.pageSize" + @pagination="getList" + /> + </ContentWrap> + + <!-- 表单弹窗:添加/修改 --> + <DmModuleForm ref="formRef" @success="getList" /> + +</template> +<script lang="ts" setup> +import DmModuleForm from './DmModuleForm.vue' +import * as DmModule from '@/api/model/pre/dm' + +defineOptions({name: 'DataDmModule'}) + + const message = useMessage() // 消息弹窗 + const {t} = useI18n() // 国际化 + + const loading = ref(true) // 列表的加载中 + const total = ref(0) // 列表的总页数 + const list = ref([]) // 列表的数据 + const queryParams = reactive({ + pageNo: 1, + pageSize: 10, + modulename: undefined, + }) + const queryFormRef = ref() // 搜索的表单 + const exportLoading = ref(false) // 导出的加载中 + + /** 查询列表 */ + const getList = async () => { + loading.value = true + try { + const page = await DmModule.getDmModulePage(queryParams) + list.value = page.list + total.value = page.total + } finally { + loading.value = false + } + } + + /** 搜索按钮操作 */ + const handleQuery = () => { + queryParams.pageNo = 1 + getList() + } + + /** 重置按钮操作 */ + const resetQuery = () => { + queryFormRef.value.resetFields() + handleQuery() + } + + /** 添加/修改操作 */ + const formRef = ref() + const openForm = (type: string, id?: number) => { + formRef.value.open(type, id) + } + + /** 删除按钮操作 */ + const handleDelete = async (id: number) => { + try { + // 删除的二次确认 + await message.delConfirm() + // 发起删除 + await DmModule.deleteDmModule(id) + message.success(t('common.delSuccess')) + // 刷新列表 + await getList() + } catch { + } + } + + /** 初始化 **/ + onMounted(async () => { + await getList() + }) +</script> diff --git a/src/views/model/pre/item/ItemTypeForm.vue b/src/views/model/pre/item/ItemTypeForm.vue new file mode 100644 index 0000000..5131d27 --- /dev/null +++ b/src/views/model/pre/item/ItemTypeForm.vue @@ -0,0 +1,115 @@ +<template> + <Dialog v-model="dialogVisible" :title="dialogTitle" width="50%"> + <el-form + ref="formRef" + v-loading="formLoading" + :model="formData" + :rules="formRules" + label-width="120px" + > + <el-row> + <el-col :span="24"> + <el-form-item label="名称" prop="itemtypename"> + <el-input v-model="formData.itemtypename" placeholder="请输入名称"/> + </el-form-item> + </el-col> + </el-row> + <el-row> + <el-col :span="24"> + <el-form-item label="类名" prop="itemclasstype"> + <el-input v-model="formData.itemclasstype" placeholder="请输入类名"/> + </el-form-item> + </el-col> + </el-row> + <el-row> + <el-col :span="24"> + <el-form-item label="程序集" prop="assemblyname"> + <el-input v-model="formData.assemblyname" placeholder="请输入程序集"/> + </el-form-item> + </el-col> + </el-row> + </el-form> + <template #footer> + <el-button :disabled="formLoading" type="primary" @click="submitForm">确 定</el-button> + <el-button @click="dialogVisible = false">取 消</el-button> + </template> + </Dialog> +</template> +<script lang="ts" setup> +import * as MmItemType from '@/api/model/pre/item' + +defineOptions({name: 'DataMmItemTypeForm'}) + +const {t} = useI18n() // 国际化 +const message = useMessage() // 消息弹窗 +const dialogVisible = ref(false) // 弹窗的是否展示 +const dialogTitle = ref('') // 弹窗的标题 +const formLoading = ref(false) // 表单的加载中:1)修改时的数据加载;2)提交的按钮禁用 +const formType = ref('') // 表单的类型:create - 新增;update - 修改 +const formData = ref({ + id: undefined, + itemtypename: undefined, + itemclasstype: undefined, + assemblyname: undefined, +}) +const formRules = reactive({ + itemtypename: [{required: true, message: '名称不能为空', trigger: 'blur'}], + itemclasstype: [{required: true, message: '类名不能为空', trigger: 'blur'}], +}) +const formRef = ref() // 表单 Ref + +/** 打开弹窗 */ +const open = async (type: string, id?: number) => { + dialogVisible.value = true + dialogTitle.value = t('action.' + type) + formType.value = type + resetForm() + // 修改时,设置数据 + if (id) { + formLoading.value = true + try { + formData.value = await MmItemType.getMmItemType(id) + } finally { + formLoading.value = false + } + } +} +defineExpose({open}) // 提供 open 方法,用于打开弹窗 + +/** 提交表单 */ +const emit = defineEmits(['success']) // 定义 success 事件,用于操作成功后的回调 +const submitForm = async () => { + // 校验表单 + if (!formRef) return + const valid = await formRef.value.validate() + if (!valid) return + // 提交请求 + formLoading.value = true + try { + const data = formData.value as unknown as MmItemType.MmItemTypeVO + if (formType.value === 'create') { + await MmItemType.createMmItemType(data) + message.success(t('common.createSuccess')) + } else { + await MmItemType.updateMmItemType(data) + message.success(t('common.updateSuccess')) + } + dialogVisible.value = false + // 发送操作成功的事件 + emit('success') + } finally { + formLoading.value = false + } +} + +/** 重置表单 */ +const resetForm = () => { + formData.value = { + id: undefined, + itemtypename: undefined, + itemclasstype: undefined, + assemblyname: undefined, + } + formRef.value?.resetFields() +} +</script> diff --git a/src/views/model/pre/item/index.vue b/src/views/model/pre/item/index.vue new file mode 100644 index 0000000..21df860 --- /dev/null +++ b/src/views/model/pre/item/index.vue @@ -0,0 +1,151 @@ +<template> + <!-- 搜索 --> + <ContentWrap> + <el-form + class="-mb-15px" + :model="queryParams" + ref="queryFormRef" + :inline="true" + label-width="68px" + > + <el-form-item label="名称" prop="itemtypename"> + <el-input + v-model="queryParams.itemtypename" + placeholder="请输入名称" + clearable + @keyup.enter="handleQuery" + class="!w-240px" + /> + </el-form-item> + <el-form-item> + <el-button @click="handleQuery"> + <Icon icon="ep:search" class="mr-5px" /> + 搜索 + </el-button> + <el-button @click="resetQuery"> + <Icon icon="ep:refresh" class="mr-5px" /> + 重置 + </el-button> + <el-button + type="primary" + plain + @click="openForm('create')" + v-hasPermi="['system:tenant:create']" + > + <Icon icon="ep:plus" class="mr-5px" /> + 新增 + </el-button> + </el-form-item> + </el-form> + </ContentWrap> + + <!-- 列表 --> + <ContentWrap> + <el-table v-loading="loading" :data="list"> + <el-table-column label="名称" align="center" prop="itemtypename" /> + <el-table-column label="类名" align="center" prop="itemclasstype" /> + <el-table-column label="程序集" align="center" prop="assemblyname" /> + + <el-table-column label="操作" align="center" min-width="110" fixed="right"> + <template #default="scope"> + <el-button + link + type="primary" + @click="openForm('update', scope.row.id)" + v-hasPermi="['system:tenant:update']" + > + 编辑 + </el-button> + <el-button + link + type="danger" + @click="handleDelete(scope.row.id)" + v-hasPermi="['system:tenant:delete']" + > + 删除 + </el-button> + </template> + </el-table-column> + </el-table> + <!-- 分页 --> + <Pagination + :total="total" + v-model:page="queryParams.pageNo" + v-model:limit="queryParams.pageSize" + @pagination="getList" + /> + </ContentWrap> + + <!-- 表单弹窗:添加/修改 --> + <MmItemTypeForm ref="formRef" @success="getList" /> + +</template> +<script lang="ts" setup> +import MmItemTypeForm from './ItemTypeForm.vue' +import * as MmItemType from '@/api/model/pre/item' + +defineOptions({name: 'DataMmItemType'}) + + const message = useMessage() // 消息弹窗 + const {t} = useI18n() // 国际化 + + const loading = ref(true) // 列表的加载中 + const total = ref(0) // 列表的总页数 + const list = ref([]) // 列表的数据 + const queryParams = reactive({ + pageNo: 1, + pageSize: 10, + itemtypename: undefined, + }) + const queryFormRef = ref() // 搜索的表单 + const exportLoading = ref(false) // 导出的加载中 + + /** 查询列表 */ + const getList = async () => { + loading.value = true + try { + const page = await MmItemType.getMmItemTypePage(queryParams) + list.value = page.list + total.value = page.total + } finally { + loading.value = false + } + } + + /** 搜索按钮操作 */ + const handleQuery = () => { + queryParams.pageNo = 1 + getList() + } + + /** 重置按钮操作 */ + const resetQuery = () => { + queryFormRef.value.resetFields() + handleQuery() + } + + /** 添加/修改操作 */ + const formRef = ref() + const openForm = (type: string, id?: number) => { + formRef.value.open(type, id) + } + + /** 删除按钮操作 */ + const handleDelete = async (id: number) => { + try { + // 删除的二次确认 + await message.delConfirm() + // 发起删除 + await MmItemType.deleteMmItemType(id) + message.success(t('common.delSuccess')) + // 刷新列表 + await getList() + } catch { + } + } + + /** 初始化 **/ + onMounted(async () => { + await getList() + }) +</script> diff --git a/src/views/model/pre/predict/MmPredictItemForm.vue b/src/views/model/pre/predict/MmPredictItemForm.vue new file mode 100644 index 0000000..9117ab0 --- /dev/null +++ b/src/views/model/pre/predict/MmPredictItemForm.vue @@ -0,0 +1,209 @@ +<template> + <Dialog v-model="dialogVisible" :title="dialogTitle" width="50%"> + <el-form + ref="formRef" + v-loading="formLoading" + :model="formData" + :rules="formRules" + label-width="120px" + > + <el-row> + <el-col :span="12"> + <el-form-item label="编号" prop="itemno"> + <el-input v-model="formData.itemno" placeholder="请输入编号"/> + </el-form-item> + </el-col> + <el-col :span="12"> + <el-form-item label="预测项名" prop="itemname"> + <el-input v-model="formData.itemname" placeholder="请输入预测项名"/> + </el-form-item> + </el-col> + </el-row> + <el-row> + <el-col :span="12"> + <el-form-item label="类型ID" prop="itemtypeid"> + <el-input v-model="formData.itemtypeid" placeholder="请输入类型ID"/> + </el-form-item> + </el-col> + <el-col :span="12"> + <el-form-item label="类型名称" prop="itemtypename"> + <el-input v-model="formData.itemtypename" placeholder="请输入类型名称"/> + </el-form-item> + </el-col> + </el-row> + <el-row> + <el-col :span="12"> + <el-form-item label="粒度" prop="granularity"> + <el-input v-model="formData.granularity" placeholder="请输入粒度"/> + </el-form-item> + </el-col> + <el-col :span="12"> + <el-form-item label="是否融合" prop="isfuse"> + <el-input v-model="formData.isfuse" placeholder="请输入是否融合"/> + </el-form-item> + </el-col> + </el-row> + <el-row> + <el-col :span="12"> + <el-form-item label="是否检查" prop="workchecked"> + <el-input v-model="formData.workchecked" placeholder="请输入是否检查"/> + </el-form-item> + </el-col> + <el-col :span="12"> + <el-form-item label="模块ID" prop="moduleid"> + <el-input v-model="formData.moduleid" placeholder="请输入模块ID"/> + </el-form-item> + </el-col> + </el-row> + <el-row> + <el-col :span="12"> + <el-form-item label="排序" prop="itemorder"> + <el-input v-model="formData.itemorder" placeholder="请输入排序"/> + </el-form-item> + </el-col> + <el-col :span="12"> + <el-form-item label="是否启用" prop="status"> + <el-input v-model="formData.status" placeholder="请输入是否启用"/> + </el-form-item> + </el-col> + </el-row> + <el-row> + <el-col :span="12"> + <el-form-item label="类别ID" prop="categoryid"> + <el-input v-model="formData.categoryid" placeholder="请输入类别ID"/> + </el-form-item> + </el-col> + <el-col :span="12"> + <el-form-item label="数据点ID" prop="pointid"> + <el-input v-model="formData.pointid" placeholder="请输入数据点ID"/> + </el-form-item> + </el-col> + </el-row> + <el-row> + <el-col :span="12"> + <el-form-item label="数据点名称" prop="tagname"> + <el-input v-model="formData.tagname" placeholder="请输入数据点名称"/> + </el-form-item> + </el-col> + <el-col :span="12"> + <el-form-item label="存放表ID" prop="resulttableid"> + <el-input v-model="formData.resulttableid" placeholder="请输入存放表ID"/> + </el-form-item> + </el-col> + </el-row> + <el-row> + <el-col :span="12"> + <el-form-item label="存放表" prop="tablename"> + <el-input v-model="formData.tablename" placeholder="请输入存放表"/> + </el-form-item> + </el-col> + </el-row> + </el-form> + <template #footer> + <el-button :disabled="formLoading" type="primary" @click="submitForm">确 定</el-button> + <el-button @click="dialogVisible = false">取 消</el-button> + </template> + </Dialog> +</template> +<script lang="ts" setup> +import * as MmPredictItem from '@/api/model/pre/predict' + +defineOptions({name: 'DataMmPredictItemForm'}) + +const {t} = useI18n() // 国际化 +const message = useMessage() // 消息弹窗 +const dialogVisible = ref(false) // 弹窗的是否展示 +const dialogTitle = ref('') // 弹窗的标题 +const formLoading = ref(false) // 表单的加载中:1)修改时的数据加载;2)提交的按钮禁用 +const formType = ref('') // 表单的类型:create - 新增;update - 修改 +const formData = ref({ + id: undefined, + itemno: undefined, + itemname: undefined, + itemtypeid: undefined, + itemtypename: undefined, + granularity: undefined, + isfuse: undefined, + workchecked: undefined, + moduleid: undefined, + itemorder: undefined, + status: undefined, + categoryid: undefined, + pointid: undefined, + tagname: undefined, + resulttableid: undefined, + tablename: undefined, +}) +const formRules = reactive({ + itemno: [{required: true, message: '编号不能为空', trigger: 'blur'}], + itemname: [{required: true, message: '预测项名不能为空', trigger: 'blur'}], +}) +const formRef = ref() // 表单 Ref + +/** 打开弹窗 */ +const open = async (type: string, id?: number) => { + dialogVisible.value = true + dialogTitle.value = t('action.' + type) + formType.value = type + resetForm() + // 修改时,设置数据 + if (id) { + formLoading.value = true + try { + formData.value = await MmPredictItem.getMmPredictItem(id) + } finally { + formLoading.value = false + } + } +} +defineExpose({open}) // 提供 open 方法,用于打开弹窗 + +/** 提交表单 */ +const emit = defineEmits(['success']) // 定义 success 事件,用于操作成功后的回调 +const submitForm = async () => { + // 校验表单 + if (!formRef) return + const valid = await formRef.value.validate() + if (!valid) return + // 提交请求 + formLoading.value = true + try { + const data = formData.value as unknown as MmPredictItem.MmPredictItemVO + if (formType.value === 'create') { + await MmPredictItem.createMmPredictItem(data) + message.success(t('common.createSuccess')) + } else { + await MmPredictItem.updateMmPredictItem(data) + message.success(t('common.updateSuccess')) + } + dialogVisible.value = false + // 发送操作成功的事件 + emit('success') + } finally { + formLoading.value = false + } +} + +/** 重置表单 */ +const resetForm = () => { + formData.value = { + id: undefined, + itemno: undefined, + itemname: undefined, + itemtypeid: undefined, + itemtypename: undefined, + granularity: undefined, + isfuse: undefined, + workchecked: undefined, + moduleid: undefined, + itemorder: undefined, + status: undefined, + categoryid: undefined, + pointid: undefined, + tagname: undefined, + resulttableid: undefined, + tablename: undefined, + } + formRef.value?.resetFields() +} +</script> diff --git a/src/views/model/pre/predict/index.vue b/src/views/model/pre/predict/index.vue new file mode 100644 index 0000000..8e516fc --- /dev/null +++ b/src/views/model/pre/predict/index.vue @@ -0,0 +1,173 @@ +<template> + <!-- 搜索 --> + <ContentWrap> + <el-form + class="-mb-15px" + :model="queryParams" + ref="queryFormRef" + :inline="true" + label-width="68px" + > + <el-form-item label="编号" prop="itemno"> + <el-input + v-model="queryParams.itemno" + placeholder="请输入编号" + clearable + @keyup.enter="handleQuery" + class="!w-240px" + /> + </el-form-item> + <el-form-item label="预测项名" prop="itemname"> + <el-input + v-model="queryParams.itemname" + placeholder="请输入预测项名" + clearable + @keyup.enter="handleQuery" + class="!w-240px" + /> + </el-form-item> + <el-form-item> + <el-button @click="handleQuery"> + <Icon icon="ep:search" class="mr-5px" /> + 搜索 + </el-button> + <el-button @click="resetQuery"> + <Icon icon="ep:refresh" class="mr-5px" /> + 重置 + </el-button> + <el-button + type="primary" + plain + @click="openForm('create')" + v-hasPermi="['system:tenant:create']" + > + <Icon icon="ep:plus" class="mr-5px" /> + 新增 + </el-button> + </el-form-item> + </el-form> + </ContentWrap> + + <!-- 列表 --> + <ContentWrap> + <el-table v-loading="loading" :data="list"> + <el-table-column label="编号" align="center" prop="itemno" /> + <el-table-column label="预测项名" align="center" prop="itemname" /> + <el-table-column label="类型ID" align="center" prop="itemtypeid" /> + <el-table-column label="类型名称" align="center" prop="itemtypename" /> + <el-table-column label="粒度" align="center" prop="granularity" /> + <el-table-column label="是否融合" align="center" prop="isfuse" /> + <el-table-column label="是否检查" align="center" prop="workchecked" /> + <el-table-column label="模块ID" align="center" prop="moduleid" /> + <el-table-column label="排序" align="center" prop="itemorder" /> + <el-table-column label="是否启用" align="center" prop="status" /> + <el-table-column label="类别ID" align="center" prop="categoryid" /> + <el-table-column label="数据点ID" align="center" prop="pointid" /> + <el-table-column label="数据点名称" align="center" prop="tagname" /> + <el-table-column label="存放表ID" align="center" prop="resulttableid" /> + <el-table-column label="存放表" align="center" prop="tablename" /> + + <el-table-column label="操作" align="center" min-width="110" fixed="right"> + <template #default="scope"> + <el-button + link + type="primary" + @click="openForm('update', scope.row.id)" + v-hasPermi="['system:tenant:update']" + > + 编辑 + </el-button> + <el-button + link + type="danger" + @click="handleDelete(scope.row.id)" + v-hasPermi="['system:tenant:delete']" + > + 删除 + </el-button> + </template> + </el-table-column> + </el-table> + <!-- 分页 --> + <Pagination + :total="total" + v-model:page="queryParams.pageNo" + v-model:limit="queryParams.pageSize" + @pagination="getList" + /> + </ContentWrap> + + <!-- 表单弹窗:添加/修改 --> + <MmPredictItemForm ref="formRef" @success="getList" /> + +</template> +<script lang="ts" setup> +import MmPredictItemForm from './MmPredictItemForm.vue' +import * as MmPredictItem from '@/api/model/pre/dm' + +defineOptions({name: 'DataMmPredictItem'}) + + const message = useMessage() // 消息弹窗 + const {t} = useI18n() // 国际化 + + const loading = ref(true) // 列表的加载中 + const total = ref(0) // 列表的总页数 + const list = ref([]) // 列表的数据 + const queryParams = reactive({ + pageNo: 1, + pageSize: 10, + itemno: undefined, + itemname: undefined, + }) + const queryFormRef = ref() // 搜索的表单 + const exportLoading = ref(false) // 导出的加载中 + + /** 查询列表 */ + const getList = async () => { + loading.value = true + try { + const page = await MmPredictItem.getMmPredictItemPage(queryParams) + list.value = page.list + total.value = page.total + } finally { + loading.value = false + } + } + + /** 搜索按钮操作 */ + const handleQuery = () => { + queryParams.pageNo = 1 + getList() + } + + /** 重置按钮操作 */ + const resetQuery = () => { + queryFormRef.value.resetFields() + handleQuery() + } + + /** 添加/修改操作 */ + const formRef = ref() + const openForm = (type: string, id?: number) => { + formRef.value.open(type, id) + } + + /** 删除按钮操作 */ + const handleDelete = async (id: number) => { + try { + // 删除的二次确认 + await message.delConfirm() + // 发起删除 + await MmPredictItem.deleteMmPredictItem(id) + message.success(t('common.delSuccess')) + // 刷新列表 + await getList() + } catch { + } + } + + /** 初始化 **/ + onMounted(async () => { + await getList() + }) +</script> diff --git a/src/views/model/pre/result/MmResultTableForm.vue b/src/views/model/pre/result/MmResultTableForm.vue new file mode 100644 index 0000000..bcb0afa --- /dev/null +++ b/src/views/model/pre/result/MmResultTableForm.vue @@ -0,0 +1,96 @@ +<template> + <Dialog v-model="dialogVisible" :title="dialogTitle" width="50%"> + <el-form + ref="formRef" + v-loading="formLoading" + :model="formData" + :rules="formRules" + label-width="120px" + > + <el-row> + <el-col :span="12"> + <el-form-item label="表名" prop="tablename"> + <el-input v-model="formData.tablename" placeholder="请输入表名"/> + </el-form-item> + </el-col> + </el-row> + </el-form> + <template #footer> + <el-button :disabled="formLoading" type="primary" @click="submitForm">确 定</el-button> + <el-button @click="dialogVisible = false">取 消</el-button> + </template> + </Dialog> +</template> +<script lang="ts" setup> +import * as MmResultTable from '@/api/model/pre/result' + +defineOptions({name: 'DataMmResultTableForm'}) + +const {t} = useI18n() // 国际化 +const message = useMessage() // 消息弹窗 +const dialogVisible = ref(false) // 弹窗的是否展示 +const dialogTitle = ref('') // 弹窗的标题 +const formLoading = ref(false) // 表单的加载中:1)修改时的数据加载;2)提交的按钮禁用 +const formType = ref('') // 表单的类型:create - 新增;update - 修改 +const formData = ref({ + id: undefined, + tablename: undefined, +}) +const formRules = reactive({ + tablename: [{required: true, message: '表名不能为空', trigger: 'blur'}], +}) +const formRef = ref() // 表单 Ref + +/** 打开弹窗 */ +const open = async (type: string, id?: number) => { + dialogVisible.value = true + dialogTitle.value = t('action.' + type) + formType.value = type + resetForm() + // 修改时,设置数据 + if (id) { + formLoading.value = true + try { + formData.value = await MmResultTable.getMmResultTable(id) + } finally { + formLoading.value = false + } + } +} +defineExpose({open}) // 提供 open 方法,用于打开弹窗 + +/** 提交表单 */ +const emit = defineEmits(['success']) // 定义 success 事件,用于操作成功后的回调 +const submitForm = async () => { + // 校验表单 + if (!formRef) return + const valid = await formRef.value.validate() + if (!valid) return + // 提交请求 + formLoading.value = true + try { + const data = formData.value as unknown as MmResultTable.MmResultTableVO + if (formType.value === 'create') { + await MmResultTable.createMmResultTable(data) + message.success(t('common.createSuccess')) + } else { + await MmResultTable.updateMmResultTable(data) + message.success(t('common.updateSuccess')) + } + dialogVisible.value = false + // 发送操作成功的事件 + emit('success') + } finally { + formLoading.value = false + } +} + +/** 重置表单 */ +const resetForm = () => { + formData.value = { + id: undefined, + tablename: undefined, + } + formRef.value?.resetFields() +} +</script> diff --git a/src/views/model/pre/result/index.vue b/src/views/model/pre/result/index.vue new file mode 100644 index 0000000..49d2411 --- /dev/null +++ b/src/views/model/pre/result/index.vue @@ -0,0 +1,149 @@ +<template> + <!-- 搜索 --> + <ContentWrap> + <el-form + class="-mb-15px" + :model="queryParams" + ref="queryFormRef" + :inline="true" + label-width="68px" + > + <el-form-item label="表名" prop="tablename"> + <el-input + v-model="queryParams.tablename" + placeholder="请输入表名" + clearable + @keyup.enter="handleQuery" + class="!w-240px" + /> + </el-form-item> + <el-form-item> + <el-button @click="handleQuery"> + <Icon icon="ep:search" class="mr-5px" /> + 搜索 + </el-button> + <el-button @click="resetQuery"> + <Icon icon="ep:refresh" class="mr-5px" /> + 重置 + </el-button> + <el-button + type="primary" + plain + @click="openForm('create')" + v-hasPermi="['system:tenant:create']" + > + <Icon icon="ep:plus" class="mr-5px" /> + 新增 + </el-button> + </el-form-item> + </el-form> + </ContentWrap> + + <!-- 列表 --> + <ContentWrap> + <el-table v-loading="loading" :data="list"> + <el-table-column label="表名" align="center" prop="tablename" /> + + <el-table-column label="操作" align="center" min-width="110" fixed="right"> + <template #default="scope"> + <el-button + link + type="primary" + @click="openForm('update', scope.row.id)" + v-hasPermi="['system:tenant:update']" + > + 编辑 + </el-button> + <el-button + link + type="danger" + @click="handleDelete(scope.row.id)" + v-hasPermi="['system:tenant:delete']" + > + 删除 + </el-button> + </template> + </el-table-column> + </el-table> + <!-- 分页 --> + <Pagination + :total="total" + v-model:page="queryParams.pageNo" + v-model:limit="queryParams.pageSize" + @pagination="getList" + /> + </ContentWrap> + + <!-- 表单弹窗:添加/修改 --> + <MmPredictItemForm ref="formRef" @success="getList" /> + +</template> +<script lang="ts" setup> +import MmPredictItemForm from './MmResultTableForm.vue' +import * as MmPredictItem from '@/api/model/pre/dm' + +defineOptions({name: 'DataMmPredictItem'}) + + const message = useMessage() // 消息弹窗 + const {t} = useI18n() // 国际化 + + const loading = ref(true) // 列表的加载中 + const total = ref(0) // 列表的总页数 + const list = ref([]) // 列表的数据 + const queryParams = reactive({ + pageNo: 1, + pageSize: 10, + tablename: undefined, + }) + const queryFormRef = ref() // 搜索的表单 + const exportLoading = ref(false) // 导出的加载中 + + /** 查询列表 */ + const getList = async () => { + loading.value = true + try { + const page = await MmPredictItem.getMmPredictItemPage(queryParams) + list.value = page.list + total.value = page.total + } finally { + loading.value = false + } + } + + /** 搜索按钮操作 */ + const handleQuery = () => { + queryParams.pageNo = 1 + getList() + } + + /** 重置按钮操作 */ + const resetQuery = () => { + queryFormRef.value.resetFields() + handleQuery() + } + + /** 添加/修改操作 */ + const formRef = ref() + const openForm = (type: string, id?: number) => { + formRef.value.open(type, id) + } + + /** 删除按钮操作 */ + const handleDelete = async (id: number) => { + try { + // 删除的二次确认 + await message.delConfirm() + // 发起删除 + await MmPredictItem.deleteMmPredictItem(id) + message.success(t('common.delSuccess')) + // 刷新列表 + await getList() + } catch { + } + } + + /** 初始化 **/ + onMounted(async () => { + await getList() + }) +</script> diff --git a/src/views/mpk/MpkForm.vue b/src/views/mpk/MpkForm.vue new file mode 100644 index 0000000..ee6fb7e --- /dev/null +++ b/src/views/mpk/MpkForm.vue @@ -0,0 +1,278 @@ +<template> + <Dialog v-model="dialogVisible" :title="dialogTitle"> + <el-form + ref="formRef" + v-loading="formLoading" + :model="formData" + :rules="formRules" + label-width="80px" + > + <el-divider content-position="left">模型信息</el-divider> + <el-row :gutter="8"> + <el-col :span="12"> + <el-form-item label="模型名称" prop="pyName"> + <el-input disabled v-model="formData.pyName" placeholder=""/> + </el-form-item> + </el-col> + <el-col :span="12"> + <el-upload + ref="uploadRef" + v-model:file-list="fileList" + :show-file-list="false" + :action="importUrl" + :auto-upload="true" + :disabled="uploadLoading" + :before-upload="beforeUpload" + :headers="uploadHeaders" + :on-error="submitFormError" + :on-success="submitFormSuccess" + accept=".pyd" + > + <el-button type="primary"><Icon icon="ep:upload" />模型上传</el-button> + </el-upload> + </el-col> + </el-row> + <el-row :gutter="8"> + <el-col :span="12"> + <el-form-item label="包名" prop="pkgName"> + <el-input v-model="formData.pkgName" placeholder=""/> + </el-form-item> + </el-col> + <el-col :span="12"> + <el-form-item label="模型路径" prop="pyModule"> + <el-input v-model="formData.pyModule" placeholder=""/> + </el-form-item> + </el-col> + </el-row> + <el-row :gutter="20"> + <el-col :span="24"> + <el-form-item label="备注" prop="remark"> + <el-input v-model="formData.remark" placeholder="" type="textarea"/> + </el-form-item> + </el-col> + </el-row> + <el-divider content-position="left">模型方法</el-divider> + <el-row :gutter="20"> + <el-col :span="4"> + <el-button type="primary" size="small" @click="addRow()">新增</el-button> + </el-col> + </el-row> + <el-table :data="formData.modelMethods" border> + <el-table-column + prop="" + label="方法名" + align="center" + width="250"> + <template #default="scope"> + <el-select size="small" v-model="scope.row.methodName"> + <el-option + v-for="item in getDictOptions(DICT_TYPE.MODEL_METHOD)" + :key="item.value" + :label="item.label" + :value="item.value" + :disabled="methodSelectDisabled(item.value)" + /> + </el-select> + </template> + </el-table-column> + <el-table-column + prop="" + label="输入个数" + align="center"> + <template #default="scope"> + <el-input-number size="small" v-model="scope.row.dataLength" :min="1" :max="50"/> + </template> + </el-table-column> + <el-table-column + prop="" + label="是否有model" + align="center"> + <template #default="scope"> + <el-switch size="small" v-model="scope.row.model" :active-value="1" + :inactive-value="0"/> + </template> + </el-table-column> + <el-table-column label="操作" fixed="right" header-align="center" align="center" width="100"> + <template #default="scope"> + <el-button + @click="deleteRow(scope.$index)" + key="danger" + type="danger" + link + >删除 + </el-button> + </template> + </el-table-column> + </el-table> + </el-form> + <template #footer> + <el-button type="primary" @click="submitForm">确 定</el-button> + <el-button @click="dialogVisible = false">取 消</el-button> + </template> + </Dialog> +</template> +<script lang="ts" setup> + import {DICT_TYPE, getDictOptions} from '@/utils/dict' + import * as MpkApi from '@/api/mpk/mpk' + import {FormRules} from 'element-plus' + import {getAccessToken, getTenantId} from "@/utils/auth"; + + + const {t} = useI18n() // 国际化 + const message = useMessage() // 消息弹窗 + + const dialogVisible = ref(false) // 弹窗的是否展示 + const dialogTitle = ref('') // 弹窗的标题 + const formLoading = ref(false) // 表单的加载中:1)修改时的数据加载;2)提交的按钮禁用 + const formType = ref('') // 表单的类型:create - 新增;update - 修改 + const formData = ref({ + id: undefined, + pyName: undefined, + pkgName: undefined, + pyType: undefined, + className: undefined, + pyModule: undefined, + remark: undefined, + modelMethods: [], + filePath: undefined, + }) + + const formRules = reactive<FormRules>({ + pyName: [ + {required: true, message: '模型名称不能为空,请上传模型文件', trigger: 'blur'} + ], + pyType: [ + {required: true, message: '模型类型不能为空', trigger: 'blur'} + ], + pkgName: [ + {required: true, message: '包名不能为空', trigger: 'blur'} + ], + className: [ + {required: true, message: '类名不能为空', trigger: 'blur'} + ], + pyModule: [ + {required: true, message: '模型路径不能为空', trigger: 'blur'} + ], + }) + + const formRef = ref() // 表单 Ref + + /** 打开弹窗 */ + const open = async (type: string, id?: number) => { + dialogVisible.value = true + dialogTitle.value = t('action.' + type) + formType.value = type + resetForm() + // 修改时,设置数据 + if (id) { + formLoading.value = true + try { + formData.value = await MpkApi.getMpk(id) + } finally { + formLoading.value = false + } + } + } + defineExpose({open}) // 提供 open 方法,用于打开弹窗 + + /** 提交表单 */ + const emit = defineEmits(['success']) // 定义 success 事件,用于操作成功后的回调 + const submitForm = async () => { + // 校验表单 + if (!formRef) return + const valid = await formRef.value.validate() + if (!valid) return + // 模型方法校验 + if (formData.value.modelMethods?.length <= 0) { + message.error('模型方法为空') + return + } + // 模型方法名称校验 + if (formData.value.modelMethods.some(e => e.methodName === undefined || e.methodName === '')) { + message.error('存在不合法模型方法名') + return + } + // 提交请求 + formLoading.value = true + try { + const data = formData.value as unknown as MpkApi.MpkVO + if (formType.value === 'create') { + await MpkApi.createMpk(data) + message.success(t('common.createSuccess')) + } else { + await MpkApi.updateMpk(data) + message.success(t('common.updateSuccess')) + } + dialogVisible.value = false + // 发送操作成功的事件 + emit('success') + } finally { + formLoading.value = false + } + } + + /** 重置表单 */ + const resetForm = () => { + formData.value = { + id: undefined, + pyName: undefined, + pkgName: undefined, + pyType: undefined, + className: undefined, + pyModule: undefined, + remark: undefined, + modelMethods: [], + filePath: undefined + } + formRef.value?.resetFields() + } + + const addRow = function () { + formData.value.modelMethods.push({ + methodName: undefined, + dataLength: 1, + model: 0 + }) + } + const deleteRow = function (index) { + formData.value.modelMethods.splice(index, 1) + } + + // 模型方法下拉禁用 + const methodSelectDisabled = (value) => { + if (formData.value.modelMethods.some(e => e.methodName === value)) { + return true; + } + return false; + } + + const fileList = ref([]) // 文件列表 + const importUrl = import.meta.env.VITE_BASE_URL + import.meta.env.VITE_API_URL + '/model/mpk/file/upload' + const uploadLoading = ref(false) // 表单的加载中 + const uploadHeaders = ref() // 上传 Header 头 + const beforeUpload = function (file) { + // 提交请求 + uploadHeaders.value = { + Authorization: 'Bearer ' + getAccessToken(), + 'tenant-id': getTenantId() + } + uploadLoading.value = true + return true; + } + const submitFormError = (): void => { + message.error('上传失败!') + uploadLoading.value = false + } + const submitFormSuccess = (response: any) => { + if (response.code !== 0) { + message.error(response.msg) + uploadLoading.value = false + return + } + const data = response.data; + formData.value.filePath = data.filePath + formData.value.pyName = data.fileName.replace('.pyd','') + message.success('上传成功') + uploadLoading.value = false + } +</script> diff --git a/src/views/mpk/MpkGenerator.vue b/src/views/mpk/MpkGenerator.vue new file mode 100644 index 0000000..07ccef1 --- /dev/null +++ b/src/views/mpk/MpkGenerator.vue @@ -0,0 +1,49 @@ +<template> + <Dialog v-model="dialogVisible" :title="dialogTitle"> + <el-input + type="textarea" + :rows="4" + placeholder="备注" + v-model="remark"/> + <div style="width: 100%;display: flex;flex-direction: row;justify-content: end;margin-top: 16px"> + <el-button @click="generatorCode()" type="primary">生成</el-button> + </div> + </Dialog> +</template> +<script lang="ts" setup> + import * as MpkApi from '@/api/mpk/mpk' + import download from "@/utils/download"; + import {formatToDateString} from "@/utils/dateUtil"; + + + const { t } = useI18n() // 国际化 + const message = useMessage() // 消息弹窗 + + const dialogVisible = ref(false) // 弹窗的是否展示 + const dialogTitle = ref('生成代码') // 弹窗的标题 + + const remark = ref('') + const id = ref() + const zipFileName = ref() + + /** 打开弹窗 */ + const open = async (modelId: string,pyName: string) => { + dialogVisible.value = true + id.value = modelId; + zipFileName.value = pyName + '_' + formatToDateString(new Date()) + '.zip'; + remark.value = ""; + } + defineExpose({ open }) // 提供 open 方法,用于打开弹窗 + + /** 提交表单 */ + const generatorCode = async () => { + const param = { + 'id': id.value, + 'remark': remark.value, + 'zipFileName': zipFileName.value + } + const data = await MpkApi.generatorCode(param) + download.zip(data, zipFileName.value) + dialogVisible.value = false + } +</script> diff --git a/src/views/mpk/MpkGeneratorHistory.vue b/src/views/mpk/MpkGeneratorHistory.vue new file mode 100644 index 0000000..fb79acc --- /dev/null +++ b/src/views/mpk/MpkGeneratorHistory.vue @@ -0,0 +1,109 @@ +<template> + <Dialog v-model="dialogVisible" :title="dialogTitle" width="80%"> + <!-- 搜索工作栏 --> + <ContentWrap> + <el-form + class="-mb-15px" + :model="queryParams" + ref="queryFormRef" + :inline="true" + label-width="68px" + > + <el-form-item prop="startTime"> + <el-date-picker + v-model="queryParams.startTime" + type="datetime" + value-format="YYYY-MM-DD HH:mm:ss" + placeholder="选择日期时间"/> + </el-form-item> + <el-form-item prop="endTime"> + <el-date-picker + v-model="queryParams.endTime" + type="datetime" + value-format="YYYY-MM-DD HH:mm:ss" + placeholder="选择日期时间"/> + </el-form-item> + <el-form-item> + <el-button @click="getList"><Icon icon="ep:search" class="mr-5px" /> 搜索</el-button> + </el-form-item> + </el-form> + </ContentWrap> + + <!-- 列表 --> + <ContentWrap> + <el-table + v-loading="loading" + :data="list" + row-key="id" + border + > + <el-table-column label="文件名" header-align="center" align="center"> + <template #default="scope"> + <a style="cursor: pointer;color: #409eff" @click="downloadHistory(scope.row.id,scope.row.fileName)">{{ scope.row.fileName }}</a> + </template> + </el-table-column> + <el-table-column prop="remark" label="备注" header-align="center" align="center"/> + <el-table-column prop="createTime" label="生成时间" :formatter="dateFormatter" header-align="center" align="center" width="200"/> + </el-table> + <!-- 分页 --> + <Pagination + v-model:limit="queryParams.pageSize" + v-model:page="queryParams.page" + :total="total" + @pagination="getList" + /> + </ContentWrap> + </Dialog> +</template> +<script lang="ts" setup> + import download from "@/utils/download"; + import * as HistoryApi from "@/api/mpk/mpkHistory"; + import { dateFormatter } from '@/utils/formatTime' + + + const { t } = useI18n() // 国际化 + const message = useMessage() // 消息弹窗 + + const dialogVisible = ref(false) // 弹窗的是否展示 + const dialogTitle = ref('生成历史') // 弹窗的标题 + + const loading = ref(true) // 列表的加载中 + const total = ref(0) // 列表的总页数 + const list = ref([]) // 字典表格数据 + const queryParams = reactive({ + page: 1, + pageSize: 10, + mdkId: '', + startTime: undefined, + endTime: undefined, + }) + + /** 打开弹窗 */ + const open = async (mdkId: String) => { + dialogVisible.value = true + queryParams.mdkId = mdkId; + queryParams.startTime = undefined; + queryParams.endTime = undefined; + getList() + } + defineExpose({ open }) // 提供 open 方法,用于打开弹窗 + + const getList = async () => { + loading.value = true + try { + const data = await HistoryApi.getPage(queryParams) + list.value = data.list + total.value = data.total + } finally { + loading.value = false + } + } + + const downloadHistory = async (id,fileName) => { + const param = { + 'id': id, + } + const data = await HistoryApi.download(param) + download.zip(data, fileName) + } +</script> diff --git a/src/views/mpk/MpkRun.vue b/src/views/mpk/MpkRun.vue new file mode 100644 index 0000000..2a5f7f2 --- /dev/null +++ b/src/views/mpk/MpkRun.vue @@ -0,0 +1,243 @@ +<template> + <Dialog v-model="dialogVisible" :title="dialogTitle"> + <el-form + class="-mb-15px" + :model="formData" + ref="formRef" + :inline="true" + :rules="formRules" + label-width="68px" + v-loading="formLoading" + > + <el-form-item style="width: 100%"> + <el-divider content-position="left">模型信息</el-divider> + </el-form-item> + <el-form-item label="全类名" style="width: 90%" prop="className"> + <el-input v-model="formData.className" placeholder=""/> + </el-form-item> + <el-form-item label="方法名" prop="methodName"> + <el-select v-model="formData.methodName" @change="methodChange" style="width: 240px"> + <el-option + v-for="item in methodList" + :key="item.id" + :label="item.methodName" + :value="item.methodName" + /> + </el-select> + </el-form-item> + <el-divider content-position="left">模型参数信息</el-divider> + <el-row :gutter="20"> + <el-col :span="2" style="margin-bottom: 10px;margin-left: 20px"> + <el-button tag="a" href="/template/模型参数导入模板.xlsx" download="模型参数导入模板.xlsx" style="text-decoration: none;" type="primary" size="small" link>模板下载</el-button> + </el-col> + <el-col :span="2" style="margin-bottom: 10px;"> + <el-upload + ref="uploadRef" + v-model:file-list="fileList" + :show-file-list="false" + :action="importUrl" + :auto-upload="true" + :disabled="formLoading" + :before-upload="beforeUpload" + :headers="uploadHeaders" + :on-error="submitFormError" + :on-success="submitFormSuccess" + accept=".xlsx" + > + <el-button type="primary" size="small" link>参数导入</el-button> + </el-upload> + </el-col> + </el-row> + <el-row v-for="(item,index) in formData.datas" :key="index" :gutter="20"> + <el-col :span="20"> + <el-form-item :label="'参数_' + (index)" required style="width: 100%"> + <el-input v-model="formData.datas[index]" placeholder="" /> + </el-form-item> + </el-col> + </el-row> + <el-row v-if="hasModel" :gutter="20"> + <el-col :span="20"> + <el-form-item label="model" required style="width: 100%"> + <el-input v-model="formData.model" placeholder="" /> + </el-form-item> + </el-col> + </el-row> + <el-divider content-position="left">模型设置信息</el-divider> + <el-row :gutter="20"> + <el-col :span="4"> + <el-button type="primary" size="small" @click="addRow()">新增</el-button> + </el-col> + </el-row> + <el-table :data="formData.modelSettings" border> + <el-table-column + prop="" + label="参数key" + align="center"> + <template #default="scope"> + <el-input size="small" v-model="scope.row.settingKey" maxlength="50" clearable /> + </template> + </el-table-column> + <el-table-column + prop="" + label="参数value" + align="center"> + <template #default="scope"> + <el-input size="small" v-model="scope.row.settingValue" maxlength="50" clearable /> + </template> + </el-table-column> + <el-table-column label="操作" fixed="right" header-align="center" align="center" width="100"> + <template #default="scope"> + <el-button + @click="deleteRow(scope.$index)" + key="danger" + type="danger" + link + >删除</el-button> + </template> + </el-table-column> + </el-table> + <el-divider content-position="left">模型运行结果</el-divider> + <el-input v-model="modelRunResult" placeholder="" rows="4" type="textarea" /> + <div style="display: flex;flex-direction: row;justify-content: end;margin-top: 16px"> + <el-button :loading="modelRunloading" type="primary" @click="modelRun()">运行</el-button> + </div> + </el-form> + </Dialog> +</template> +<script lang="ts" setup> + import * as MpkApi from '@/api/mpk/mpk' + import {FormRules} from "element-plus"; + import {getAccessToken, getTenantId} from "@/utils/auth"; + + const { t } = useI18n() // 国际化 + const message = useMessage() // 消息弹窗 + + const dialogVisible = ref(false) // 弹窗的是否展示 + const dialogTitle = ref('模型运行') // 弹窗的标题 + + const formData = reactive({ + className: '', + methodName: '', + datas: [], + modelSettings: [], + model: undefined + }) + + // 模型方法下拉列表 + const methodList = ref([]) + const hasModel = ref(false) + + /** 打开弹窗 */ + const open = async (row) => { + dialogVisible.value = true + formData.className = row.pkgName + '.impl.' + row.pyName + 'Impl'; + const mpk = await MpkApi.getMpk(row.id) + methodList.value = mpk.modelMethods + formData.methodName = mpk.modelMethods[0].methodName + formData.datas = [] + for (let i = 0 ; i < mpk.modelMethods[0].dataLength ; i++) { + formData.datas[i] = '[[]]' + } + hasModel.value = mpk.modelMethods[0].model === 1 + } + defineExpose({ open }) // 提供 open 方法,用于打开弹窗 + + const formRules = reactive<FormRules>({ + methodName: [ + {required: true, message: '方法名不能为空', trigger: 'blur'} + ], + className: [ + {required: true, message: '全类名不能为空', trigger: 'blur'} + ] + }) + + const addRow = function () { + formData.modelSettings.push({ + settingKey: '', + settingValue: '' + }) + } + const deleteRow = function (index) { + formData.modelSettings.splice(index, 1) + } + const methodChange = function (value) { + formData.datas = [] + for (let i = 0 ; i < methodList.value.find(e => e.methodName === value)?.dataLength ; i++) { + formData.datas[i] = '[[]]' + } + hasModel.value = methodList.value.find(e => e.methodName === value)?.model === 1 + } + + const fileList = ref([]) // 文件列表 + const importUrl = + import.meta.env.VITE_BASE_URL + import.meta.env.VITE_API_URL + '/model/mpk/api/import' + const formLoading = ref(false) // 表单的加载中 + const uploadHeaders = ref() // 上传 Header 头 + /** 上传错误提示 */ + const submitFormError = (): void => { + message.error('导入失败,请检查导入文件!') + formLoading.value = false + } + const submitFormSuccess = (response: any) => { + if (response.code !== 0) { + message.error(response.msg) + formLoading.value = false + return + } + const datas = response.data; + for (let i=0;i<formData.datas.length;i++) { + formData.datas[i] = datas[i] + } + message.success('导入成功') + formLoading.value = false + } + const beforeUpload = function (file) { + // 提交请求 + uploadHeaders.value = { + Authorization: 'Bearer ' + getAccessToken(), + 'tenant-id': getTenantId() + } + formLoading.value = true + return true; + } + + // 模型运行结果 + const modelRunResult = ref('') + // 模型运行loading + const modelRunloading = ref(false) + // 表单 Ref + const formRef = ref() + // 运行 + const modelRun = async () => { +// 校验表单 + if (!formRef) return + const valid = await formRef.value.validate() + if (!valid) return + // 提交请求 + modelRunloading.value = true + try { + const data = { + ...formData + } + + //处理modelSettings + let settingsPredict = {}; + data.modelSettings.forEach(e => { + settingsPredict[e.settingKey] = e.settingValue; + }) + data.modelSettings = settingsPredict + data.hasModel = hasModel.value + if (data.hasModel && data.model) { + data.model = {model_path:data.model} + }else { + data.model = undefined + } + + modelRunResult.value = await MpkApi.modelRun(data) + modelRunloading.value = false + message.success('运行成功') + } finally { + modelRunloading.value = false + } + } +</script> diff --git a/src/views/mpk/ProjectForm.vue b/src/views/mpk/ProjectForm.vue new file mode 100644 index 0000000..37fee70 --- /dev/null +++ b/src/views/mpk/ProjectForm.vue @@ -0,0 +1,153 @@ +<template> + <Dialog v-model="dialogVisible" :title="dialogTitle"> + <el-form + ref="formRef" + v-loading="formLoading" + :model="formData" + :rules="formRules" + label-width="80px" + > + <el-row :gutter="20"> + <el-col :span="20"> + <el-form-item label="项目名称" prop="projectName" style="width: 100%"> + <el-input v-model="formData.projectName" placeholder="" style="width: 100%"/> + </el-form-item> + </el-col> + </el-row> + <el-row :gutter="20"> + <el-col :span="20"> + <el-form-item label="项目编码" prop="projectCode" style="width: 100%"> + <el-input v-model="formData.projectCode" placeholder="" style="width: 100%"/> + </el-form-item> + </el-col> + </el-row> + <el-row :gutter="20"> + <el-col> + <el-form-item label="关联模型" prop="models"> + <el-transfer :props="{key: 'id',label: 'pyName'}" :titles="['未选模型', '已选模型']" target-order="unshift" filterable :filter-method="filterMethod" v-model="formData.models" :data="modelList"> + <template #default="{ option }"> + <span :title="option.pyName">{{ option.pyName}}</span> + </template> + </el-transfer> + </el-form-item> + </el-col> + </el-row> + </el-form> + <template #footer> + <el-button type="primary" @click="submitForm">确 定</el-button> + <el-button @click="dialogVisible = false">取 消</el-button> + </template> + </Dialog> +</template> +<script lang="ts" setup> + import * as ProjectApi from '@/api/mpk/project' + import * as MpkApi from '@/api/mpk/mpk' + import {FormRules} from 'element-plus' + + + const {t} = useI18n() // 国际化 + const message = useMessage() // 消息弹窗 + + const dialogVisible = ref(false) // 弹窗的是否展示 + const dialogTitle = ref('') // 弹窗的标题 + const formLoading = ref(false) // 表单的加载中:1)修改时的数据加载;2)提交的按钮禁用 + const formType = ref('') // 表单的类型:create - 新增;update - 修改 + const formData = ref({ + id: undefined, + projectName: undefined, + projectCode: undefined, + }) + + + const formRules = reactive<FormRules>({ + projectName: [ + {required: true, message: '项目名称不能为空', trigger: 'blur'}, + ], + projectCode: [ + {required: true, message: '项目编码不能为空', trigger: 'blur'}, + ], + }) + + const formRef = ref() // 表单 Ref + + /** 打开弹窗 */ + const open = async (type: string, id?: number) => { + dialogVisible.value = true + dialogTitle.value = t('action.' + type) + formType.value = type + getModelList(); + resetForm() + // 修改时,设置数据 + if (id) { + formLoading.value = true + try { + const data = await ProjectApi.getProject(id) + data.models = data.models.map(e => e.id) + formData.value = { + ...data + } + } finally { + formLoading.value = false + } + } + } + defineExpose({open}) // 提供 open 方法,用于打开弹窗 + + /** 提交表单 */ + const emit = defineEmits(['success']) // 定义 success 事件,用于操作成功后的回调 + const submitForm = async () => { + // 校验表单 + if (!formRef) return + const valid = await formRef.value.validate() + if (!valid) return + // 提交请求 + formLoading.value = true + try { + const data = { + ...formData.value + } + data.models = data.models.map(e => { + return {id: e} + }) + if (formType.value === 'create') { + await ProjectApi.createProject(data) + message.success(t('common.createSuccess')) + } else { + await ProjectApi.updateProject(data) + message.success(t('common.updateSuccess')) + } + dialogVisible.value = false + // 发送操作成功的事件 + emit('success') + } finally { + formLoading.value = false + } + } + + /** 重置表单 */ + const resetForm = () => { + formData.value = { + id: undefined, + projectName: undefined, + projectCode: undefined, + } + formRef.value?.resetFields() + } + + // 所有模型列表 + const modelList = ref([]) + const getModelList = async () => { + modelList.value = await MpkApi.list() + } + + // 模型筛选 + const filterMethod = function (query, item) { + return item.pyName.toLowerCase().indexOf(query.toLowerCase()) !== -1 + } +</script> + +<style scoped> + :deep(.el-transfer-panel) { + width: 35%; + } +</style> diff --git a/src/views/mpk/ProjectPackage.vue b/src/views/mpk/ProjectPackage.vue new file mode 100644 index 0000000..86f3d77 --- /dev/null +++ b/src/views/mpk/ProjectPackage.vue @@ -0,0 +1,96 @@ +<template> + <Dialog v-model="dialogVisible" :title="dialogTitle"> + <el-form + ref="formRef" + v-loading="formLoading" + :model="formData" + :rules="formRules" + label-width="80px" + > + <el-row> + <el-col :span="8"> + <el-form-item label="版本号" prop="version"> + <el-input v-model="formData.version" placeholder="请输入版本号"/> + </el-form-item> + </el-col> + </el-row> + <el-row> + <el-col :span="24"> + <el-form-item label="更新日志" prop="log"> + <el-input type="textarea" :rows="4" placeholder="请输入更新日志" v-model="formData.log"/> + </el-form-item> + </el-col> + </el-row> + <el-row justify="end"> + <el-col :span="3"> + <el-button @click="packageProject()" type="primary">打包</el-button> + </el-col> + </el-row> + </el-form> + </Dialog> +</template> +<script lang="ts" setup> + import * as ProjectApi from '@/api/mpk/project' + import download from "@/utils/download"; + import {FormRules} from "element-plus"; + import {formatToDateString} from "@/utils/dateUtil"; + + + const { t } = useI18n() // 国际化 + const message = useMessage() // 消息弹窗 + + const dialogVisible = ref(false) // 弹窗的是否展示 + const dialogTitle = ref('打包') // 弹窗的标题 + const formLoading = ref(false) // 表单的加载中 + + const formRules = reactive<FormRules>({ + version: [ + {required: true, message: '版本号不能为空', trigger: 'blur'}, + ], + log: [ + {required: true, message: '更新日志不能为空', trigger: 'blur'}, + ] + }) + + const formData = reactive({ + log: undefined, + projectId: undefined, + projectName: undefined, + projectCode: undefined, + ids: undefined, + version: undefined, + }) + + /** 打开弹窗 */ + const open = async (projectId,projectName,projectCode,ids) => { + dialogVisible.value = true + formData.projectId = projectId + formData.projectName = projectName + formData.projectCode = projectCode + formData.ids = ids + formData.log = undefined + formData.version = 'V' + } + defineExpose({ open }) // 提供 open 方法,用于打开弹窗 + + const formRef = ref() // 表单 Ref + /** 提交表单 */ + const packageProject = async () => { + // 校验表单 + try { + if (!formRef) return + const valid = await formRef.value.validate() + if (!valid) return + + formLoading.value = true + formData.zipFileName = 'IAILMPK.' + formData.projectCode + '.' + formatToDateString(new Date()) + '.zip' + const data = await ProjectApi.packageProject(formData) + debugger + download.zip(data, formData.zipFileName) + formLoading.value = false + dialogVisible.value = false + } catch (e) { + formLoading.value = false + } + } +</script> diff --git a/src/views/mpk/ProjectPackageHistory.vue b/src/views/mpk/ProjectPackageHistory.vue new file mode 100644 index 0000000..8548540 --- /dev/null +++ b/src/views/mpk/ProjectPackageHistory.vue @@ -0,0 +1,155 @@ +<template> + <ContentWrap> + <el-form + class="-mb-15px" + :model="queryParams" + ref="queryFormRef" + :inline="true" + label-width="68px" + > + <el-form-item label="项目名称" prop="projectId"> + <el-select v-model="queryParams.projectId" class="!w-240px"> + <el-option + v-for="item in projectList" + :key="item.id" + :label="item.projectName" + :value="item.id" + /> + </el-select> + </el-form-item> + <el-form-item label="开始时间" prop="startTime"> + <el-date-picker + v-model="queryParams.startTime" + type="datetime" + value-format="YYYY-MM-DD HH:mm:ss" + placeholder="选择日期时间"/> + </el-form-item> + <el-form-item label="结束时间" prop="endTime"> + <el-date-picker + v-model="queryParams.endTime" + type="datetime" + value-format="YYYY-MM-DD HH:mm:ss" + placeholder="选择日期时间"/> + </el-form-item> + <el-form-item> + <el-button @click="handleQuery"> + <Icon icon="ep:search" class="mr-5px"/> + 搜索 + </el-button> + <el-button @click="resetQuery"> + <Icon icon="ep:refresh" class="mr-5px"/> + 重置 + </el-button> + </el-form-item> + </el-form> + </ContentWrap> + + <!-- 列表 --> + <ContentWrap> + <el-table v-loading="loading" :data="list"> + <el-table-column label="文件名" header-align="center" align="center" width="400"> + <template #default="scope"> + <a style="cursor: pointer;color: #409eff" + @click="downloadHistory(scope.row.filePath,scope.row.fileName)">{{ scope.row.fileName + }}</a> + </template> + </el-table-column> + <el-table-column prop="version" label="版本号" header-align="center" align="center" width="200"/> + <el-table-column prop="log" label="更新日志" header-align="center" align="center"/> + <el-table-column prop="createTime" label="打包时间" :formatter="dateFormatter" header-align="center" align="center" width="200"/> + <el-table-column label="操作" align="center" width="230px"> + <template #default="scope"> + <el-button + link + type="primary" + @click="viewPackageModel(scope.row.id)" + > + <Icon icon="ep:link"/> + 查看关联模型 + </el-button> + </template> + </el-table-column> + + </el-table> + <!-- 分页 --> + <Pagination + :total="total" + v-model:page="queryParams.pageNo" + v-model:limit="queryParams.pageSize" + @pagination="getList" + /> + </ContentWrap> + + <PackageModel ref="packageModelRef"/> +</template> +<script lang="ts" setup> + import download from "@/utils/download"; + import * as PackageHistoryApi from '@/api/mpk/projectPackageHistory' + import * as ProjectApi from '@/api/mpk/project' + import {dateFormatter} from '@/utils/formatTime' + import PackageModel from './ProjectPackageModelDialog.vue' + + defineOptions({name: 'ProjectPackageHistory'}) + + const message = useMessage() // 消息弹窗 + const {t} = useI18n() // 国际化 + const route = useRoute() // 路由 + + const loading = ref(true) // 列表的加载中 + const total = ref(0) // 列表的总页数 + const list = ref([]) // 列表的数据 + const queryParams = reactive({ + pageNo: 1, + pageSize: 10, + projectId: route.params.projectId, + startTime: undefined, + endTime: undefined, + }) + const queryFormRef = ref() // 搜索的表单 + const projectList = ref() // 字典类型的列表 + + /** 查询列表 */ + const getList = async () => { + loading.value = true + try { + const data = await PackageHistoryApi.getPage(queryParams) + list.value = data.list + total.value = data.total + } finally { + loading.value = false + } + } + + /** 搜索按钮操作 */ + const handleQuery = () => { + queryParams.pageNo = 1 + getList() + } + + /** 重置按钮操作 */ + const resetQuery = () => { + queryFormRef.value.resetFields() + handleQuery() + } + + const downloadHistory = async (filePath,fileName) => { + const param = { + filePath, + fileName, + } + const data = await PackageHistoryApi.download(param) + download.zip(data, fileName) + } + + const packageModelRef = ref() + const viewPackageModel = (id) => { + packageModelRef.value.open('package',id) + } + + /** 初始化 **/ + onMounted(async () => { + await getList() + // 查询字典(精简)列表 + projectList.value = await ProjectApi.list() + }) +</script> diff --git a/src/views/mpk/ProjectPackageModelDialog.vue b/src/views/mpk/ProjectPackageModelDialog.vue new file mode 100644 index 0000000..531b66f --- /dev/null +++ b/src/views/mpk/ProjectPackageModelDialog.vue @@ -0,0 +1,119 @@ +<template> + <Dialog v-model="dialogVisible" :title="dialogTitle" width="80%"> + <!-- 搜索工作栏 --> + <ContentWrap> + <el-form + class="-mb-15px" + :model="queryParams" + ref="queryFormRef" + :inline="true" + label-width="68px" + > + <el-form-item label="模型名称" prop="pyName"> + <el-input + v-model="queryParams.pyName" + placeholder="请输入模型名称" + clearable + class="!w-240px" + /> + </el-form-item> + <el-form-item> + <el-button @click="getList"><Icon icon="ep:search" class="mr-5px" /> 搜索</el-button> + </el-form-item> + </el-form> + </ContentWrap> + + <!-- 列表 --> + <ContentWrap> + <el-table + v-loading="loading" + :data="list" + row-key="id" + border + > + <el-table-column prop="pyName" label="模型名称"/> + <el-table-column prop="pkgName" label="包名"/> + <el-table-column prop="pyModule" label="模型路径" width="300px"/> + <el-table-column prop="remark" label="备注" width="300px"/> + <el-table-column label="模型方法" type="expand" width="100px"> + <template #default="props"> + <el-table :data="props.row.modelMethods"> + <el-table-column align="center" label="方法名" prop="methodName" /> + <el-table-column align="center" label="参数长度" prop="dataLength" /> + <el-table-column align="center" label="是否有model" prop="model" :formatter="(row,column,cellValue) => cellValue === 1 ? 'true' : 'false'" /> + </el-table> + </template> + </el-table-column> + </el-table> + <!-- 分页 --> + <Pagination + v-model:limit="queryParams.pageSize" + v-model:page="queryParams.page" + :total="total" + @pagination="getList" + /> + </ContentWrap> + </Dialog> +</template> +<script lang="ts" setup> + import download from "@/utils/download"; + import * as projectHistoryApi from '@/api/mpk/projectPackageHistory' + import * as projectApi from '@/api/mpk/project' + import { dateFormatter } from '@/utils/formatTime' + + + const { t } = useI18n() // 国际化 + const message = useMessage() // 消息弹窗 + + const dialogVisible = ref(false) // 弹窗的是否展示 + const dialogTitle = ref('关联模型') // 弹窗的标题 + + const loading = ref(true) // 列表的加载中 + const total = ref(0) // 列表的总页数 + const list = ref([]) // 字典表格数据 + const queryParams = reactive({ + page: 1, + pageSize: 10, + packageHistoryId: undefined, + projectId: undefined, + pyName: undefined, + }) + + const dialogType = ref('') + + /** 打开弹窗 */ + const open = async (type: String,id: String) => { + dialogVisible.value = true + dialogType.value = type + + if (dialogType.value === 'package') { + queryParams.packageHistoryId = id; + }else if (dialogType.value === 'project') { + queryParams.projectId = id; + } + + queryParams.pyName = undefined; + getList() + } + defineExpose({ open }) // 提供 open 方法,用于打开弹窗 + + const getList = async () => { + loading.value = true + try { + let data = undefined; + if (dialogType.value === 'package') { + data = await projectHistoryApi.getPackageModel(queryParams) + data.list.forEach(e => { + e.modelMethods = JSON.parse(e.methodInfo) + }) + }else if (dialogType.value === 'project') { + data = await projectApi.getProjectModel(queryParams) + } + + list.value = data.list + total.value = data.total + } finally { + loading.value = false + } + } +</script> diff --git a/src/views/mpk/mpk.vue b/src/views/mpk/mpk.vue new file mode 100644 index 0000000..9354e60 --- /dev/null +++ b/src/views/mpk/mpk.vue @@ -0,0 +1,210 @@ +<template> + <!-- 搜索工作栏 --> + <ContentWrap> + <el-form + class="-mb-15px" + :model="queryParams" + ref="queryFormRef" + :inline="true" + label-width="68px" + > + <el-form-item label="模型名称" prop="pyName"> + <el-input + v-model="queryParams.pyName" + placeholder="请输入模型名称" + clearable + class="!w-240px" + /> + </el-form-item> + <el-form-item> + <el-button @click="handleQuery"> + <Icon icon="ep:search" class="mr-5px"/> + 搜索 + </el-button> + <el-button @click="resetQuery"> + <Icon icon="ep:refresh" class="mr-5px"/> + 重置 + </el-button> + <el-button + type="primary" + plain + @click="openForm('create')" + v-hasPermi="['mpk:create']" + > + <Icon icon="ep:plus" class="mr-5px"/> + 新增 + </el-button> + </el-form-item> + </el-form> + </ContentWrap> + + <!-- 列表 --> + <ContentWrap> + <el-table + v-loading="loading" + :data="list" + row-key="id" + > + <el-table-column prop="pyName" label="模型名称"/> + <el-table-column prop="pkgName" label="包名"/> + <el-table-column prop="pyModule" label="模型路径" width="200px"/> + <el-table-column prop="remark" label="备注" width="300px"/> + <el-table-column prop="createDate" label="创建时间" :formatter="dateFormatter" width="170px"/> + <el-table-column label="操作" align="center" width="200px"> + <template #default="scope"> + <div class="flex items-center justify-center"> + <el-button link type="primary" @click="openForm('update', scope.row.id)" v-hasPermi="['mpk:update']"> + <Icon icon="ep:edit"/>修改 + </el-button> + <el-button link type="danger" @click="handleDelete(scope.row.id)" v-hasPermi="['mpk:delete']"> + <Icon icon="ep:delete"/>删除 + </el-button> + <div class="pl-12px"> + <el-dropdown @command="(command) => handleCommand(command, scope.row)" trigger="click"> + <el-button type="primary" link> + <Icon icon="ep:d-arrow-right" /> 更多 + </el-button> + <template #dropdown> + <el-dropdown-menu> + <el-dropdown-item + command="generatorCode" + > + 生成代码 + </el-dropdown-item> + <el-dropdown-item + command="generatorHistory" + > + 生成历史 + </el-dropdown-item> + <el-dropdown-item + command="mpkRunDialog" + > + 运行 + </el-dropdown-item> + </el-dropdown-menu> + </template> + </el-dropdown> + </div> + </div> + </template> + </el-table-column> + </el-table> + <!-- 分页 --> + <Pagination + v-model:limit="queryParams.pageSize" + v-model:page="queryParams.page" + :total="total" + @pagination="getList" + /> + </ContentWrap> + + <!-- 表单弹窗:添加/修改 --> + <MpkForm ref="formRef" @success="getList"/> + <MpkGenerator ref="mpkGenerator"/> + <GeneratorCodeHistory ref="generatorCodeHistory"/> + <MpkRun ref="mpkRun"/> +</template> +<script lang="ts" setup> + import {dateFormatter} from '@/utils/formatTime' + import * as MpkApi from '@/api/mpk/mpk' + import MpkForm from './MpkForm.vue' + import MpkGenerator from './MpkGenerator.vue' + import GeneratorCodeHistory from './MpkGeneratorHistory.vue' + import MpkRun from './MpkRun.vue' + import * as UserApi from "@/api/system/user"; + + defineOptions({name: 'Mpk'}) + + const message = useMessage() // 消息弹窗 + const {t} = useI18n() // 国际化 + + const loading = ref(true) // 列表的加载中 + const total = ref(0) // 列表的总页数 + const list = ref([]) // 字典表格数据 + const queryParams = reactive({ + page: 1, + pageSize: 10, + pyName: '' + }) + const queryFormRef = ref() // 搜索的表单 + + const getList = async () => { + loading.value = true + try { + const data = await MpkApi.getPage(queryParams) + list.value = data.list + total.value = data.total + } finally { + loading.value = false + } + } + + /** 操作分发 */ + const handleCommand = (command: string, row) => { + switch (command) { + case 'generatorCode': + generatorCode(row.id,row.pyName) + break + case 'generatorHistory': + generatorHistory(row.id) + break + case 'mpkRunDialog': + mpkRunDialog(row) + break + default: + break + } + } + + const mpkGenerator = ref(); + const generatorCode = (id,pyName) => { + mpkGenerator.value.open(id,pyName); + } + + const generatorCodeHistory = ref(); + const generatorHistory = (id) => { + generatorCodeHistory.value.open(id); + } + + const mpkRun = ref(); + const mpkRunDialog = (row) => { + mpkRun.value.open(row); + } + + /** 搜索按钮操作 */ + const handleQuery = () => { + getList() + } + + /** 重置按钮操作 */ + const resetQuery = () => { + queryParams.page = 1 + queryFormRef.value.resetFields() + handleQuery() + } + + /** 添加/修改操作 */ + const formRef = ref() + const openForm = (type: string, id?: number) => { + formRef.value.open(type, id) + } + + /** 删除按钮操作 */ + const handleDelete = async (id: number) => { + try { + // 删除的二次确认 + await message.delConfirm() + // 发起删除 + await MpkApi.deleteMpk(id) + message.success(t('common.delSuccess')) + // 刷新列表 + await getList() + } catch { + } + } + + /** 初始化 **/ + onMounted(async () => { + await getList() + }) +</script> diff --git a/src/views/mpk/project.vue b/src/views/mpk/project.vue new file mode 100644 index 0000000..cc4a287 --- /dev/null +++ b/src/views/mpk/project.vue @@ -0,0 +1,228 @@ +<template> + <!-- 搜索工作栏 --> + <ContentWrap> + <el-form + class="-mb-15px" + :model="queryParams" + ref="queryFormRef" + :inline="true" + label-width="68px" + > + <el-form-item label="项目名称" prop="projectName"> + <el-input + v-model="queryParams.projectName" + placeholder="请输入项目名称" + clearable + class="!w-240px" + /> + </el-form-item> + <el-form-item label="项目编码" prop="projectCode"> + <el-input + v-model="queryParams.projectCode" + placeholder="请输入项目编码" + clearable + class="!w-240px" + /> + </el-form-item> + <el-form-item> + <el-button @click="handleQuery"> + <Icon icon="ep:search" class="mr-5px"/> + 搜索 + </el-button> + <el-button @click="resetQuery"> + <Icon icon="ep:refresh" class="mr-5px"/> + 重置 + </el-button> + <el-button + type="primary" + plain + @click="openForm('create')" + v-hasPermi="['project:create']" + > + <Icon icon="ep:plus" class="mr-5px"/> + 新增 + </el-button> + </el-form-item> + </el-form> + </ContentWrap> + + <!-- 列表 --> + <ContentWrap> + <el-table + v-loading="loading" + :data="list" + row-key="id" + > + <el-table-column prop="projectName" label="项目名称"/> + <el-table-column prop="projectCode" label="项目编码"/> + <el-table-column prop="createTime" label="创建时间" :formatter="dateFormatter" width="300px"/> + <el-table-column label="操作" align="center" width="300px"> + <template #default="scope"> + <div class="flex items-center justify-center"> + <el-button + link + type="primary" + @click="openForm('update', scope.row.id)" + v-hasPermi="['project:update']" + > + <Icon icon="ep:edit"/> + 修改 + </el-button> + <el-button + link + type="danger" + @click="handleDelete(scope.row.id)" + v-hasPermi="['project:delete']" + > + <Icon icon="ep:delete"/> + 删除 + </el-button> + <el-button + link + type="primary" + @click="viewRelevanceModel(scope.row.id)" + > + <Icon icon="ep:link"/> + 查看关联模型 + </el-button> + <div class="pl-12px"> + <el-dropdown @command="(command) => handleCommand(command, scope.row)" + trigger="click"> + <el-button type="primary" link> + <Icon icon="ep:d-arrow-right"/> + 更多 + </el-button> + <template #dropdown> + <el-dropdown-menu> + <el-dropdown-item + command="packageModel" + > + <el-button link>打包</el-button> + </el-dropdown-item> + <el-dropdown-item + > + <router-link :to="'/project/package/history/' + scope.row.id"> + <el-button link>打包历史</el-button> + </router-link> + </el-dropdown-item> + </el-dropdown-menu> + </template> + </el-dropdown> + </div> + </div> + </template> + </el-table-column> + </el-table> + <!-- 分页 --> + <Pagination + v-model:limit="queryParams.pageSize" + v-model:page="queryParams.page" + :total="total" + @pagination="getList" + /> + </ContentWrap> + + <!-- 表单弹窗:添加/修改 --> + <ProjectForm ref="formRef" @success="getList"/> + <ProjectPackage ref="projectPackageRef"/> + <RelevanceModel ref="relevanceModelRef"/> +</template> +<script lang="ts" setup> + import {dateFormatter} from '@/utils/formatTime' + import * as ProjectApi from '@/api/mpk/project' + import ProjectForm from './ProjectForm.vue' + import ProjectPackage from './ProjectPackage.vue' + import RelevanceModel from './ProjectPackageModelDialog.vue' + + defineOptions({name: 'Project'}) + + const message = useMessage() // 消息弹窗 + const {t} = useI18n() // 国际化 + + const loading = ref(true) // 列表的加载中 + const total = ref(0) // 列表的总页数 + const list = ref([]) // 字典表格数据 + const queryParams = reactive({ + page: 1, + pageSize: 10, + projectName: '', + projectCode: '' + }) + const queryFormRef = ref() // 搜索的表单 + + const getList = async () => { + loading.value = true + try { + const data = await ProjectApi.getPage(queryParams) + list.value = data.list + total.value = data.total + } finally { + loading.value = false + } + } + + /** 操作分发 */ + const handleCommand = (command: string, row) => { + switch (command) { + case 'packageModel': + packageModel(row.id, row.projectName, row.projectCode, row.models) + break + default: + break + } + } + + //打包 + const projectPackageRef = ref(); + const packageModel = (projectId, projectName, projectCode, models) => { + let ids = models.map(e => e.id); + if (ids && ids.length > 0) { + projectPackageRef.value.open(projectId, projectName, projectCode, ids.join(",")); + } else { + message.error("请先为项目添加模型!") + } + } + + /** 搜索按钮操作 */ + const handleQuery = () => { + getList() + } + + /** 重置按钮操作 */ + const resetQuery = () => { + queryParams.page = 1 + queryFormRef.value.resetFields() + handleQuery() + } + + /** 添加/修改操作 */ + const formRef = ref() + const openForm = (type: string, id?: number) => { + formRef.value.open(type, id) + } + + /** 删除按钮操作 */ + const handleDelete = async (id: number) => { + try { + // 删除的二次确认 + await message.delConfirm() + // 发起删除 + await ProjectApi.deleteProject(id) + message.success(t('common.delSuccess')) + // 刷新列表 + await getList() + } catch { + } + } + + // 查看关联模型 + const relevanceModelRef = ref() + const viewRelevanceModel = (id) => { + relevanceModelRef.value.open('project',id) + } + + /** 初始化 **/ + onMounted(async () => { + await getList() + }) +</script> -- Gitblit v1.9.3