Compare commits

...

7 Commits

@ -86,9 +86,13 @@ export const MoldBrandApi = {
getMoldList: async (params) => {
return await request.get({ url: `/erp/mold-brand/getMoldList`, params })
},
// 查询模具列表
// 查询全部模具列表
getMoldAllList: async () => {
return await request.get({ url: `/erp/mold-brand/getMoldAllList`})
return await request.get({ url: `/erp/mold-brand/getMoldAllList` })
},
// 查询在途模具列表(用于上模)
getInTransitMoldAllList: async () => {
return await request.get({ url: `/erp/mold/getInTransitMoldAllList` })
},
// 获得模具分页
getMoldPage: async (params) => {

@ -51,6 +51,11 @@ export const DeviceModelAttributeApi = {
return await request.download({ url: `/iot/device-model-attribute/export-excel`, params })
},
// 下载采集设备模型-点位管理导入模板
importDeviceModelAttributeTemplate: async () => {
return await request.download({ url: `/iot/device-model-attribute/get-import-template` })
},
operationAnalysisDetails: async (params: {
deviceId: number
modelId?: number

@ -4,9 +4,10 @@ import request from '@/config/axios'
export interface MoldOperateVO {
id: number // ID
operateType: string // 操作类型
moldId: number // 关联模具id
moldId: number | string // 关联模具id(上模/下模剩余模具,支持逗号分隔)
deviceId: number // 关联设备id
remark: string // 备注
lowerMoldId?: number | string // 下模的模具id
}
// 模具上下模 API
@ -41,8 +42,8 @@ export const MoldOperateApi = {
return await request.download({ url: `/mes/mold-operate/export-excel`, params })
},
// 查询设备是否有模具
getMoldOperateMold: async (id: number) => {
return await request.get({ url: `/mes/mold-operate/get-mold?id=` + id })
// 查询设备可下模具列表
getLowerMoldList: async (id: number) => {
return await request.get({ url: `/mes/mold-operate/getLowerMoldList`, params: { id } })
},
}

@ -44,6 +44,7 @@ export default {
importMessage: 'Whether to confirm import data item?',
createSuccess: 'Create Success',
updateSuccess: 'Update Success',
total: 'Total',
delMessage: 'Delete the selected data?',
delDataMessage: 'Delete the data?',
delNoData: 'Please select the data to delete',
@ -58,6 +59,203 @@ export default {
copyError: 'Copy Error',
code:'Auto-generate on Save'
},
ErpStock: {
Warehouse: {
name: 'Warehouse Name',
status: 'Warehouse Status',
address: 'Warehouse Address',
warehousePrice: 'Storage Fee',
truckagePrice: 'Truckage Fee',
principal: 'Principal',
remark: 'Remark',
sort: 'Sort',
defaultStatus: 'Default Status',
createTime: 'Create Time',
placeholderName: 'Please enter warehouse name',
placeholderStatus: 'Please select warehouse status',
placeholderAddress: 'Please enter warehouse address',
placeholderPrincipal: 'Please enter principal',
placeholderSort: 'Please enter sort',
placeholderRemark: 'Please enter remark',
validatorNameRequired: 'Warehouse name is required',
validatorSortRequired: 'Sort is required',
validatorStatusRequired: 'Status is required',
confirmDefaultStatus: 'Are you sure to {action} "{name}" as default?',
set: 'set',
cancel: 'cancel',
exportName: 'Warehouse.xls'
},
Stock: {
product: 'Product',
warehouse: 'Warehouse',
code: 'Code',
name: 'Name',
category: 'Category',
unit: 'Unit',
count: 'Stock Quantity',
placeholderProduct: 'Please select product',
placeholderWarehouse: 'Please select warehouse',
exportName: 'Product Stock.xls'
},
In: {
no: 'Inbound No',
product: 'Product',
inTime: 'Inbound Time',
warehouse: 'Warehouse',
creator: 'Creator',
status: 'Status',
remark: 'Remark',
supplier: 'Supplier',
productInfo: 'Product Info',
count: 'Quantity',
price: 'Amount',
totalPrice: 'Total Price',
inType: 'Inbound Type',
tabProduct: 'Product Inbound',
tabMaterial: 'Material Inbound',
tabPart: 'Part Inbound',
tabOther: 'Other Inbound',
placeholderNo: 'Please enter inbound no',
placeholderNoAuto: 'Auto-generated on save',
placeholderProduct: 'Please select product',
placeholderWarehouse: 'Please select warehouse',
placeholderCreator: 'Please select creator',
placeholderStatus: 'Please select status',
placeholderRemark: 'Please enter remark',
placeholderSupplier: 'Please select supplier',
placeholderInTime: 'Select inbound time',
placeholderInType: 'Please select inbound type',
validatorInTimeRequired: 'Inbound time is required',
validatorInTypeRequired: 'Inbound type is required',
confirmApprove: 'Are you sure to approve this inbound order?',
confirmReverseApprove: 'Are you sure to reverse approve this inbound order?',
approveSuccess: 'Approve success',
reverseApproveSuccess: 'Reverse approve success',
exportName: 'Other Inbound Order.xls',
list: 'Inbound Product List',
addItem: 'Add Inbound Product'
},
Out: {
no: 'Outbound No',
customer: 'Customer',
outTime: 'Outbound Time',
outType: 'Outbound Type',
warehouse: 'Warehouse',
remark: 'Remark',
file: 'Attachment',
list: 'Outbound Product List',
tabOther: 'Other Outbound',
tabPart: 'Part Outbound',
tabMaterial: 'Material Outbound',
tabProduct: 'Product Outbound',
tabPick: 'Pick Outbound',
placeholderNo: 'Auto-generated on save',
placeholderCustomer: 'Please select customer',
placeholderOutTime: 'Select outbound time',
placeholderOutType: 'Please select outbound type',
placeholderRemark: 'Please enter remark',
validatorOutTimeRequired: 'Outbound time is required',
validatorOutTypeRequired: 'Outbound type is required',
confirmApprove: 'Are you sure to approve this outbound order?',
confirmReverseApprove: 'Are you sure to reverse approve this outbound order?',
approveSuccess: 'Approve success',
reverseApproveSuccess: 'Reverse approve success',
exportName: 'Other Outbound Order.xls',
addItem: 'Add Outbound Product'
},
Item: {
index: 'Index',
warehouse: 'Warehouse Name',
product: 'Product Name',
stock: 'Stock',
barcode: 'Barcode',
unit: 'Unit',
count: 'Quantity',
price: 'Price',
totalPrice: 'Total Price',
remark: 'Remark',
action: 'Action',
placeholderWarehouse: 'Please select warehouse',
placeholderProduct: 'Please select product',
validatorWarehouseRequired: 'Warehouse is required',
validatorProductRequired: 'Product is required',
validatorCountRequired: 'Quantity is required'
},
Check: {
no: 'Check No',
product: 'Product',
checkTime: 'Check Time',
warehouse: 'Warehouse',
creator: 'Creator',
status: 'Status',
remark: 'Remark',
productNames: 'Product Names',
count: 'Quantity',
price: 'Amount',
totalPrice: 'Total Price',
placeholderNo: 'Please enter check no',
placeholderNoAuto: 'Auto-generated on save',
placeholderProduct: 'Please select product',
placeholderWarehouse: 'Please select warehouse',
placeholderCreator: 'Please select creator',
placeholderStatus: 'Please select status',
placeholderRemark: 'Please enter remark',
placeholderCheckTime: 'Select check time',
validatorCheckTimeRequired: 'Check time is required',
confirmApprove: 'Are you sure to approve this check order?',
confirmReverseApprove: 'Are you sure to reverse approve this check order?',
approveSuccess: 'Approve success',
reverseApproveSuccess: 'Reverse approve success',
exportName: 'Check Order.xls',
list: 'Check Product List',
addItem: 'Add Check Product',
item: {
warehouse: 'Warehouse Name',
bookStock: 'Book Stock',
actualStock: 'Actual Stock',
profitLoss: 'Profit/Loss',
placeholderWarehouse: 'Please select warehouse name',
validatorWarehouseRequired: 'Warehouse name is required'
}
},
Move: {
no: 'Transfer No',
product: 'Product',
moveTime: 'Transfer Time',
fromWarehouse: 'Warehouse',
creator: 'Creator',
status: 'Status',
remark: 'Remark',
productNames: 'Product Info',
count: 'Quantity',
price: 'Amount',
totalPrice: 'Total Price',
placeholderNo: 'Please enter transfer no',
placeholderNoAuto: 'Auto-generated on save',
placeholderProduct: 'Please select product',
placeholderWarehouse: 'Please select warehouse',
placeholderCreator: 'Please select creator',
placeholderStatus: 'Please select status',
placeholderRemark: 'Please enter remark',
placeholderMoveTime: 'Select transfer time',
validatorMoveTimeRequired: 'Transfer time is required',
confirmApprove: 'Are you sure to approve this transfer order?',
confirmReverseApprove: 'Are you sure to reverse approve this transfer order?',
approveSuccess: 'Approve success',
reverseApproveSuccess: 'Reverse approve success',
exportName: 'Stock Transfer Order.xls',
list: 'Transfer Product List',
addItem: 'Add Transfer Product',
item: {
fromWarehouse: 'From Warehouse',
toWarehouse: 'To Warehouse',
placeholderFromWarehouse: 'Please select from warehouse',
placeholderToWarehouse: 'Please select to warehouse',
validatorFromWarehouseRequired: 'From warehouse is required',
validatorToWarehouseRequired: 'To warehouse is required'
}
}
},
lock: {
lockScreen: 'Lock screen',
lock: 'Lock',
@ -296,6 +494,7 @@ export default {
delete: 'Delete',
edit: 'Edit',
update: 'Update',
copy: 'Copy',
preview: 'Preview',
more: 'More',
sync: 'Sync',
@ -2012,6 +2211,7 @@ export default {
operateTypeDown: 'Mold Down',
mold: 'Mold',
moldName: 'Mold Name',
lowerMold: 'Lower Mold',
device: 'Device',
deviceName: 'Device Name',
remark: 'Remark',
@ -2026,6 +2226,7 @@ export default {
export: 'Export',
exportFilename: 'MoldOperate.xls',
placeholderMold: 'Please select mold',
placeholderLowerMold: 'Please select lower mold',
placeholderRemark: 'Please input remark',
placeholderCreateTimeStart: 'Start Date',
placeholderCreateTimeEnd: 'End Date',
@ -2035,6 +2236,7 @@ export default {
validatorOperateTypeRequired: 'Operation type can not be empty',
validatorDeviceRequired: 'Device can not be empty',
validatorMoldRequired: 'Mold can not be empty',
validatorLowerMoldRequired: 'Lower mold can not be empty',
alertNeedRemoveMoldFirst: 'Please remove the mold from this device first!',
alertNoMoldOnDevice: 'No mold is installed on this device!'
},
@ -3060,5 +3262,347 @@ export default {
exportFilename: 'FormingRecord.xls'
}
},
DataCollection: {
DeviceAttributeType: {
moduleName: 'Acquisition Point Type',
index: 'Index',
code: 'Type Code',
name: 'Type Name',
sort: 'Display Order',
remark: 'Remark',
createTime: 'Create Time',
operate: 'Operate',
search: 'Search',
reset: 'Reset',
create: 'Create',
batchDelete: 'Batch Delete',
export: 'Export',
placeholderCode: 'Please enter type code',
placeholderName: 'Please enter type name',
placeholderSort: 'Please enter display order',
placeholderRemark: 'Please enter remark',
dialogOk: 'Confirm',
dialogCancel: 'Cancel',
validatorCodeRequired: 'Type code can not be empty',
validatorNameRequired: 'Type name can not be empty',
validatorSortRequired: 'Display order can not be empty',
exportFilename: 'AcquisitionPointType.xls'
},
DeviceModel: {
moduleName: 'Acquisition Device Model',
index: 'Index',
code: 'Model Code',
name: 'Model Name',
protocol: 'Protocol',
remark: 'Remark',
createTime: 'Create Time',
operate: 'Operate',
search: 'Search',
reset: 'Reset',
create: 'Create',
batchDelete: 'Batch Delete',
export: 'Export',
placeholderCode: 'Please enter model code',
placeholderName: 'Please enter model name',
placeholderProtocol: 'Please select protocol',
placeholderRemark: 'Please enter remark',
dialogOk: 'Confirm',
dialogCancel: 'Cancel',
validatorCodeRequired: 'Model code can not be empty',
validatorNameRequired: 'Model name can not be empty',
validatorProtocolRequired: 'Protocol can not be empty',
exportFilename: 'AcquisitionDeviceModel.xls',
attributeModuleName: 'Point Management',
attributeCode: 'Point Code',
attributeName: 'Point Name',
attributeType: 'Point Type',
dataType: 'Data Type',
address: 'Register Address',
dataUnit: 'Unit',
ratio: 'Ratio',
placeholderAttributeCode: 'Please enter point code',
placeholderAttributeName: 'Please enter point name',
placeholderAttributeType: 'Please select point type',
placeholderDataType: 'Please select data type',
placeholderAddress: 'Please enter register address',
placeholderDataUnit: 'Please select unit',
placeholderRatio: 'Please enter ratio',
placeholderAttributeRemark: 'Please enter remark',
validatorAttributeCodeRequired: 'Point code can not be empty',
validatorAttributeNameRequired: 'Point name can not be empty',
attributeExportFilename: 'AcquisitionDeviceModelPoint.xls',
ruleTabLabel: 'Point Rule',
ruleIdentifier: 'Identifier',
ruleFieldName: 'Name',
ruleFieldRule: 'Rule',
ruleDefaultValue: 'Default Value',
ruleCreateTime: 'Create Time',
ruleOperate: 'Operate',
ruleSearchIdentifierPlaceholder: 'Please enter identifier',
ruleSearchFieldNamePlaceholder: 'Please enter name',
ruleSearchDefaultValuePlaceholder: 'Please enter default value',
ruleSearch: 'Search',
ruleReset: 'Reset',
ruleCreateButton: 'Add Alarm Rule',
ruleEditRuleButton: 'Edit',
ruleDeleteRuleButton: 'Delete',
ruleDialogTitle: 'Edit Point Rule',
ruleDialogIdentifier: 'Identifier',
ruleDialogFieldName: 'Name',
ruleDialogDefaultValue: 'Default Value',
ruleDialogAlarmLevel: 'Alarm Level',
ruleDialogFieldRule: 'Point Rule',
ruleDialogRule: 'Rule',
ruleDialogRuleAttribute: 'Point',
ruleDialogRuleOperator: 'Condition',
ruleDialogRuleValue: 'Value',
ruleDialogAlarmLevelPlaceholder: 'Please select alarm level',
ruleDialogFieldRulePlaceholder: 'Please select point rule',
ruleDialogRuleAttributePlaceholder: 'Please select point',
ruleDialogRuleOperatorPlaceholder: 'Please select condition',
ruleDialogRuleValuePlaceholder: 'Please enter value'
},
Device: {
moduleName: 'Acquisition Device',
index: 'Index',
deviceCode: 'Device Code',
deviceName: 'Device Name',
operatingStatus: 'Operating Status',
protocol: 'Protocol',
status: 'Connection Status',
sampleCycle: 'Sample Cycle(s)',
isEnable: 'Enabled',
collectionTime: 'Collection Time',
operate: 'Operation',
search: 'Search',
reset: 'Reset',
create: 'Create',
batchDelete: 'Batch Delete',
export: 'Export',
placeholderDeviceCode: 'Please enter device code',
placeholderDeviceName: 'Please enter device name',
placeholderModel: 'Please select device model',
placeholderSampleCycle: 'Please enter sample cycle',
placeholderUrl: 'Please enter endpoint URL',
placeholderUsername: 'Please enter username',
placeholderPassword: 'Please enter password',
model: 'Device Model',
url: 'Endpoint URL',
username: 'Username',
password: 'Password',
settingDialogTitle: 'Device Settings',
connect: 'Connect',
disconnect: 'Disconnect',
attributeModuleName: 'Point',
attributeCode: 'Point Code',
attributeName: 'Point Name',
attributeType: 'Point Type',
dataType: 'Data Type',
address: 'Register Address',
dataUnit: 'Unit',
ratio: 'Ratio',
remark: 'Remark',
deviceAttributeTabLabel: 'Device Attributes',
deviceRuleTabLabel: 'Point Rules',
currentDeviceLabel: 'Current Device: ',
alarmHistoryTitle: 'Device Alarm History Data',
alarmRuleName: 'Rule Name',
alarmPointName: 'Point Name',
alarmPointValue: 'Point Value',
alarmLevel: 'Alarm Level',
emptyDescription: 'Click "Point" in the device list to view points and rules',
exportFilename: 'IoTDevice.xls',
attributeExportFilename: 'AcquisitionDevice-Point.xls',
attributeLatestValue: 'Latest Value',
attributeLatestCollectionTime: 'Latest Collection Time',
attributeSort: 'Order',
attributePlaceholderSort: 'Please enter order',
placeholderAttributeCode: 'Please enter point code',
placeholderAttributeName: 'Please enter point name',
placeholderAttributeType: 'Please select point type',
placeholderDataType: 'Please select data type',
placeholderAddress: 'Please enter register address',
placeholderDataUnit: 'Please enter unit',
placeholderRatio: 'Please enter ratio',
placeholderRemark: 'Please enter remark',
validatorDeviceCodeRequired: 'Device code can not be empty',
validatorDeviceNameRequired: 'Device name can not be empty',
validatorSampleCycleRequired: 'Sample cycle can not be empty',
validatorIsEnableRequired: 'Enable status can not be empty',
validatorUrlRequired: 'Endpoint URL can not be empty',
attributeValidatorCodeRequired: 'Point code can not be empty',
attributeValidatorNameRequired: 'Point name can not be empty',
attributeValidatorCodeNoChinese: 'Point code can not contain Chinese characters',
attributeValidatorSortNumber: 'Order must contain only numbers',
attributeValidatorRemarkTooLong: 'Remark can not exceed 100 characters',
messageSelectDeviceRequired: 'Please select a device',
messageDeviceInfoMissingForRules: 'Device information is missing, unable to load point rules'
},
RunReport: {
moduleName: 'Device Operation Report',
searchDeviceCodeLabel: 'Device Code',
searchDeviceCodePlaceholder: 'Please enter device code',
searchDeviceNameLabel: 'Device Name',
searchDeviceNamePlaceholder: 'Please enter device name',
searchTimeRangeLabel: 'Device Running Time',
searchTimeRangeStartPlaceholder: 'Start Time',
searchTimeRangeEndPlaceholder: 'End Time',
searchButtonText: 'Search',
resetButtonText: 'Reset',
exportButtonText: 'Export',
tableDeviceCodeColumn: 'Device Code',
tableDeviceNameColumn: 'Device Name',
tableRunningTimeColumn: 'Running Time (Hours)',
tableStandbyTimeColumn: 'Standby Time (Hours)',
tableFaultTimeColumn: 'Fault Time (Hours)',
tableWarningTimeColumn: 'Warning Time (Hours)',
tableUtilizationRateColumn: 'Utilization Rate',
tableStartTimeColumn: 'Device Run Start Time',
tableEndTimeColumn: 'Device Run End Time',
exportFilename: 'DeviceOperationReport.xls'
},
RealTimeMonitoring: {
moduleName: 'Real-time Data Monitoring',
searchLineCodeLabel: 'Line Code',
searchLineCodePlaceholder: 'Please enter line code',
searchLineNameLabel: 'Line Name',
searchLineNamePlaceholder: 'Please enter line name',
searchDeviceCodeLabel: 'Device Code',
searchDeviceCodePlaceholder: 'Please enter device code',
searchDeviceNameLabel: 'Device Name',
searchDeviceNamePlaceholder: 'Please enter device name',
searchButtonText: 'Search',
resetButtonText: 'Reset',
exportButtonText: 'Export',
tableLineCodeColumn: 'Line Code',
tableLineNameColumn: 'Line Name',
tableDeviceCodeColumn: 'Device Code',
tableDeviceNameColumn: 'Device Name',
tableStatusColumn: 'Connection Status',
tableCollectionTimeColumn: 'Latest Collection Time',
tableOperateColumn: 'Operation',
tableActionSingleMonitorLabel: 'Single Device Monitoring',
dialogTitle: 'Single Device Monitoring',
dialogDeviceNameLabel: 'Device Name: ',
dialogCollectionTimeLabel: 'Collection Time: ',
emptyDescription: 'No data',
defaultGroupName: 'Default',
defaultFieldLabelPrefix: 'Field ',
messageDeviceInfoIncomplete: 'Device information is incomplete',
exportFilename: 'RealTimeMonitoringDevice.xls'
},
HistoryData: {
moduleName: 'History Record Query',
searchLineCodeLabel: 'Line Code',
searchLineCodePlaceholder: 'Please enter line code',
searchLineNameLabel: 'Line Name',
searchLineNamePlaceholder: 'Please enter line name',
searchDeviceCodeLabel: 'Device Code',
searchDeviceCodePlaceholder: 'Please enter device code',
searchDeviceNameLabel: 'Device Name',
searchDeviceNamePlaceholder: 'Please enter device name',
searchButtonText: 'Search',
resetButtonText: 'Reset',
exportButtonText: 'Export',
tableLineCodeColumn: 'Line Code',
tableLineNameColumn: 'Line Name',
tableDeviceCodeColumn: 'Device Code',
tableDeviceNameColumn: 'Device Name',
tableCollectionTimeColumn: 'Collection Time',
tableOperateColumn: 'Operation',
tableActionHistoryLabel: 'History',
dialogTitlePrefix: 'History: ',
dialogCollectionTimeLabel: 'Collection Time',
dialogCollectionTimeStartPlaceholder: 'Start Time',
dialogCollectionTimeEndPlaceholder: 'End Time',
dialogSearchButtonText: 'Search',
dialogResetButtonText: 'Reset',
dialogRecordCollectionTimePrefix: 'Collection Time: ',
emptyDescription: 'No data',
defaultFieldLabelPrefix: 'Field ',
exportFilename: 'HistoryDataDevice.xls'
},
DeviceParamAnalysis: {
moduleName: 'Device Operation Parameter Analysis',
treeSearchPlaceholder: 'Search device or parameter',
formTimeLabel: 'Time',
formTimeStartPlaceholder: 'Start Date',
formTimeEndPlaceholder: 'End Date',
shortcutLast7Days: 'Last 7 Days',
shortcutLastWeek: 'Last Week',
shortcutLastMonth: 'Last Month',
shortcutLast3Months: 'Last 3 Months',
searchButtonText: 'Search',
resetButtonText: 'Reset',
emptyDescription: 'No data',
emptySelectNodeDescription: 'Please select a node on the left',
selectedParamTitle: 'Node: {label}{unit}',
defaultSeriesName: 'Parameter',
messageLoadTreeFailed: 'Failed to load tree data',
messageNodeNoParams: 'No parameters under this node',
messageDeviceNoParams: 'No parameters under this device',
messageFetchChartFailed: 'Failed to load chart data'
}
}
}

@ -44,6 +44,7 @@ export default {
importMessage: '是否确认导入数据项?',
createSuccess: '新增成功',
updateSuccess: '修改成功',
total: '合计',
delMessage: '是否删除所选中数据?',
delDataMessage: '是否删除数据?',
delNoData: '请选择需要删除的数据',
@ -58,6 +59,203 @@ export default {
copyError: '复制失败',
code:'编码保存后自动生成'
},
ErpStock: {
Warehouse: {
name: '仓库名称',
status: '仓库状态',
address: '仓库地址',
warehousePrice: '仓储费',
truckagePrice: '搬运费',
principal: '负责人',
remark: '备注',
sort: '排序',
defaultStatus: '是否默认',
createTime: '创建时间',
placeholderName: '请输入仓库名称',
placeholderStatus: '请选择仓库状态',
placeholderAddress: '请输入仓库地址',
placeholderPrincipal: '请输入负责人',
placeholderSort: '请输入排序',
placeholderRemark: '请输入备注',
validatorNameRequired: '仓库名称不能为空',
validatorSortRequired: '排序不能为空',
validatorStatusRequired: '开启状态不能为空',
confirmDefaultStatus: '确认要{action}"{name}"默认吗?',
set: '设置',
cancel: '取消',
exportName: '仓库.xls'
},
Stock: {
product: '产品',
warehouse: '仓库',
code: '编码',
name: '名称',
category: '分类',
unit: '单位',
count: '库存量',
placeholderProduct: '请选择产品',
placeholderWarehouse: '请选择仓库',
exportName: '产品库存.xls'
},
In: {
no: '入库单号',
product: '产品',
inTime: '入库时间',
warehouse: '仓库',
creator: '创建人',
status: '状态',
remark: '备注',
supplier: '供应商',
productInfo: '产品信息',
count: '数量',
price: '金额',
totalPrice: '合计金额',
inType: '入库类型',
tabProduct: '产品入库',
tabMaterial: '原料入库',
tabPart: '备件入库',
tabOther: '其他入库',
placeholderNo: '请输入入库单号',
placeholderNoAuto: '保存时自动生成',
placeholderProduct: '请选择产品',
placeholderWarehouse: '请选择仓库',
placeholderCreator: '请选择创建人',
placeholderStatus: '请选择状态',
placeholderRemark: '请输入备注',
placeholderSupplier: '请选择供应商',
placeholderInTime: '选择入库时间',
placeholderInType: '请选择入库类型',
validatorInTimeRequired: '入库时间不能为空',
validatorInTypeRequired: '入库类型不能为空',
confirmApprove: '确定审批该入库单吗?',
confirmReverseApprove: '确定反审批该入库单吗?',
approveSuccess: '审批成功',
reverseApproveSuccess: '反审批成功',
exportName: '其它入库单.xls',
list: '入库产品清单',
addItem: '添加入库产品'
},
Out: {
no: '出库单号',
customer: '客户',
outTime: '出库时间',
outType: '出库类型',
warehouse: '仓库',
remark: '备注',
file: '附件',
list: '出库产品清单',
tabOther: '其他出库',
tabPart: '备件出库',
tabMaterial: '原料出库',
tabProduct: '产品出库',
tabPick: '领料出库',
placeholderNo: '保存时自动生成',
placeholderCustomer: '请选择客户',
placeholderOutTime: '选择出库时间',
placeholderOutType: '请选择出库类型',
placeholderRemark: '请输入备注',
validatorOutTimeRequired: '出库时间不能为空',
validatorOutTypeRequired: '出库类型不能为空',
confirmApprove: '确定审批该出库单吗?',
confirmReverseApprove: '确定反审批该出库单吗?',
approveSuccess: '审批成功',
reverseApproveSuccess: '反审批成功',
exportName: '其它出库单.xls',
addItem: '添加出库产品'
},
Item: {
index: '序号',
warehouse: '仓库名称',
product: '产品名称',
stock: '库存',
barcode: '条码',
unit: '单位',
count: '数量',
price: '产品单价',
totalPrice: '合计金额',
remark: '备注',
action: '操作',
placeholderWarehouse: '请选择仓库',
placeholderProduct: '请选择产品',
validatorWarehouseRequired: '仓库不能为空',
validatorProductRequired: '产品不能为空',
validatorCountRequired: '产品数量不能为空'
},
Check: {
no: '盘点单号',
product: '产品',
checkTime: '盘点时间',
warehouse: '仓库',
creator: '创建人',
status: '状态',
remark: '备注',
productNames: '产品物料名称',
count: '数量',
price: '金额',
totalPrice: '合计金额',
placeholderNo: '请输入盘点单号',
placeholderNoAuto: '保存时自动生成',
placeholderProduct: '请选择产品',
placeholderWarehouse: '请选择仓库',
placeholderCreator: '请选择创建人',
placeholderStatus: '请选择状态',
placeholderRemark: '请输入备注',
placeholderCheckTime: '选择盘点时间',
validatorCheckTimeRequired: '盘点时间不能为空',
confirmApprove: '确定审批该盘点单吗?',
confirmReverseApprove: '确定反审批该盘点单吗?',
approveSuccess: '审批成功',
reverseApproveSuccess: '反审批成功',
exportName: '其它盘点单.xls',
list: '盘点产品物料清单',
addItem: '添加盘点产品',
item: {
warehouse: '仓库名字',
bookStock: '账面库存',
actualStock: '实际库存',
profitLoss: '盈亏数量',
placeholderWarehouse: '请选择仓库名字',
validatorWarehouseRequired: '仓库名字不能为空'
}
},
Move: {
no: '调拨单号',
product: '产品',
moveTime: '调度时间',
fromWarehouse: '仓库',
creator: '创建人',
status: '状态',
remark: '备注',
productNames: '产品信息',
count: '数量',
price: '金额',
totalPrice: '合计金额',
placeholderNo: '请输入调拨单号',
placeholderNoAuto: '保存时自动生成',
placeholderProduct: '请选择产品',
placeholderWarehouse: '请选择仓库',
placeholderCreator: '请选择创建人',
placeholderStatus: '请选择状态',
placeholderRemark: '请输入备注',
placeholderMoveTime: '选择调度时间',
validatorMoveTimeRequired: '调度时间不能为空',
confirmApprove: '确定审批该调拨单吗?',
confirmReverseApprove: '确定反审批该调拨单吗?',
approveSuccess: '审批成功',
reverseApproveSuccess: '反审批成功',
exportName: '库存调拨单.xls',
list: '调度产品清单',
addItem: '添加调度产品',
item: {
fromWarehouse: '调出仓库',
toWarehouse: '调入仓库',
placeholderFromWarehouse: '请选择调出仓库',
placeholderToWarehouse: '请选择调入仓库',
validatorFromWarehouseRequired: '调出仓库不能为空',
validatorToWarehouseRequired: '调入仓库不能为空'
}
}
},
lock: {
lockScreen: '锁定屏幕',
lock: '锁定',
@ -298,6 +496,7 @@ export default {
delete: '删除',
edit: '编辑',
update: '编辑',
copy: '复制',
preview: '预览',
more: '更多',
sync: '同步',
@ -1594,6 +1793,7 @@ export default {
operateTypeDown: '下模',
mold: '模具',
moldName: '模具名称',
lowerMold: '下模模具',
device: '设备',
deviceName: '设备名称',
remark: '备注',
@ -1608,6 +1808,7 @@ export default {
export: '导出',
exportFilename: '模具上下模.xls',
placeholderMold: '请选择模具',
placeholderLowerMold: '请选择下模模具',
placeholderRemark: '请输入备注',
placeholderCreateTimeStart: '开始日期',
placeholderCreateTimeEnd: '结束日期',
@ -1617,6 +1818,7 @@ export default {
validatorOperateTypeRequired: '操作类型不能为空',
validatorDeviceRequired: '关联设备不能为空',
validatorMoldRequired: '关联模具不能为空',
validatorLowerMoldRequired: '下模模具不能为空',
alertNeedRemoveMoldFirst: '请先将该设备上的模具换下!',
alertNoMoldOnDevice: '该设备没有安装模具!'
},
@ -3048,5 +3250,347 @@ export default {
exportFilename: '成型记录.xls'
}
},
DataCollection: {
DeviceAttributeType: {
moduleName: '采集点类型',
index: '序号',
code: '类型编码',
name: '类型名称',
sort: '显示顺序',
remark: '备注',
createTime: '创建时间',
operate: '操作',
search: '搜索',
reset: '重置',
create: '新增',
batchDelete: '批量删除',
export: '导出',
placeholderCode: '请输入类型编码',
placeholderName: '请输入类型名称',
placeholderSort: '请输入显示顺序',
placeholderRemark: '请输入备注',
dialogOk: '确 定',
dialogCancel: '取 消',
validatorCodeRequired: '类型编码不能为空',
validatorNameRequired: '类型名称不能为空',
validatorSortRequired: '显示顺序不能为空',
exportFilename: '采集点类型.xls'
},
DeviceModel: {
moduleName: '采集设备模型',
index: '序号',
code: '模型编码',
name: '模型名称',
protocol: '通讯协议',
remark: '备注',
createTime: '创建时间',
operate: '操作',
search: '搜索',
reset: '重置',
create: '新增',
batchDelete: '批量删除',
export: '导出',
placeholderCode: '请输入模型编码',
placeholderName: '请输入模型名称',
placeholderProtocol: '请选择通讯协议',
placeholderRemark: '请输入备注',
dialogOk: '确 定',
dialogCancel: '取 消',
validatorCodeRequired: '模型编码不能为空',
validatorNameRequired: '模型名称不能为空',
validatorProtocolRequired: '通讯协议不能为空',
exportFilename: '采集设备模型.xls',
attributeModuleName: '采集点管理',
attributeCode: '点位编码',
attributeName: '点位名称',
attributeType: '点位类型',
dataType: '数据类型',
address: '寄存器地址',
dataUnit: '单位',
ratio: '倍率',
placeholderAttributeCode: '请输入点位编码',
placeholderAttributeName: '请输入点位名称',
placeholderAttributeType: '请选择点位类型',
placeholderDataType: '请选择数据类型',
placeholderAddress: '请输入寄存器地址',
placeholderDataUnit: '请选择单位',
placeholderRatio: '请输入倍率',
placeholderAttributeRemark: '请输入备注',
validatorAttributeCodeRequired: '点位编码不能为空',
validatorAttributeNameRequired: '点位名称不能为空',
attributeExportFilename: '采集设备模型-点位管理.xls',
ruleTabLabel: '点位规则',
ruleIdentifier: '标识符',
ruleFieldName: '名称',
ruleFieldRule: '规则',
ruleDefaultValue: '默认值',
ruleCreateTime: '创建时间',
ruleOperate: '操作',
ruleSearchIdentifierPlaceholder: '请输入标识符',
ruleSearchFieldNamePlaceholder: '请输入名称',
ruleSearchDefaultValuePlaceholder: '请输入默认值',
ruleSearch: '搜索',
ruleReset: '重置',
ruleCreateButton: '新增告警规则',
ruleEditRuleButton: '编辑',
ruleDeleteRuleButton: '删除',
ruleDialogTitle: '编辑点位规则',
ruleDialogIdentifier: '标识符',
ruleDialogFieldName: '名称',
ruleDialogDefaultValue: '默认值',
ruleDialogAlarmLevel: '告警登记',
ruleDialogFieldRule: '点位规则',
ruleDialogRule: '规则',
ruleDialogRuleAttribute: '点位',
ruleDialogRuleOperator: '条件',
ruleDialogRuleValue: '数值',
ruleDialogAlarmLevelPlaceholder: '请选择告警登记',
ruleDialogFieldRulePlaceholder: '请选择点位规则',
ruleDialogRuleAttributePlaceholder: '请选择点位',
ruleDialogRuleOperatorPlaceholder: '请选择条件',
ruleDialogRuleValuePlaceholder: '请输入数值'
},
Device: {
moduleName: '采集设备',
index: '序号',
deviceCode: '设备编号',
deviceName: '设备名称',
operatingStatus: '运行状态',
protocol: '采集协议',
status: '连接状态',
sampleCycle: '采集周期(s)',
isEnable: '是否启用',
collectionTime: '采集时间',
operate: '操作',
search: '搜索',
reset: '重置',
create: '新增',
batchDelete: '批量删除',
export: '导出',
placeholderDeviceCode: '请输入设备编号',
placeholderDeviceName: '请输入设备名称',
placeholderModel: '请选择设备模型',
placeholderSampleCycle: '请输入采集周期',
placeholderUrl: '请输入端点URL',
placeholderUsername: '请输入用户名',
placeholderPassword: '请输入密码',
model: '设备模型',
url: '端点URL',
username: '用户名',
password: '密码',
settingDialogTitle: '设备设置',
connect: '连接',
disconnect: '断开连接',
attributeModuleName: '点位',
attributeCode: '点位编码',
attributeName: '点位名称',
attributeType: '点位类型',
dataType: '数据类型',
address: '寄存器地址',
dataUnit: '单位',
ratio: '倍率',
remark: '备注',
deviceAttributeTabLabel: '设备属性',
deviceRuleTabLabel: '点位规则',
currentDeviceLabel: '当前设备:',
alarmHistoryTitle: '设备告警历史数据',
alarmRuleName: '规则名称',
alarmPointName: '点位名称',
alarmPointValue: '点位值',
alarmLevel: '告警等级',
emptyDescription: '请点击设备列表的“点位”查看采集点和点位规则',
exportFilename: '物联设备.xls',
attributeExportFilename: '采集设备-点位管理.xls',
attributeLatestValue: '最新值',
attributeLatestCollectionTime: '最新采集时间',
attributeSort: '顺序',
attributePlaceholderSort: '请输入顺序',
placeholderAttributeCode: '请输入点位编码',
placeholderAttributeName: '请输入点位名称',
placeholderAttributeType: '请选择点位类型',
placeholderDataType: '请选择数据类型',
placeholderAddress: '请输入寄存器地址',
placeholderDataUnit: '请输入单位',
placeholderRatio: '请输入倍率',
placeholderRemark: '请输入备注',
validatorDeviceCodeRequired: '设备编号不能为空',
validatorDeviceNameRequired: '设备名称不能为空',
validatorSampleCycleRequired: '采集周期不能为空',
validatorIsEnableRequired: '是否启用不能为空',
validatorUrlRequired: '端点URL不能为空',
attributeValidatorCodeRequired: '点位编码不能为空',
attributeValidatorNameRequired: '点位名称不能为空',
attributeValidatorCodeNoChinese: '点位编码不允许输入中文',
attributeValidatorSortNumber: '顺序只能输入数字',
attributeValidatorRemarkTooLong: '备注不能超过100字',
messageSelectDeviceRequired: '请选择一个物联设备',
messageDeviceInfoMissingForRules: '设备信息缺失,无法加载点位规则'
},
RunReport: {
moduleName: '设备运行报表',
searchDeviceCodeLabel: '设备编码',
searchDeviceCodePlaceholder: '请输入设备编码',
searchDeviceNameLabel: '设备名称',
searchDeviceNamePlaceholder: '请输入设备名称',
searchTimeRangeLabel: '设备运行时间',
searchTimeRangeStartPlaceholder: '开始时间',
searchTimeRangeEndPlaceholder: '结束时间',
searchButtonText: '搜索',
resetButtonText: '重置',
exportButtonText: '导出',
tableDeviceCodeColumn: '设备编码',
tableDeviceNameColumn: '设备名称',
tableRunningTimeColumn: '运行时间(小时)',
tableStandbyTimeColumn: '待机时间(小时)',
tableFaultTimeColumn: '故障时间(小时)',
tableWarningTimeColumn: '警告时间(小时)',
tableUtilizationRateColumn: '稼动率',
tableStartTimeColumn: '设备运行开始时间',
tableEndTimeColumn: '设备运行结束时间',
exportFilename: '设备运行报表.xls'
},
RealTimeMonitoring: {
moduleName: '数据实时监控',
searchLineCodeLabel: '产线编码',
searchLineCodePlaceholder: '请输入产线编码',
searchLineNameLabel: '产线名称',
searchLineNamePlaceholder: '请输入产线名称',
searchDeviceCodeLabel: '设备编码',
searchDeviceCodePlaceholder: '请输入设备编码',
searchDeviceNameLabel: '设备名称',
searchDeviceNamePlaceholder: '请输入设备名称',
searchButtonText: '搜索',
resetButtonText: '重置',
exportButtonText: '导出',
tableLineCodeColumn: '产线编码',
tableLineNameColumn: '产线名称',
tableDeviceCodeColumn: '设备编码',
tableDeviceNameColumn: '设备名称',
tableStatusColumn: '连接状态',
tableCollectionTimeColumn: '最新采集时间',
tableOperateColumn: '操作',
tableActionSingleMonitorLabel: '单设备监控',
dialogTitle: '单设备监控',
dialogDeviceNameLabel: '设备名称:',
dialogCollectionTimeLabel: '采集时间:',
emptyDescription: '暂无数据',
defaultGroupName: '默认',
defaultFieldLabelPrefix: '字段',
messageDeviceInfoIncomplete: '设备信息不完整',
exportFilename: '实时监控设备.xls'
},
HistoryData: {
moduleName: '历史记录查询',
searchLineCodeLabel: '产线编码',
searchLineCodePlaceholder: '请输入产线编码',
searchLineNameLabel: '产线名称',
searchLineNamePlaceholder: '请输入产线名称',
searchDeviceCodeLabel: '设备编码',
searchDeviceCodePlaceholder: '请输入设备编码',
searchDeviceNameLabel: '设备名称',
searchDeviceNamePlaceholder: '请输入设备名称',
searchButtonText: '搜索',
resetButtonText: '重置',
exportButtonText: '导出',
tableLineCodeColumn: '产线编码',
tableLineNameColumn: '产线名称',
tableDeviceCodeColumn: '设备编码',
tableDeviceNameColumn: '设备名称',
tableCollectionTimeColumn: '采集时间',
tableOperateColumn: '操作',
tableActionHistoryLabel: '历史记录',
dialogTitlePrefix: '历史记录:',
dialogCollectionTimeLabel: '采集时间',
dialogCollectionTimeStartPlaceholder: '开始时间',
dialogCollectionTimeEndPlaceholder: '结束时间',
dialogSearchButtonText: '查询',
dialogResetButtonText: '重置',
dialogRecordCollectionTimePrefix: '采集时间:',
emptyDescription: '暂无数据',
defaultFieldLabelPrefix: '字段',
exportFilename: '历史数据设备.xls'
},
DeviceParamAnalysis: {
moduleName: '设备运行参数分析',
treeSearchPlaceholder: '搜索设备或参数',
formTimeLabel: '时间',
formTimeStartPlaceholder: '开始日期',
formTimeEndPlaceholder: '结束日期',
shortcutLast7Days: '最近 7 天',
shortcutLastWeek: '上周',
shortcutLastMonth: '上个月',
shortcutLast3Months: '三个月内',
searchButtonText: '搜索',
resetButtonText: '重置',
emptyDescription: '暂无数据',
emptySelectNodeDescription: '请选择左侧节点',
selectedParamTitle: '节点:{label}{unit}',
defaultSeriesName: '参数',
messageLoadTreeFailed: '获取树数据失败',
messageNodeNoParams: '该节点下暂无参数',
messageDeviceNoParams: '该设备下没有参数',
messageFetchChartFailed: '获取图表数据失败'
}
}
}

@ -4,39 +4,39 @@
ref="formRef"
:model="formData"
:rules="formRules"
label-width="100px"
label-width="auto"
v-loading="formLoading"
:disabled="disabled"
>
<el-row :gutter="20">
<el-col :span="8">
<el-form-item label="盘点单号" prop="no">
<el-input disabled v-model="formData.no" placeholder="保存时自动生成" />
<el-form-item :label="t('ErpStock.Check.no')" prop="no">
<el-input disabled v-model="formData.no" :placeholder="t('ErpStock.Check.placeholderNoAuto')" />
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="盘点时间" prop="checkTime">
<el-form-item :label="t('ErpStock.Check.checkTime')" prop="checkTime">
<el-date-picker
v-model="formData.checkTime"
type="date"
value-format="x"
placeholder="选择盘点时间"
:placeholder="t('ErpStock.Check.placeholderCheckTime')"
class="!w-1/1"
/>
</el-form-item>
</el-col>
<el-col :span="16">
<el-form-item label="备注" prop="remark">
<el-form-item :label="t('ErpStock.Check.remark')" prop="remark">
<el-input
type="textarea"
v-model="formData.remark"
:rows="1"
placeholder="请输入备注"
:placeholder="t('ErpStock.Check.placeholderRemark')"
/>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="附件" prop="fileUrl">
<el-form-item :label="t('ErpStock.Out.file')" prop="fileUrl">
<UploadFile :is-show-tip="false" v-model="formData.fileUrl" :limit="1" />
</el-form-item>
</el-col>
@ -45,16 +45,16 @@
<!-- 子表的表单 -->
<ContentWrap>
<el-tabs v-model="subTabsName" class="-mt-15px -mb-10px">
<el-tab-pane label="盘点产品物料清单" name="item">
<el-tab-pane :label="t('ErpStock.Check.list')" name="item">
<StockCheckItemForm ref="itemFormRef" :items="formData.items" :disabled="disabled" />
</el-tab-pane>
</el-tabs>
</ContentWrap>
<template #footer>
<el-button @click="submitForm" type="primary" :disabled="formLoading" v-if="!disabled">
{{ t('common.ok') }}
</el-button>
<el-button @click="dialogVisible = false"> </el-button>
<el-button @click="dialogVisible = false">{{ t('common.cancel') }}</el-button>
</template>
</Dialog>
</template>
@ -81,7 +81,7 @@ const formData = ref({
items: []
})
const formRules = reactive({
checkTime: [{ required: true, message: '盘点时间不能为空', trigger: 'blur' }]
checkTime: [{ required: true, message: t('ErpStock.Check.validatorCheckTimeRequired'), trigger: 'blur' }]
})
const disabled = computed(() => formType.value === 'detail')
const formRef = ref() // Ref

@ -9,8 +9,8 @@
:disabled="disabled"
>
<el-table :data="formData" show-summary :summary-method="getSummaries" class="-mt-10px">
<el-table-column label="序号" type="index" align="center" width="60" />
<el-table-column label="仓库名字" min-width="125">
<el-table-column :label="t('ErpStock.Item.index')" type="index" align="center" width="60" />
<el-table-column :label="t('ErpStock.Check.item.warehouse')" min-width="125">
<template #default="{ row, $index }">
<el-form-item
:prop="`${$index}.warehouseId`"
@ -21,7 +21,7 @@
v-model="row.warehouseId"
clearable
filterable
placeholder="请选择仓库名字"
:placeholder="t('ErpStock.Check.item.placeholderWarehouse')"
@change="onChangeWarehouse($event, row)"
>
<el-option
@ -34,7 +34,7 @@
</el-form-item>
</template>
</el-table-column>
<el-table-column label="产品名称" min-width="180">
<el-table-column :label="t('ErpStock.Item.product')" min-width="180">
<template #default="{ row, $index }">
<el-form-item :prop="`${$index}.productId`" :rules="formRules.productId" class="mb-0px!">
<el-select
@ -42,7 +42,7 @@
clearable
filterable
@change="onChangeProduct($event, row)"
placeholder="请选择产品"
:placeholder="t('ErpStock.Item.placeholderProduct')"
>
<el-option
v-for="item in productList"
@ -54,28 +54,28 @@
</el-form-item>
</template>
</el-table-column>
<el-table-column label="产品物料编码" min-width="150">
<el-table-column :label="t('ErpStock.Check.item.barCode')" min-width="150">
<template #default="{ row }">
<el-form-item class="mb-0px!">
<el-input disabled v-model="row.productBarCode" />
</el-form-item>
</template>
</el-table-column>
<el-table-column label="账面库存" min-width="100">
<el-table-column :label="t('ErpStock.Check.item.bookStock')" min-width="100">
<template #default="{ row }">
<el-form-item class="mb-0px!">
<el-input disabled v-model="row.stockCount" :formatter="erpCountInputFormatter" />
</el-form-item>
</template>
</el-table-column>
<el-table-column label="单位" min-width="80">
<el-table-column :label="t('ErpStock.Item.unit')" min-width="80">
<template #default="{ row }">
<el-form-item class="mb-0px!">
<el-input disabled v-model="row.productUnitName" />
</el-form-item>
</template>
</el-table-column>
<el-table-column label="实际库存" fixed="right" min-width="140">
<el-table-column :label="t('ErpStock.Check.item.actualStock')" fixed="right" min-width="140">
<template #default="{ row, $index }">
<el-form-item
:prop="`${$index}.actualCount`"
@ -91,7 +91,7 @@
</el-form-item>
</template>
</el-table-column>
<el-table-column label="盈亏数量" prop="count" fixed="right" min-width="110">
<el-table-column :label="t('ErpStock.Check.item.profitLoss')" prop="count" fixed="right" min-width="110">
<template #default="{ row, $index }">
<el-form-item :prop="`${$index}.count`" :rules="formRules.count" class="mb-0px!">
<el-input
@ -103,7 +103,7 @@
</el-form-item>
</template>
</el-table-column>
<el-table-column label="产品单价" fixed="right" min-width="120">
<el-table-column :label="t('ErpStock.Item.price')" fixed="right" min-width="120">
<template #default="{ row, $index }">
<el-form-item :prop="`${$index}.productPrice`" class="mb-0px!">
<el-input-number
@ -116,21 +116,21 @@
</el-form-item>
</template>
</el-table-column>
<el-table-column label="合计金额" prop="totalPrice" fixed="right" min-width="100">
<el-table-column :label="t('ErpStock.Item.totalPrice')" prop="totalPrice" fixed="right" min-width="100">
<template #default="{ row, $index }">
<el-form-item :prop="`${$index}.totalPrice`" class="mb-0px!">
<el-input disabled v-model="row.totalPrice" :formatter="erpPriceInputFormatter" />
</el-form-item>
</template>
</el-table-column>
<el-table-column label="备注" min-width="150">
<el-table-column :label="t('ErpStock.Item.remark')" min-width="150">
<template #default="{ row, $index }">
<el-form-item :prop="`${$index}.remark`" class="mb-0px!">
<el-input v-model="row.remark" placeholder="请输入备注" />
<el-input v-model="row.remark" :placeholder="t('ErpStock.Check.placeholderRemark')" />
</el-form-item>
</template>
</el-table-column>
<el-table-column align="center" fixed="right" label="操作" width="60">
<el-table-column align="center" fixed="right" :label="t('ErpStock.Item.action')" width="60">
<template #default="{ $index }">
<el-button @click="handleDelete($index)" link></el-button>
</template>
@ -138,7 +138,7 @@
</el-table>
</el-form>
<el-row justify="center" class="mt-3" v-if="!disabled">
<el-button @click="handleAdd" round>+ 添加盘点产品</el-button>
<el-button @click="handleAdd" round>+ {{ t('ErpStock.Check.addItem') }}</el-button>
</el-row>
</template>
<script setup lang="ts">
@ -204,7 +204,7 @@ const getSummaries = (param: SummaryMethodProps) => {
const sums: string[] = []
columns.forEach((column, index) => {
if (index === 0) {
sums[index] = '合计'
sums[index] = t('common.total')
return
}
if (['count', 'totalPrice'].includes(column.property)) {

@ -8,23 +8,23 @@
:model="queryParams"
ref="queryFormRef"
:inline="true"
label-width="68px"
label-width="auto"
>
<el-form-item label="盘点单号" prop="no">
<el-form-item :label="t('ErpStock.Check.no')" prop="no">
<el-input
v-model="queryParams.no"
placeholder="请输入盘点单号"
:placeholder="t('ErpStock.Check.placeholderNo')"
clearable
@keyup.enter="handleQuery"
class="!w-240px"
/>
</el-form-item>
<el-form-item label="产品" prop="productId">
<el-form-item :label="t('ErpStock.Check.product')" prop="productId">
<el-select
v-model="queryParams.productId"
clearable
filterable
placeholder="请选择产品"
:placeholder="t('ErpStock.Check.placeholderProduct')"
class="!w-240px"
>
<el-option
@ -35,23 +35,23 @@
/>
</el-select>
</el-form-item>
<el-form-item label="盘点时间" prop="checkTime">
<el-form-item :label="t('ErpStock.Check.checkTime')" prop="checkTime">
<el-date-picker
v-model="queryParams.checkTime"
value-format="YYYY-MM-DD HH:mm:ss"
type="daterange"
start-placeholder="开始日期"
end-placeholder="结束日期"
:start-placeholder="t('common.startTimeText')"
:end-placeholder="t('common.endTimeText')"
:default-time="[new Date('1 00:00:00'), new Date('1 23:59:59')]"
class="!w-240px"
/>
</el-form-item>
<el-form-item label="仓库" prop="warehouseId">
<el-form-item :label="t('ErpStock.Check.warehouse')" prop="warehouseId">
<el-select
v-model="queryParams.warehouseId"
clearable
filterable
placeholder="请选择仓库"
:placeholder="t('ErpStock.Check.placeholderWarehouse')"
class="!w-240px"
>
<el-option
@ -62,12 +62,12 @@
/>
</el-select>
</el-form-item>
<el-form-item label="创建人" prop="creator">
<el-form-item :label="t('ErpStock.Check.creator')" prop="creator">
<el-select
v-model="queryParams.creator"
clearable
filterable
placeholder="请选择创建人"
:placeholder="t('ErpStock.Check.placeholderCreator')"
class="!w-240px"
>
<el-option
@ -78,8 +78,8 @@
/>
</el-select>
</el-form-item>
<el-form-item label="状态" prop="status">
<el-select v-model="queryParams.status" placeholder="请选择状态" clearable class="!w-240px">
<el-form-item :label="t('ErpStock.Check.status')" prop="status">
<el-select v-model="queryParams.status" :placeholder="t('ErpStock.Check.placeholderStatus')" clearable class="!w-240px">
<el-option
v-for="dict in getIntDictOptions(DICT_TYPE.ERP_AUDIT_STATUS)"
:key="dict.value"
@ -88,25 +88,25 @@
/>
</el-select>
</el-form-item>
<!-- <el-form-item label="备注" prop="remark">
<!-- <el-form-item :label="t('ErpStock.Check.remark')" prop="remark">
<el-input
v-model="queryParams.remark"
placeholder="请输入备注"
:placeholder="t('ErpStock.Check.placeholderRemark')"
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 @click="handleQuery"><Icon icon="ep:search" class="mr-5px" /> {{ t('common.query') }}</el-button>
<el-button @click="resetQuery"><Icon icon="ep:refresh" class="mr-5px" /> {{ t('common.reset') }}</el-button>
<el-button
type="primary"
plain
@click="openForm('create')"
v-hasPermi="['erp:stock-check:create']"
>
<Icon icon="ep:plus" class="mr-5px" /> 新增
<Icon icon="ep:plus" class="mr-5px" /> {{ t('action.add') }}
</el-button>
<el-button
type="success"
@ -115,7 +115,7 @@
:loading="exportLoading"
v-hasPermi="['erp:stock-check:export']"
>
<Icon icon="ep:download" class="mr-5px" /> 导出
<Icon icon="ep:download" class="mr-5px" /> {{ t('action.export') }}
</el-button>
<el-button
type="danger"
@ -124,7 +124,7 @@
v-hasPermi="['erp:stock-check:delete']"
:disabled="selectionList.length === 0"
>
<Icon icon="ep:delete" class="mr-5px" /> 删除
<Icon icon="ep:delete" class="mr-5px" /> {{ t('action.del') }}
</el-button>
</el-form-item>
</el-form>
@ -139,44 +139,44 @@
:show-overflow-tooltip="true"
@selection-change="handleSelectionChange"
>
<el-table-column width="30" label="选择" type="selection" />
<el-table-column label="盘点单号" align="center" prop="no" />
<!-- <el-table-column label="产品物料编码" align="left" sortable prop="productBarCode" min-width="200" /> -->
<el-table-column label="产品物料名称" align="left" sortable prop="productNames"/>
<el-table-column width="30" :label="t('action.select')" type="selection" />
<el-table-column :label="t('ErpStock.Check.no')" align="center" prop="no" />
<!-- <el-table-column :label="t('ErpStock.Check.productBarCode')" align="left" sortable prop="productBarCode" min-width="200" /> -->
<el-table-column :label="t('ErpStock.Check.productNames')" align="left" sortable prop="productNames"/>
<el-table-column
label="盘点时间"
:label="t('ErpStock.Check.checkTime')"
align="center"
prop="checkTime"
:formatter="dateFormatter2"
/>
<el-table-column label="创建人" align="center" prop="creatorName" />
<el-table-column :label="t('ErpStock.Check.creator')" align="center" prop="creatorName" />
<el-table-column
label="数量"
:label="t('ErpStock.Check.count')"
align="right"
sortable
prop="totalCount"
:formatter="erpCountTableColumnFormatter"
/>
<el-table-column
label="金额"
:label="t('ErpStock.Check.price')"
align="right"
sortable
prop="totalPrice"
:formatter="erpPriceTableColumnFormatter"
/>
<el-table-column label="状态" align="center" fixed="right" width="90" prop="status">
<el-table-column :label="t('ErpStock.Check.status')" align="center" fixed="right" width="90" prop="status">
<template #default="scope">
<dict-tag :type="DICT_TYPE.ERP_AUDIT_STATUS" :value="scope.row.status" />
</template>
</el-table-column>
<el-table-column label="操作" align="center" fixed="right" width="220">
<el-table-column :label="t('action.operate')" align="center" fixed="right" width="220">
<template #default="scope">
<el-button
link
@click="openForm('detail', scope.row.id)"
v-hasPermi="['erp:stock-check:query']"
>
详情
{{ t('action.detail') }}
</el-button>
<el-button
link
@ -185,7 +185,7 @@
v-hasPermi="['erp:stock-check:update']"
:disabled="scope.row.status === 20"
>
编辑
{{ t('action.edit') }}
</el-button>
<el-button
link
@ -194,7 +194,7 @@
v-hasPermi="['erp:stock-check:update-status']"
v-if="scope.row.status === 10"
>
审批
{{ t('ErpStock.Check.confirmApprove').replace('确定', '').replace('该盘点单吗?', '') }}
</el-button>
<el-button
link
@ -203,7 +203,7 @@
v-hasPermi="['erp:stock-check:update-status']"
v-else
>
反审批
{{ t('ErpStock.Check.confirmReverseApprove').replace('确定', '').replace('该盘点单吗?', '') }}
</el-button>
<el-button
link
@ -211,7 +211,7 @@
@click="handleDelete([scope.row.id])"
v-hasPermi="['erp:stock-check:delete']"
>
删除
{{ t('action.del') }}
</el-button>
</template>
</el-table-column>
@ -315,10 +315,10 @@ const handleDelete = async (ids: number[]) => {
const handleUpdateStatus = async (id: number, status: number) => {
try {
//
await message.confirm(`确定${status === 20 ? '审批' : '反审批'}该盘点单吗?`)
await message.confirm(status === 20 ? t('ErpStock.Check.confirmApprove') : t('ErpStock.Check.confirmReverseApprove'))
//
await StockCheckApi.updateStockCheckStatus(id, status)
message.success(`${status === 20 ? '审批' : '反审批'}成功`)
message.success(status === 20 ? t('ErpStock.Check.approveSuccess') : t('ErpStock.Check.reverseApproveSuccess'))
//
await getList()
} catch {}
@ -332,7 +332,7 @@ const handleExport = async () => {
//
exportLoading.value = true
const data = await StockCheckApi.exportStockCheck(queryParams)
download.excel(data, '其它盘点单.xls')
download.excel(data, t('ErpStock.Check.exportName'))
} catch {
} finally {
exportLoading.value = false

@ -37,20 +37,17 @@
<el-table-column label="产品名称" min-width="180">
<template #default="{ row, $index }">
<el-form-item :prop="`${$index}.productId`" :rules="formRules.productId" class="mb-0px!">
<el-select
<el-cascader
v-model="row.productId"
:options="productCascaderOptions"
:props="productCascaderProps"
:show-all-levels="false"
clearable
filterable
@change="onChangeProduct($event, row)"
placeholder="请选择产品"
>
<el-option
v-for="item in productList"
:key="item.id"
:label="item.name"
:value="item.id"
/>
</el-select>
class="!w-100%"
/>
</el-form-item>
</template>
</el-table-column>
@ -156,6 +153,36 @@ const productList = ref<ProductVO[]>([]) // 产品列表
const warehouseList = ref<WarehouseVO[]>([]) //
const defaultWarehouse = ref<WarehouseVO>(undefined) //
const productCascaderProps = {
emitPath: false,
value: 'value',
label: 'label',
children: 'children'
}
const productCascaderOptions = computed(() => {
const map = new Map<number | string, { value: number | string; label: string; children: any[] }>()
for (const item of productList.value) {
const categoryKey = item.categoryId ?? item.categoryName ?? ''
const categoryLabel = item.categoryName ?? String(categoryKey)
if (!map.has(categoryKey)) {
map.set(categoryKey, {
value: categoryKey,
label: categoryLabel,
children: []
})
}
const group = map.get(categoryKey)
if (group) {
group.children.push({
value: item.id,
label: item.name
})
}
}
return Array.from(map.values())
})
/** 初始化设置入库项 */
watch(
() => props.items,

@ -4,39 +4,39 @@
ref="formRef"
:model="formData"
:rules="formRules"
label-width="100px"
label-width="auto"
v-loading="formLoading"
:disabled="disabled"
>
<el-row :gutter="20">
<el-col :span="8">
<el-form-item label="调拨单号" prop="no">
<el-input disabled v-model="formData.no" placeholder="保存时自动生成" />
<el-form-item :label="t('ErpStock.Move.no')" prop="no">
<el-input disabled v-model="formData.no" :placeholder="t('ErpStock.Move.placeholderNoAuto')" />
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="调拨时间" prop="moveTime">
<el-form-item :label="t('ErpStock.Move.moveTime')" prop="moveTime">
<el-date-picker
v-model="formData.moveTime"
type="date"
value-format="x"
placeholder="选择调度时间"
:placeholder="t('ErpStock.Move.placeholderMoveTime')"
class="!w-1/1"
/>
</el-form-item>
</el-col>
<el-col :span="16">
<el-form-item label="备注" prop="remark">
<el-form-item :label="t('ErpStock.Move.remark')" prop="remark">
<el-input
type="textarea"
v-model="formData.remark"
:rows="1"
placeholder="请输入备注"
:placeholder="t('ErpStock.Move.placeholderRemark')"
/>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="附件" prop="fileUrl">
<el-form-item :label="t('ErpStock.Out.file')" prop="fileUrl">
<UploadFile :is-show-tip="false" v-model="formData.fileUrl" :limit="1" />
</el-form-item>
</el-col>
@ -45,16 +45,16 @@
<!-- 子表的表单 -->
<ContentWrap>
<el-tabs v-model="subTabsName" class="-mt-15px -mb-10px">
<el-tab-pane label="调度产品清单" name="item">
<el-tab-pane :label="t('ErpStock.Move.list')" name="item">
<StockMoveItemForm ref="itemFormRef" :items="formData.items" :disabled="disabled" />
</el-tab-pane>
</el-tabs>
</ContentWrap>
<template #footer>
<el-button @click="submitForm" type="primary" :disabled="formLoading" v-if="!disabled">
{{ t('common.ok') }}
</el-button>
<el-button @click="dialogVisible = false"> </el-button>
<el-button @click="dialogVisible = false">{{ t('common.cancel') }}</el-button>
</template>
</Dialog>
</template>
@ -81,7 +81,7 @@ const formData = ref({
items: []
})
const formRules = reactive({
moveTime: [{ required: true, message: '调度时间不能为空', trigger: 'blur' }]
moveTime: [{ required: true, message: t('ErpStock.Move.validatorMoveTimeRequired'), trigger: 'blur' }]
})
const disabled = computed(() => formType.value === 'detail')
const formRef = ref() // Ref

@ -160,6 +160,8 @@ import {
getSumValue
} from '@/utils'
const { t } = useI18n() //
const props = defineProps<{
items: undefined
disabled: false
@ -168,10 +170,10 @@ const formLoading = ref(false) // 表单的加载中
const formData = ref([])
const formRules = reactive({
inId: [{ required: true, message: '调度编号不能为空', trigger: 'blur' }],
fromWarehouseId: [{ required: true, message: '调出仓库不能为空', trigger: 'blur' }],
toWarehouseId: [{ required: true, message: '调入仓库不能为空', trigger: 'blur' }],
productId: [{ required: true, message: '产品不能为空', trigger: 'blur' }],
count: [{ required: true, message: '产品数量不能为空', trigger: 'blur' }]
fromWarehouseId: [{ required: true, message: t('ErpStock.Move.item.validatorFromWarehouseRequired'), trigger: 'blur' }],
toWarehouseId: [{ required: true, message: t('ErpStock.Move.item.validatorToWarehouseRequired'), trigger: 'blur' }],
productId: [{ required: true, message: t('ErpStock.Item.validatorProductRequired'), trigger: 'blur' }],
count: [{ required: true, message: t('ErpStock.Item.validatorCountRequired'), trigger: 'blur' }]
})
const formRef = ref([]) // Ref
const productList = ref<ProductVO[]>([]) //
@ -208,7 +210,7 @@ const getSummaries = (param: SummaryMethodProps) => {
const sums: string[] = []
columns.forEach((column, index) => {
if (index === 0) {
sums[index] = '合计'
sums[index] = t('common.total')
return
}
if (['count', 'totalPrice'].includes(column.property)) {

@ -7,23 +7,23 @@
:model="queryParams"
ref="queryFormRef"
:inline="true"
label-width="68px"
label-width="auto"
>
<el-form-item label="调拨单号" prop="no">
<el-form-item :label="t('ErpStock.Move.no')" prop="no">
<el-input
v-model="queryParams.no"
placeholder="请输入调拨单号"
:placeholder="t('ErpStock.Move.placeholderNo')"
clearable
@keyup.enter="handleQuery"
class="!w-240px"
/>
</el-form-item>
<el-form-item label="产品" prop="productId">
<el-form-item :label="t('ErpStock.Move.product')" prop="productId">
<el-select
v-model="queryParams.productId"
clearable
filterable
placeholder="请选择产品"
:placeholder="t('ErpStock.Move.placeholderProduct')"
class="!w-240px"
>
<el-option
@ -34,23 +34,23 @@
/>
</el-select>
</el-form-item>
<el-form-item label="调度时间" prop="moveTime">
<el-form-item :label="t('ErpStock.Move.moveTime')" prop="moveTime">
<el-date-picker
v-model="queryParams.moveTime"
value-format="YYYY-MM-DD HH:mm:ss"
type="daterange"
start-placeholder="开始日期"
end-placeholder="结束日期"
:start-placeholder="t('common.startTimeText')"
:end-placeholder="t('common.endTimeText')"
:default-time="[new Date('1 00:00:00'), new Date('1 23:59:59')]"
class="!w-240px"
/>
</el-form-item>
<el-form-item label="仓库" prop="fromWarehouseId">
<el-form-item :label="t('ErpStock.Move.fromWarehouse')" prop="fromWarehouseId">
<el-select
v-model="queryParams.fromWarehouseId"
clearable
filterable
placeholder="请选择仓库"
:placeholder="t('ErpStock.Move.placeholderWarehouse')"
class="!w-240px"
>
<el-option
@ -61,12 +61,12 @@
/>
</el-select>
</el-form-item>
<el-form-item label="创建人" prop="creator">
<el-form-item :label="t('ErpStock.Move.creator')" prop="creator">
<el-select
v-model="queryParams.creator"
clearable
filterable
placeholder="请选择创建人"
:placeholder="t('ErpStock.Move.placeholderCreator')"
class="!w-240px"
>
<el-option
@ -77,8 +77,8 @@
/>
</el-select>
</el-form-item>
<el-form-item label="状态" prop="status">
<el-select v-model="queryParams.status" placeholder="请选择状态" clearable class="!w-240px">
<el-form-item :label="t('ErpStock.Move.status')" prop="status">
<el-select v-model="queryParams.status" :placeholder="t('ErpStock.Move.placeholderStatus')" clearable class="!w-240px">
<el-option
v-for="dict in getIntDictOptions(DICT_TYPE.ERP_AUDIT_STATUS)"
:key="dict.value"
@ -87,25 +87,25 @@
/>
</el-select>
</el-form-item>
<!-- <el-form-item label="备注" prop="remark">
<!-- <el-form-item :label="t('ErpStock.Move.remark')" prop="remark">
<el-input
v-model="queryParams.remark"
placeholder="请输入备注"
:placeholder="t('ErpStock.Move.placeholderRemark')"
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 @click="handleQuery"><Icon icon="ep:search" class="mr-5px" /> {{ t('common.query') }}</el-button>
<el-button @click="resetQuery"><Icon icon="ep:refresh" class="mr-5px" /> {{ t('common.reset') }}</el-button>
<el-button
type="primary"
plain
@click="openForm('create')"
v-hasPermi="['erp:stock-move:create']"
>
<Icon icon="ep:plus" class="mr-5px" /> 新增
<Icon icon="ep:plus" class="mr-5px" /> {{ t('action.add') }}
</el-button>
<el-button
type="success"
@ -114,7 +114,7 @@
:loading="exportLoading"
v-hasPermi="['erp:stock-move:export']"
>
<Icon icon="ep:download" class="mr-5px" /> 导出
<Icon icon="ep:download" class="mr-5px" /> {{ t('action.export') }}
</el-button>
<el-button
type="danger"
@ -123,7 +123,7 @@
v-hasPermi="['erp:stock-move:delete']"
:disabled="selectionList.length === 0"
>
<Icon icon="ep:delete" class="mr-5px" /> 删除
<Icon icon="ep:delete" class="mr-5px" /> {{ t('action.del') }}
</el-button>
</el-form-item>
</el-form>
@ -138,44 +138,44 @@
:show-overflow-tooltip="true"
@selection-change="handleSelectionChange"
>
<el-table-column label="选择" type="selection" />
<el-table-column label="调拨单号" align="center" prop="no" />
<el-table-column label="产品信息" align="left" prop="productNames" />
<el-table-column :label="t('action.select')" type="selection" />
<el-table-column :label="t('ErpStock.Move.no')" align="center" prop="no" />
<el-table-column :label="t('ErpStock.Move.productNames')" align="left" prop="productNames" />
<el-table-column
label="调度时间"
:label="t('ErpStock.Move.moveTime')"
align="center"
prop="moveTime"
sortable
:formatter="dateFormatter2"
/>
<el-table-column label="创建人" align="center" prop="creatorName" />
<el-table-column :label="t('ErpStock.Move.creator')" align="center" prop="creatorName" />
<el-table-column
label="数量"
:label="t('ErpStock.Move.count')"
align="right"
sortable
prop="totalCount"
:formatter="erpCountTableColumnFormatter"
/>
<el-table-column
label="金额"
:label="t('ErpStock.Move.price')"
align="right"
sortable
prop="totalPrice"
:formatter="erpPriceTableColumnFormatter"
/>
<el-table-column label="状态" align="center" fixed="right" prop="status">
<el-table-column :label="t('ErpStock.Move.status')" align="center" fixed="right" prop="status">
<template #default="scope">
<dict-tag :type="DICT_TYPE.ERP_AUDIT_STATUS" :value="scope.row.status" />
</template>
</el-table-column>
<el-table-column label="操作" align="center" fixed="right">
<el-table-column :label="t('action.operate')" align="center" fixed="right">
<template #default="scope">
<el-button
link
@click="openForm('detail', scope.row.id)"
v-hasPermi="['erp:stock-move:query']"
>
详情
{{ t('action.detail') }}
</el-button>
<el-button
link
@ -184,7 +184,7 @@
v-hasPermi="['erp:stock-move:update']"
:disabled="scope.row.status === 20"
>
编辑
{{ t('action.edit') }}
</el-button>
<el-button
link
@ -193,7 +193,7 @@
v-hasPermi="['erp:stock-move:update-status']"
v-if="scope.row.status === 10"
>
审批
{{ t('ErpStock.Move.confirmApprove').replace('确定', '').replace('该调拨单吗?', '') }}
</el-button>
<el-button
link
@ -202,7 +202,7 @@
v-hasPermi="['erp:stock-move:update-status']"
v-else
>
反审批
{{ t('ErpStock.Move.confirmReverseApprove').replace('确定', '').replace('该调拨单吗?', '') }}
</el-button>
<el-button
link
@ -210,7 +210,7 @@
@click="handleDelete([scope.row.id])"
v-hasPermi="['erp:stock-move:delete']"
>
删除
{{ t('action.del') }}
</el-button>
</template>
</el-table-column>
@ -314,10 +314,10 @@ const handleDelete = async (ids: number[]) => {
const handleUpdateStatus = async (id: number, status: number) => {
try {
//
await message.confirm(`确定${status === 20 ? '审批' : '反审批'}该调拨单吗?`)
await message.confirm(status === 20 ? t('ErpStock.Move.confirmApprove') : t('ErpStock.Move.confirmReverseApprove'))
//
await StockMoveApi.updateStockMoveStatus(id, status)
message.success(`${status === 20 ? '审批' : '反审批'}成功`)
message.success(status === 20 ? t('ErpStock.Move.approveSuccess') : t('ErpStock.Move.reverseApproveSuccess'))
//
await getList()
} catch {}
@ -331,7 +331,7 @@ const handleExport = async () => {
//
exportLoading.value = true
const data = await StockMoveApi.exportStockMove(queryParams)
download.excel(data, '库存调拨单.xls')
download.excel(data, t('ErpStock.Move.exportName'))
} catch {
} finally {
exportLoading.value = false

@ -10,17 +10,17 @@
>
<el-row :gutter="20">
<el-col :span="8">
<el-form-item label="出库单号" prop="no">
<el-input disabled v-model="formData.no" placeholder="保存时自动生成" />
<el-form-item :label="t('ErpStock.Out.no')" prop="no">
<el-input disabled v-model="formData.no" :placeholder="t('ErpStock.Out.placeholderNo')" />
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="客户" prop="customerId">
<el-form-item :label="t('ErpStock.Out.customer')" prop="customerId">
<el-select
v-model="formData.customerId"
clearable
filterable
placeholder="请选择客户"
:placeholder="t('ErpStock.Out.placeholderCustomer')"
class="!w-1/1"
>
<el-option
@ -33,23 +33,23 @@
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="出库时间" prop="outTime">
<el-form-item :label="t('ErpStock.Out.outTime')" prop="outTime">
<el-date-picker
v-model="formData.outTime"
type="date"
value-format="x"
placeholder="选择出库时间"
:placeholder="t('ErpStock.Out.placeholderOutTime')"
class="!w-1/1"
/>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="出库类型" prop="outType">
<el-form-item :label="t('ErpStock.Out.outType')" prop="outType">
<el-select
v-model="formData.outType"
clearable
filterable
placeholder="请选择出库类型"
:placeholder="t('ErpStock.Out.placeholderOutType')"
class="!w-1/1"
>
<el-option
@ -65,18 +65,18 @@
<el-col :span="8">
<el-form-item label="备注" prop="remark">
<el-form-item :label="t('ErpStock.Out.remark')" prop="remark">
<el-input
type="textarea"
v-model="formData.remark"
:rows="1"
placeholder="请输入备注"
:placeholder="t('ErpStock.Out.placeholderRemark')"
/>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="附件" prop="fileUrl">
<el-form-item :label="t('ErpStock.Out.file')" prop="fileUrl">
<UploadFile :is-show-tip="false" v-model="formData.fileUrl" :limit="1" />
</el-form-item>
</el-col>
@ -85,16 +85,16 @@
<!-- 子表的表单 -->
<ContentWrap>
<el-tabs v-model="subTabsName" class="-mt-15px -mb-10px">
<el-tab-pane label="出库产品清单" name="item">
<el-tab-pane :label="t('ErpStock.Out.list')" name="item">
<StockOutItemForm ref="itemFormRef" :items="formData.items" :disabled="disabled" />
</el-tab-pane>
</el-tabs>
</ContentWrap>
<template #footer>
<el-button @click="submitForm" type="primary" :disabled="formLoading" v-if="!disabled">
{{ t('common.ok') }}
</el-button>
<el-button @click="dialogVisible = false"> </el-button>
<el-button @click="dialogVisible = false">{{ t('common.cancel') }}</el-button>
</template>
</Dialog>
</template>
@ -123,8 +123,8 @@ const formData = ref({
items: []
})
const formRules = reactive({
outTime: [{ required: true, message: '出库时间不能为空', trigger: 'blur' }],
outType: [{ required: true, message: '出库类型不能为空', trigger: 'blur' }]
outTime: [{ required: true, message: t('ErpStock.Out.validatorOutTimeRequired'), trigger: 'blur' }],
outType: [{ required: true, message: t('ErpStock.Out.validatorOutTypeRequired'), trigger: 'blur' }]
})
const disabled = computed(() => formType.value === 'detail')
const formRef = ref() // Ref

@ -37,20 +37,17 @@
<el-table-column label="产品名称" min-width="180">
<template #default="{ row, $index }">
<el-form-item :prop="`${$index}.productId`" :rules="formRules.productId" class="mb-0px!">
<el-select
<el-cascader
v-model="row.productId"
:options="productCascaderOptions"
:props="productCascaderProps"
:show-all-levels="false"
clearable
filterable
@change="onChangeProduct($event, row)"
placeholder="请选择产品"
>
<el-option
v-for="item in productList"
:key="item.id"
:label="item.name"
:value="item.id"
/>
</el-select>
class="!w-100%"
/>
</el-form-item>
</template>
</el-table-column>
@ -156,6 +153,36 @@ const productList = ref<ProductVO[]>([]) // 产品列表
const warehouseList = ref<WarehouseVO[]>([]) //
const defaultWarehouse = ref<WarehouseVO>(undefined) //
const productCascaderProps = {
emitPath: false,
value: 'value',
label: 'label',
children: 'children'
}
const productCascaderOptions = computed(() => {
const map = new Map<number | string, { value: number | string; label: string; children: any[] }>()
for (const item of productList.value) {
const categoryKey = item.categoryId ?? item.categoryName ?? ''
const categoryLabel = item.categoryName ?? String(categoryKey)
if (!map.has(categoryKey)) {
map.set(categoryKey, {
value: categoryKey,
label: categoryLabel,
children: []
})
}
const group = map.get(categoryKey)
if (group) {
group.children.push({
value: item.id,
label: item.name
})
}
}
return Array.from(map.values())
})
/** 初始化设置出库项 */
watch(
() => props.items,

@ -8,14 +8,14 @@
:model="queryParams"
ref="queryFormRef"
:inline="true"
label-width="68px"
label-width="auto"
>
<el-form-item label="产品" prop="productId">
<el-form-item :label="t('ErpStock.Stock.product')" prop="productId">
<el-select
v-model="queryParams.productId"
clearable
filterable
placeholder="请选择产品"
:placeholder="t('ErpStock.Stock.placeholderProduct')"
class="!w-240px"
>
<el-option
@ -27,12 +27,12 @@
</el-select>
</el-form-item>
<el-form-item label="仓库" prop="warehouseId">
<el-form-item :label="t('ErpStock.Stock.warehouse')" prop="warehouseId">
<el-select
v-model="queryParams.warehouseId"
clearable
filterable
placeholder="请选择仓库"
:placeholder="t('ErpStock.Stock.placeholderWarehouse')"
class="!w-240px"
>
<el-option
@ -44,15 +44,15 @@
</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 @click="handleQuery"><Icon icon="ep:search" class="mr-5px" /> {{ t('common.query') }}</el-button>
<el-button @click="resetQuery"><Icon icon="ep:refresh" class="mr-5px" /> {{ t('common.reset') }}</el-button>
<el-button
type="primary"
plain
@click="openForm('create')"
v-hasPermi="['erp:stock:create']"
>
<Icon icon="ep:plus" class="mr-5px" /> 新增
<Icon icon="ep:plus" class="mr-5px" /> {{ t('action.add') }}
</el-button>
<el-button
type="success"
@ -61,7 +61,7 @@
:loading="exportLoading"
v-hasPermi="['erp:stock:export']"
>
<Icon icon="ep:download" class="mr-5px" /> 导出
<Icon icon="ep:download" class="mr-5px" /> {{ t('action.export') }}
</el-button>
</el-form-item>
</el-form>
@ -87,19 +87,19 @@
/>
</el-tabs>
<el-table v-loading="loading" :data="list" :stripe="true" :show-overflow-tooltip="true">
<el-table-column label="编码" align="left" sortable prop="barCode" />
<el-table-column label="名称" align="left" sortable prop="productName" />
<el-table-column label="分类" align="center" prop="categoryName" />
<el-table-column label="单位" align="center" prop="unitName" />
<el-table-column :label="t('ErpStock.Stock.code')" align="left" sortable prop="barCode" />
<el-table-column :label="t('ErpStock.Stock.name')" align="left" sortable prop="productName" />
<el-table-column :label="t('ErpStock.Stock.category')" align="center" prop="categoryName" />
<el-table-column :label="t('ErpStock.Stock.unit')" align="center" prop="unitName" />
<el-table-column
label="库存量"
:label="t('ErpStock.Stock.count')"
align="right"
sortable
prop="count"
:formatter="erpCountTableColumnFormatter"
/>
<el-table-column label="仓库" align="center" prop="warehouseName" />
<el-table-column :label="t('ErpStock.Stock.warehouse')" align="center" prop="warehouseName" />
</el-table>
<!-- 分页 -->
<Pagination
@ -193,7 +193,7 @@ const handleExport = async () => {
//
exportLoading.value = true
const data = await StockApi.exportStock(queryParams)
download.excel(data, '产品库存.xls')
download.excel(data, t('ErpStock.Stock.exportName'))
} catch {
} finally {
exportLoading.value = false

@ -8,13 +8,13 @@
label-width="100px"
v-loading="formLoading"
>
<el-form-item label="仓库名称" prop="name">
<el-input v-model="formData.name" placeholder="请输入仓库名称" :disabled = "formType === 'update'"/>
<el-form-item :label="t('ErpStock.Warehouse.name')" prop="name">
<el-input v-model="formData.name" :placeholder="t('ErpStock.Warehouse.placeholderName')" :disabled = "formType === 'update'"/>
</el-form-item>
<el-form-item label="仓库地址" prop="address">
<el-input v-model="formData.address" placeholder="请输入仓库地址" />
<el-form-item :label="t('ErpStock.Warehouse.address')" prop="address">
<el-input v-model="formData.address" :placeholder="t('ErpStock.Warehouse.placeholderAddress')" />
</el-form-item>
<el-form-item label="仓库状态" prop="status">
<el-form-item :label="t('ErpStock.Warehouse.status')" prop="status">
<el-radio-group v-model="formData.status">
<el-radio
v-for="dict in getIntDictOptions(DICT_TYPE.COMMON_STATUS)"
@ -43,24 +43,24 @@
class="!w-1/1"
/>
</el-form-item> -->
<el-form-item label="负责人" prop="principal">
<el-input v-model="formData.principal" placeholder="请输入负责人" />
<el-form-item :label="t('ErpStock.Warehouse.principal')" prop="principal">
<el-input v-model="formData.principal" :placeholder="t('ErpStock.Warehouse.placeholderPrincipal')" />
</el-form-item>
<el-form-item label="排序" prop="sort">
<el-form-item :label="t('ErpStock.Warehouse.sort')" prop="sort">
<el-input-number
v-model="formData.sort"
placeholder="请输入排序"
:placeholder="t('ErpStock.Warehouse.placeholderSort')"
:precision="0"
class="!w-1/1"
/>
</el-form-item>
<el-form-item label="备注" prop="remark">
<el-input type="textarea" v-model="formData.remark" placeholder="请输入备注" />
<el-form-item :label="t('ErpStock.Warehouse.remark')" prop="remark">
<el-input type="textarea" v-model="formData.remark" :placeholder="t('ErpStock.Warehouse.placeholderRemark')" />
</el-form-item>
</el-form>
<template #footer>
<el-button @click="submitForm" type="primary" :disabled="formLoading"> </el-button>
<el-button @click="dialogVisible = false"> </el-button>
<el-button @click="submitForm" type="primary" :disabled="formLoading">{{ t('common.ok') }}</el-button>
<el-button @click="dialogVisible = false">{{ t('common.cancel') }}</el-button>
</template>
</Dialog>
</template>
@ -91,9 +91,9 @@ const formData = ref({
status: undefined
})
const formRules = reactive({
name: [{ required: true, message: '仓库名称不能为空', trigger: 'blur' }],
sort: [{ required: true, message: '排序不能为空', trigger: 'blur' }],
status: [{ required: true, message: '开启状态不能为空', trigger: 'blur' }]
name: [{ required: true, message: t('ErpStock.Warehouse.validatorNameRequired'), trigger: 'blur' }],
sort: [{ required: true, message: t('ErpStock.Warehouse.validatorSortRequired'), trigger: 'blur' }],
status: [{ required: true, message: t('ErpStock.Warehouse.validatorStatusRequired'), trigger: 'blur' }]
})
const formRef = ref() // Ref

@ -7,7 +7,7 @@
v-if="formType === 'setting' && formData.deviceName"
class="text-12px leading-16px text-[var(--el-text-color-secondary)]"
>
设备名称{{ formData.deviceName }}
{{ t('DataCollection.Device.deviceName') + t('common.colon') + formData.deviceName }}
</div>
</div>
</template>
@ -15,15 +15,21 @@
ref="formRef"
:model="formData"
:rules="activeRules"
label-width="100px"
label-width="120px"
v-loading="formLoading"
>
<template v-if="formType === 'create'">
<el-form-item label="设备编号" prop="deviceCode">
<el-input v-model="formData.deviceCode" placeholder="请输入设备编号" />
<el-form-item :label="t('DataCollection.Device.deviceCode')" prop="deviceCode">
<el-input
v-model="formData.deviceCode"
:placeholder="t('DataCollection.Device.placeholderDeviceCode')"
/>
</el-form-item>
<el-form-item label="设备名称" prop="deviceName">
<el-input v-model="formData.deviceName" placeholder="请输入设备名称" />
<el-form-item :label="t('DataCollection.Device.deviceName')" prop="deviceName">
<el-input
v-model="formData.deviceName"
:placeholder="t('DataCollection.Device.placeholderDeviceName')"
/>
</el-form-item>
</template>
<!-- <el-form-item label="设备类型" prop="deviceType">
@ -63,23 +69,26 @@
<el-input v-model="formData.offLineDuration" placeholder="请输入离线间隔" />
</el-form-item> -->
<template v-if="formType === 'create'">
<el-form-item label="模型选择" prop="deviceModelId">
<el-form-item :label="t('DataCollection.Device.model')" prop="deviceModelId">
<el-select
v-model="formData.deviceModelId"
clearable
filterable
placeholder="请选择设备模型"
:placeholder="t('DataCollection.Device.placeholderModel')"
>
<el-option v-for="item in modelList" :key="item.id" :label="item.name" :value="item.id" />
</el-select>
</el-form-item>
<el-form-item label="采集周期/s" prop="sampleCycle">
<el-input v-model="formData.sampleCycle" placeholder="请输入采集周期" />
<el-form-item :label="t('DataCollection.Device.sampleCycle')" prop="sampleCycle">
<el-input
v-model="formData.sampleCycle"
:placeholder="t('DataCollection.Device.placeholderSampleCycle')"
/>
</el-form-item>
<!-- <el-form-item label="备注" prop="remark">
<el-input v-model="formData.remark" placeholder="请输入备注" />
</el-form-item> -->
<el-form-item label="是否启用" prop="isEnable">
<el-form-item :label="t('DataCollection.Device.isEnable')" prop="isEnable">
<el-radio-group v-model="formData.isEnable">
<el-radio
v-for="dict in getBoolDictOptions(DICT_TYPE.INFRA_BOOLEAN_STRING)"
@ -93,10 +102,13 @@
</template>
<template v-else-if="formType === 'update'">
<el-form-item label="采集周期/s" prop="sampleCycle">
<el-input v-model="formData.sampleCycle" placeholder="请输入采集周期" />
<el-form-item :label="t('DataCollection.Device.sampleCycle')" prop="sampleCycle">
<el-input
v-model="formData.sampleCycle"
:placeholder="t('DataCollection.Device.placeholderSampleCycle')"
/>
</el-form-item>
<el-form-item label="是否启用" prop="isEnable">
<el-form-item :label="t('DataCollection.Device.isEnable')" prop="isEnable">
<el-radio-group v-model="formData.isEnable">
<el-radio
v-for="dict in getBoolDictOptions(DICT_TYPE.INFRA_BOOLEAN_STRING)"
@ -110,20 +122,32 @@
</template>
<template v-else>
<el-form-item label="端点URL" prop="url">
<el-input v-model="formData.url" placeholder="请输入端点URL" />
<el-form-item :label="t('DataCollection.Device.url')" prop="url">
<el-input
v-model="formData.url"
:placeholder="t('DataCollection.Device.placeholderUrl')"
/>
</el-form-item>
<el-form-item label="用户名" prop="username">
<el-input v-model="formData.username" placeholder="请输入用户名" />
<el-form-item :label="t('DataCollection.Device.username')" prop="username">
<el-input
v-model="formData.username"
:placeholder="t('DataCollection.Device.placeholderUsername')"
/>
</el-form-item>
<el-form-item label="密码" prop="password">
<el-input v-model="formData.password" placeholder="请输入密码" show-password />
<el-form-item :label="t('DataCollection.Device.password')" prop="password">
<el-input
v-model="formData.password"
:placeholder="t('DataCollection.Device.placeholderPassword')"
show-password
/>
</el-form-item>
</template>
</el-form>
<template #footer>
<el-button @click="dialogVisible = false"> </el-button>
<el-button @click="submitForm" type="primary" :disabled="formLoading"> </el-button>
<el-button @click="dialogVisible = false">{{ t('common.cancel') }}</el-button>
<el-button @click="submitForm" type="primary" :disabled="formLoading">
{{ t('common.ok') }}
</el-button>
</template>
</Dialog>
</template>
@ -188,7 +212,8 @@ const formRef = ref() // 表单 Ref
/** 打开弹窗 */
const open = async (type: string, id?: number) => {
dialogVisible.value = true
dialogTitle.value = type === 'setting' ? '设备设置' : t('action.' + type)
dialogTitle.value =
type === 'setting' ? t('DataCollection.Device.settingDialogTitle') : t('action.' + type)
formType.value = type
resetForm()
//

@ -4,33 +4,39 @@
ref="formRef"
:model="formData"
:rules="formRules"
label-width="100px"
label-width="120px"
v-loading="formLoading"
>
<el-form-item label="点位编码" prop="attributeCode">
<el-form-item :label="t('DataCollection.Device.attributeCode')" prop="attributeCode">
<el-input
v-model="formData.attributeCode"
placeholder="请输入点位编码"
:placeholder="t('DataCollection.Device.placeholderAttributeCode')"
@input="handleAttributeCodeInput"
:disabled = "formType === 'update'"
/>
</el-form-item>
<el-form-item label="点位名称" prop="attributeName">
<el-input v-model="formData.attributeName" placeholder="请输入点位名称" />
<el-form-item :label="t('DataCollection.Device.attributeName')" prop="attributeName">
<el-input
v-model="formData.attributeName"
:placeholder="t('DataCollection.Device.placeholderAttributeName')"
/>
</el-form-item>
<el-form-item label="点位类型" prop="attributeType">
<el-form-item :label="t('DataCollection.Device.attributeType')" prop="attributeType">
<el-select
v-model="formData.attributeType"
clearable
filterable
placeholder="请选择点位类型"
:placeholder="t('DataCollection.Device.placeholderAttributeType')"
@change="handleAttributeTypeChange"
>
<el-option v-for="item in typeList" :key="item.id" :label="item.name" :value="item.id" />
</el-select>
</el-form-item>
<el-form-item label="数据类型" prop="dataType">
<el-select v-model="formData.dataType" placeholder="请选择数据类型">
<el-form-item :label="t('DataCollection.Device.dataType')" prop="dataType">
<el-select
v-model="formData.dataType"
:placeholder="t('DataCollection.Device.placeholderDataType')"
>
<el-option
v-for="dict in getStrDictOptions(DICT_TYPE.IOT_DEVICE_DATA_TYPE)"
:key="dict.value"
@ -39,30 +45,39 @@
/>
</el-select>
</el-form-item>
<el-form-item label="寄存器地址" prop="address">
<el-input v-model="formData.address" placeholder="请输入寄存器地址" />
</el-form-item>
<el-form-item label="单位" prop="dataUnit">
<el-input v-model="formData.dataUnit" placeholder="请输入单位" />
<el-form-item :label="t('DataCollection.Device.address')" prop="address">
<el-input
v-model="formData.address"
:placeholder="t('DataCollection.Device.placeholderAddress')"
/>
</el-form-item>
<el-form-item label="倍率" prop="ratio">
<el-input v-model="formData.ratio" placeholder="请输入倍率" :disabled="!ratioEnabled" />
<el-form-item :label="t('DataCollection.Device.dataUnit')" prop="dataUnit">
<el-input
v-model="formData.dataUnit"
:placeholder="t('DataCollection.Device.placeholderDataUnit')"
/>
</el-form-item>
<el-form-item label="顺序" prop="sort">
<el-input v-model="formData.sort" placeholder="请输入顺序" @input="handleSortInput" />
<el-form-item :label="t('DataCollection.Device.ratio')" prop="ratio">
<el-input
v-model="formData.ratio"
:placeholder="t('DataCollection.Device.placeholderRatio')"
:disabled="!ratioEnabled"
/>
</el-form-item>
<el-form-item label="备注" prop="remark">
<el-form-item :label="t('DataCollection.Device.remark')" prop="remark">
<el-input
v-model="formData.remark"
placeholder="请输入备注"
:placeholder="t('DataCollection.Device.placeholderRemark')"
maxlength="100"
show-word-limit
/>
</el-form-item>
</el-form>
<template #footer>
<el-button @click="dialogVisible = false"> </el-button>
<el-button @click="submitForm" type="primary" :disabled="formLoading"> </el-button>
<el-button @click="dialogVisible = false">{{ t('common.cancel') }}</el-button>
<el-button @click="submitForm" type="primary" :disabled="formLoading">
{{ t('common.ok') }}
</el-button>
</template>
</Dialog>
</template>
@ -102,7 +117,6 @@ const formData = ref({
address: undefined as string | undefined,
dataUnit: undefined as string | undefined,
ratio: undefined as string | undefined,
sort: undefined as string | undefined,
remark: undefined as string | undefined,
deviceId: undefined as number | undefined
})
@ -138,9 +152,6 @@ const handleAttributeCodeInput = (val: string) => {
formData.value.attributeCode = val?.replace(/[\u4e00-\u9fa5]/g, '')
}
const handleSortInput = (val: string) => {
formData.value.sort = val?.replace(/\D/g, '')
}
const handleAttributeTypeChange = (val: number | string) => {
const matched = typeList.value.find(
@ -151,7 +162,7 @@ const handleAttributeTypeChange = (val: number | string) => {
const formRules = reactive({
attributeCode: [
{ required: true, message: '点位编码不能为空', trigger: 'blur' },
{ required: true, message: t('DataCollection.Device.attributeValidatorCodeRequired'), trigger: 'blur' },
{
validator: (_rule: any, value: string, callback: any) => {
if (!value) {
@ -159,24 +170,7 @@ const formRules = reactive({
return
}
if (/[\u4e00-\u9fa5]/.test(value)) {
callback(new Error('点位编码不允许输入中文'))
return
}
callback()
},
trigger: ['blur', 'change']
}
],
attributeName: [{ required: true, message: '点位名称不能为空', trigger: 'blur' }],
sort: [
{
validator: (_rule: any, value: string, callback: any) => {
if (!value) {
callback()
return
}
if (!/^\d+$/.test(value)) {
callback(new Error('顺序只能输入数字'))
callback(new Error(t('DataCollection.Device.attributeValidatorCodeNoChinese')))
return
}
callback()
@ -184,11 +178,12 @@ const formRules = reactive({
trigger: ['blur', 'change']
}
],
attributeName: [{ required: true, message: t('DataCollection.Device.attributeValidatorNameRequired'), trigger: 'blur' }],
remark: [
{
validator: (_rule: any, value: string, callback: any) => {
if (value && value.length > 100) {
callback(new Error('备注不能超过100字'))
callback(new Error(t('DataCollection.Device.attributeValidatorRemarkTooLong')))
return
}
callback()
@ -210,17 +205,10 @@ const buildSubmitData = () => {
address,
dataUnit,
ratio,
sort,
remark,
deviceId
} = formData.value
const parsedSort =
sort === undefined || sort === null || sort === ''
? undefined
: Number.isNaN(Number(sort))
? undefined
: Number(sort)
const data: any = {
attributeCode,
attributeName,
@ -230,7 +218,6 @@ const buildSubmitData = () => {
address,
dataUnit,
ratio: ratioEnabled.value ? ratio : undefined,
sort: parsedSort,
remark,
deviceId
}
@ -257,11 +244,6 @@ const open = async (type: string, id?: number, deviceId: number) => {
;(formData.value as any).deviceId = deviceId
}
const currentSort = (formData.value as any)?.sort
if (currentSort !== undefined && currentSort !== null) {
;(formData.value as any).sort = String(currentSort)
}
const currentType = (formData.value as any)?.attributeType
if (currentType !== undefined && currentType !== null && currentType !== '') {
const matched = typeList.value.find(
@ -319,7 +301,6 @@ const resetForm = () => {
address: undefined,
dataUnit: undefined,
ratio: undefined,
sort: undefined,
remark: undefined,
deviceId: undefined
}

@ -1,38 +1,72 @@
<template>
<ContentWrap>
<el-form class="-mb-15px" :model="queryParams" ref="queryFormRef" :inline="true" label-width="100px">
<el-form-item label="点位编码" prop="attributeCode">
<el-form
class="-mb-15px"
:model="queryParams"
ref="queryFormRef"
:inline="true"
label-width="120px"
>
<el-form-item :label="t('DataCollection.Device.attributeCode')" prop="attributeCode">
<el-input
v-model="queryParams.attributeCode" placeholder="请输入点位编码" clearable @keyup.enter="handleQuery"
class="!w-240px" />
v-model="queryParams.attributeCode"
:placeholder="t('DataCollection.Device.placeholderAttributeCode')"
clearable
@keyup.enter="handleQuery"
class="!w-240px"
/>
</el-form-item>
<el-form-item label="点位名称" prop="attributeName">
<el-form-item :label="t('DataCollection.Device.attributeName')" prop="attributeName">
<el-input
v-model="queryParams.attributeName" placeholder="请输入点位名称" clearable @keyup.enter="handleQuery"
class="!w-240px" />
v-model="queryParams.attributeName"
:placeholder="t('DataCollection.Device.placeholderAttributeName')"
clearable
@keyup.enter="handleQuery"
class="!w-240px"
/>
</el-form-item>
<el-form-item label="点位类型" prop="attributeType">
<el-select v-model="queryParams.attributeType" clearable filterable placeholder="请选择" class="!w-240px">
<el-form-item :label="t('DataCollection.Device.attributeType')" prop="attributeType">
<el-select
v-model="queryParams.attributeType"
clearable
filterable
:placeholder="t('DataCollection.Device.placeholderAttributeType')"
class="!w-240px"
>
<el-option v-for="item in typeList" :key="item.id" :label="item.name" :value="item.name" />
</el-select>
</el-form-item>
<el-form-item>
<el-button @click="handleQuery">
<Icon icon="ep:search" class="mr-5px" /> 搜索
<Icon icon="ep:search" class="mr-5px" /> {{ t('DataCollection.Device.search') }}
</el-button>
<el-button @click="resetQuery">
<Icon icon="ep:refresh" class="mr-5px" /> 重置
<Icon icon="ep:refresh" class="mr-5px" /> {{ t('DataCollection.Device.reset') }}
</el-button>
<el-button type="primary" plain @click="openForm('create')" v-hasPermi="['iot:device:create']">
<Icon icon="ep:plus" class="mr-5px" /> 新增
<el-button
type="primary"
plain
@click="openForm('create')"
v-hasPermi="['iot:device:create']"
>
<Icon icon="ep:plus" class="mr-5px" /> {{ t('DataCollection.Device.create') }}
</el-button>
<el-button
type="success" plain @click="handleExport" :loading="exportLoading"
v-hasPermi="['iot:device:export']">
<Icon icon="ep:download" class="mr-5px" /> 导出
type="success"
plain
@click="handleExport"
:loading="exportLoading"
v-hasPermi="['iot:device:export']"
>
<Icon icon="ep:download" class="mr-5px" /> {{ t('DataCollection.Device.export') }}
</el-button>
<el-button type="danger" plain @click="handleBatchDelete" v-hasPermi="['iot:device:delete']">
<Icon icon="ep:delete" class="mr-5px" /> 批量删除
<el-button
type="danger"
plain
@click="handleBatchDelete"
v-hasPermi="['iot:device:delete']"
>
<Icon icon="ep:delete" class="mr-5px" /> {{ t('DataCollection.Device.batchDelete') }}
</el-button>
</el-form-item>
</el-form>
@ -43,38 +77,97 @@ type="success" plain @click="handleExport" :loading="exportLoading"
ref="tableRef" v-loading="loading" :data="list" :stripe="true" :show-overflow-tooltip="true" row-key="id"
@selection-change="handleSelectionChange">
<el-table-column type="selection" width="55" reserve-selection />
<el-table-column label="点位编码" align="left" prop="attributeCode" width="150px" />
<el-table-column label="点位名称" align="left" prop="attributeName" width="150px" />
<el-table-column label="点位类型" align="center" prop="typeName" width="140px" />
<el-table-column label="数据类型" align="center" prop="dataType" width="120px">
<el-table-column
:label="t('DataCollection.Device.attributeCode')"
align="left"
prop="attributeCode"
width="150px"
/>
<el-table-column
:label="t('DataCollection.Device.attributeName')"
align="left"
prop="attributeName"
width="150px"
/>
<el-table-column
:label="t('DataCollection.Device.attributeType')"
align="center"
prop="typeName"
width="140px"
/>
<el-table-column
:label="t('DataCollection.Device.dataType')"
align="center"
prop="dataType"
width="120px"
>
<template #default="scope">
<dict-tag :type="DICT_TYPE.IOT_DEVICE_DATA_TYPE" :value="scope.row.dataType" />
</template>
</el-table-column>
<el-table-column label="寄存器地址" align="center" prop="address" min-width="140px" />
<el-table-column label="最新值" align="center" prop="addressValue" min-width="120px">
<el-table-column
:label="t('DataCollection.Device.address')"
align="center"
prop="address"
min-width="140px"
/>
<el-table-column
:label="t('DataCollection.Device.attributeLatestValue')"
align="center"
prop="addressValue"
min-width="120px"
>
<template #default="scope">
{{ formatAddressValue(scope.row.addressValue) }}
</template>
</el-table-column>
<el-table-column label="单位" align="center" prop="dataUnit" width="80px" />
<el-table-column label="倍率" align="center" prop="ratio" width="80px" />
<el-table-column
label="最新采集时间" align="center" prop="latestCollectionTime" :formatter="dateFormatter"
width="170px" />
<el-table-column label="顺序" align="center" prop="sort" width="80px">
<template #default="scope">
{{ scope.row.sort ?? '-' }}
</template>
</el-table-column>
<el-table-column label="备注" align="center" prop="remark" min-width="160px" />
<el-table-column label="操作" align="center" width="150px" fixed="right">
:label="t('DataCollection.Device.dataUnit')"
align="center"
prop="dataUnit"
width="80px"
/>
<el-table-column
:label="t('DataCollection.Device.ratio')"
align="center"
prop="ratio"
width="80px"
/>
<el-table-column
:label="t('DataCollection.Device.attributeLatestCollectionTime')"
align="center"
prop="latestCollectionTime"
:formatter="dateFormatter"
width="170px"
/>
<el-table-column
:label="t('DataCollection.Device.remark')"
align="center"
prop="remark"
min-width="160px"
/>
<el-table-column
:label="t('DataCollection.Device.operate')"
align="center"
width="150px"
fixed="right"
>
<template #default="scope">
<el-button link type="primary" @click="openForm('update', scope.row.id)" v-hasPermi="['iot:device:update']">
编辑
<el-button
link
type="primary"
@click="openForm('update', scope.row.id)"
v-hasPermi="['iot:device:update']"
>
{{ t('action.edit') }}
</el-button>
<el-button link type="danger" @click="handleDelete(scope.row.id)" v-hasPermi="['iot:device:delete']">
删除
<el-button
link
type="danger"
@click="handleDelete(scope.row.id)"
v-hasPermi="['iot:device:delete']"
>
{{ t('action.delete') }}
</el-button>
</template>
</el-table-column>
@ -197,7 +290,7 @@ const resetQuery = () => {
const formRef = ref()
const openForm = (type: string, id?: number) => {
if (!props.deviceId) {
message.error('请选择一个物联设备')
message.error(t('DataCollection.Device.messageSelectDeviceRequired'))
return
}
formRef.value.open(type, id, props.deviceId)
@ -224,7 +317,7 @@ const handleDelete = async (ids: number | number[]) => {
const handleBatchDelete = async () => {
if (!selectedIds.value.length) {
message.error('请选择需要删除的数据')
message.error(t('common.delNoData'))
return
}
await handleDelete(selectedIds.value)
@ -240,7 +333,7 @@ const handleExport = async () => {
params.ids = selectedIds.value.join(',')
}
const data = await DeviceModelAttributeApi.exportDeviceModelAttribute(params)
download.excel(data, '采集设备-点位管理.xls')
download.excel(data, t('DataCollection.Device.attributeExportFilename'))
} catch {
} finally {
exportLoading.value = false

@ -1,15 +1,21 @@
<template>
<ContentWrap>
<!-- 搜索工作栏 -->
<el-form class="-mb-15px" :model="queryParams" ref="queryFormRef" :inline="true" label-width="68px">
<el-form-item label="设备编号" prop="deviceCode">
<el-form class="-mb-15px" :model="queryParams" ref="queryFormRef" :inline="true" label-width="120px">
<el-form-item :label="t('DataCollection.Device.deviceCode')" prop="deviceCode">
<el-input
v-model="queryParams.deviceCode" placeholder="请输入设备编号" clearable @keyup.enter="handleQuery"
v-model="queryParams.deviceCode"
:placeholder="t('DataCollection.Device.placeholderDeviceCode')"
clearable
@keyup.enter="handleQuery"
class="!w-240px" />
</el-form-item>
<el-form-item label="设备名称" prop="deviceName">
<el-form-item :label="t('DataCollection.Device.deviceName')" prop="deviceName">
<el-input
v-model="queryParams.deviceName" placeholder="请输入设备名称" clearable @keyup.enter="handleQuery"
v-model="queryParams.deviceName"
:placeholder="t('DataCollection.Device.placeholderDeviceName')"
clearable
@keyup.enter="handleQuery"
class="!w-240px" />
</el-form-item>
@ -42,21 +48,21 @@ v-model="queryParams.deviceName" placeholder="请输入设备名称" clearable @
</el-form-item> -->
<el-form-item>
<el-button @click="handleQuery">
<Icon icon="ep:search" class="mr-5px" /> 搜索
<Icon icon="ep:search" class="mr-5px" /> {{ t('DataCollection.Device.search') }}
</el-button>
<el-button @click="resetQuery">
<Icon icon="ep:refresh" class="mr-5px" /> 重置
<Icon icon="ep:refresh" class="mr-5px" /> {{ t('DataCollection.Device.reset') }}
</el-button>
<el-button type="primary" plain @click="openForm('create')" v-hasPermi="['iot:device:create']">
<Icon icon="ep:plus" class="mr-5px" /> 新增
<Icon icon="ep:plus" class="mr-5px" /> {{ t('DataCollection.Device.create') }}
</el-button>
<el-button
type="success" plain @click="handleExport" :loading="exportLoading"
type="success" plain @click="handleExport" :loading="exportLoading"
v-hasPermi="['iot:device:export']">
<Icon icon="ep:download" class="mr-5px" /> 导出
<Icon icon="ep:download" class="mr-5px" /> {{ t('DataCollection.Device.export') }}
</el-button>
<el-button type="danger" plain @click="handleBatchDelete" v-hasPermi="['iot:device:delete']">
<Icon icon="ep:delete" class="mr-5px" /> 批量删除
<Icon icon="ep:delete" class="mr-5px" /> {{ t('DataCollection.Device.batchDelete') }}
</el-button>
</el-form-item>
</el-form>
@ -65,12 +71,12 @@ type="success" plain @click="handleExport" :loading="exportLoading"
<!-- 列表 -->
<ContentWrap>
<el-table
ref="tableRef" v-loading="loading" :data="list" :stripe="true" :show-overflow-tooltip="true" row-key="id"
ref="tableRef" v-loading="loading" :data="list" :stripe="true" :show-overflow-tooltip="true" row-key="id"
@selection-change="handleSelectionChange">
<el-table-column type="selection" width="55" reserve-selection />
<el-table-column label="设备编号" align="left" prop="deviceCode" />
<el-table-column label="设备名称" align="left" prop="deviceName" />
<el-table-column label="运行状态" align="center" prop="operatingStatus" width="120px">
<el-table-column :label="t('DataCollection.Device.deviceCode')" align="left" prop="deviceCode" />
<el-table-column :label="t('DataCollection.Device.deviceName')" align="left" prop="deviceName" />
<el-table-column :label="t('DataCollection.Device.operatingStatus')" align="center" prop="operatingStatus" width="120px">
<template #default="scope">
<el-tag
size="small"
@ -84,18 +90,18 @@ ref="tableRef" v-loading="loading" :data="list" :stripe="true" :show-overflow-to
<!-- <template #default="scope">
<dict-tag :type="DICT_TYPE.IOT_DEVICE_TYPE" :value="scope.row.deviceType" />
</template>
</el-table-column> -->
<el-table-column label="采集协议" align="left" prop="protocol" width="120px">
</el-table-column> -->
<el-table-column :label="t('DataCollection.Device.protocol')" align="left" prop="protocol" width="120px">
<template #default="scope">
<dict-tag :type="DICT_TYPE.IOT_PROTOCOL" :value="scope.row.protocol" />
</template>
</el-table-column>
<el-table-column label="连接状态" align="center" prop="status" width="120px">
<el-table-column :label="t('DataCollection.Device.status')" align="center" prop="status" width="120px">
<template #default="scope">
<dict-tag :type="DICT_TYPE.IOT_GATEWAY_STATUS" :value="scope.row.status" />
</template>
</el-table-column>
<el-table-column label="采集周期(s)" align="center" prop="sampleCycle" width="120px" />
<el-table-column :label="t('DataCollection.Device.sampleCycle')" align="center" prop="sampleCycle" width="120px" />
<!-- <el-table-column label="读主题" align="center" prop="readTopic" />
<el-table-column label="写主题" align="center" prop="writeTopic" />
@ -117,37 +123,57 @@ ref="tableRef" v-loading="loading" :data="list" :stripe="true" :show-overflow-to
:formatter="dateFormatter"
width="170px"
/> -->
<el-table-column label="是否启用" align="center" prop="isEnable" width="120px">
<el-table-column :label="t('DataCollection.Device.isEnable')" align="center" prop="isEnable" width="120px">
<template #default="scope">
<dict-tag :type="DICT_TYPE.INFRA_BOOLEAN_STRING" :value="scope.row.isEnable" />
</template>
</el-table-column>
<el-table-column
label="采集时间"
:label="t('DataCollection.Device.collectionTime')"
align="center"
prop="collectionTime"
width="180px"
:formatter="dateFormatter"
/>
<el-table-column label="操作" align="center" fixed="right" width="380px">
<el-table-column :label="t('DataCollection.Device.operate')" align="center" fixed="right" width="380px">
<template #default="scope">
<el-button link type="primary" @click.stop="handleShowAttribute(scope.row)">点位</el-button>
<el-button link type="primary" @click="openForm('setting', scope.row.id)" v-hasPermi="['iot:device:update']">
设置
<el-button link type="primary" @click.stop="handleShowAttribute(scope.row)">{{ t('DataCollection.Device.attributeModuleName') }}</el-button>
<el-button
link
type="primary"
@click="openForm('setting', scope.row.id)"
v-hasPermi="['iot:device:update']"
>
{{ t('DataCollection.Device.settingDialogTitle') }}
</el-button>
<el-button link type="primary" @click="handleCopy(scope.row.id)" v-hasPermi="['iot:device:create']">
复制
<el-button
link
type="primary"
@click="handleCopy(scope.row.id)"
v-hasPermi="['iot:device:create']"
>
{{ t('action.copy') }}
</el-button>
<el-button link type="primary" @click.stop="handleEdit(scope.row)" v-hasPermi="['iot:device:update']">
编辑
<el-button
link
type="primary"
@click.stop="handleEdit(scope.row)"
v-hasPermi="['iot:device:update']"
>
{{ t('action.edit') }}
</el-button>
<el-button
link :type="isRowConnected(scope.row) ? 'warning' : 'success'"
link :type="isRowConnected(scope.row) ? 'warning' : 'success'"
:loading="!!connectLoadingMap[scope.row.id]" @click.stop="handleToggleConnect(scope.row)">
{{ isRowConnected(scope.row) ? '断开连接' : '连接' }}
{{ isRowConnected(scope.row) ? t('DataCollection.Device.disconnect') : t('DataCollection.Device.connect') }}
</el-button>
<el-button link type="danger" @click="handleDelete(scope.row.id)" v-hasPermi="['iot:device:delete']">
删除
<el-button
link
type="danger"
@click="handleDelete(scope.row.id)"
v-hasPermi="['iot:device:delete']"
>
{{ t('action.delete') }}
</el-button>
</template>
</el-table-column>
@ -165,11 +191,11 @@ link :type="isRowConnected(scope.row) ? 'warning' : 'success'"
<template v-if="attributeDeviceId">
<div class="mb-10px flex items-center justify-between text-sm text-gray-500">
<div>
当前设备<span class="font-medium text-gray-700">{{ attributeDeviceName || '-' }}</span>
{{ t('DataCollection.Device.currentDeviceLabel') }}<span class="font-medium text-gray-700">{{ attributeDeviceName || '-' }}</span>
</div>
<div>
<el-button type="primary" link @click="handleShowDeviceAlarmHistory">
设备告警历史数据
{{ t('DataCollection.Device.alarmHistoryTitle') }}
</el-button>
</div>
</div>
@ -183,30 +209,30 @@ link :type="isRowConnected(scope.row) ? 'warning' : 'success'"
:model="ruleQueryParams"
ref="ruleQueryFormRef"
:inline="true"
label-width="80px"
label-width="120px"
>
<el-form-item label="标识符" prop="identifier">
<el-form-item :label="t('DataCollection.DeviceModel.ruleIdentifier')" prop="identifier">
<el-input
v-model="ruleQueryParams.identifier"
placeholder="请输入标识符"
:placeholder="t('DataCollection.DeviceModel.ruleSearchIdentifierPlaceholder')"
clearable
@keyup.enter="handleRuleQuery"
class="!w-200px"
/>
</el-form-item>
<el-form-item label="名称" prop="fieldName">
<el-form-item :label="t('DataCollection.DeviceModel.ruleFieldName')" prop="fieldName">
<el-input
v-model="ruleQueryParams.fieldName"
placeholder="请输入名称"
:placeholder="t('DataCollection.DeviceModel.ruleSearchFieldNamePlaceholder')"
clearable
@keyup.enter="handleRuleQuery"
class="!w-200px"
/>
</el-form-item>
<el-form-item label="默认值" prop="defaultValue">
<el-form-item :label="t('DataCollection.DeviceModel.ruleDefaultValue')" prop="defaultValue">
<el-input
v-model="ruleQueryParams.defaultValue"
placeholder="请输入默认值"
:placeholder="t('DataCollection.DeviceModel.ruleSearchDefaultValuePlaceholder')"
clearable
@keyup.enter="handleRuleQuery"
class="!w-200px"
@ -214,17 +240,17 @@ link :type="isRowConnected(scope.row) ? 'warning' : 'success'"
</el-form-item>
<el-form-item>
<el-button @click="handleRuleQuery">
<Icon icon="ep:search" class="mr-5px" /> 搜索
<Icon icon="ep:search" class="mr-5px" /> {{ t('DataCollection.DeviceModel.ruleSearch') }}
</el-button>
<el-button @click="resetRuleQuery">
<Icon icon="ep:refresh" class="mr-5px" /> 重置
<Icon icon="ep:refresh" class="mr-5px" /> {{ t('DataCollection.DeviceModel.ruleReset') }}
</el-button>
</el-form-item>
</el-form>
<div class="mb-10px text-right">
<el-button type="primary" @click="openCreateRuleForm">
新增告警规则
{{ t('DataCollection.DeviceModel.ruleCreateButton') }}
</el-button>
</div>
@ -235,21 +261,21 @@ link :type="isRowConnected(scope.row) ? 'warning' : 'success'"
:show-overflow-tooltip="true"
row-key="id"
>
<el-table-column label="标识符" align="center" prop="identifier" />
<el-table-column label="名称" align="center" prop="fieldName" />
<el-table-column label="规则" align="center" prop="fieldRule" />
<el-table-column label="默认值" align="center" prop="defaultValue" />
<el-table-column :label="t('DataCollection.DeviceModel.ruleIdentifier')" align="center" prop="identifier" />
<el-table-column :label="t('DataCollection.DeviceModel.ruleFieldName')" align="center" prop="fieldName" />
<el-table-column :label="t('DataCollection.DeviceModel.ruleFieldRule')" align="center" prop="fieldRule" />
<el-table-column :label="t('DataCollection.DeviceModel.ruleDefaultValue')" align="center" prop="defaultValue" />
<el-table-column
label="创建时间"
:label="t('DataCollection.DeviceModel.ruleCreateTime')"
align="center"
prop="createTime"
:formatter="dateFormatter"
width="180px"
/>
<el-table-column label="操作" align="center" width="160px">
<el-table-column :label="t('DataCollection.DeviceModel.ruleOperate')" align="center" width="160px">
<template #default="scope">
<el-button link type="primary" @click="openRuleForm(scope.row)">
编辑
{{ t('DataCollection.DeviceModel.ruleEditRuleButton') }}
</el-button>
<el-button
v-if="(scope.row.identifier || '').toString().toUpperCase() === 'ALARM'"
@ -257,7 +283,7 @@ link :type="isRowConnected(scope.row) ? 'warning' : 'success'"
type="danger"
@click="handleRuleDelete(scope.row.id)"
>
删除
{{ t('DataCollection.DeviceModel.ruleDeleteRuleButton') }}
</el-button>
</template>
</el-table-column>
@ -269,22 +295,25 @@ link :type="isRowConnected(scope.row) ? 'warning' : 'success'"
@pagination="getRuleList"
/>
<el-dialog v-model="ruleDialogVisible" title="编辑点位规则" width="880px" draggable>
<el-form :model="ruleForm" ref="ruleFormRef" label-width="90px">
<el-form-item label="标识符">
<el-dialog v-model="ruleDialogVisible" :title="t('DataCollection.DeviceModel.ruleDialogTitle')" width="880px" draggable>
<el-form :model="ruleForm" ref="ruleFormRef" label-width="120px">
<el-form-item :label="t('DataCollection.DeviceModel.ruleDialogIdentifier')">
<el-input v-model="ruleForm.identifier" disabled />
</el-form-item>
<el-form-item label="名称">
<el-form-item :label="t('DataCollection.DeviceModel.ruleDialogFieldName')">
<el-input v-model="ruleForm.fieldName" disabled />
</el-form-item>
<el-form-item label="默认值">
<el-form-item :label="t('DataCollection.DeviceModel.ruleDialogDefaultValue')">
<el-input v-model="ruleForm.defaultValue" disabled />
</el-form-item>
<el-form-item
v-if="(ruleForm.identifier || '').toString().toUpperCase() === 'ALARM'"
label="告警登记"
:label="t('DataCollection.DeviceModel.ruleDialogAlarmLevel')"
>
<el-select v-model="ruleForm.alarmLevel" placeholder="请选择告警登记">
<el-select
v-model="ruleForm.alarmLevel"
:placeholder="t('DataCollection.DeviceModel.ruleDialogAlarmLevelPlaceholder')"
>
<el-option
v-for="dict in getStrDictOptions(DICT_TYPE.IOT_ALARM_REGISTRATION)"
:key="dict.value"
@ -296,10 +325,10 @@ link :type="isRowConnected(scope.row) ? 'warning' : 'success'"
<div class="flex flex-col w-full">
<div class="border border-gray-200 dark:border-gray-600 rounded-md py-12px">
<el-form-item label="点位规则">
<el-form-item :label="t('DataCollection.DeviceModel.ruleDialogFieldRule')">
<el-select
v-model="ruleForm.fieldRule"
placeholder="请选择点位规则"
:placeholder="t('DataCollection.DeviceModel.ruleDialogFieldRulePlaceholder')"
class="!w-240px"
:disabled="!currentRuleOptions.length"
>
@ -312,11 +341,11 @@ link :type="isRowConnected(scope.row) ? 'warning' : 'success'"
/>
</el-select>
</el-form-item>
<el-form-item label="规则">
<el-form-item :label="t('DataCollection.DeviceModel.ruleDialogRule')">
<div class="flex items-center gap-8px">
<el-select
v-model="ruleForm.ruleAttributeId"
placeholder="请选择点位"
:placeholder="t('DataCollection.DeviceModel.ruleDialogRuleAttributePlaceholder')"
class="!w-240px"
>
<el-option
@ -328,7 +357,7 @@ link :type="isRowConnected(scope.row) ? 'warning' : 'success'"
</el-select>
<el-select
v-model="ruleForm.ruleOperator"
placeholder="请选择条件"
:placeholder="t('DataCollection.DeviceModel.ruleDialogRuleOperatorPlaceholder')"
class="!w-160px"
>
<el-option
@ -341,7 +370,7 @@ link :type="isRowConnected(scope.row) ? 'warning' : 'success'"
<el-input
v-if="ruleForm.ruleOperator !== 'TRUE' && ruleForm.ruleOperator !== 'FALSE'"
v-model="ruleForm.ruleValue"
placeholder="请输入符号值"
:placeholder="t('DataCollection.DeviceModel.ruleDialogRuleValuePlaceholder')"
class="!w-200px"
/>
</div>
@ -353,10 +382,10 @@ link :type="isRowConnected(scope.row) ? 'warning' : 'success'"
:key="index"
class="border border-gray-200 dark:border-gray-600 rounded-md px-16px py-12px"
>
<el-form-item label="点位规则">
<el-form-item :label="t('DataCollection.DeviceModel.ruleDialogFieldRule')">
<el-select
v-model="item.rule"
placeholder="请选择点位规则"
:placeholder="t('DataCollection.DeviceModel.ruleDialogFieldRulePlaceholder')"
class="!w-240px"
>
<el-option
@ -368,11 +397,11 @@ link :type="isRowConnected(scope.row) ? 'warning' : 'success'"
/>
</el-select>
</el-form-item>
<el-form-item label="规则">
<el-form-item :label="t('DataCollection.DeviceModel.ruleDialogRule')">
<div class="flex items-center gap-8px">
<el-select
v-model="item.id"
placeholder="请选择点位"
:placeholder="t('DataCollection.DeviceModel.ruleDialogRuleAttributePlaceholder')"
class="!w-240px"
>
<el-option
@ -384,7 +413,7 @@ link :type="isRowConnected(scope.row) ? 'warning' : 'success'"
</el-select>
<el-select
v-model="item.operator"
placeholder="请选择条件"
:placeholder="t('DataCollection.DeviceModel.ruleDialogRuleOperatorPlaceholder')"
class="!w-160px"
>
<el-option
@ -397,11 +426,11 @@ link :type="isRowConnected(scope.row) ? 'warning' : 'success'"
<el-input
v-if="item.operator !== 'TRUE' && item.operator !== 'FALSE'"
v-model="item.operatorRule"
placeholder="请输入符号值"
:placeholder="t('DataCollection.DeviceModel.ruleDialogRuleValuePlaceholder')"
class="!w-200px"
/>
<el-button type="danger" link @click="handleRemovePointRule(index)">
删除
{{ t('DataCollection.DeviceModel.ruleDeleteRuleButton') }}
</el-button>
</div>
</el-form-item>
@ -409,32 +438,38 @@ link :type="isRowConnected(scope.row) ? 'warning' : 'success'"
<el-form-item v-if="isRunningIdentifier" label=" ">
<el-button type="primary" link @click="handleAddPointRule">
+ 添加规则
+ {{ t('DataCollection.DeviceModel.ruleCreateButton') }}
</el-button>
</el-form-item>
</div>
</el-form>
<template #footer>
<span class="dialog-footer">
<el-button @click="ruleDialogVisible = false"> </el-button>
<el-button type="primary" :loading="ruleFormLoading" @click="handleRuleSubmit"> </el-button>
<el-button @click="ruleDialogVisible = false">{{ t('DataCollection.DeviceModel.dialogCancel') }}</el-button>
<el-button type="primary" :loading="ruleFormLoading" @click="handleRuleSubmit">{{ t('DataCollection.DeviceModel.dialogOk') }}</el-button>
</span>
</template>
</el-dialog>
<el-dialog v-model="createRuleDialogVisible" title="新增告警规则" width="520px" draggable>
<el-form :model="createRuleForm" ref="createRuleFormRef" label-width="90px">
<el-form-item label="标识符">
<el-dialog v-model="createRuleDialogVisible" :title="t('DataCollection.DeviceModel.ruleCreateButton')" width="520px" draggable>
<el-form :model="createRuleForm" ref="createRuleFormRef" label-width="120px">
<el-form-item :label="t('DataCollection.DeviceModel.ruleDialogIdentifier')">
<el-input v-model="createRuleForm.identifier" disabled />
</el-form-item>
<el-form-item label="名称">
<el-input v-model="createRuleForm.fieldName" placeholder="请输入名称" />
<el-form-item :label="t('DataCollection.DeviceModel.ruleDialogFieldName')">
<el-input
v-model="createRuleForm.fieldName"
:placeholder="t('DataCollection.DeviceModel.ruleSearchFieldNamePlaceholder')"
/>
</el-form-item>
<el-form-item label="默认值">
<el-form-item :label="t('DataCollection.DeviceModel.ruleDialogDefaultValue')">
<el-input v-model="createRuleForm.defaultValue" disabled />
</el-form-item>
<el-form-item label="告警登记">
<el-select v-model="createRuleForm.alarmLevel" placeholder="请选择告警登记">
<el-form-item :label="t('DataCollection.DeviceModel.ruleDialogAlarmLevel')">
<el-select
v-model="createRuleForm.alarmLevel"
:placeholder="t('DataCollection.DeviceModel.ruleDialogAlarmLevelPlaceholder')"
>
<el-option
v-for="dict in getStrDictOptions(DICT_TYPE.IOT_ALARM_REGISTRATION)"
:key="dict.value"
@ -446,9 +481,9 @@ link :type="isRowConnected(scope.row) ? 'warning' : 'success'"
</el-form>
<template #footer>
<span class="dialog-footer">
<el-button @click="createRuleDialogVisible = false"> </el-button>
<el-button @click="createRuleDialogVisible = false">{{ t('DataCollection.DeviceModel.dialogCancel') }}</el-button>
<el-button type="primary" :loading="createRuleFormLoading" @click="handleCreateRuleSubmit">
{{ t('DataCollection.DeviceModel.dialogOk') }}
</el-button>
</span>
</template>
@ -456,10 +491,10 @@ link :type="isRowConnected(scope.row) ? 'warning' : 'success'"
</el-tab-pane>
</el-tabs>
</template>
<el-empty v-else description="请点击设备列表的“点位”查看采集点和点位规则" />
<el-empty v-else :description="t('DataCollection.Device.emptyDescription')" />
</ContentWrap>
<Dialog title="设备告警历史数据" v-model="deviceAlarmDialogVisible" width="800px">
<Dialog :title="t('DataCollection.Device.alarmHistoryTitle')" v-model="deviceAlarmDialogVisible" width="800px">
<el-table
:data="deviceAlarmList"
v-loading="deviceAlarmLoading"
@ -467,10 +502,10 @@ link :type="isRowConnected(scope.row) ? 'warning' : 'success'"
:show-overflow-tooltip="true"
:max-height="700"
>
<el-table-column label="规则名称" align="center" prop="ruleName" />
<el-table-column label="点位名称" align="center" prop="modelName" />
<el-table-column label="点位值" align="center" prop="addressValue" />
<el-table-column label="告警等级" align="center" prop="alarmLevel">
<el-table-column :label="t('DataCollection.Device.alarmRuleName')" align="center" prop="ruleName" />
<el-table-column :label="t('DataCollection.Device.alarmPointName')" align="center" prop="modelName" />
<el-table-column :label="t('DataCollection.Device.alarmPointValue')" align="center" prop="addressValue" />
<el-table-column :label="t('DataCollection.Device.alarmLevel')" align="center" prop="alarmLevel">
<template #default="scope">
<dict-tag :type="DICT_TYPE.IOT_ALARM_REGISTRATION" :value="scope.row.alarmLevel" />
</template>
@ -601,7 +636,7 @@ const handleDelete = async (ids: number | number[]) => {
const handleBatchDelete = async () => {
if (!selectedIds.value.length) {
message.error('请选择需要删除的数据')
message.error(t('common.delNoData'))
return
}
await handleDelete(selectedIds.value)
@ -610,7 +645,7 @@ const handleBatchDelete = async () => {
const handleCopy = async (id: number) => {
try {
await DeviceApi.copyDevice(id)
message.success('复制成功')
message.success(t('common.copySuccess'))
await getList()
} catch { }
}
@ -627,7 +662,7 @@ const handleExport = async () => {
ids: selectedIds.value.length ? selectedIds.value.join(',') : undefined
}
const data = await DeviceApi.exportDevice(params)
download.excel(data, '物联设备.xls')
download.excel(data, t('DataCollection.Device.exportFilename'))
} catch {
} finally {
exportLoading.value = false
@ -653,11 +688,11 @@ const attributeDeviceName = ref('')
const deviceTabActive = ref('deviceAttribute')
const deviceAttributeTabLabel = computed(() => {
return '设备属性'
return t('DataCollection.Device.deviceAttributeTabLabel')
})
const deviceRuleTabLabel = computed(() => {
return '点位规则'
return t('DataCollection.Device.deviceRuleTabLabel')
})
const handleShowAttribute = (row: any) => {
@ -803,7 +838,7 @@ const isRunningIdentifier = computed(() => {
const openRuleForm = async (row: DevicePointRuleVO & { pointRulesVOList?: any[] }) => {
const deviceId = row.deviceId || attributeDeviceId.value
if (!deviceId) {
message.error('设备信息缺失,无法加载点位规则')
message.error(t('DataCollection.Device.messageDeviceInfoMissingForRules'))
return
}
@ -910,7 +945,7 @@ const handleRuleSubmit = async () => {
}
await request.put({ url: '/iot/device-point-rules/update', data: payload })
message.success('保存成功')
message.success(t('common.updateSuccess'))
ruleDialogVisible.value = false
await getRuleList()
} finally {
@ -1079,7 +1114,7 @@ const deviceAlarmList = ref<any[]>([])
const handleShowDeviceAlarmHistory = async () => {
if (!attributeDeviceId.value) {
message.error('请选择一个物联设备')
message.error(t('DataCollection.Device.messageSelectDeviceRequired'))
return
}
deviceAlarmDialogVisible.value = true

@ -2,7 +2,13 @@
<el-row :gutter="20">
<el-col :span="6" :xs="24">
<ContentWrap class="h-1/1">
<el-input v-model="keyword" clearable placeholder="搜索设备或参数" class="!w-1/1" @input="handleKeywordChange" />
<el-input
v-model="keyword"
clearable
:placeholder="t('DataCollection.DeviceParamAnalysis.treeSearchPlaceholder')"
class="!w-1/1"
@input="handleKeywordChange"
/>
<div class="mt-12px">
<el-tree
ref="treeRef" v-loading="treeLoading" :data="treeData" :props="treeProps" node-key="id"
@ -13,19 +19,27 @@ ref="treeRef" v-loading="treeLoading" :data="treeData" :props="treeProps" node-k
<el-col :span="18" :xs="24">
<ContentWrap>
<el-form class="-mb-15px" :inline="true">
<el-form-item label="时间">
<el-form class="-mb-15px device-param-analysis-form" :inline="true" label-width="auto">
<el-form-item :label="t('DataCollection.DeviceParamAnalysis.formTimeLabel')">
<el-date-picker
v-model="dateRange" type="daterange" start-placeholder="开始日期" end-placeholder="结束日期"
value-format="YYYY-MM-DD" :shortcuts="dateShortcuts"
:default-time="[new Date('1 00:00:00'), new Date('1 23:59:59')]" class="!w-360px" />
v-model="dateRange"
type="daterange"
:start-placeholder="t('DataCollection.DeviceParamAnalysis.formTimeStartPlaceholder')"
:end-placeholder="t('DataCollection.DeviceParamAnalysis.formTimeEndPlaceholder')"
value-format="YYYY-MM-DD"
:shortcuts="dateShortcuts"
:default-time="[new Date('1 00:00:00'), new Date('1 23:59:59')]"
class="!w-360px"
/>
</el-form-item>
<el-form-item>
<el-button :disabled="!selectedParam" @click="handleQuery">
<Icon icon="ep:search" class="mr-5px" /> 搜索
<Icon icon="ep:search" class="mr-5px" />
{{ t('DataCollection.DeviceParamAnalysis.searchButtonText') }}
</el-button>
<el-button :disabled="!selectedParam" @click="resetQuery">
<Icon icon="ep:refresh" class="mr-5px" /> 重置
<Icon icon="ep:refresh" class="mr-5px" />
{{ t('DataCollection.DeviceParamAnalysis.resetButtonText') }}
</el-button>
</el-form-item>
</el-form>
@ -34,8 +48,14 @@ v-model="dateRange" type="daterange" start-placeholder="开始日期" end-placeh
<ContentWrap>
<el-alert v-if="selectedParam" :title="selectedParamTitle" type="info" :closable="false" class="mb-12px" />
<div v-loading="chartLoading">
<el-empty v-if="chartState === 'empty'" description="暂无数据" />
<el-empty v-else-if="!selectedParam" description="请选择左侧节点" />
<el-empty
v-if="chartState === 'empty'"
:description="t('DataCollection.DeviceParamAnalysis.emptyDescription')"
/>
<el-empty
v-else-if="!selectedParam"
:description="t('DataCollection.DeviceParamAnalysis.emptySelectNodeDescription')"
/>
<EChart v-else-if="chartState === 'ready'" :key="chartRenderKey" :options="chartOption" height="70vh" />
</div>
</ContentWrap>
@ -53,6 +73,8 @@ import { handleTree } from '@/utils/tree'
defineOptions({ name: 'DeviceParamAnalysis' })
const { t } = useI18n()
type TreeNodeType = 'device' | 'param'
type DeviceTreeNode = {
@ -117,7 +139,7 @@ const dateRange = ref<[string, string]>(buildDefaultDateRange())
const dateShortcuts = [
{
text: '最近 7 天',
text: t('DataCollection.DeviceParamAnalysis.shortcutLast7Days'),
value: () => {
const end = dayjs().endOf('day').toDate()
const start = dayjs().subtract(6, 'day').startOf('day').toDate()
@ -125,7 +147,7 @@ const dateShortcuts = [
}
},
{
text: '上周',
text: t('DataCollection.DeviceParamAnalysis.shortcutLastWeek'),
value: () => {
const start = dayjs().subtract(1, 'week').startOf('week').toDate()
const end = dayjs().subtract(1, 'week').endOf('week').toDate()
@ -133,7 +155,7 @@ const dateShortcuts = [
}
},
{
text: '上个月',
text: t('DataCollection.DeviceParamAnalysis.shortcutLastMonth'),
value: () => {
const start = dayjs().subtract(1, 'month').startOf('month').toDate()
const end = dayjs().subtract(1, 'month').endOf('month').toDate()
@ -141,7 +163,7 @@ const dateShortcuts = [
}
},
{
text: '三个月内',
text: t('DataCollection.DeviceParamAnalysis.shortcutLast3Months'),
value: () => {
const end = dayjs().endOf('day').toDate()
const start = dayjs().subtract(3, 'month').startOf('day').toDate()
@ -153,8 +175,11 @@ const dateShortcuts = [
const selectedParamTitle = computed(() => {
const param = selectedParam.value
if (!param) return ''
const unitText = param.unit ? `${param.unit}` : ''
return `节点:${param.label}${unitText}`
const unitText = param.unit ? ` (${param.unit})` : ''
return t('DataCollection.DeviceParamAnalysis.selectedParamTitle', {
label: param.label,
unit: unitText
})
})
const chartOption = computed<EChartsOption>(() => {
@ -281,7 +306,7 @@ const loadTree = async () => {
chartSeries.value = []
}
} catch {
message.error('获取树数据失败')
message.error(t('DataCollection.DeviceParamAnalysis.messageLoadTreeFailed'))
} finally {
treeLoading.value = false
}
@ -344,7 +369,7 @@ const fetchChart = async () => {
chartXAxis.value = []
chartSeries.value = []
chartState.value = 'empty'
message.warning('该节点下暂无参数')
message.warning(t('DataCollection.DeviceParamAnalysis.messageNodeNoParams'))
return
}
@ -386,12 +411,14 @@ const fetchChart = async () => {
} else {
chartXAxis.value = keys
const values = keys.map((k) => toNumber(firstRow[k]))
chartSeries.value = [{ name: param?.label || '参数', data: values }]
chartSeries.value = [
{ name: param?.label || t('DataCollection.DeviceParamAnalysis.defaultSeriesName'), data: values }
]
}
chartState.value = chartXAxis.value.length && chartSeries.value.length ? 'ready' : 'empty'
} catch {
message.error('获取图表数据失败')
message.error(t('DataCollection.DeviceParamAnalysis.messageFetchChartFailed'))
chartState.value = 'idle'
} finally {
chartLoading.value = false
@ -418,7 +445,7 @@ const handleTreeNodeClick = async (data: DeviceTreeNode) => {
selectedModelId.value = undefined
chartState.value = 'empty'
resetChartData()
message.warning('该设备下没有参数')
message.warning(t('DataCollection.DeviceParamAnalysis.messageDeviceNoParams'))
return
}
@ -459,6 +486,10 @@ onMounted(async () => {
</script>
<style scoped lang="scss">
.device-param-analysis-form :deep(.el-form-item__label) {
min-width: 100px;
}
:deep(.el-tree) {
max-height: calc(100vh - 280px);
overflow: auto;

@ -4,25 +4,25 @@
ref="formRef"
:model="formData"
:rules="formRules"
label-width="100px"
label-width="120px"
v-loading="formLoading"
>
<el-form-item label="分类编码" prop="code">
<el-input v-model="formData.code" placeholder="请输入分类编码" :disabled = "formType === 'update'"/>
<el-form-item :label="t('DataCollection.DeviceAttributeType.code')" prop="code">
<el-input v-model="formData.code" :placeholder="t('DataCollection.DeviceAttributeType.placeholderCode')" :disabled = "formType === 'update'"/>
</el-form-item>
<el-form-item label="分类名称" prop="name">
<el-input v-model="formData.name" placeholder="请输入分类名称" />
<el-form-item :label="t('DataCollection.DeviceAttributeType.name')" prop="name">
<el-input v-model="formData.name" :placeholder="t('DataCollection.DeviceAttributeType.placeholderName')" />
</el-form-item>
<el-form-item label="分类顺序" prop="sort">
<el-input v-model="formData.sort" placeholder="请输入分类顺序" />
<el-form-item :label="t('DataCollection.DeviceAttributeType.sort')" prop="sort">
<el-input v-model="formData.sort" :placeholder="t('DataCollection.DeviceAttributeType.placeholderSort')" />
</el-form-item>
<el-form-item label="备注" prop="remark">
<el-input v-model="formData.remark" placeholder="请输入备注" />
<el-form-item :label="t('DataCollection.DeviceAttributeType.remark')" prop="remark">
<el-input v-model="formData.remark" :placeholder="t('DataCollection.DeviceAttributeType.placeholderRemark')" />
</el-form-item>
</el-form>
<template #footer>
<el-button @click="submitForm" type="primary" :disabled="formLoading"> </el-button>
<el-button @click="dialogVisible = false"> </el-button>
<el-button @click="submitForm" type="primary" :disabled="formLoading">{{ t('DataCollection.DeviceAttributeType.dialogOk') }}</el-button>
<el-button @click="dialogVisible = false">{{ t('DataCollection.DeviceAttributeType.dialogCancel') }}</el-button>
</template>
</Dialog>
</template>
@ -47,9 +47,9 @@ const formData = ref({
remark: undefined,
})
const formRules = reactive({
code: [{ required: true, message: '分类编码不能为空', trigger: 'blur' }],
name: [{ required: true, message: '分类名称不能为空', trigger: 'blur' }],
sort: [{ required: true, message: '分类顺序不能为空', trigger: 'blur' }],
code: [{ required: true, message: t('DataCollection.DeviceAttributeType.validatorCodeRequired'), trigger: 'blur' }],
name: [{ required: true, message: t('DataCollection.DeviceAttributeType.validatorNameRequired'), trigger: 'blur' }],
sort: [{ required: true, message: t('DataCollection.DeviceAttributeType.validatorSortRequired'), trigger: 'blur' }],
})
const formRef = ref() // Ref

@ -1,26 +1,25 @@
<template>
<ContentWrap>
<!-- 搜索工作栏 -->
<el-form
class="-mb-15px"
:model="queryParams"
ref="queryFormRef"
:inline="true"
label-width="68px"
label-width="120px"
>
<el-form-item label="分类编码" prop="code">
<el-form-item :label="t('DataCollection.DeviceAttributeType.code')" prop="code">
<el-input
v-model="queryParams.code"
placeholder="请输入分类编码"
:placeholder="t('DataCollection.DeviceAttributeType.placeholderCode')"
clearable
@keyup.enter="handleQuery"
class="!w-240px"
/>
</el-form-item>
<el-form-item label="分类名称" prop="name">
<el-form-item :label="t('DataCollection.DeviceAttributeType.name')" prop="name">
<el-input
v-model="queryParams.name"
placeholder="请输入分类名称"
:placeholder="t('DataCollection.DeviceAttributeType.placeholderName')"
clearable
@keyup.enter="handleQuery"
class="!w-240px"
@ -47,15 +46,15 @@
/>
</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 @click="handleQuery"><Icon icon="ep:search" class="mr-5px" /> {{ t('DataCollection.DeviceAttributeType.search') }}</el-button>
<el-button @click="resetQuery"><Icon icon="ep:refresh" class="mr-5px" /> {{ t('DataCollection.DeviceAttributeType.reset') }}</el-button>
<el-button
type="primary"
plain
@click="openForm('create')"
v-hasPermi="['iot:device-attribute-type:create']"
>
<Icon icon="ep:plus" class="mr-5px" /> 新增
<Icon icon="ep:plus" class="mr-5px" /> {{ t('DataCollection.DeviceAttributeType.create') }}
</el-button>
<el-button
type="danger"
@ -63,7 +62,7 @@
@click="handleBatchDelete"
v-hasPermi="['iot:device-attribute-type:delete']"
>
<Icon icon="ep:delete" class="mr-5px" /> 批量删除
<Icon icon="ep:delete" class="mr-5px" /> {{ t('DataCollection.DeviceAttributeType.batchDelete') }}
</el-button>
<el-button
type="success"
@ -72,7 +71,7 @@
:loading="exportLoading"
v-hasPermi="['iot:device-attribute-type:export']"
>
<Icon icon="ep:download" class="mr-5px" /> 导出
<Icon icon="ep:download" class="mr-5px" /> {{ t('DataCollection.DeviceAttributeType.export') }}
</el-button>
</el-form-item>
</el-form>
@ -90,18 +89,18 @@
@selection-change="handleSelectionChange"
>
<el-table-column type="selection" width="55" reserve-selection />
<el-table-column label="分类编码" align="center" prop="code" />
<el-table-column label="分类名称" align="center" prop="name" />
<el-table-column label="分类顺序" align="center" prop="sort" />
<el-table-column label="备注" align="center" prop="remark" />
<el-table-column :label="t('DataCollection.DeviceAttributeType.code')" align="center" prop="code" />
<el-table-column :label="t('DataCollection.DeviceAttributeType.name')" align="center" prop="name" />
<el-table-column :label="t('DataCollection.DeviceAttributeType.sort')" align="center" prop="sort" />
<el-table-column :label="t('DataCollection.DeviceAttributeType.remark')" align="center" prop="remark" />
<el-table-column
label="创建时间"
:label="t('DataCollection.DeviceAttributeType.createTime')"
align="center"
prop="createTime"
:formatter="dateFormatter"
width="180px"
/>
<el-table-column label="操作" align="center" width="150px" fixed="right">
<el-table-column :label="t('DataCollection.DeviceAttributeType.operate')" align="center" width="150px" fixed="right">
<template #default="scope">
<el-button
link
@ -109,7 +108,7 @@
@click="openForm('update', scope.row.id)"
v-hasPermi="['iot:device-attribute-type:update']"
>
编辑
{{ t('action.edit') }}
</el-button>
<el-button
link
@ -117,7 +116,7 @@
@click="handleDelete(scope.row.id)"
v-hasPermi="['iot:device-attribute-type:delete']"
>
删除
{{ t('action.del') }}
</el-button>
</template>
</el-table-column>
@ -235,7 +234,7 @@ const handleExport = async () => {
ids: selectedIds.value.length ? selectedIds.value.join(',') : undefined,
}
const data = await DeviceAttributeTypeApi.exportDeviceAttributeType(params)
download.excel(data, '采集点分类.xls')
download.excel(data, t('DataCollection.DeviceAttributeType.exportFilename'))
} catch {
} finally {
exportLoading.value = false

@ -4,17 +4,24 @@
ref="formRef"
:model="formData"
:rules="formRules"
label-width="100px"
label-width="120px"
v-loading="formLoading"
>
<el-form-item label="模型编码" prop="code">
<el-input v-model="formData.code" placeholder="请输入模型编码" :disabled = "formType === 'update'"/>
<el-form-item :label="t('DataCollection.DeviceModel.code')" prop="code">
<el-input
v-model="formData.code"
:placeholder="t('DataCollection.DeviceModel.placeholderCode')"
:disabled = "formType === 'update'"/>
</el-form-item>
<el-form-item label="模型名称" prop="name">
<el-input v-model="formData.name" placeholder="请输入模型名称" />
<el-form-item :label="t('DataCollection.DeviceModel.name')" prop="name">
<el-input
v-model="formData.name"
:placeholder="t('DataCollection.DeviceModel.placeholderName')" />
</el-form-item>
<el-form-item label="通讯协议" prop="protocol">
<el-select v-model="formData.protocol" placeholder="请选择通讯协议">
<el-form-item :label="t('DataCollection.DeviceModel.protocol')" prop="protocol">
<el-select
v-model="formData.protocol"
:placeholder="t('DataCollection.DeviceModel.placeholderProtocol')">
<el-option
v-for="dict in getStrDictOptions(DICT_TYPE.IOT_PROTOCOL)"
:key="dict.value"
@ -23,13 +30,15 @@
/>
</el-select>
</el-form-item>
<el-form-item label="备注" prop="remark">
<el-input v-model="formData.remark" placeholder="请输入备注" />
<el-form-item :label="t('DataCollection.DeviceModel.remark')" prop="remark">
<el-input
v-model="formData.remark"
:placeholder="t('DataCollection.DeviceModel.placeholderRemark')" />
</el-form-item>
</el-form>
<template #footer>
<el-button @click="submitForm" type="primary" :disabled="formLoading"> </el-button>
<el-button @click="dialogVisible = false"> </el-button>
<el-button @click="submitForm" type="primary" :disabled="formLoading">{{ t('DataCollection.DeviceModel.dialogOk') }}</el-button>
<el-button @click="dialogVisible = false">{{ t('DataCollection.DeviceModel.dialogCancel') }}</el-button>
</template>
</Dialog>
</template>
@ -55,9 +64,9 @@ const formData = ref({
remark: undefined,
})
const formRules = reactive({
code: [{ required: true, message: '分类编码不能为空', trigger: 'blur' }],
name: [{ required: true, message: '分类名称不能为空', trigger: 'blur' }],
protocol: [{ required: true, message: '通讯协议不能为空', trigger: 'blur' }],
code: [{ required: true, message: t('DataCollection.DeviceModel.validatorCodeRequired'), trigger: 'blur' }],
name: [{ required: true, message: t('DataCollection.DeviceModel.validatorNameRequired'), trigger: 'blur' }],
protocol: [{ required: true, message: t('DataCollection.DeviceModel.validatorProtocolRequired'), trigger: 'blur' }],
})
const formRef = ref() // Ref
@ -114,4 +123,4 @@ const resetForm = () => {
}
formRef.value?.resetFields()
}
</script>
</script>

@ -4,29 +4,36 @@
ref="formRef"
:model="formData"
:rules="formRules"
label-width="100px"
label-width="120px"
v-loading="formLoading"
>
<el-form-item label="点位编码" prop="attributeCode">
<el-input v-model="formData.attributeCode" placeholder="请输入点位编码" :disabled = "formType === 'update'"/>
<el-form-item :label="t('DataCollection.DeviceModel.attributeCode')" prop="attributeCode">
<el-input
v-model="formData.attributeCode"
:placeholder="t('DataCollection.DeviceModel.placeholderAttributeCode')"
:disabled = "formType === 'update'"/>
</el-form-item>
<el-form-item label="点位名称" prop="attributeName">
<el-input v-model="formData.attributeName" placeholder="请输入点位名称" />
<el-form-item :label="t('DataCollection.DeviceModel.attributeName')" prop="attributeName">
<el-input
v-model="formData.attributeName"
:placeholder="t('DataCollection.DeviceModel.placeholderAttributeName')" />
</el-form-item>
<el-form-item label="点位类型" prop="attributeType">
<el-form-item :label="t('DataCollection.DeviceModel.attributeType')" prop="attributeType">
<el-select
v-model="formData.attributeType"
clearable
filterable
placeholder="请选择点位类型"
:placeholder="t('DataCollection.DeviceModel.placeholderAttributeType')"
class="!w-180px"
@change="handleAttributeTypeChange"
>
<el-option v-for="item in typeList" :key="item.id" :label="item.name" :value="item.id" />
</el-select>
</el-form-item>
<el-form-item label="数据类型" prop="dataType">
<el-select v-model="formData.dataType" placeholder="请选择数据类型">
<el-form-item :label="t('DataCollection.DeviceModel.dataType')" prop="dataType">
<el-select
v-model="formData.dataType"
:placeholder="t('DataCollection.DeviceModel.placeholderDataType')">
<el-option
v-for="dict in getStrDictOptions(DICT_TYPE.IOT_DEVICE_DATA_TYPE)"
:key="dict.value"
@ -35,12 +42,16 @@
/>
</el-select>
</el-form-item>
<el-form-item label="寄存器地址" prop="address">
<el-input v-model="formData.address" placeholder="请输入寄存器地址" />
<el-form-item :label="t('DataCollection.DeviceModel.address')" prop="address">
<el-input
v-model="formData.address"
:placeholder="t('DataCollection.DeviceModel.placeholderAddress')" />
</el-form-item>
<el-form-item label="单位" prop="dataUnit">
<el-select v-model="formData.dataUnit" placeholder="请选择单位">
<el-form-item :label="t('DataCollection.DeviceModel.dataUnit')" prop="dataUnit">
<el-select
v-model="formData.dataUnit"
:placeholder="t('DataCollection.DeviceModel.placeholderDataUnit')">
<el-option
v-for="dict in getStrDictOptions(DICT_TYPE.IOT_DEVICE_ATTRIBUTE_UNIT)"
:key="dict.value"
@ -49,16 +60,20 @@
/>
</el-select>
</el-form-item>
<el-form-item label="倍率" prop="ratio">
<el-input v-model="formData.ratio" placeholder="请输入倍率" />
<el-form-item :label="t('DataCollection.DeviceModel.ratio')" prop="ratio">
<el-input
v-model="formData.ratio"
:placeholder="t('DataCollection.DeviceModel.placeholderRatio')" />
</el-form-item>
<el-form-item label="备注" prop="remark">
<el-input v-model="formData.remark" placeholder="请输入备注" />
<el-form-item :label="t('DataCollection.DeviceModel.remark')" prop="remark">
<el-input
v-model="formData.remark"
:placeholder="t('DataCollection.DeviceModel.placeholderAttributeRemark')" />
</el-form-item>
</el-form>
<template #footer>
<el-button @click="submitForm" type="primary" :disabled="formLoading"> </el-button>
<el-button @click="dialogVisible = false"> </el-button>
<el-button @click="submitForm" type="primary" :disabled="formLoading">{{ t('DataCollection.DeviceModel.dialogOk') }}</el-button>
<el-button @click="dialogVisible = false">{{ t('DataCollection.DeviceModel.dialogCancel') }}</el-button>
</template>
</Dialog>
</template>
@ -106,8 +121,8 @@ const formData = ref({
deviceModelId: undefined,
})
const formRules = reactive({
attributeCode: [{ required: true, message: '点位编码不能为空', trigger: 'blur' }],
attributeName: [{ required: true, message: '点位名称不能为空', trigger: 'blur' }],
attributeCode: [{ required: true, message: t('DataCollection.DeviceModel.validatorAttributeCodeRequired'), trigger: 'blur' }],
attributeName: [{ required: true, message: t('DataCollection.DeviceModel.validatorAttributeNameRequired'), trigger: 'blur' }],
})
const formRef = ref() // Ref

@ -1,19 +1,23 @@
<template>
<ContentWrap>
<!-- 搜索工作栏 -->
<el-form class="-mb-15px" :model="queryParams" ref="queryFormRef" :inline="true" label-width="100px">
<el-form-item label="点位编码" prop="attributeCode">
<el-form class="-mb-15px" :model="queryParams" ref="queryFormRef" :inline="true" label-width="120px">
<el-form-item :label="t('DataCollection.DeviceModel.attributeCode')" prop="attributeCode">
<el-input
v-model="queryParams.attributeCode" placeholder="请输入点位编码" clearable @keyup.enter="handleQuery"
v-model="queryParams.attributeCode"
:placeholder="t('DataCollection.DeviceModel.placeholderAttributeCode')" clearable @keyup.enter="handleQuery"
class="!w-240px" />
</el-form-item>
<el-form-item label="点位名称" prop="attributeName">
<el-form-item :label="t('DataCollection.DeviceModel.attributeName')" prop="attributeName">
<el-input
v-model="queryParams.attributeName" placeholder="请输入点位名称" clearable @keyup.enter="handleQuery"
v-model="queryParams.attributeName"
:placeholder="t('DataCollection.DeviceModel.placeholderAttributeName')" clearable @keyup.enter="handleQuery"
class="!w-240px" />
</el-form-item>
<el-form-item label="点位类型" prop="attributeType">
<el-select v-model="queryParams.attributeType" clearable filterable placeholder="请选择" class="!w-240px">
<el-form-item :label="t('DataCollection.DeviceModel.attributeType')" prop="attributeType">
<el-select
v-model="queryParams.attributeType" clearable filterable
:placeholder="t('DataCollection.DeviceModel.placeholderAttributeType')" class="!w-240px">
<el-option v-for="item in typeList" :key="item.id" :label="item.name" :value="item.id" />
</el-select>
</el-form-item>
@ -39,21 +43,24 @@ v-model="queryParams.attributeName" placeholder="请输入点位名称" clearabl
</el-form-item> -->
<el-form-item>
<el-button @click="handleQuery">
<Icon icon="ep:search" class="mr-5px" /> 搜索
<Icon icon="ep:search" class="mr-5px" /> {{ t('DataCollection.DeviceModel.search') }}
</el-button>
<el-button @click="resetQuery">
<Icon icon="ep:refresh" class="mr-5px" /> 重置
<Icon icon="ep:refresh" class="mr-5px" /> {{ t('DataCollection.DeviceModel.reset') }}
</el-button>
<el-button type="primary" plain @click="openForm('create')" v-hasPermi="['iot:device-model:create']">
<Icon icon="ep:plus" class="mr-5px" /> 新增
<Icon icon="ep:plus" class="mr-5px" /> {{ t('DataCollection.DeviceModel.create') }}
</el-button>
<el-button type="warning" plain @click="openImport" v-hasPermi="['iot:device-model:import']">
<Icon icon="ep:upload" class="mr-5px" /> {{ t('action.import') }}
</el-button>
<el-button
type="success" plain @click="handleExport" :loading="exportLoading"
v-hasPermi="['iot:device-model:export']">
<Icon icon="ep:download" class="mr-5px" /> 导出
<Icon icon="ep:download" class="mr-5px" /> {{ t('DataCollection.DeviceModel.export') }}
</el-button>
<el-button type="danger" plain @click="handleBatchDelete" v-hasPermi="['iot:device-model:delete']">
<Icon icon="ep:delete" class="mr-5px" /> 批量删除
<Icon icon="ep:delete" class="mr-5px" /> {{ t('DataCollection.DeviceModel.batchDelete') }}
</el-button>
</el-form-item>
@ -67,25 +74,27 @@ ref="tableRef" v-loading="loading" :data="list" :stripe="true" :show-overflow-to
@selection-change="handleSelectionChange">
<el-table-column type="selection" width="55" reserve-selection />
<!-- <el-table-column label="ID" align="center" prop="id" /> -->
<el-table-column label="点位编码" align="center" prop="attributeCode" />
<el-table-column label="点位名称" align="center" prop="attributeName" />
<el-table-column label="点位类型" align="center" prop="typeName" />
<el-table-column label="数据类型" align="center" prop="dataType" />
<el-table-column label="寄存器地址" align="center" prop="address" />
<el-table-column label="单位" align="center" prop="dataUnit" />
<el-table-column label="倍率" align="center" prop="ratio" />
<el-table-column label="备注" align="center" prop="remark" />
<el-table-column :label="t('DataCollection.DeviceModel.attributeCode')" align="center" prop="attributeCode" />
<el-table-column :label="t('DataCollection.DeviceModel.attributeName')" align="center" prop="attributeName" />
<el-table-column :label="t('DataCollection.DeviceModel.attributeType')" align="center" prop="typeName" />
<el-table-column :label="t('DataCollection.DeviceModel.dataType')" align="center" prop="dataType" />
<el-table-column :label="t('DataCollection.DeviceModel.address')" align="center" prop="address" />
<el-table-column :label="t('DataCollection.DeviceModel.dataUnit')" align="center" prop="dataUnit" />
<el-table-column :label="t('DataCollection.DeviceModel.ratio')" align="center" prop="ratio" />
<el-table-column :label="t('DataCollection.DeviceModel.remark')" align="center" prop="remark" />
<!-- <el-table-column label="采集设备模型id" align="center" prop="deviceModelId" /> -->
<el-table-column label="创建时间" align="center" prop="createTime" :formatter="dateFormatter" width="180px" />
<el-table-column label="操作" align="center" width="150px" fixed="right">
<el-table-column
:label="t('DataCollection.DeviceModel.createTime')" align="center" prop="createTime"
:formatter="dateFormatter" width="180px" />
<el-table-column :label="t('DataCollection.DeviceModel.operate')" align="center" width="150px" fixed="right">
<template #default="scope">
<el-button
link type="primary" @click="openForm('update', scope.row.id)"
v-hasPermi="['iot:device-model:update']">
编辑
{{ t('action.edit') }}
</el-button>
<el-button link type="danger" @click="handleDelete(scope.row.id)" v-hasPermi="['iot:device-model:delete']">
删除
{{ t('action.del') }}
</el-button>
</template>
</el-table-column>
@ -98,6 +107,37 @@ link type="primary" @click="openForm('update', scope.row.id)"
<!-- 表单弹窗添加/修改 -->
<DeviceModelAttributeForm ref="formRef" @success="getList" />
<!-- 导入弹窗 -->
<Dialog v-model="importDialogVisible" :title="t('action.import')" width="400">
<el-upload
ref="uploadRef" v-model:file-list="importFileList" :action="importUrl + '?updateSupport=' + updateSupport" :auto-upload="false"
:disabled="importLoading" :headers="uploadHeaders" :limit="1" :on-error="handleImportError"
:on-exceed="handleImportExceed" :on-success="handleImportSuccess" accept=".xlsx, .xls" drag>
<Icon icon="ep:upload" />
<div class="el-upload__text">
将文件拖到此处或点击上传
</div>
<template #tip>
<div class="el-upload__tip text-center">
<div class="el-upload__tip">
<el-checkbox v-model="updateSupport" />
是否更新已存在的数据
</div>
<span>仅支持 .xlsx, .xls 格式</span>
<el-link
:underline="false" style="font-size: 12px; vertical-align: baseline" type="primary"
@click="importTemplate">
下载导入模板
</el-link>
</div>
</template>
</el-upload>
<template #footer>
<el-button :disabled="importLoading" type="primary" @click="submitImport">{{ t('common.ok') }}</el-button>
<el-button @click="importDialogVisible = false">{{ t('common.cancel') }}</el-button>
</template>
</Dialog>
</template>
<script setup lang="ts">
@ -106,6 +146,7 @@ import download from '@/utils/download'
import { DeviceModelAttributeApi, DeviceModelAttributeVO } from '@/api/iot/devicemodelattribute'
import DeviceModelAttributeForm from './DeviceModelAttributeForm.vue'
import { DeviceAttributeTypeApi, DeviceAttributeTypeVO } from '@/api/iot/deviceattributetype'
import { getAccessToken, getTenantId } from '@/utils/auth'
const props = defineProps<{
id?: number // id
@ -139,6 +180,15 @@ const queryParams = reactive({
const queryFormRef = ref() //
const exportLoading = ref(false) //
const importDialogVisible = ref(false)
const importLoading = ref(false)
const uploadRef = ref()
const importUrl =
import.meta.env.VITE_BASE_URL + import.meta.env.VITE_API_URL + '/iot/device-model-attribute/import'
const uploadHeaders = ref()
const importFileList = ref([])
const updateSupport = ref(0)
const selectedIds = ref<number[]>([])
const handleSelectionChange = (rows: any[]) => {
selectedIds.value = rows?.map((row) => row.id).filter((id) => id !== undefined) ?? []
@ -197,6 +247,17 @@ const openForm = (type: string, id?: number) => {
formRef.value.open(type, id, props.id)
}
const openImport = () => {
if (!props.id) {
message.error('请选择一个采集设备模型')
return
}
importDialogVisible.value = true
importLoading.value = false
importFileList.value = []
updateSupport.value = 0
}
/** 删除按钮操作 */
const buildIdsParam = (ids: number | number[]) => {
@ -244,6 +305,45 @@ const handleExport = async () => {
}
}
const submitImport = async () => {
if (importFileList.value.length === 0) {
message.error('请选择导入文件')
return
}
uploadHeaders.value = {
Authorization: 'Bearer ' + getAccessToken(),
tenantId: getTenantId(),
}
importLoading.value = true
uploadRef.value?.submit()
}
const handleImportSuccess = (response: any) => {
if (!response || response.code !== 0) {
message.error(response?.msg || '导入失败')
importLoading.value = false
return
}
message.success('导入成功')
importLoading.value = false
importDialogVisible.value = false
getList()
}
const handleImportError = () => {
message.error('导入失败')
importLoading.value = false
}
const handleImportExceed = () => {
message.error('只能上传一个文件')
}
const importTemplate = async () => {
const res = await DeviceModelAttributeApi.importDeviceModelAttributeTemplate()
download.excel(res, '采集设备模型-点位导入模板.xls')
}
/** 初始化 **/
onMounted(async () => {
typeList.value = await DeviceAttributeTypeApi.getDeviceAttributeTypeList()

@ -1,20 +1,30 @@
<template>
<ContentWrap>
<!-- 搜索工作栏 -->
<el-form class="-mb-15px" :model="queryParams" ref="queryFormRef" :inline="true" label-width="68px">
<el-form-item label="模型编码" prop="code">
<el-form class="-mb-15px" :model="queryParams" ref="queryFormRef" :inline="true" label-width="120px">
<el-form-item :label="t('DataCollection.DeviceModel.code')" prop="code">
<el-input
v-model="queryParams.code" placeholder="请输入模型编码" clearable @keyup.enter="handleQuery"
v-model="queryParams.code"
:placeholder="t('DataCollection.DeviceModel.placeholderCode')"
clearable
@keyup.enter="handleQuery"
class="!w-240px" />
</el-form-item>
<el-form-item label="模型名称" prop="name">
<el-form-item :label="t('DataCollection.DeviceModel.name')" prop="name">
<el-input
v-model="queryParams.name" placeholder="请输入模型名称" clearable @keyup.enter="handleQuery"
v-model="queryParams.name"
:placeholder="t('DataCollection.DeviceModel.placeholderName')"
clearable
@keyup.enter="handleQuery"
class="!w-240px" />
</el-form-item>
<el-form-item label="通讯协议" prop="protocol">
<el-select v-model="queryParams.protocol" placeholder="请选择通讯协议" clearable class="!w-240px">
<el-form-item :label="t('DataCollection.DeviceModel.protocol')" prop="protocol">
<el-select
v-model="queryParams.protocol"
:placeholder="t('DataCollection.DeviceModel.placeholderProtocol')"
clearable
class="!w-240px">
<el-option
v-for="dict in getStrDictOptions(DICT_TYPE.IOT_PROTOCOL)" :key="dict.value" :label="dict.label"
:value="dict.value" />
@ -43,21 +53,21 @@ v-for="dict in getStrDictOptions(DICT_TYPE.IOT_PROTOCOL)" :key="dict.value" :lab
</el-form-item> -->
<el-form-item>
<el-button @click="handleQuery">
<Icon icon="ep:search" class="mr-5px" /> 搜索
<Icon icon="ep:search" class="mr-5px" /> {{ t('DataCollection.DeviceModel.search') }}
</el-button>
<el-button @click="resetQuery">
<Icon icon="ep:refresh" class="mr-5px" /> 重置
<Icon icon="ep:refresh" class="mr-5px" /> {{ t('DataCollection.DeviceModel.reset') }}
</el-button>
<el-button type="primary" plain @click="openForm('create')" v-hasPermi="['iot:device-model:create']">
<Icon icon="ep:plus" class="mr-5px" /> 新增
<Icon icon="ep:plus" class="mr-5px" /> {{ t('DataCollection.DeviceModel.create') }}
</el-button>
<el-button type="danger" plain @click="handleBatchDelete" v-hasPermi="['iot:device-model:delete']">
<Icon icon="ep:delete" class="mr-5px" /> 批量删除
<Icon icon="ep:delete" class="mr-5px" /> {{ t('DataCollection.DeviceModel.batchDelete') }}
</el-button>
<el-button
type="success" plain @click="handleExport" :loading="exportLoading"
v-hasPermi="['iot:device-model:export']">
<Icon icon="ep:download" class="mr-5px" /> 导出
<Icon icon="ep:download" class="mr-5px" /> {{ t('DataCollection.DeviceModel.export') }}
</el-button>
</el-form-item>
</el-form>
@ -66,74 +76,74 @@ type="success" plain @click="handleExport" :loading="exportLoading"
<!-- 列表 -->
<ContentWrap>
<el-table
ref="tableRef" v-loading="loading" :data="list" :stripe="true" :show-overflow-tooltip="true"
ref="tableRef" v-loading="loading" :data="list" :stripe="true" :show-overflow-tooltip="true"
highlight-current-row row-key="id" @selection-change="handleSelectionChange">
<el-table-column type="selection" width="55" reserve-selection />
<el-table-column label="模型编码" align="center" prop="code" />
<el-table-column label="模型名称" align="center" prop="name" />
<el-table-column align="center" label="通讯协议" prop="protocol" min-width="150">
<el-table-column :label="t('DataCollection.DeviceModel.code')" align="center" prop="code" />
<el-table-column :label="t('DataCollection.DeviceModel.name')" align="center" prop="name" />
<el-table-column align="center" :label="t('DataCollection.DeviceModel.protocol')" prop="protocol" min-width="150">
<template #default="scope">
<dict-tag :type="DICT_TYPE.IOT_PROTOCOL" :value="scope.row.protocol" />
</template>
</el-table-column>
<el-table-column label="备注" align="center" prop="remark" />
<el-table-column :label="t('DataCollection.DeviceModel.remark')" align="center" prop="remark" />
<!-- <el-table-column label="创建时间" align="center" prop="createTime" :formatter="dateFormatter" width="180px" /> -->
<el-table-column label="操作" align="center" min-width="120px">
<el-table-column :label="t('DataCollection.DeviceModel.operate')" align="center" min-width="120px">
<template #default="scope">
<el-button link type="primary" @click.stop="handleShowAttribute(scope.row)">点位</el-button>
<el-button link type="primary" @click.stop="handleShowAttribute(scope.row)">{{ t('DataCollection.DeviceModel.attributeModuleName') }}</el-button>
<el-button link type="primary" @click="handleCopy(scope.row.id)" v-hasPermi="['iot:device-model:create']">
复制
{{ t('action.copy') }}
</el-button>
<el-button
link type="primary" @click="openForm('update', scope.row.id)"
v-hasPermi="['iot:device-model:update']">
编辑
{{ t('action.edit') }}
</el-button>
<el-button link type="danger" @click="handleDelete(scope.row.id)" v-hasPermi="['iot:device-model:delete']">
删除
{{ t('action.del') }}
</el-button>
</template>
</el-table-column>
</el-table>
<!-- 分页 -->
<Pagination
:total="total" v-model:page="queryParams.pageNo" v-model:limit="queryParams.pageSize"
:total="total" v-model:page="queryParams.pageNo" v-model:limit="queryParams.pageSize"
@pagination="getList" />
</ContentWrap>
<ContentWrap>
<template v-if="attributeModelId">
<div class="mb-10px text-sm text-gray-500">
当前模型<span class="font-medium text-gray-700">{{ attributeModelName || '-' }}</span>
{{ t('DataCollection.DeviceModel.moduleName') }}<span class="font-medium text-gray-700">{{ attributeModelName || '-' }}</span>
</div>
<el-tabs model-value="modelAttribute">
<el-tab-pane :label="modelAttributeTabLabel" name="modelAttribute">
<el-tab-pane :label="t('DataCollection.DeviceModel.attributeModuleName')" name="modelAttribute">
<ModelAttributeList :id="attributeModelId" />
</el-tab-pane>
<el-tab-pane :label="modelRuleTabLabel" name="modelRule">
<el-form class="-mb-15px" :model="ruleQueryParams" ref="ruleQueryFormRef" :inline="true" label-width="80px">
<el-form-item label="标识符" prop="identifier">
<el-tab-pane :label="t('DataCollection.DeviceModel.ruleTabLabel')" name="modelRule">
<el-form class="-mb-15px" :model="ruleQueryParams" ref="ruleQueryFormRef" :inline="true" label-width="120px">
<el-form-item :label="t('DataCollection.DeviceModel.ruleIdentifier')" prop="identifier">
<el-input
v-model="ruleQueryParams.identifier"
placeholder="请输入标识符"
:placeholder="t('DataCollection.DeviceModel.ruleSearchIdentifierPlaceholder')"
clearable
@keyup.enter="handleRuleQuery"
class="!w-200px"
/>
</el-form-item>
<el-form-item label="名称" prop="fieldName">
<el-form-item :label="t('DataCollection.DeviceModel.ruleFieldName')" prop="fieldName">
<el-input
v-model="ruleQueryParams.fieldName"
placeholder="请输入名称"
:placeholder="t('DataCollection.DeviceModel.ruleSearchFieldNamePlaceholder')"
clearable
@keyup.enter="handleRuleQuery"
class="!w-200px"
/>
</el-form-item>
<el-form-item label="默认值" prop="defaultValue">
<el-form-item :label="t('DataCollection.DeviceModel.ruleDefaultValue')" prop="defaultValue">
<el-input
v-model="ruleQueryParams.defaultValue"
placeholder="请输入默认值"
:placeholder="t('DataCollection.DeviceModel.ruleSearchDefaultValuePlaceholder')"
clearable
@keyup.enter="handleRuleQuery"
class="!w-200px"
@ -141,17 +151,17 @@ link type="primary" @click="openForm('update', scope.row.id)"
</el-form-item>
<el-form-item>
<el-button @click="handleRuleQuery">
<Icon icon="ep:search" class="mr-5px" /> 搜索
<Icon icon="ep:search" class="mr-5px" /> {{ t('DataCollection.DeviceModel.ruleSearch') }}
</el-button>
<el-button @click="resetRuleQuery">
<Icon icon="ep:refresh" class="mr-5px" /> 重置
<Icon icon="ep:refresh" class="mr-5px" /> {{ t('DataCollection.DeviceModel.ruleReset') }}
</el-button>
</el-form-item>
</el-form>
<div class="mb-10px text-right">
<el-button type="primary" @click="openCreateRuleForm">
新增告警规则
{{ t('DataCollection.DeviceModel.ruleCreateButton') }}
</el-button>
</div>
@ -162,15 +172,15 @@ link type="primary" @click="openForm('update', scope.row.id)"
:show-overflow-tooltip="true"
row-key="id"
>
<el-table-column label="标识符" align="center" prop="identifier" />
<el-table-column label="名称" align="center" prop="fieldName" />
<el-table-column label="规则" align="center" prop="fieldRule" />
<el-table-column label="默认值" align="center" prop="defaultValue" />
<el-table-column label="创建时间" align="center" prop="createTime" :formatter="dateFormatter" width="180px" />
<el-table-column label="操作" align="center" width="160px">
<el-table-column :label="t('DataCollection.DeviceModel.ruleIdentifier')" align="center" prop="identifier" />
<el-table-column :label="t('DataCollection.DeviceModel.ruleFieldName')" align="center" prop="fieldName" />
<el-table-column :label="t('DataCollection.DeviceModel.ruleFieldRule')" align="center" prop="fieldRule" />
<el-table-column :label="t('DataCollection.DeviceModel.ruleDefaultValue')" align="center" prop="defaultValue" />
<el-table-column :label="t('DataCollection.DeviceModel.ruleCreateTime')" align="center" prop="createTime" :formatter="dateFormatter" width="180px" />
<el-table-column :label="t('DataCollection.DeviceModel.ruleOperate')" align="center" width="160px">
<template #default="scope">
<el-button link type="primary" @click="openRuleForm(scope.row)">
编辑
{{ t('DataCollection.DeviceModel.ruleEditRuleButton') }}
</el-button>
<el-button
v-if="(scope.row.identifier || '').toString().toUpperCase() === 'ALARM'"
@ -178,7 +188,7 @@ link type="primary" @click="openForm('update', scope.row.id)"
type="danger"
@click="handleRuleDelete(scope.row.id)"
>
删除
{{ t('DataCollection.DeviceModel.ruleDeleteRuleButton') }}
</el-button>
</template>
</el-table-column>
@ -189,23 +199,25 @@ link type="primary" @click="openForm('update', scope.row.id)"
v-model:limit="ruleQueryParams.pageSize"
@pagination="getRuleList"
/>
<el-dialog v-model="ruleDialogVisible" title="编辑点位规则" width="880px" draggable>
<el-form :model="ruleForm" ref="ruleFormRef" label-width="90px">
<el-form-item label="标识符">
<el-dialog v-model="ruleDialogVisible" :title="t('DataCollection.DeviceModel.ruleDialogTitle')" width="880px" draggable>
<el-form :model="ruleForm" ref="ruleFormRef" label-width="120px">
<el-form-item :label="t('DataCollection.DeviceModel.ruleDialogIdentifier')">
<el-input v-model="ruleForm.identifier" disabled />
</el-form-item>
<el-form-item label="名称">
<el-form-item :label="t('DataCollection.DeviceModel.ruleDialogFieldName')">
<el-input v-model="ruleForm.fieldName" disabled />
</el-form-item>
<el-form-item label="默认值">
<el-form-item :label="t('DataCollection.DeviceModel.ruleDialogDefaultValue')">
<el-input v-model="ruleForm.defaultValue" disabled />
</el-form-item>
<el-form-item
v-if="(ruleForm.identifier || '').toString().toUpperCase() === 'ALARM'"
label="告警登记"
:label="t('DataCollection.DeviceModel.ruleDialogAlarmLevel')"
>
<el-select v-model="ruleForm.alarmLevel" placeholder="请选择告警登记">
<el-select
v-model="ruleForm.alarmLevel"
:placeholder="t('DataCollection.DeviceModel.ruleDialogAlarmLevelPlaceholder')"
>
<el-option
v-for="dict in getStrDictOptions(DICT_TYPE.IOT_ALARM_REGISTRATION)"
:key="dict.value"
@ -217,10 +229,10 @@ link type="primary" @click="openForm('update', scope.row.id)"
<div class="flex flex-col w-full">
<div class="border border-gray-200 dark:border-gray-600 rounded-md py-12px">
<el-form-item label="点位规则">
<el-form-item :label="t('DataCollection.DeviceModel.ruleDialogFieldRule')">
<el-select
v-model="ruleForm.fieldRule"
placeholder="请选择点位规则"
:placeholder="t('DataCollection.DeviceModel.ruleDialogFieldRulePlaceholder')"
class="!w-240px"
:disabled="!currentRuleOptions.length"
>
@ -233,11 +245,11 @@ link type="primary" @click="openForm('update', scope.row.id)"
/>
</el-select>
</el-form-item>
<el-form-item label="规则">
<el-form-item :label="t('DataCollection.DeviceModel.ruleDialogRule')">
<div class="flex items-center gap-8px">
<el-select
v-model="ruleForm.ruleAttributeId"
placeholder="请选择点位"
:placeholder="t('DataCollection.DeviceModel.ruleDialogRuleAttributePlaceholder')"
class="!w-240px"
>
<el-option
@ -249,7 +261,7 @@ link type="primary" @click="openForm('update', scope.row.id)"
</el-select>
<el-select
v-model="ruleForm.ruleOperator"
placeholder="请选择条件"
:placeholder="t('DataCollection.DeviceModel.ruleDialogRuleOperatorPlaceholder')"
class="!w-160px"
>
<el-option
@ -262,7 +274,7 @@ link type="primary" @click="openForm('update', scope.row.id)"
<el-input
v-if="ruleForm.ruleOperator !== 'TRUE' && ruleForm.ruleOperator !== 'FALSE'"
v-model="ruleForm.ruleValue"
placeholder="请输入符号值"
:placeholder="t('DataCollection.DeviceModel.ruleDialogRuleValuePlaceholder')"
class="!w-200px"
/>
</div>
@ -274,10 +286,10 @@ link type="primary" @click="openForm('update', scope.row.id)"
:key="index"
class="border border-gray-200 dark:border-gray-600 rounded-md px-16px py-12px"
>
<el-form-item label="点位规则">
<el-form-item :label="t('DataCollection.DeviceModel.ruleDialogFieldRule')">
<el-select
v-model="item.rule"
placeholder="请选择点位规则"
:placeholder="t('DataCollection.DeviceModel.ruleDialogFieldRulePlaceholder')"
class="!w-240px"
>
<el-option
@ -289,11 +301,11 @@ link type="primary" @click="openForm('update', scope.row.id)"
/>
</el-select>
</el-form-item>
<el-form-item label="规则">
<el-form-item :label="t('DataCollection.DeviceModel.ruleDialogRule')">
<div class="flex items-center gap-8px">
<el-select
v-model="item.id"
placeholder="请选择点位"
:placeholder="t('DataCollection.DeviceModel.ruleDialogRuleAttributePlaceholder')"
class="!w-240px"
>
<el-option
@ -305,7 +317,7 @@ link type="primary" @click="openForm('update', scope.row.id)"
</el-select>
<el-select
v-model="item.operator"
placeholder="请选择条件"
:placeholder="t('DataCollection.DeviceModel.ruleDialogRuleOperatorPlaceholder')"
class="!w-160px"
>
<el-option
@ -318,11 +330,11 @@ link type="primary" @click="openForm('update', scope.row.id)"
<el-input
v-if="item.operator !== 'TRUE' && item.operator !== 'FALSE'"
v-model="item.operatorRule"
placeholder="请输入符号值"
:placeholder="t('DataCollection.DeviceModel.ruleDialogRuleValuePlaceholder')"
class="!w-200px"
/>
<el-button type="danger" link @click="handleRemovePointRule(index)">
删除
{{ t('DataCollection.DeviceModel.ruleDeleteRuleButton') }}
</el-button>
</div>
</el-form-item>
@ -330,36 +342,39 @@ link type="primary" @click="openForm('update', scope.row.id)"
<el-form-item v-if="isRunningIdentifier" label=" ">
<el-button type="primary" link @click="handleAddPointRule">
+ 添加规则
+ {{ t('DataCollection.DeviceModel.ruleCreateButton') }}
</el-button>
</el-form-item>
</div>
</el-form>
<template #footer>
<span class="dialog-footer">
<el-button @click="ruleDialogVisible = false"> </el-button>
<el-button type="primary" :loading="ruleFormLoading" @click="handleRuleSubmit"> </el-button>
<el-button @click="ruleDialogVisible = false">{{ t('DataCollection.DeviceModel.dialogCancel') }}</el-button>
<el-button type="primary" :loading="ruleFormLoading" @click="handleRuleSubmit">{{ t('DataCollection.DeviceModel.dialogOk') }}</el-button>
</span>
</template>
</el-dialog>
<el-dialog v-model="createRuleDialogVisible" title="新增告警规则" width="520px" draggable>
<el-form :model="createRuleForm" ref="createRuleFormRef" label-width="90px">
<el-form-item label="标识符">
<el-dialog v-model="createRuleDialogVisible" :title="t('DataCollection.DeviceModel.ruleCreateButton')" width="520px" draggable>
<el-form :model="createRuleForm" ref="createRuleFormRef" label-width="120px">
<el-form-item :label="t('DataCollection.DeviceModel.ruleDialogIdentifier')">
<el-input v-model="createRuleForm.identifier" disabled />
</el-form-item>
<el-form-item label="名称">
<el-input v-model="createRuleForm.fieldName" placeholder="请输入名称" />
<el-form-item :label="t('DataCollection.DeviceModel.ruleDialogFieldName')">
<el-input
v-model="createRuleForm.fieldName"
:placeholder="t('DataCollection.DeviceModel.ruleSearchFieldNamePlaceholder')"
/>
</el-form-item>
<el-form-item label="默认值">
<el-form-item :label="t('DataCollection.DeviceModel.ruleDialogDefaultValue')">
<el-input v-model="createRuleForm.defaultValue" disabled />
</el-form-item>
</el-form>
<template #footer>
<span class="dialog-footer">
<el-button @click="createRuleDialogVisible = false"> </el-button>
<el-button @click="createRuleDialogVisible = false">{{ t('DataCollection.DeviceModel.dialogCancel') }}</el-button>
<el-button type="primary" :loading="createRuleFormLoading" @click="handleCreateRuleSubmit">
{{ t('DataCollection.DeviceModel.dialogOk') }}
</el-button>
</span>
</template>
@ -367,7 +382,10 @@ link type="primary" @click="openForm('update', scope.row.id)"
</el-tab-pane>
</el-tabs>
</template>
<el-empty v-else description="请点击设备模型列表的“点位”查看采集点和点位规则" />
<el-empty
v-else
:description="t('DataCollection.DeviceModel.moduleName') + t('common.colon') + t('DataCollection.DeviceModel.attributeModuleName') + t('DataCollection.DeviceModel.ruleTabLabel')"
/>
</ContentWrap>
<!-- 表单弹窗添加/修改 -->
<DeviceModelForm ref="formRef" @success="getList" />

@ -1,23 +1,28 @@
<template>
<Dialog v-model="dialogVisible" :title="dialogTitle" width="900" :scroll="true" max-height="80vh" align-center>
<div class="single-device-dialog">
<el-form class="-mb-15px" :inline="true" label-width="80px">
<el-form-item label="采集时间">
<el-form class="-mb-15px history-single-device-form" :inline="true" label-width="auto">
<el-form-item :label="t('DataCollection.HistoryData.dialogCollectionTimeLabel')">
<el-date-picker
v-model="collectionTimeRange" value-format="YYYY-MM-DD HH:mm:ss" type="datetimerange"
start-placeholder="开始时间" end-placeholder="结束时间"
:default-time="[new Date('1 00:00:00'), new Date('1 23:59:59')]" class="!w-360px" />
v-model="collectionTimeRange"
value-format="YYYY-MM-DD HH:mm:ss"
type="datetimerange"
:start-placeholder="t('DataCollection.HistoryData.dialogCollectionTimeStartPlaceholder')"
:end-placeholder="t('DataCollection.HistoryData.dialogCollectionTimeEndPlaceholder')"
:default-time="[new Date('1 00:00:00'), new Date('1 23:59:59')]"
class="!w-360px"
/>
</el-form-item>
<el-form-item>
<el-button @click="handleQuery"></el-button>
<el-button @click="resetQuery"></el-button>
<el-button @click="handleQuery">{{ t('DataCollection.HistoryData.dialogSearchButtonText') }}</el-button>
<el-button @click="resetQuery">{{ t('DataCollection.HistoryData.dialogResetButtonText') }}</el-button>
</el-form-item>
</el-form>
<ContentWrap v-loading="loading">
<div v-if="recordGroups.length" class="single-device-dialog__record-list">
<div v-for="group in recordGroups" :key="group.key" class="single-device-dialog__record">
<div class="single-device-dialog__record-title">
采集时间{{ group.collectTime || '-' }}
{{ t('DataCollection.HistoryData.dialogRecordCollectionTimePrefix') }}{{ group.collectTime || '-' }}
</div>
<div v-if="group.sections.length" class="single-device-dialog__table-grid">
<div
@ -26,7 +31,10 @@ v-for="section in group.sections" :key="`${group.key}-${section.key}`"
<div class="single-device-dialog__section-title">
{{ section.title }}
</div>
<el-empty v-if="!section.columns.length" description="暂无数据" />
<el-empty
v-if="!section.columns.length"
:description="t('DataCollection.HistoryData.emptyDescription')"
/>
<el-table
v-else :data="section.rows" :border="true" :header-cell-style="headerCellStyle"
:cell-style="bodyCellStyle" size="small">
@ -40,10 +48,10 @@ v-for="col in section.columns" :key="col.prop" :prop="col.prop" :label="col.labe
</el-table>
</div>
</div>
<el-empty v-else description="暂无数据" />
<el-empty v-else :description="t('DataCollection.HistoryData.emptyDescription')" />
</div>
</div>
<el-empty v-else description="暂无数据" />
<el-empty v-else :description="t('DataCollection.HistoryData.emptyDescription')" />
</ContentWrap>
</div>
</Dialog>
@ -72,6 +80,8 @@ type RecordGroup = {
sections: Section[]
}
const { t } = useI18n()
const props = defineProps<{
modelValue: boolean
deviceId?: string | number
@ -93,7 +103,7 @@ const dialogVisible = computed({
const dialogTitle = computed(() => {
const name = props.deviceName ? props.deviceName : '-'
return `历史记录:${name}`
return `${t('DataCollection.HistoryData.dialogTitlePrefix')}${name}`
})
@ -165,7 +175,8 @@ const buildSectionsFromGroups = (groups: Record<string, any[]>): Section[] => {
if (Array.isArray(list) && list.length) {
list.forEach((item: any, index: number) => {
const prop = `col${index}`
const label = item?.attributeName ?? `字段${index + 1}`
const label =
item?.attributeName ?? `${t('DataCollection.HistoryData.defaultFieldLabelPrefix')}${index + 1}`
columns.push({ prop, label })
row[prop] = item?.addressValue ?? ''
})

@ -1,43 +1,43 @@
<template>
<ContentWrap>
<el-form
class="-mb-15px"
class="-mb-15px history-data-form"
:model="queryParams"
ref="queryFormRef"
:inline="true"
label-width="80px"
label-width="auto"
>
<el-form-item label="产线编码" prop="lineNode">
<el-form-item :label="t('DataCollection.HistoryData.searchLineCodeLabel')" prop="lineNode">
<el-input
v-model="queryParams.lineNode"
placeholder="请输入产线编码"
:placeholder="t('DataCollection.HistoryData.searchLineCodePlaceholder')"
clearable
@keyup.enter="handleQuery"
class="!w-240px"
/>
</el-form-item>
<el-form-item label="产线名称" prop="lineName">
<el-form-item :label="t('DataCollection.HistoryData.searchLineNameLabel')" prop="lineName">
<el-input
v-model="queryParams.lineName"
placeholder="请输入产线名称"
:placeholder="t('DataCollection.HistoryData.searchLineNamePlaceholder')"
clearable
@keyup.enter="handleQuery"
class="!w-240px"
/>
</el-form-item>
<el-form-item label="设备编码" prop="deviceCode">
<el-form-item :label="t('DataCollection.HistoryData.searchDeviceCodeLabel')" prop="deviceCode">
<el-input
v-model="queryParams.deviceCode"
placeholder="请输入设备编码"
:placeholder="t('DataCollection.HistoryData.searchDeviceCodePlaceholder')"
clearable
@keyup.enter="handleQuery"
class="!w-240px"
/>
</el-form-item>
<el-form-item label="设备名称" prop="deviceName">
<el-form-item :label="t('DataCollection.HistoryData.searchDeviceNameLabel')" prop="deviceName">
<el-input
v-model="queryParams.deviceName"
placeholder="请输入设备名称"
:placeholder="t('DataCollection.HistoryData.searchDeviceNamePlaceholder')"
clearable
@keyup.enter="handleQuery"
class="!w-240px"
@ -45,13 +45,16 @@
</el-form-item>
<el-form-item>
<el-button @click="handleQuery">
<Icon icon="ep:search" class="mr-5px" /> 搜索
<Icon icon="ep:search" class="mr-5px" />
{{ t('DataCollection.HistoryData.searchButtonText') }}
</el-button>
<el-button @click="resetQuery">
<Icon icon="ep:refresh" class="mr-5px" /> 重置
<Icon icon="ep:refresh" class="mr-5px" />
{{ t('DataCollection.HistoryData.resetButtonText') }}
</el-button>
<el-button type="success" plain @click="handleExport" :loading="exportLoading">
<Icon icon="ep:download" class="mr-5px" /> 导出
<Icon icon="ep:download" class="mr-5px" />
{{ t('DataCollection.HistoryData.exportButtonText') }}
</el-button>
</el-form-item>
</el-form>
@ -67,21 +70,46 @@
@selection-change="handleSelectionChange"
>
<el-table-column type="selection" width="55" reserve-selection />
<el-table-column label="产线编码" align="left" prop="lineNode" min-width="140px" />
<el-table-column label="产线名称" align="left" prop="lineName" min-width="160px" />
<el-table-column label="设备编码" align="left" prop="deviceCode" min-width="140px" />
<el-table-column label="设备名称" align="left" prop="deviceName" min-width="160px" />
<el-table-column
label="采集时间"
:label="t('DataCollection.HistoryData.tableLineCodeColumn')"
align="left"
prop="lineNode"
min-width="140px"
/>
<el-table-column
:label="t('DataCollection.HistoryData.tableLineNameColumn')"
align="left"
prop="lineName"
min-width="160px"
/>
<el-table-column
:label="t('DataCollection.HistoryData.tableDeviceCodeColumn')"
align="left"
prop="deviceCode"
min-width="140px"
/>
<el-table-column
:label="t('DataCollection.HistoryData.tableDeviceNameColumn')"
align="left"
prop="deviceName"
min-width="160px"
/>
<el-table-column
:label="t('DataCollection.HistoryData.tableCollectionTimeColumn')"
align="center"
prop="collectionTime"
:formatter="dateFormatter"
width="180px"
/>
<el-table-column label="操作" align="center" fixed="right" width="150px">
<el-table-column
:label="t('DataCollection.HistoryData.tableOperateColumn')"
align="center"
fixed="right"
width="150px"
>
<template #default="scope">
<el-button link type="primary" @click="handleSingleView(scope.row)">
历史记录
{{ t('DataCollection.HistoryData.tableActionHistoryLabel') }}
</el-button>
</template>
</el-table-column>
@ -110,6 +138,7 @@ import HistorySingleDeviceDialog from './HistorySingleDeviceDialog.vue'
defineOptions({ name: 'HistoryData' })
const message = useMessage()
const { t } = useI18n()
const loading = ref(true)
const list = ref<LineDeviceVO[]>([])
@ -215,10 +244,16 @@ const handleExport = async () => {
ids: selectedIds.value.length ? selectedIds.value.join(',') : undefined
}
const data = await DeviceApi.exportLineDevice(params)
download.excel(data, '历史数据设备.xls')
download.excel(data, t('DataCollection.HistoryData.exportFilename'))
} catch {
} finally {
exportLoading.value = false
}
}
</script>
<style scoped lang="scss">
.history-data-form :deep(.el-form-item__label) {
min-width: 100px;
}
</style>

@ -2,8 +2,8 @@
<Dialog v-model="dialogVisible" :title="dialogTitle" width="1200">
<div class="single-device-dialog">
<div class="single-device-dialog__header">
<div>设备名称{{ deviceName || '-' }}</div>
<div>采集时间{{ displayTime }}</div>
<div>{{ t('DataCollection.RealTimeMonitoring.dialogDeviceNameLabel') }}{{ deviceName || '-' }}</div>
<div>{{ t('DataCollection.RealTimeMonitoring.dialogCollectionTimeLabel') }}{{ displayTime }}</div>
</div>
<ContentWrap v-loading="loading">
<div v-if="sections.length" class="single-device-dialog__table-grid">
@ -11,7 +11,10 @@
<div class="single-device-dialog__section-title">
{{ section.title }}
</div>
<el-empty v-if="!section.columns.length" description="暂无数据" />
<el-empty
v-if="!section.columns.length"
:description="t('DataCollection.RealTimeMonitoring.emptyDescription')"
/>
<el-table
v-else :data="section.rows" :border="true" :header-cell-style="headerCellStyle"
:cell-style="bodyCellStyle" size="small">
@ -25,7 +28,10 @@ v-for="col in section.columns" :key="col.prop" :prop="col.prop" :label="col.labe
</el-table>
</div>
</div>
<el-empty v-else description="暂无数据" />
<el-empty
v-else
:description="t('DataCollection.RealTimeMonitoring.emptyDescription')"
/>
</ContentWrap>
</div>
</Dialog>
@ -49,6 +55,8 @@ type Section = {
rows: SectionRow[]
}
const { t } = useI18n()
const props = defineProps<{
modelValue: boolean
deviceId?: string | number
@ -70,7 +78,7 @@ const dialogVisible = computed({
})
const dialogTitle = computed(() => {
return '单设备监控'
return t('DataCollection.RealTimeMonitoring.dialogTitle')
})
const loading = ref(false)
@ -136,7 +144,8 @@ const buildSectionsFromGroups = (groups: Record<string, any[]>): Section[] => {
if (Array.isArray(list) && list.length) {
list.forEach((item: any, index: number) => {
const prop = `col${index}`
const label = item?.attributeName ?? `字段${index + 1}`
const label =
item?.attributeName ?? `${t('DataCollection.RealTimeMonitoring.defaultFieldLabelPrefix')}${index + 1}`
columns.push({ prop, label })
row[prop] = item?.addressValue ?? ''
})
@ -160,12 +169,12 @@ const fetchList = async () => {
try {
const res: any = await DeviceApi.getSingleDevice({ deviceId: props.deviceId })
const groups = Array.isArray(res)
? { 默认: res }
? { [t('DataCollection.RealTimeMonitoring.defaultGroupName')]: res }
: {
...toGroupMap(res?.data),
...toGroupMap(res?.data?.data),
...toGroupMap(res)
}
...toGroupMap(res?.data),
...toGroupMap(res?.data?.data),
...toGroupMap(res)
}
sections.value = buildSectionsFromGroups(groups)
} finally {
loading.value = false

@ -1,35 +1,60 @@
<template>
<ContentWrap>
<el-form class="-mb-15px" :model="queryParams" ref="queryFormRef" :inline="true" label-width="68px">
<el-form-item label="产线编码" prop="lineNode">
<el-form
class="-mb-15px real-time-monitoring-form"
:model="queryParams"
ref="queryFormRef"
:inline="true"
label-width="auto"
>
<el-form-item :label="t('DataCollection.RealTimeMonitoring.searchLineCodeLabel')" prop="lineNode">
<el-input
v-model="queryParams.lineNode" placeholder="请输入产线编码" clearable @keyup.enter="handleQuery"
class="!w-240px" />
v-model="queryParams.lineNode"
:placeholder="t('DataCollection.RealTimeMonitoring.searchLineCodePlaceholder')"
clearable
@keyup.enter="handleQuery"
class="!w-240px"
/>
</el-form-item>
<el-form-item label="产线名称" prop="lineName">
<el-form-item :label="t('DataCollection.RealTimeMonitoring.searchLineNameLabel')" prop="lineName">
<el-input
v-model="queryParams.lineName" placeholder="请输入产线名称" clearable @keyup.enter="handleQuery"
class="!w-240px" />
v-model="queryParams.lineName"
:placeholder="t('DataCollection.RealTimeMonitoring.searchLineNamePlaceholder')"
clearable
@keyup.enter="handleQuery"
class="!w-240px"
/>
</el-form-item>
<el-form-item label="设备编码" prop="deviceCode">
<el-form-item :label="t('DataCollection.RealTimeMonitoring.searchDeviceCodeLabel')" prop="deviceCode">
<el-input
v-model="queryParams.deviceCode" placeholder="请输入设备编码" clearable @keyup.enter="handleQuery"
class="!w-240px" />
v-model="queryParams.deviceCode"
:placeholder="t('DataCollection.RealTimeMonitoring.searchDeviceCodePlaceholder')"
clearable
@keyup.enter="handleQuery"
class="!w-240px"
/>
</el-form-item>
<el-form-item label="设备名称" prop="deviceName">
<el-form-item :label="t('DataCollection.RealTimeMonitoring.searchDeviceNameLabel')" prop="deviceName">
<el-input
v-model="queryParams.deviceName" placeholder="请输入设备名称" clearable @keyup.enter="handleQuery"
class="!w-240px" />
v-model="queryParams.deviceName"
:placeholder="t('DataCollection.RealTimeMonitoring.searchDeviceNamePlaceholder')"
clearable
@keyup.enter="handleQuery"
class="!w-240px"
/>
</el-form-item>
<el-form-item>
<el-button @click="handleQuery">
<Icon icon="ep:search" class="mr-5px" /> 搜索
<Icon icon="ep:search" class="mr-5px" />
{{ t('DataCollection.RealTimeMonitoring.searchButtonText') }}
</el-button>
<el-button @click="resetQuery">
<Icon icon="ep:refresh" class="mr-5px" /> 重置
<Icon icon="ep:refresh" class="mr-5px" />
{{ t('DataCollection.RealTimeMonitoring.resetButtonText') }}
</el-button>
<el-button type="success" plain @click="handleExport" :loading="exportLoading">
<Icon icon="ep:download" class="mr-5px" /> 导出
<Icon icon="ep:download" class="mr-5px" />
{{ t('DataCollection.RealTimeMonitoring.exportButtonText') }}
</el-button>
</el-form-item>
</el-form>
@ -45,19 +70,57 @@ v-model="queryParams.deviceName" placeholder="请输入设备名称" clearable @
@selection-change="handleSelectionChange"
>
<el-table-column type="selection" width="55" reserve-selection />
<el-table-column label="产线编码" align="left" prop="lineNode" min-width="140px" />
<el-table-column label="产线名称" align="left" prop="lineName" min-width="160px" />
<el-table-column label="设备编码" align="left" prop="deviceCode" min-width="140px" />
<el-table-column label="设备名称" align="left" prop="deviceName" min-width="160px" />
<el-table-column label="连接状态" align="center" prop="status" width="120px">
<el-table-column
:label="t('DataCollection.RealTimeMonitoring.tableLineCodeColumn')"
align="left"
prop="lineNode"
min-width="140px"
/>
<el-table-column
:label="t('DataCollection.RealTimeMonitoring.tableLineNameColumn')"
align="left"
prop="lineName"
min-width="160px"
/>
<el-table-column
:label="t('DataCollection.RealTimeMonitoring.tableDeviceCodeColumn')"
align="left"
prop="deviceCode"
min-width="140px"
/>
<el-table-column
:label="t('DataCollection.RealTimeMonitoring.tableDeviceNameColumn')"
align="left"
prop="deviceName"
min-width="160px"
/>
<el-table-column
:label="t('DataCollection.RealTimeMonitoring.tableStatusColumn')"
align="center"
prop="status"
width="120px"
>
<template #default="scope">
<dict-tag :type="DICT_TYPE.IOT_GATEWAY_STATUS" :value="scope.row.status" />
</template>
</el-table-column>
<el-table-column label="最新采集时间" align="center" prop="collectionTime" :formatter="dateFormatter" width="180px" />
<el-table-column label="操作" align="center" fixed="right" width="150px">
<el-table-column
:label="t('DataCollection.RealTimeMonitoring.tableCollectionTimeColumn')"
align="center"
prop="collectionTime"
:formatter="dateFormatter"
width="180px"
/>
<el-table-column
:label="t('DataCollection.RealTimeMonitoring.tableOperateColumn')"
align="center"
fixed="right"
width="150px"
>
<template #default="scope">
<el-button link type="primary" @click="handleSingleMonitor(scope.row)"></el-button>
<el-button link type="primary" @click="handleSingleMonitor(scope.row)">
{{ t('DataCollection.RealTimeMonitoring.tableActionSingleMonitorLabel') }}
</el-button>
</template>
</el-table-column>
</el-table>
@ -84,6 +147,7 @@ import SingleDeviceMonitorDialog from './SingleDeviceMonitorDialog.vue'
defineOptions({ name: 'RealTimeMonitoring' })
const message = useMessage()
const { t } = useI18n()
const loading = ref(true)
const list = ref<LineDeviceVO[]>([])
@ -155,7 +219,7 @@ const resetQuery = () => {
const handleSingleMonitor = (row: LineDeviceVO) => {
const deviceId = (row as any)?.deviceId ?? row?.id
if (deviceId === undefined || deviceId === null || deviceId === '') {
message.error('设备信息不完整')
message.error(t('DataCollection.RealTimeMonitoring.messageDeviceInfoIncomplete'))
return
}
monitorDeviceId.value = deviceId
@ -173,7 +237,7 @@ const handleExport = async () => {
ids: selectedIds.value.length ? selectedIds.value.join(',') : undefined
}
const data = await DeviceApi.exportLineDevice(params)
download.excel(data, '实时监控设备.xls')
download.excel(data, t('DataCollection.RealTimeMonitoring.exportFilename'))
} catch {
} finally {
exportLoading.value = false
@ -184,3 +248,9 @@ onMounted(() => {
getList()
})
</script>
<style scoped lang="scss">
.real-time-monitoring-form :deep(.el-form-item__label) {
min-width: 100px;
}
</style>

@ -1,44 +1,53 @@
<template>
<ContentWrap>
<el-form class="-mb-15px" :model="queryParams" ref="queryFormRef" :inline="true" label-width="120px">
<el-form-item label="设备编码" prop="deviceCode">
<el-form
class="-mb-15px run-report-form"
:model="queryParams"
ref="queryFormRef"
:inline="true"
label-width="auto"
>
<el-form-item :label="t('DataCollection.RunReport.searchDeviceCodeLabel')" prop="deviceCode">
<el-input
v-model="queryParams.deviceCode"
placeholder="请输入设备编码"
:placeholder="t('DataCollection.RunReport.searchDeviceCodePlaceholder')"
clearable
@keyup.enter="handleQuery"
class="!w-240px"
/>
</el-form-item>
<el-form-item label="设备名称" prop="deviceName">
<el-form-item :label="t('DataCollection.RunReport.searchDeviceNameLabel')" prop="deviceName">
<el-input
v-model="queryParams.deviceName"
placeholder="请输入设备名称"
:placeholder="t('DataCollection.RunReport.searchDeviceNamePlaceholder')"
clearable
@keyup.enter="handleQuery"
class="!w-240px"
/>
</el-form-item>
<el-form-item label="设备运行时间" prop="timeRange">
<el-form-item :label="t('DataCollection.RunReport.searchTimeRangeLabel')" prop="timeRange">
<el-date-picker
v-model="queryParams.timeRange"
type="datetimerange"
value-format="YYYY-MM-DD HH:mm:ss"
start-placeholder="开始时间"
end-placeholder="结束时间"
:start-placeholder="t('DataCollection.RunReport.searchTimeRangeStartPlaceholder')"
:end-placeholder="t('DataCollection.RunReport.searchTimeRangeEndPlaceholder')"
:default-time="[new Date('1 00:00:00'), new Date('1 23:59:59')]"
class="!w-360px"
/>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="handleQuery">
<Icon icon="ep:search" class="mr-5px" /> 搜索
<Icon icon="ep:search" class="mr-5px" />
{{ t('DataCollection.RunReport.searchButtonText') }}
</el-button>
<el-button @click="resetQuery">
<Icon icon="ep:refresh" class="mr-5px" /> 重置
<Icon icon="ep:refresh" class="mr-5px" />
{{ t('DataCollection.RunReport.resetButtonText') }}
</el-button>
<el-button type="success" plain @click="handleExport" :loading="exportLoading">
<Icon icon="ep:download" class="mr-5px" /> 导出
<Icon icon="ep:download" class="mr-5px" />
{{ t('DataCollection.RunReport.exportButtonText') }}
</el-button>
</el-form-item>
</el-form>
@ -46,15 +55,60 @@
<ContentWrap>
<el-table v-loading="loading" :data="list" :stripe="true" :show-overflow-tooltip="true" row-key="id">
<el-table-column label="设备编码" align="left" prop="deviceCode" min-width="140px" />
<el-table-column label="设备名称" align="left" prop="deviceName" min-width="160px" />
<el-table-column label="运行时间(小时)" align="center" prop="totalRunningTime" min-width="140px" />
<el-table-column label="待机时间(小时)" align="center" prop="totalStandbyTime" min-width="140px" />
<el-table-column label="故障时间(小时)" align="center" prop="totalFaultTime" min-width="140px" />
<el-table-column label="警告时间(小时)" align="center" prop="totalWarningTime" min-width="140px" />
<el-table-column label="稼动率" align="center" prop="utilizationRate" min-width="120px" />
<el-table-column label="设备运行开始时间" align="center" prop="startTime" min-width="120px" />
<el-table-column label="设备运行结束时间" align="center" prop="endTime" min-width="120px" />
<el-table-column
:label="t('DataCollection.RunReport.tableDeviceCodeColumn')"
align="left"
prop="deviceCode"
min-width="140px"
/>
<el-table-column
:label="t('DataCollection.RunReport.tableDeviceNameColumn')"
align="left"
prop="deviceName"
min-width="160px"
/>
<el-table-column
:label="t('DataCollection.RunReport.tableRunningTimeColumn')"
align="center"
prop="totalRunningTime"
min-width="140px"
/>
<el-table-column
:label="t('DataCollection.RunReport.tableStandbyTimeColumn')"
align="center"
prop="totalStandbyTime"
min-width="140px"
/>
<el-table-column
:label="t('DataCollection.RunReport.tableFaultTimeColumn')"
align="center"
prop="totalFaultTime"
min-width="140px"
/>
<el-table-column
:label="t('DataCollection.RunReport.tableWarningTimeColumn')"
align="center"
prop="totalWarningTime"
min-width="140px"
/>
<el-table-column
:label="t('DataCollection.RunReport.tableUtilizationRateColumn')"
align="center"
prop="utilizationRate"
min-width="120px"
/>
<el-table-column
:label="t('DataCollection.RunReport.tableStartTimeColumn')"
align="center"
prop="startTime"
min-width="120px"
/>
<el-table-column
:label="t('DataCollection.RunReport.tableEndTimeColumn')"
align="center"
prop="endTime"
min-width="120px"
/>
</el-table>
<Pagination
:total="total" v-model:page="queryParams.pageNo" v-model:limit="queryParams.pageSize"
@ -68,6 +122,8 @@ import { DeviceOperationRecordApi, type DeviceOperationRecordVO, type DeviceOper
defineOptions({ name: 'IotRunReport' })
const { t } = useI18n()
const loading = ref(false)
const list = ref<DeviceOperationRecordVO[]>([])
const total = ref(0)
@ -119,7 +175,7 @@ const handleExport = async () => {
queryParams.endTime = range[1]
const params = queryParams as unknown as DeviceOperationRecordPageParams
const data = await DeviceOperationRecordApi.exportDeviceOperationReport(params)
download.excel(data, '设备运行报表.xls')
download.excel(data, t('DataCollection.RunReport.exportFilename'))
} catch {
} finally {
exportLoading.value = false
@ -130,3 +186,9 @@ onMounted(() => {
getList()
})
</script>
<style scoped lang="scss">
.run-report-form :deep(.el-form-item__label) {
min-width: 120px;
}
</style>

@ -13,19 +13,27 @@
<el-radio :label="2">{{ t('MoldManagement.MoldOperate.operateTypeDown') }}</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item :label="t('MoldManagement.MoldOperate.device')" prop="deviceId">
<el-select
v-model="formData.deviceId" filterable clearable :loading="deviceLoading"
:placeholder="t('MoldManagement.MoldOperate.placeholderDevice')" class="!w-full" @change="deviceChange(formData.deviceId)">
<el-option v-for="opt in deviceOptions" :key="String(opt.value)" :label="opt.label" :value="opt.value" />
</el-select>
<el-form-item :label="t('MoldManagement.MoldOperate.device')" prop="deviceId" v-if="formData.operateType != null">
<el-select
v-model="formData.deviceId"
filterable
clearable
:loading="deviceLoading"
:placeholder="t('MoldManagement.MoldOperate.placeholderDevice')"
class="!w-full"
@change="deviceChange(formData.deviceId)"
>
<el-option v-for="opt in deviceOptions" :key="String(opt.value)" :label="opt.label" :value="opt.value" />
</el-select>
</el-form-item>
<el-form-item :label="t('MoldManagement.MoldOperate.mold')" prop="moldId" v-if = "formData.operateType == '1'">
<el-form-item :label="t('MoldManagement.MoldOperate.mold')" prop="moldId" v-if="formData.operateType == '1'">
<el-select
v-model="formData.moldId"
multiple
clearable
filterable
:placeholder="t('MoldManagement.MoldOperate.placeholderMold')"
class="!w-full"
>
<el-option
v-for="item in moldList"
@ -35,6 +43,27 @@ v-model="formData.deviceId" filterable clearable :loading="deviceLoading"
/>
</el-select>
</el-form-item>
<el-form-item
v-if="formData.operateType == '2' && formData.deviceId"
:label="t('MoldManagement.MoldOperate.lowerMold')"
prop="lowerMoldId"
>
<el-select
v-model="formData.lowerMoldId"
multiple
clearable
filterable
:placeholder="t('MoldManagement.MoldOperate.placeholderLowerMold')"
class="!w-full"
>
<el-option
v-for="item in lowerMoldList"
:key="item.id"
:label="item.name || item.moldName || `ID:${item.id}`"
:value="item.id"
/>
</el-select>
</el-form-item>
<el-form-item :label="t('MoldManagement.MoldOperate.remark')" prop="remark">
<el-input v-model="formData.remark" :placeholder="t('MoldManagement.MoldOperate.placeholderRemark')" />
</el-form-item>
@ -55,11 +84,13 @@ defineOptions({ name: 'MoldOperateForm' })
const { t } = useI18n() //
const message = useMessage() //
const moldList = ref<MoldVO[]>([]) //
const moldList = ref<MoldVO[]>([]) //
const lowerMoldList = ref<any[]>([]) //
const deviceLoading = ref(false)
const deviceOptions = ref<{ label: string; value: number; raw?: DeviceLedgerVO }[]>([])
const deviceOptionsLoaded = ref(false)
const initializingOperateType = ref(false)
const dialogVisible = ref(false) //
const dialogTitle = ref('') //
@ -71,11 +102,40 @@ const formData = ref({
moldId: undefined,
deviceId: undefined,
remark: undefined,
lowerMoldId: undefined,
})
const validateMoldId = (_rule: any, value: any, callback: (error?: Error) => void) => {
if (String(formData.value.operateType) !== '1') {
callback()
return
}
const hasValue = Array.isArray(value) ? value.length > 0 : value !== undefined && value !== null && value !== ''
if (!hasValue) {
callback(new Error(t('MoldManagement.MoldOperate.validatorMoldRequired')))
} else {
callback()
}
}
const validateLowerMoldId = (_rule: any, value: any, callback: (error?: Error) => void) => {
if (String(formData.value.operateType) !== '2') {
callback()
return
}
const hasValue = Array.isArray(value) ? value.length > 0 : value !== undefined && value !== null && value !== ''
if (!hasValue) {
callback(new Error(t('MoldManagement.MoldOperate.validatorLowerMoldRequired')))
} else {
callback()
}
}
const formRules = reactive({
moldId: [{ required: true, message: t('MoldManagement.MoldOperate.validatorMoldRequired'), trigger: 'blur' }],
operateType: [{ required: true, message: t('MoldManagement.MoldOperate.validatorOperateTypeRequired'), trigger: 'blur' }],
deviceId: [{ required: true, message: t('MoldManagement.MoldOperate.validatorDeviceRequired'), trigger: 'blur' }],
moldId: [{ validator: validateMoldId, trigger: 'change' }],
lowerMoldId: [{ validator: validateLowerMoldId, trigger: 'change' }],
})
const formRef = ref() // Ref
@ -85,14 +145,35 @@ const open = async (type: string, id?: number) => {
dialogTitle.value = t('action.' + type)
formType.value = type
resetForm()
moldList.value = await MoldBrandApi.getMoldAllList()
await ensureDeviceOptionsLoaded()
//
if (id) {
formLoading.value = true
try {
formData.value = await MoldOperateApi.getMoldOperate(id)
initializingOperateType.value = true
const data = await MoldOperateApi.getMoldOperate(id)
formData.value = {
...formData.value,
...data,
lowerMoldId: (data as any).lowerMoldId,
}
//
if (String(formData.value.operateType) === '1') {
if (typeof formData.value.moldId === 'string') {
const parts = formData.value.moldId.split(',').map((v: string) => Number(v)).filter((v) => !Number.isNaN(v))
formData.value.moldId = parts as any
}
await loadUpMoldList()
} else if (String(formData.value.operateType) === '2') {
const rawLower = (formData.value as any).lowerMoldId
if (typeof rawLower === 'string') {
const parts = rawLower.split(',').map((v: string) => Number(v)).filter((v) => !Number.isNaN(v))
;(formData.value as any).lowerMoldId = parts
}
await loadLowerMoldList()
}
} finally {
initializingOperateType.value = false
formLoading.value = false
}
}
@ -106,7 +187,7 @@ const emit = defineEmits(['success']) // 定义 success 事件,用于操作成
// await formRef.value.validate()
// //
// if (formData.value.operateType === '1') {
// const data = await MoldOperateApi.getMoldOperateMold(formData.value.deviceId)
// const data = await someApiToCheck(formData.value.deviceId)
// if (data === true) {
// message.alert('')
// return;
@ -139,22 +220,33 @@ const submitForm = async () => {
// 1.
await formRef.value.validate()
// 2.
if (formData.value.operateType == '1') {
const data = await MoldOperateApi.getMoldOperateMold(formData.value.deviceId)
if (data === true) {
message.alert(t('MoldManagement.MoldOperate.alertNeedRemoveMoldFirst'))
return
}
} else {
const data = await MoldOperateApi.getMoldOperateMold(formData.value.deviceId)
if (data === false) {
message.alert(t('MoldManagement.MoldOperate.alertNoMoldOnDevice'))
return
}
}
// 2.
const raw = formData.value as any
const submitData: any = {
id: raw.id,
operateType: raw.operateType,
deviceId: raw.deviceId,
remark: raw.remark,
}
if (String(raw.operateType) === '1') {
const ids = Array.isArray(raw.moldId) ? raw.moldId : raw.moldId != null ? [raw.moldId] : []
submitData.moldId = ids.map((v: any) => v).join(',')
} else if (String(raw.operateType) === '2') {
const allIds = lowerMoldList.value
.map((item: any) => item?.id)
.filter((id: any) => id !== undefined && id !== null)
const lowerIds = Array.isArray(raw.lowerMoldId)
? raw.lowerMoldId
: raw.lowerMoldId != null
? [raw.lowerMoldId]
: []
submitData.lowerMoldId = lowerIds.map((v: any) => v).join(',')
const lowerIdSet = new Set(lowerIds.map((v: any) => String(v)))
const remainIds = allIds.filter((id: any) => !lowerIdSet.has(String(id)))
submitData.moldId = remainIds.join(',')
}
// 3.
const submitData = formData.value as unknown as MoldOperateVO
if (formType.value === 'create') {
await MoldOperateApi.createMoldOperate(submitData)
message.success(t('common.createSuccess'))
@ -192,18 +284,47 @@ const ensureDeviceOptionsLoaded = async () => {
//
const deviceChange = async (deviceId:number) => {
const data = await MoldOperateApi.getMoldOperateMold(deviceId)
if (formData.value.operateType == '1') {
if (data === true) {
message.alert(t('MoldManagement.MoldOperate.alertNeedRemoveMoldFirst'))
}
} else {
if (data === false) {
message.alert(t('MoldManagement.MoldOperate.alertNoMoldOnDevice'))
if (String(formData.value.operateType) === '2' && deviceId) {
await loadLowerMoldList()
formData.value.lowerMoldId = undefined as any
}
}
const loadUpMoldList = async () => {
moldList.value = await MoldBrandApi.getInTransitMoldAllList()
}
const loadLowerMoldList = async () => {
if (!formData.value.deviceId) {
lowerMoldList.value = []
return
}
const list = await MoldOperateApi.getLowerMoldList(formData.value.deviceId)
lowerMoldList.value = Array.isArray(list) ? list : []
}
watch(
() => formData.value.operateType,
async (val) => {
if (initializingOperateType.value) {
return
}
formData.value.deviceId = undefined as any
formData.value.moldId = undefined as any
formData.value.lowerMoldId = undefined as any
moldList.value = []
lowerMoldList.value = []
if (!val) {
return
}
if (String(val) === '1') {
await loadUpMoldList()
} else if (String(val) === '2') {
await loadLowerMoldList()
}
}
)
/** 重置表单 */
const resetForm = () => {
formData.value = {
@ -212,6 +333,7 @@ const resetForm = () => {
moldId: undefined,
deviceId: undefined,
remark: undefined,
lowerMoldId: undefined,
}
formRef.value?.resetFields()
}

Loading…
Cancel
Save