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