houzhongjian
2024-09-13 185cd91d7c835085c5bf5ff1bd8ec948d859f076
Merge remote-tracking branch 'origin/master'
已修改5个文件
已添加57个文件
7024 ■■■■■ 文件已修改
public/template/模型参数导入模板.xlsx 补丁 | 查看 | 原始文档 | blame | 历史
src/api/data/channel/http/index.ts 43 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/data/channel/kio/index.ts 40 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/data/channel/opcda/index.ts 40 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/data/channel/opcua/index.ts 44 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/data/da/point/index.ts 49 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/data/ind/category/index.ts 42 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/data/ind/data/data.field.ts 35 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/data/ind/data/data.set.ts 40 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/model/pre/dm/index.ts 37 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/model/pre/item/index.ts 37 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/model/pre/predict/index.ts 50 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/model/pre/result/index.ts 35 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/model/sche/model/index.ts 66 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/model/sche/scheme/index.ts 46 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/mpk/mpk.ts 46 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/mpk/mpkHistory.ts 10 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/mpk/project.ts 33 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/mpk/projectPackageHistory.ts 13 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/router/modules/remaining.ts 46 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/utils/dateUtil.ts 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/utils/dict.ts 12 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/data/channel/http/HttpApiForm.vue 155 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/data/channel/http/index.vue 156 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/data/channel/kio/KioDeviceForm.vue 132 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/data/channel/kio/index.vue 152 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/data/channel/modbus/ModBusDeviceForm.vue 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/data/channel/modbus/index.vue 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/data/channel/opcda/OpcDaDeviceForm.vue 138 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/data/channel/opcda/index.vue 152 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/data/channel/opcua/OpcUaDeviceForm.vue 167 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/data/channel/opcua/index.vue 157 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/data/da/point/DaPointForm.vue 202 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/data/da/point/index.vue 172 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/data/ind/category/CategoryForm.vue 141 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/data/ind/category/index.vue 159 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/data/ind/data/DataSetForm.vue 129 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/data/ind/data/field/DataSetFieldForm.vue 124 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/data/ind/data/field/index.vue 155 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/data/ind/data/index.vue 161 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/model/mcs/sche/model/ScheduleModelForm.vue 400 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/model/mcs/sche/model/index.vue 172 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/model/mcs/sche/scheme/ScheduleSchemeForm.vue 215 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/model/mcs/sche/scheme/index.vue 178 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/model/pre/dm/DmModuleForm.vue 136 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/model/pre/dm/index.vue 154 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/model/pre/item/ItemTypeForm.vue 115 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/model/pre/item/index.vue 151 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/model/pre/predict/MmPredictItemForm.vue 209 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/model/pre/predict/index.vue 173 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/model/pre/result/MmResultTableForm.vue 96 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/model/pre/result/index.vue 149 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/mpk/MpkForm.vue 278 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/mpk/MpkGenerator.vue 49 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/mpk/MpkGeneratorHistory.vue 109 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/mpk/MpkRun.vue 243 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/mpk/ProjectForm.vue 153 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/mpk/ProjectPackage.vue 96 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/mpk/ProjectPackageHistory.vue 155 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/mpk/ProjectPackageModelDialog.vue 119 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/mpk/mpk.vue 210 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/mpk/project.vue 228 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
public/template/模型参数导入模板.xlsx
Binary files differ
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 })
}
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 })
}
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 })
}
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 })
}
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 })
}
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 })
}
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 })
}
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 })
}
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 })
}
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 })
}
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 })
}
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 })
}
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'] = []
}
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 })
}
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'})
}
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 })
}
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 })
}
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 })
}
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
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
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',
}
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>
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>
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>
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>
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() // 消息弹窗
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() // 国际化
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>