Merge remote-tracking branch 'yudao/master'

pull/347/head
jason 2026-05-28 17:26:34 +08:00
commit a1d6c8bdb3
664 changed files with 37684 additions and 2379 deletions

View File

@ -60,6 +60,7 @@
"pinia": "catalog:",
"steady-xml": "catalog:",
"tinymce": "catalog:",
"tyme4ts": "catalog:",
"video.js": "catalog:",
"vue": "catalog:",
"vue-dompurify-html": "catalog:",

View File

@ -24,7 +24,7 @@ export namespace RuleSceneApi {
operator?: string;
value?: any;
cronExpression?: string;
conditionGroups?: TriggerCondition[][];
conditionGroups?: TriggerCondition[][]; // 后端结构List<List<TriggerCondition>>;外层「或」、组内「且」
}
/** 场景联动规则的触发条件 */
@ -80,13 +80,6 @@ export function deleteSceneRule(id: number) {
return requestClient.delete(`/iot/scene-rule/delete?id=${id}`);
}
/** 批量删除场景联动规则 */
export function deleteSceneRuleList(ids: number[]) {
return requestClient.delete('/iot/scene-rule/delete-list', {
params: { ids: ids.join(',') },
});
}
/** 更新场景联动规则状态 */
export function updateSceneRuleStatus(id: number, status: number) {
return requestClient.put(`/iot/scene-rule/update-status`, {

View File

@ -148,8 +148,8 @@ export const ThingModelFormRules: Record<string, Rule[]> = {
identifier: [
{ required: true, message: '标识符不能为空', trigger: 'blur' },
{
pattern: /^\w{1,50}$/,
message: '支持大小写字母、数字和下划线,不超过 50 个字符',
pattern: /^[a-zA-Z][a-zA-Z0-9_]{0,31}$/,
message: '支持大小写字母、数字和下划线,必须以字母开头,不超过 32 个字符',
trigger: 'blur',
},
{

View File

@ -51,7 +51,5 @@ export function deleteAutoCodeRule(id: number) {
/** 导出编码规则 */
export function exportAutoCodeRule(params: PageParam) {
return requestClient.download('/mes/md/auto-code-rule/export-excel', {
params,
});
return requestClient.download('/mes/md/auto-code-rule/export-excel', { params });
}

View File

@ -34,9 +34,7 @@ export namespace MesMdItemApi {
/** 查询物料产品分页 */
export function getItemPage(params: PageParam) {
return requestClient.get<PageResult<MesMdItemApi.Item>>('/mes/md/item/page', {
params,
});
return requestClient.get<PageResult<MesMdItemApi.Item>>('/mes/md/item/page', { params });
}
/** 查询物料产品详情 */

View File

@ -0,0 +1,54 @@
import type { PageParam, PageResult } from '@vben/request';
import { requestClient } from '#/api/request';
export namespace MesProAndonConfigApi {
/** MES 安灯配置 */
export interface AndonConfig {
id?: number; // 编号
reason?: string; // 呼叫原因
level?: number; // 级别
handlerRoleId?: number; // 处置角色编号
handlerRoleName?: string; // 处置角色名称
handlerUserId?: number; // 处置人编号
handlerUserNickname?: string; // 处置人昵称
remark?: string; // 备注
}
}
/** 查询安灯配置分页 */
export function getAndonConfigPage(params: PageParam) {
return requestClient.get<PageResult<MesProAndonConfigApi.AndonConfig>>(
'/mes/pro/andon-config/page',
{ params },
);
}
/** 查询安灯配置列表 */
export function getAndonConfigList() {
return requestClient.get<MesProAndonConfigApi.AndonConfig[]>(
'/mes/pro/andon-config/list',
);
}
/** 查询安灯配置详情 */
export function getAndonConfig(id: number) {
return requestClient.get<MesProAndonConfigApi.AndonConfig>(
`/mes/pro/andon-config/get?id=${id}`,
);
}
/** 新增安灯配置 */
export function createAndonConfig(data: MesProAndonConfigApi.AndonConfig) {
return requestClient.post('/mes/pro/andon-config/create', data);
}
/** 修改安灯配置 */
export function updateAndonConfig(data: MesProAndonConfigApi.AndonConfig) {
return requestClient.put('/mes/pro/andon-config/update', data);
}
/** 删除安灯配置 */
export function deleteAndonConfig(id: number) {
return requestClient.delete(`/mes/pro/andon-config/delete?id=${id}`);
}

View File

@ -0,0 +1,76 @@
import type { PageParam, PageResult } from '@vben/request';
import { requestClient } from '#/api/request';
export namespace MesProAndonRecordApi {
/** MES 安灯记录 */
export interface AndonRecord {
id?: number;
configId?: number; // 安灯配置编号
workstationId?: number; // 工作站编号
workstationCode?: string; // 工作站编码
workstationName?: string; // 工作站名称
workOrderId?: number; // 生产工单编号
workOrderCode?: string; // 工单编码
processId?: number; // 工序编号
processName?: string; // 工序名称
userId?: number; // 发起用户编号
userNickname?: string; // 发起人昵称
reason?: string; // 呼叫原因
level?: number; // 级别
status?: number; // 处置状态
handleTime?: number; // 处置时间(毫秒时间戳)
handlerUserId?: number; // 处置人编号
handlerUserNickname?: string; // 处置人昵称
remark?: string; // 备注
createTime?: number; // 发起时间
}
/** MES 安灯记录分页查询参数 */
export interface PageParams extends PageParam {
workstationId?: number; // 工作站编号
userId?: number; // 发起用户编号
handlerUserId?: number; // 处置人编号
status?: number; // 处置状态
createTime?: string[]; // 发起时间区间
}
}
/** 查询安灯记录分页 */
export function getAndonRecordPage(params: MesProAndonRecordApi.PageParams) {
return requestClient.get<PageResult<MesProAndonRecordApi.AndonRecord>>(
'/mes/pro/andon-record/page',
{ params },
);
}
/** 查询安灯记录详情 */
export function getAndonRecord(id: number) {
return requestClient.get<MesProAndonRecordApi.AndonRecord>(
`/mes/pro/andon-record/get?id=${id}`,
);
}
/** 新增安灯记录 */
export function createAndonRecord(data: MesProAndonRecordApi.AndonRecord) {
return requestClient.post('/mes/pro/andon-record/create', data);
}
/** 删除安灯记录 */
export function deleteAndonRecord(id: number) {
return requestClient.delete(`/mes/pro/andon-record/delete?id=${id}`);
}
/** 更新安灯记录(保存/已处置) */
export function updateAndonRecord(data: MesProAndonRecordApi.AndonRecord) {
return requestClient.put('/mes/pro/andon-record/update', data);
}
/** 导出安灯记录 Excel */
export function exportAndonRecord(
params: Partial<MesProAndonRecordApi.PageParams>,
) {
return requestClient.download('/mes/pro/andon-record/export-excel', {
params,
});
}

View File

@ -0,0 +1,113 @@
import type { PageParam, PageResult } from '@vben/request';
import { requestClient } from '#/api/request';
export namespace MesProFeedbackApi {
/** MES 生产报工 */
export interface Feedback {
id?: number;
code?: string; // 报工单编号
type?: number; // 报工类型
channel?: string; // 报工途径
feedbackTime?: number; // 报工时间
workstationId?: number; // 工作站编号
workstationCode?: string; // 工作站编码
workstationName?: string; // 工作站名称
routeId?: number; // 工艺路线编号
routeCode?: string; // 工艺路线编码
processId?: number; // 工序编号
processCode?: string; // 工序编码
processName?: string; // 工序名称
checkFlag?: boolean; // 是否需要检验
workOrderId?: number; // 生产工单编号
workOrderCode?: string; // 工单编码
workOrderName?: string; // 工单名称
taskId?: number; // 生产任务编号
taskCode?: string; // 任务编码
itemId?: number; // 产品物料编号
itemCode?: string; // 物料编码
itemName?: string; // 物料名称
itemSpecification?: string; // 规格型号
unitMeasureId?: number; // 单位编号
unitMeasureName?: string; // 单位名称
expireDate?: number; // 过期日期
scheduledQuantity?: number; // 排产数量
feedbackQuantity?: number; // 本次报工数量
qualifiedQuantity?: number; // 合格品数量
unqualifiedQuantity?: number; // 不良品数量
uncheckQuantity?: number; // 待检测数量
laborScrapQuantity?: number; // 工废数量
materialScrapQuantity?: number; // 料废数量
otherScrapQuantity?: number; // 其他废品数量
feedbackUserId?: number; // 报工用户编号
feedbackUserNickname?: string; // 报工人昵称
approveUserId?: number; // 审核用户编号
approveUserNickname?: string; // 审核人昵称
status?: number; // 状态
remark?: string; // 备注
creator?: string; // 创建人
createTime?: number; // 创建时间
}
/** MES 生产报工分页查询参数 */
export interface PageParams extends PageParam {
code?: string;
type?: number;
workOrderId?: number;
itemId?: number;
feedbackUserId?: number;
creator?: string;
status?: number;
feedbackTime?: string[];
}
}
/** 查询生产报工分页 */
export function getFeedbackPage(params: MesProFeedbackApi.PageParams) {
return requestClient.get<PageResult<MesProFeedbackApi.Feedback>>(
'/mes/pro/feedback/page',
{ params },
);
}
/** 查询生产报工详情 */
export function getFeedback(id: number) {
return requestClient.get<MesProFeedbackApi.Feedback>(
`/mes/pro/feedback/get?id=${id}`,
);
}
/** 新增生产报工 */
export function createFeedback(data: MesProFeedbackApi.Feedback) {
return requestClient.post<number>('/mes/pro/feedback/create', data);
}
/** 修改生产报工 */
export function updateFeedback(data: MesProFeedbackApi.Feedback) {
return requestClient.put('/mes/pro/feedback/update', data);
}
/** 删除生产报工 */
export function deleteFeedback(id: number) {
return requestClient.delete(`/mes/pro/feedback/delete?id=${id}`);
}
/** 导出生产报工 Excel */
export function exportFeedback(params: Partial<MesProFeedbackApi.PageParams>) {
return requestClient.download('/mes/pro/feedback/export-excel', { params });
}
/** 提交生产报工 */
export function submitFeedback(id: number) {
return requestClient.put(`/mes/pro/feedback/submit?id=${id}`);
}
/** 驳回生产报工 */
export function rejectFeedback(id: number) {
return requestClient.put(`/mes/pro/feedback/reject?id=${id}`);
}
/** 审批生产报工(返回是否已审批完成) */
export function approveFeedback(id: number) {
return requestClient.put<boolean>(`/mes/pro/feedback/approve?id=${id}`);
}

View File

@ -0,0 +1,49 @@
import { requestClient } from '#/api/request';
export namespace MesProProcessContentApi {
/** MES 生产工序内容(操作步骤) */
export interface ProcessContent {
id?: number;
processId?: number;
sort?: number;
content?: string;
device?: string;
material?: string;
docUrl?: string;
remark?: string;
createTime?: Date;
}
}
/** 按工序编号查询工序内容列表 */
export function getProcessContentListByProcessId(processId: number) {
return requestClient.get<MesProProcessContentApi.ProcessContent[]>(
`/mes/pro/process-content/list-by-process?processId=${processId}`,
);
}
/** 查询工序内容详情 */
export function getProcessContent(id: number) {
return requestClient.get<MesProProcessContentApi.ProcessContent>(
`/mes/pro/process-content/get?id=${id}`,
);
}
/** 新增工序内容 */
export function createProcessContent(
data: MesProProcessContentApi.ProcessContent,
) {
return requestClient.post('/mes/pro/process-content/create', data);
}
/** 修改工序内容 */
export function updateProcessContent(
data: MesProProcessContentApi.ProcessContent,
) {
return requestClient.put('/mes/pro/process-content/update', data);
}
/** 删除工序内容 */
export function deleteProcessContent(id: number) {
return requestClient.delete(`/mes/pro/process-content/delete?id=${id}`);
}

View File

@ -5,7 +5,7 @@ import { requestClient } from '#/api/request';
export namespace MesProProcessApi {
/** MES 生产工序 */
export interface Process {
id: number;
id?: number;
code?: string;
name?: string;
attention?: string;
@ -36,3 +36,23 @@ export function getProcess(id: number) {
`/mes/pro/process/get?id=${id}`,
);
}
/** 新增生产工序 */
export function createProcess(data: MesProProcessApi.Process) {
return requestClient.post('/mes/pro/process/create', data);
}
/** 修改生产工序 */
export function updateProcess(data: MesProProcessApi.Process) {
return requestClient.put('/mes/pro/process/update', data);
}
/** 删除生产工序 */
export function deleteProcess(id: number) {
return requestClient.delete(`/mes/pro/process/delete?id=${id}`);
}
/** 导出生产工序 Excel */
export function exportProcess(params: any) {
return requestClient.download('/mes/pro/process/export-excel', { params });
}

View File

@ -0,0 +1,65 @@
import type { PageParam, PageResult } from '@vben/request';
import { requestClient } from '#/api/request';
export namespace MesProRouteApi {
/** MES 工艺路线 */
export interface Route {
id?: number;
code?: string;
name?: string;
description?: string;
status?: number;
remark?: string;
createTime?: Date;
}
}
/** 查询工艺路线分页 */
export function getRoutePage(params: PageParam) {
return requestClient.get<PageResult<MesProRouteApi.Route>>(
'/mes/pro/route/page',
{ params },
);
}
/** 查询工艺路线精简列表 */
export function getRouteSimpleList() {
return requestClient.get<MesProRouteApi.Route[]>(
'/mes/pro/route/simple-list',
);
}
/** 查询工艺路线详情 */
export function getRoute(id: number) {
return requestClient.get<MesProRouteApi.Route>(
`/mes/pro/route/get?id=${id}`,
);
}
/** 新增工艺路线 */
export function createRoute(data: MesProRouteApi.Route) {
return requestClient.post<number>('/mes/pro/route/create', data);
}
/** 修改工艺路线 */
export function updateRoute(data: MesProRouteApi.Route) {
return requestClient.put('/mes/pro/route/update', data);
}
/** 修改工艺路线状态 */
export function updateRouteStatus(id: number, status: number) {
return requestClient.put(
`/mes/pro/route/update-status?id=${id}&status=${status}`,
);
}
/** 删除工艺路线 */
export function deleteRoute(id: number) {
return requestClient.delete(`/mes/pro/route/delete?id=${id}`);
}
/** 导出工艺路线 Excel */
export function exportRoute(params: any) {
return requestClient.download('/mes/pro/route/export-excel', { params });
}

View File

@ -0,0 +1,70 @@
import { requestClient } from '#/api/request';
export namespace MesProRouteProcessApi {
/** MES 工艺路线工序 */
export interface RouteProcess {
id?: number;
routeId?: number;
processId?: number;
processCode?: string;
processName?: string;
sort?: number;
nextProcessId?: number;
nextProcessName?: string;
linkType?: number;
prepareTime?: number;
waitTime?: number;
colorCode?: string;
keyFlag?: boolean;
checkFlag?: boolean;
remark?: string;
createTime?: Date;
}
}
/** 按工艺路线查询工序列表 */
export function getRouteProcessListByRoute(routeId: number) {
return requestClient.get<MesProRouteProcessApi.RouteProcess[]>(
`/mes/pro/route-process/list-by-route?routeId=${routeId}`,
);
}
/** 按产品查询工序列表(自动查找关联的工艺路线) */
export function getRouteProcessListByProduct(productId: number) {
return requestClient.get<MesProRouteProcessApi.RouteProcess[]>(
`/mes/pro/route-process/list-by-product?productId=${productId}`,
);
}
/** 查询工艺路线工序详情 */
export function getRouteProcess(id: number) {
return requestClient.get<MesProRouteProcessApi.RouteProcess>(
`/mes/pro/route-process/get?id=${id}`,
);
}
/** 按工艺路线 + 工序精确查询工序配置 */
export function getRouteProcessByRouteAndProcess(
routeId: number,
processId: number,
) {
return requestClient.get<MesProRouteProcessApi.RouteProcess>(
'/mes/pro/route-process/get-by-route-and-process',
{ params: { processId, routeId } },
);
}
/** 新增工艺路线工序 */
export function createRouteProcess(data: MesProRouteProcessApi.RouteProcess) {
return requestClient.post('/mes/pro/route-process/create', data);
}
/** 修改工艺路线工序 */
export function updateRouteProcess(data: MesProRouteProcessApi.RouteProcess) {
return requestClient.put('/mes/pro/route-process/update', data);
}
/** 删除工艺路线工序 */
export function deleteRouteProcess(id: number) {
return requestClient.delete(`/mes/pro/route-process/delete?id=${id}`);
}

View File

@ -0,0 +1,48 @@
import { requestClient } from '#/api/request';
export namespace MesProRouteProductApi {
/** MES 工艺路线产品 */
export interface RouteProduct {
id?: number;
routeId?: number;
itemId?: number;
itemCode?: string;
itemName?: string;
specification?: string;
unitName?: string;
quantity?: number;
productionTime?: number;
timeUnitType?: string;
remark?: string;
createTime?: Date;
}
}
/** 按工艺路线查询产品列表 */
export function getRouteProductListByRoute(routeId: number) {
return requestClient.get<MesProRouteProductApi.RouteProduct[]>(
`/mes/pro/route-product/list-by-route?routeId=${routeId}`,
);
}
/** 查询工艺路线产品详情 */
export function getRouteProduct(id: number) {
return requestClient.get<MesProRouteProductApi.RouteProduct>(
`/mes/pro/route-product/get?id=${id}`,
);
}
/** 新增工艺路线产品 */
export function createRouteProduct(data: MesProRouteProductApi.RouteProduct) {
return requestClient.post<number>('/mes/pro/route-product/create', data);
}
/** 修改工艺路线产品 */
export function updateRouteProduct(data: MesProRouteProductApi.RouteProduct) {
return requestClient.put('/mes/pro/route-product/update', data);
}
/** 删除工艺路线产品 */
export function deleteRouteProduct(id: number) {
return requestClient.delete(`/mes/pro/route-product/delete?id=${id}`);
}

View File

@ -0,0 +1,57 @@
import { requestClient } from '#/api/request';
export namespace MesProRouteProductBomApi {
/** MES 工艺路线产品 BOM */
export interface RouteProductBom {
id?: number;
routeId?: number;
processId?: number;
productId?: number;
itemId?: number;
itemCode?: string;
itemName?: string;
specification?: string;
unitName?: string;
quantity?: number;
remark?: string;
createTime?: Date;
}
}
/** 查询工艺路线产品 BOM 列表 */
export function getRouteProductBomList(params: {
processId?: number;
productId?: number;
routeId: number;
}) {
return requestClient.get<MesProRouteProductBomApi.RouteProductBom[]>(
'/mes/pro/route-product-bom/list',
{ params },
);
}
/** 查询工艺路线产品 BOM 详情 */
export function getRouteProductBom(id: number) {
return requestClient.get<MesProRouteProductBomApi.RouteProductBom>(
`/mes/pro/route-product-bom/get?id=${id}`,
);
}
/** 新增工艺路线产品 BOM */
export function createRouteProductBom(
data: MesProRouteProductBomApi.RouteProductBom,
) {
return requestClient.post('/mes/pro/route-product-bom/create', data);
}
/** 修改工艺路线产品 BOM */
export function updateRouteProductBom(
data: MesProRouteProductBomApi.RouteProductBom,
) {
return requestClient.put('/mes/pro/route-product-bom/update', data);
}
/** 删除工艺路线产品 BOM */
export function deleteRouteProductBom(id: number) {
return requestClient.delete(`/mes/pro/route-product-bom/delete?id=${id}`);
}

View File

@ -0,0 +1,68 @@
import type { PageParam, PageResult } from '@vben/request';
import { requestClient } from '#/api/request';
export namespace MesProTaskApi {
/** MES 生产任务 */
export interface Task {
id?: number;
code?: string; // 任务编码
name?: string; // 任务名称
workOrderId?: number; // 生产工单编号
workOrderCode?: string; // 工单编码
workOrderName?: string; // 工单名称
workstationId?: number; // 工作站编号
workstationCode?: string; // 工作站编码
workstationName?: string; // 工作站名称
routeId?: number; // 工艺路线编号
processId?: number; // 工序编号
processName?: string; // 工序名称
itemId?: number; // 产品物料编号
itemCode?: string; // 产品编码
itemName?: string; // 产品名称
itemSpecification?: string; // 规格型号
unitMeasureId?: number; // 单位编号
unitMeasureName?: string; // 单位名称
quantity?: number; // 排产数量
producedQuantity?: number; // 已生产数量
qualifyQuantity?: number; // 合格品数量
unqualifyQuantity?: number; // 不良品数量
changedQuantity?: number; // 调整数量
clientId?: number; // 客户编号
clientName?: string; // 客户名称
startTime?: number; // 开始生产时间
endTime?: number; // 结束生产时间
duration?: number; // 生产时长工作日1=8小时
requestDate?: number; // 需求日期(从工单查)
finishDate?: number; // 完成日期
cancelDate?: number; // 取消日期
colorCode?: string; // 甘特图显示颜色
status?: number; // 任务状态
checkFlag?: boolean; // 是否质检(派生自工艺路线工序)
remark?: string; // 备注
}
/** MES 生产任务分页查询参数 */
export interface PageParams extends PageParam {
code?: string;
name?: string;
workOrderId?: number;
workstationId?: number;
itemId?: number;
statuses?: number[];
status?: number;
}
}
/** 查询生产任务分页 */
export function getTaskPage(params: MesProTaskApi.PageParams) {
return requestClient.get<PageResult<MesProTaskApi.Task>>(
'/mes/pro/task/page',
{ params },
);
}
/** 查询生产任务详情 */
export function getTask(id: number) {
return requestClient.get<MesProTaskApi.Task>(`/mes/pro/task/get?id=${id}`);
}

View File

@ -0,0 +1,53 @@
import type { PageParam, PageResult } from '@vben/request';
import { requestClient } from '#/api/request';
export namespace MesProWorkOrderApi {
/** MES 生产工单 */
export interface WorkOrder {
id?: number;
code?: string; // 工单编码
name?: string; // 工单名称
type?: number; // 工单类型
status?: number; // 工单状态
sourceType?: number;
productId?: number; // 产品物料编号
productCode?: string;
productName?: string;
productSpecification?: string;
quantity?: number;
unitName?: string;
routeId?: number;
routeName?: string;
clientId?: number;
clientName?: string;
planStartTime?: number | string;
planEndTime?: number | string;
actualStartTime?: number | string;
actualEndTime?: number | string;
remark?: string;
createTime?: number | string;
}
export interface PageParams extends PageParam {
code?: string;
name?: string;
status?: number;
type?: number;
}
}
/** 查询生产工单分页 */
export function getWorkOrderPage(params: MesProWorkOrderApi.PageParams) {
return requestClient.get<PageResult<MesProWorkOrderApi.WorkOrder>>(
'/mes/pro/work-order/page',
{ params },
);
}
/** 查询生产工单详情 */
export function getWorkOrder(id: number) {
return requestClient.get<MesProWorkOrderApi.WorkOrder>(
`/mes/pro/work-order/get?id=${id}`,
);
}

View File

@ -0,0 +1,71 @@
import type { PageParam, PageResult } from '@vben/request';
import { requestClient } from '#/api/request';
export namespace MesProWorkRecordApi {
/** MES 工作记录流水 */
export interface WorkRecordLog {
id?: number; // 编号
userId?: number; // 用户编号
userNickname?: string; // 用户昵称
workstationId?: number; // 工作站编号
workstationCode?: string; // 工作站编码
workstationName?: string; // 工作站名称
type?: number; // 1=上工 2=下工
remark?: string; // 备注
createTime?: Date; // 创建时间
}
/** MES 当前用户工作站绑定状态 */
export interface MyWorkRecord {
userId?: number; // 用户编号
userNickname?: string; // 用户昵称
workstationId?: number; // 工作站编号
workstationCode?: string; // 工作站编码
workstationName?: string; // 工作站名称
type?: number; // 1=上工 2=下工
clockInTime?: Date; // 上工时间
clockOutTime?: Date; // 下工时间
}
}
/** 查询工作记录分页 */
export function getWorkRecordLogPage(params: PageParam) {
return requestClient.get<PageResult<MesProWorkRecordApi.WorkRecordLog>>(
'/mes/pro/workrecord/log/page',
{ params },
);
}
/** 查询工作记录详情 */
export function getWorkRecordLog(id: number) {
return requestClient.get<MesProWorkRecordApi.WorkRecordLog>(
`/mes/pro/workrecord/log/get?id=${id}`,
);
}
/** 导出工作记录 */
export function exportWorkRecordLog(params: any) {
return requestClient.download('/mes/pro/workrecord/log/export-excel', {
params,
});
}
/** 上工(绑定工作站) */
export function clockInWorkRecord(workstationId: number) {
return requestClient.put('/mes/pro/workrecord/clock-in', null, {
params: { workstationId },
});
}
/** 下工(解绑工作站) */
export function clockOutWorkRecord() {
return requestClient.put('/mes/pro/workrecord/clock-out');
}
/** 查询当前用户绑定的工作站 */
export function getMyWorkRecord() {
return requestClient.get<MesProWorkRecordApi.MyWorkRecord>(
'/mes/pro/workrecord/get-my',
);
}

View File

@ -0,0 +1,54 @@
import type { PageParam, PageResult } from '@vben/request';
import { requestClient } from '#/api/request';
export namespace MesQcDefectApi {
/** MES 缺陷类型 */
export interface Defect {
id?: number; // 编号
code?: string; // 缺陷编码
name?: string; // 缺陷描述
type?: number; // 检测项类型
level?: number; // 缺陷等级
remark?: string; // 备注
createTime?: Date; // 创建时间
}
}
/** 查询缺陷类型分页 */
export function getDefectPage(params: PageParam) {
return requestClient.get<PageResult<MesQcDefectApi.Defect>>(
'/mes/qc/defect/page',
{ params },
);
}
/** 查询缺陷类型精简列表 */
export function getDefectSimpleList() {
return requestClient.get<MesQcDefectApi.Defect[]>('/mes/qc/defect/simple-list');
}
/** 查询缺陷类型详情 */
export function getDefect(id: number) {
return requestClient.get<MesQcDefectApi.Defect>(`/mes/qc/defect/get?id=${id}`);
}
/** 新增缺陷类型 */
export function createDefect(data: MesQcDefectApi.Defect) {
return requestClient.post('/mes/qc/defect/create', data);
}
/** 修改缺陷类型 */
export function updateDefect(data: MesQcDefectApi.Defect) {
return requestClient.put('/mes/qc/defect/update', data);
}
/** 删除缺陷类型 */
export function deleteDefect(id: number) {
return requestClient.delete(`/mes/qc/defect/delete?id=${id}`);
}
/** 导出缺陷类型 */
export function exportDefect(params: any) {
return requestClient.download('/mes/qc/defect/export-excel', { params });
}

View File

@ -0,0 +1,53 @@
import type { PageParam, PageResult } from '@vben/request';
import { requestClient } from '#/api/request';
export namespace MesQcIndicatorApi {
/** MES 质检指标 */
export interface Indicator {
id?: number; // 编号
code?: string; // 检测项编码
name?: string; // 检测项名称
type?: number; // 检测项类型
tool?: string; // 检测工具
resultType?: number; // 结果值类型
resultSpecification?: string; // 结果值属性
remark?: string; // 备注
createTime?: Date; // 创建时间
}
}
/** 查询质检指标分页 */
export function getIndicatorPage(params: PageParam) {
return requestClient.get<PageResult<MesQcIndicatorApi.Indicator>>(
'/mes/qc/indicator/page',
{ params },
);
}
/** 查询质检指标详情 */
export function getIndicator(id: number) {
return requestClient.get<MesQcIndicatorApi.Indicator>(
`/mes/qc/indicator/get?id=${id}`,
);
}
/** 新增质检指标 */
export function createIndicator(data: MesQcIndicatorApi.Indicator) {
return requestClient.post('/mes/qc/indicator/create', data);
}
/** 修改质检指标 */
export function updateIndicator(data: MesQcIndicatorApi.Indicator) {
return requestClient.put('/mes/qc/indicator/update', data);
}
/** 删除质检指标 */
export function deleteIndicator(id: number) {
return requestClient.delete(`/mes/qc/indicator/delete?id=${id}`);
}
/** 导出质检指标 */
export function exportIndicator(params: any) {
return requestClient.download('/mes/qc/indicator/export-excel', { params });
}

View File

@ -0,0 +1,51 @@
import type { PageParam, PageResult } from '@vben/request';
import { requestClient } from '#/api/request';
export namespace MesQcTemplateApi {
/** MES 质检方案 */
export interface Template {
id?: number; // 编号
code?: string; // 方案编号
name?: string; // 方案名称
types?: number[]; // 检测种类
status?: number; // 状态
remark?: string; // 备注
createTime?: Date; // 创建时间
}
}
/** 查询质检方案分页 */
export function getTemplatePage(params: PageParam) {
return requestClient.get<PageResult<MesQcTemplateApi.Template>>(
'/mes/qc/template/page',
{ params },
);
}
/** 查询质检方案详情 */
export function getTemplate(id: number) {
return requestClient.get<MesQcTemplateApi.Template>(
`/mes/qc/template/get?id=${id}`,
);
}
/** 新增质检方案 */
export function createTemplate(data: MesQcTemplateApi.Template) {
return requestClient.post('/mes/qc/template/create', data);
}
/** 修改质检方案 */
export function updateTemplate(data: MesQcTemplateApi.Template) {
return requestClient.put('/mes/qc/template/update', data);
}
/** 删除质检方案 */
export function deleteTemplate(id: number) {
return requestClient.delete(`/mes/qc/template/delete?id=${id}`);
}
/** 导出质检方案 */
export function exportTemplate(params: any) {
return requestClient.download('/mes/qc/template/export-excel', { params });
}

View File

@ -0,0 +1,57 @@
import type { PageParam, PageResult } from '@vben/request';
import { requestClient } from '#/api/request';
export namespace MesQcTemplateIndicatorApi {
/** MES 质检方案-检测指标项 */
export interface TemplateIndicator {
id?: number; // 编号
templateId?: number; // 质检方案ID
indicatorId?: number; // 质检指标ID
checkMethod?: string; // 检测方法
standardValue?: number; // 标准值
unitMeasureId?: number; // 计量单位ID
thresholdMax?: number; // 误差上限
thresholdMin?: number; // 误差下限
docUrl?: string; // 说明图URL
remark?: string; // 备注
indicatorCode?: string; // 检测项编码JOIN
indicatorName?: string; // 检测项名称JOIN
indicatorType?: number; // 检测项类型JOIN
indicatorTool?: string; // 检测工具JOIN
unitMeasureName?: string; // 计量单位名称JOIN
}
}
/** 查询检测指标项分页 */
export function getTemplateIndicatorPage(params: PageParam & { templateId?: number }) {
return requestClient.get<
PageResult<MesQcTemplateIndicatorApi.TemplateIndicator>
>('/mes/qc/template/indicator/page', { params });
}
/** 查询检测指标项详情 */
export function getTemplateIndicator(id: number) {
return requestClient.get<MesQcTemplateIndicatorApi.TemplateIndicator>(
`/mes/qc/template/indicator/get?id=${id}`,
);
}
/** 新增检测指标项 */
export function createTemplateIndicator(
data: MesQcTemplateIndicatorApi.TemplateIndicator,
) {
return requestClient.post('/mes/qc/template/indicator/create', data);
}
/** 修改检测指标项 */
export function updateTemplateIndicator(
data: MesQcTemplateIndicatorApi.TemplateIndicator,
) {
return requestClient.put('/mes/qc/template/indicator/update', data);
}
/** 删除检测指标项 */
export function deleteTemplateIndicator(id: number) {
return requestClient.delete(`/mes/qc/template/indicator/delete?id=${id}`);
}

View File

@ -0,0 +1,52 @@
import type { PageParam, PageResult } from '@vben/request';
import { requestClient } from '#/api/request';
export namespace MesQcTemplateItemApi {
/** MES 质检方案-产品关联 */
export interface TemplateItem {
id?: number; // 编号
templateId?: number; // 质检方案ID
itemId?: number; // 产品物料ID
quantityCheck?: number; // 最低检测数
quantityUnqualified?: number; // 最大不合格数
criticalRate?: number; // 最大致命缺陷率(%
majorRate?: number; // 最大严重缺陷率(%
minorRate?: number; // 最大轻微缺陷率(%
remark?: string; // 备注
itemCode?: string; // 物料编码JOIN
itemName?: string; // 物料名称JOIN
specification?: string; // 规格型号JOIN
unitMeasureName?: string; // 计量单位名称JOIN
}
}
/** 查询产品关联分页 */
export function getTemplateItemPage(params: PageParam & { templateId?: number }) {
return requestClient.get<PageResult<MesQcTemplateItemApi.TemplateItem>>(
'/mes/qc/template/item/page',
{ params },
);
}
/** 查询产品关联详情 */
export function getTemplateItem(id: number) {
return requestClient.get<MesQcTemplateItemApi.TemplateItem>(
`/mes/qc/template/item/get?id=${id}`,
);
}
/** 新增产品关联 */
export function createTemplateItem(data: MesQcTemplateItemApi.TemplateItem) {
return requestClient.post('/mes/qc/template/item/create', data);
}
/** 修改产品关联 */
export function updateTemplateItem(data: MesQcTemplateItemApi.TemplateItem) {
return requestClient.put('/mes/qc/template/item/update', data);
}
/** 删除产品关联 */
export function deleteTemplateItem(id: number) {
return requestClient.delete(`/mes/qc/template/item/delete?id=${id}`);
}

View File

@ -0,0 +1,49 @@
import type { PageParam, PageResult } from '@vben/request';
import { requestClient } from '#/api/request';
export namespace MesWmBarcodeConfigApi {
/** MES 条码配置 */
export interface BarcodeConfig {
id?: number; // 编号
format?: number; // 条码格式
bizType?: number; // 业务类型
contentFormat?: string; // 内容格式模板
contentExample?: string; // 内容样例
autoGenerateFlag?: boolean; // 是否自动生成
defaultTemplate?: string; // 默认打印模板
status?: number; // 状态
remark?: string; // 备注
createTime?: Date; // 创建时间
}
}
/** 查询条码配置分页 */
export function getBarcodeConfigPage(params: PageParam) {
return requestClient.get<PageResult<MesWmBarcodeConfigApi.BarcodeConfig>>(
'/mes/wm/barcode-config/page',
{ params },
);
}
/** 查询条码配置详情 */
export function getBarcodeConfig(id: number) {
return requestClient.get<MesWmBarcodeConfigApi.BarcodeConfig>(
`/mes/wm/barcode-config/get?id=${id}`,
);
}
/** 新增条码配置 */
export function createBarcodeConfig(data: MesWmBarcodeConfigApi.BarcodeConfig) {
return requestClient.post('/mes/wm/barcode-config/create', data);
}
/** 修改条码配置 */
export function updateBarcodeConfig(data: MesWmBarcodeConfigApi.BarcodeConfig) {
return requestClient.put('/mes/wm/barcode-config/update', data);
}
/** 删除条码配置 */
export function deleteBarcodeConfig(id: number) {
return requestClient.delete(`/mes/wm/barcode-config/delete?id=${id}`);
}

View File

@ -38,7 +38,7 @@ export function getBarcode(id: number) {
export function getBarcodeByBusiness(bizType: number, bizId: number) {
return requestClient.get<MesWmBarcodeApi.Barcode>(
'/mes/wm/barcode/get-by-business',
{ params: { bizType, bizId } },
{ params: { bizId, bizType } },
);
}
@ -57,9 +57,14 @@ export function deleteBarcode(id: number) {
return requestClient.delete(`/mes/wm/barcode/delete?id=${id}`);
}
/** 导出条码 */
export function exportBarcode(params: any) {
return requestClient.download('/mes/wm/barcode/export-excel', { params });
}
/** 生成条码内容 */
export function generateBarcodeContent(bizType: number, bizCode: string) {
return requestClient.get<string>('/mes/wm/barcode/generate-content', {
params: { bizType, bizCode },
params: { bizCode, bizType },
});
}

View File

@ -0,0 +1,37 @@
import type { PageParam, PageResult } from '@vben/request';
import { requestClient } from '#/api/request';
export namespace MesWmItemConsumeLineApi {
/** MES 物料消耗行 */
export interface ItemConsumeLine {
id?: number;
feedbackId?: number; // 报工编号
itemId?: number; // 物料编号
itemCode?: string; // 物资编码
itemName?: string; // 物资名称
specification?: string; // 规格型号
unitId?: number; // 单位编号
unitName?: string; // 单位
quantity?: number; // 消耗数量
batchCode?: string; // 批次号
locationId?: number; // 库位编号
locationName?: string; // 库位名称
remark?: string; // 备注
}
/** MES 物料消耗行分页查询参数 */
export interface PageParams extends PageParam {
feedbackId?: number;
}
}
/** 查询物料消耗行分页 */
export function getItemConsumeLinePage(
params: MesWmItemConsumeLineApi.PageParams,
) {
return requestClient.get<PageResult<MesWmItemConsumeLineApi.ItemConsumeLine>>(
'/mes/wm/item-consume-line/page',
{ params },
);
}

View File

@ -0,0 +1,61 @@
import type { PageParam, PageResult } from '@vben/request';
import { requestClient } from '#/api/request';
export namespace MesWmMaterialStockApi {
/** MES 库存台账 */
export interface MaterialStock {
id?: number; // 编号
itemTypeId?: number; // 物料分类编号
itemId?: number; // 物料编号
itemCode?: string; // 物料编码
itemName?: string; // 物料名称
specification?: string; // 规格型号
unitMeasureName?: string; // 计量单位名称
batchId?: number; // 批次编号
batchCode?: string; // 批次号
warehouseId?: number; // 仓库编号
warehouseCode?: string; // 仓库编码
warehouseName?: string; // 仓库名称
locationId?: number; // 库区编号
locationName?: string; // 库区名称
areaId?: number; // 库位编号
areaName?: string; // 库位名称
vendorId?: number; // 供应商编号
vendorName?: string; // 供应商名称
quantity?: number; // 在库数量
receiptTime?: string; // 入库日期
frozen?: boolean; // 是否冻结
createTime?: Date; // 创建时间
}
}
/** 查询库存台账分页 */
export function getMaterialStockPage(params: PageParam) {
return requestClient.get<PageResult<MesWmMaterialStockApi.MaterialStock>>(
'/mes/wm/material-stock/page',
{ params },
);
}
/** 查询库存台账详情 */
export function getMaterialStock(id: number) {
return requestClient.get<MesWmMaterialStockApi.MaterialStock>(
`/mes/wm/material-stock/get?id=${id}`,
);
}
/** 更新库存冻结状态 */
export function updateMaterialStockFrozen(data: {
frozen: boolean;
id: number;
}) {
return requestClient.put('/mes/wm/material-stock/update-frozen', data);
}
/** 导出库存台账 */
export function exportMaterialStock(params: any) {
return requestClient.download('/mes/wm/material-stock/export-excel', {
params,
});
}

View File

@ -0,0 +1,37 @@
import type { PageParam, PageResult } from '@vben/request';
import { requestClient } from '#/api/request';
export namespace MesWmProductProduceLineApi {
/** MES 产品产出行 */
export interface ProductProduceLine {
id?: number;
feedbackId?: number; // 报工编号
itemId?: number; // 物料编号
itemCode?: string; // 物资编码
itemName?: string; // 物资名称
specification?: string; // 规格型号
unitMeasureId?: number; // 单位编号
unitMeasureName?: string; // 单位
quantity?: number; // 产出数量
batchCode?: string; // 批次号
qualityStatus?: number; // 质量状态
locationId?: number; // 库位编号
locationName?: string; // 库位名称
remark?: string; // 备注
}
/** MES 产品产出行分页查询参数 */
export interface PageParams extends PageParam {
feedbackId?: number;
}
}
/** 查询产品产出行分页 */
export function getProductProduceLinePage(
params: MesWmProductProduceLineApi.PageParams,
) {
return requestClient.get<
PageResult<MesWmProductProduceLineApi.ProductProduceLine>
>('/mes/wm/product-produce-line/page', { params });
}

View File

@ -48,3 +48,18 @@ export function getWarehouseArea(id: number) {
`/mes/wm/warehouse-area/get?id=${id}`,
);
}
/** 新增库位 */
export function createWarehouseArea(data: MesWmWarehouseAreaApi.WarehouseArea) {
return requestClient.post('/mes/wm/warehouse-area/create', data);
}
/** 修改库位 */
export function updateWarehouseArea(data: MesWmWarehouseAreaApi.WarehouseArea) {
return requestClient.put('/mes/wm/warehouse-area/update', data);
}
/** 删除库位 */
export function deleteWarehouseArea(id: number) {
return requestClient.delete(`/mes/wm/warehouse-area/delete?id=${id}`);
}

View File

@ -38,3 +38,18 @@ export function getWarehouse(id: number) {
`/mes/wm/warehouse/get?id=${id}`,
);
}
/** 新增仓库 */
export function createWarehouse(data: MesWmWarehouseApi.Warehouse) {
return requestClient.post('/mes/wm/warehouse/create', data);
}
/** 修改仓库 */
export function updateWarehouse(data: MesWmWarehouseApi.Warehouse) {
return requestClient.put('/mes/wm/warehouse/update', data);
}
/** 删除仓库 */
export function deleteWarehouse(id: number) {
return requestClient.delete(`/mes/wm/warehouse/delete?id=${id}`);
}

View File

@ -38,3 +38,35 @@ export function getWarehouseLocation(id: number) {
`/mes/wm/warehouse-location/get?id=${id}`,
);
}
/** 新增库区 */
export function createWarehouseLocation(
data: MesWmWarehouseLocationApi.WarehouseLocation,
) {
return requestClient.post('/mes/wm/warehouse-location/create', data);
}
/** 修改库区 */
export function updateWarehouseLocation(
data: MesWmWarehouseLocationApi.WarehouseLocation,
) {
return requestClient.put('/mes/wm/warehouse-location/update', data);
}
/** 删除库区 */
export function deleteWarehouseLocation(id: number) {
return requestClient.delete(`/mes/wm/warehouse-location/delete?id=${id}`);
}
/** 批量设置库区下所有库位的混放规则 */
export function updateAreaByLocationId(
locationId: number,
allowItemMixing?: boolean,
allowBatchMixing?: boolean,
) {
return requestClient.put(
'/mes/wm/warehouse-location/update-by-location-id',
null,
{ params: { allowBatchMixing, allowItemMixing, locationId } },
);
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.8 KiB

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" fill="none" viewBox="0 0 12 12"><g clip-path="url(#a)"><path fill="url(#b)" fill-rule="evenodd" d="M6.958.42C6.444.216 5.61.216 5.098.42L1.15 1.975c-.77.304-.77.797 0 1.1l3.947 1.558c.514.202 1.347.202 1.86 0l3.948-1.557c.77-.304.77-.797 0-1.1L6.958.418ZM4.715 11.788a.857.857 0 0 0 .3.056c.383 0 .671-.295.671-.7V6.404c0-.49-.364-1.007-.817-1.177L1.09 3.805a.808.808 0 0 0-.284-.056c-.353 0-.581.275-.581.7V9.19c0 .508.33 1.014.763 1.177l3.726 1.422Zm2.229-.024h-.02l.073.003c.074.004.154.009.227-.019L11 10.367c.45-.168.83-.686.83-1.177V4.45c0-.413-.29-.7-.673-.7a.965.965 0 0 0-.317.055l-3.72 1.422c-.44.165-.75.67-.75 1.177v4.74c0 .42.218.621.575.621Z" clip-rule="evenodd"/></g><defs><linearGradient id="b" x1=".226" x2="11.803" y1=".267" y2="11.871" gradientUnits="userSpaceOnUse"><stop stop-color="#1B3149"/><stop offset="1" stop-color="#717D8A"/></linearGradient><clipPath id="a"><path fill="#fff" d="M0 0h12v12H0z"/></clipPath></defs></svg>

After

Width:  |  Height:  |  Size: 1011 B

View File

@ -4,6 +4,7 @@ import type { Dayjs } from 'dayjs';
import { onMounted, ref } from 'vue';
import { DatePicker, Radio, RadioGroup } from 'ant-design-vue';
import dayjs from 'dayjs';
import { getRangePickerDefaultProps } from '#/utils/rangePickerProps';
@ -19,8 +20,20 @@ const times = ref<[Dayjs, Dayjs]>(); // 日期范围
const rangePickerProps = getRangePickerDefaultProps();
const timeRangeOptions = [
rangePickerProps.presets[3]!, //
rangePickerProps.presets[1]!, // 7
rangePickerProps.presets[2]!, // 30
{
label: rangePickerProps.presets[1]!.label,
value: [
dayjs().subtract(7, 'day').startOf('day'),
dayjs().subtract(1, 'day').endOf('day'),
],
},
{
label: rangePickerProps.presets[2]!.label,
value: [
dayjs().subtract(30, 'day').startOf('day'),
dayjs().subtract(1, 'day').endOf('day'),
],
},
];
const timeRangeType = ref(timeRangeOptions[1]!.label); //

View File

@ -32,6 +32,7 @@ const props = withDefaults(defineProps<FileUploadProps>(), {
multiple: false,
api: undefined,
resultField: '',
returnText: false,
showDescription: false,
});
const emit = defineEmits([
@ -147,9 +148,6 @@ function handleUploadError(error: any) {
* @returns 是否允许上传
*/
async function beforeUpload(file: File) {
const fileContent = await file.text();
emit('returnText', fileContent);
//
if (fileList.value!.length >= props.maxNumber) {
message.error($t('ui.upload.maxNumber', [props.maxNumber]));
@ -176,6 +174,10 @@ async function beforeUpload(file: File) {
//
uploadNumber.value++;
if (props.returnText) {
const fileContent = await file.text();
emit('returnText', fileContent);
}
return true;
}

View File

@ -58,6 +58,7 @@ const textareaProps = computed(() => {
const fileUploadProps = computed(() => {
return {
...props.fileUploadProps,
returnText: true,
};
});
</script>

View File

@ -27,6 +27,7 @@ export interface FileUploadProps {
maxSize?: number; // 文件最大多少MB
multiple?: boolean; // 是否支持多选
resultField?: string; // support xxx.xxx.xx
returnText?: boolean; // 是否返回文件文本内容
showDescription?: boolean; // 是否显示下面的描述
value?: string | string[];
}

View File

@ -12,7 +12,7 @@ const routes: RouteRecordRaw[] = [
},
children: [
{
path: 'product/detail/:id',
path: 'product/product/detail/:id',
name: 'IoTProductDetail',
meta: {
title: '产品详情',
@ -30,11 +30,11 @@ const routes: RouteRecordRaw[] = [
component: () => import('#/views/iot/device/device/detail/index.vue'),
},
{
path: 'ota/firmware/detail/:id',
path: 'ota/operation/firmware/detail/:id',
name: 'IoTOtaFirmwareDetail',
meta: {
title: '固件详情',
activePath: '/iot/ota',
activePath: '/iot/operation/ota/firmware',
},
component: () => import('#/views/iot/ota/firmware/detail/index.vue'),
},

View File

@ -38,24 +38,21 @@ async function handleUpdatePublicStatusChange(
row: AiImageApi.Image,
): Promise<boolean | undefined> {
const text = newStatus ? '公开' : '私有';
return new Promise((resolve, reject) => {
confirm({
try {
await confirm({
content: `确认要将该图片切换为【${text}】吗?`,
})
.then(async () => {
//
await updateImage({
id: row.id,
publicStatus: newStatus,
});
//
message.success($t('ui.actionMessage.operationSuccess'));
resolve(true);
})
.catch(() => {
reject(new Error('取消操作'));
});
});
} catch {
return false;
}
//
await updateImage({
id: row.id,
publicStatus: newStatus,
});
//
message.success($t('ui.actionMessage.operationSuccess'));
return true;
}
const [Grid, gridApi] = useVbenVxeGrid({

View File

@ -76,24 +76,21 @@ async function handleStatusChange(
newStatus: number,
row: AiKnowledgeDocumentApi.KnowledgeDocument,
): Promise<boolean | undefined> {
return new Promise((resolve, reject) => {
confirm({
try {
await confirm({
content: `你要将${row.name}的状态切换为【${getDictLabel(DICT_TYPE.COMMON_STATUS, newStatus)}】吗?`,
})
.then(async () => {
//
await updateKnowledgeDocumentStatus({
id: row.id,
status: newStatus,
});
//
message.success($t('ui.actionMessage.operationSuccess'));
resolve(true);
})
.catch(() => {
reject(new Error('取消操作'));
});
});
} catch {
return false;
}
//
await updateKnowledgeDocumentStatus({
id: row.id,
status: newStatus,
});
//
message.success($t('ui.actionMessage.operationSuccess'));
return true;
}
const [Grid, gridApi] = useVbenVxeGrid({

View File

@ -64,21 +64,18 @@ async function handleStatusChange(
newStatus: number,
row: AiKnowledgeSegmentApi.KnowledgeSegment,
): Promise<boolean | undefined> {
return new Promise((resolve, reject) => {
confirm({
try {
await confirm({
content: `你要将片段 ${row.id} 的状态切换为【${getDictLabel(DICT_TYPE.COMMON_STATUS, newStatus)}】吗?`,
})
.then(async () => {
//
await updateKnowledgeSegmentStatus(row.id!, newStatus);
//
message.success($t('ui.actionMessage.operationSuccess'));
resolve(true);
})
.catch(() => {
reject(new Error('取消操作'));
});
});
});
} catch {
return false;
}
//
await updateKnowledgeSegmentStatus(row.id!, newStatus);
//
message.success($t('ui.actionMessage.operationSuccess'));
return true;
}
const [Grid, gridApi] = useVbenVxeGrid({

View File

@ -38,24 +38,21 @@ async function handleUpdatePublicStatusChange(
row: AiMusicApi.Music,
): Promise<boolean | undefined> {
const text = newStatus ? '公开' : '私有';
return new Promise((resolve, reject) => {
confirm({
try {
await confirm({
content: `确认要将该音乐切换为【${text}】吗?`,
})
.then(async () => {
//
await updateMusic({
id: row.id,
publicStatus: newStatus,
});
//
message.success($t('ui.actionMessage.operationSuccess'));
resolve(true);
})
.catch(() => {
reject(new Error('取消操作'));
});
});
} catch {
return false;
}
//
await updateMusic({
id: row.id,
publicStatus: newStatus,
});
//
message.success($t('ui.actionMessage.operationSuccess'));
return true;
}
const [Grid, gridApi] = useVbenVxeGrid({

View File

@ -74,28 +74,24 @@ async function handleDeleteContactBusinessList() {
message.error('请先选择商机后操作!');
return;
}
return new Promise((resolve, reject) => {
confirm({
try {
await confirm({
content: `确定要将${checkedRows.value.map((item) => item.name).join(',')}解除关联吗?`,
})
.then(async () => {
const res = await deleteContactBusinessList({
contactId: props.bizId,
businessIds: checkedRows.value.map((item) => item.id),
});
if (res) {
//
message.success($t('ui.actionMessage.operationSuccess'));
handleRefresh();
resolve(true);
} else {
reject(new Error($t('ui.actionMessage.operationFailed')));
}
})
.catch(() => {
reject(new Error('取消操作'));
});
});
} catch {
return false;
}
const res = await deleteContactBusinessList({
contactId: props.bizId,
businessIds: checkedRows.value.map((item) => item.id),
});
if (!res) {
throw new Error($t('ui.actionMessage.operationFailed'));
}
//
message.success($t('ui.actionMessage.operationSuccess'));
handleRefresh();
return true;
}
/** 查看商机详情 */

View File

@ -83,21 +83,18 @@ function handleTransfer() {
/** 转化为客户 */
async function handleTransform(): Promise<boolean | undefined> {
return new Promise((resolve, reject) => {
confirm({
try {
await confirm({
content: '确定将该线索转化为客户吗?',
})
.then(async () => {
//
await transformClue(clueId.value);
//
message.success('转化客户成功');
resolve(true);
})
.catch(() => {
reject(new Error('取消操作'));
});
});
});
} catch {
return false;
}
//
await transformClue(clueId.value);
//
message.success('转化客户成功');
return true;
}
/** 加载数据 */

View File

@ -71,28 +71,24 @@ async function handleDeleteContactBusinessList() {
message.error('请先选择联系人后操作!');
return;
}
return new Promise((resolve, reject) => {
confirm({
try {
await confirm({
content: `确定要将${checkedRows.value.map((item) => item.name).join(',')}解除关联吗?`,
})
.then(async () => {
const res = await deleteBusinessContactList({
businessId: props.bizId,
contactIds: checkedRows.value.map((item) => item.id),
});
if (res) {
//
message.success($t('ui.actionMessage.operationSuccess'));
handleRefresh();
resolve(true);
} else {
reject(new Error($t('ui.actionMessage.operationFailed')));
}
})
.catch(() => {
reject(new Error('取消操作'));
});
});
} catch {
return false;
}
const res = await deleteBusinessContactList({
businessId: props.bizId,
contactIds: checkedRows.value.map((item) => item.id),
});
if (!res) {
throw new Error($t('ui.actionMessage.operationFailed'));
}
//
message.success($t('ui.actionMessage.operationSuccess'));
handleRefresh();
return true;
}
/** 创建商机联系人关联 */

View File

@ -100,41 +100,35 @@ function handleTransfer() {
}
/** 锁定客户 */
function handleLock(lockStatus: boolean): Promise<boolean | undefined> {
return new Promise((resolve, reject) => {
confirm({
async function handleLock(lockStatus: boolean): Promise<boolean | undefined> {
try {
await confirm({
content: `确定锁定客户【${customer.value.name}】吗?`,
})
.then(async () => {
//
await lockCustomer(customerId.value, lockStatus);
//
message.success(lockStatus ? '锁定客户成功' : '解锁客户成功');
resolve(true);
})
.catch(() => {
reject(new Error('取消操作'));
});
});
});
} catch {
return false;
}
//
await lockCustomer(customerId.value, lockStatus);
//
message.success(lockStatus ? '锁定客户成功' : '解锁客户成功');
return true;
}
/** 领取客户 */
function handleReceive(): Promise<boolean | undefined> {
return new Promise((resolve, reject) => {
confirm({
async function handleReceive(): Promise<boolean | undefined> {
try {
await confirm({
content: `确定领取客户【${customer.value.name}】吗?`,
})
.then(async () => {
//
await receiveCustomer([customerId.value]);
//
message.success('领取客户成功');
resolve(true);
})
.catch(() => {
reject(new Error('取消操作'));
});
});
});
} catch {
return false;
}
//
await receiveCustomer([customerId.value]);
//
message.success('领取客户成功');
return true;
}
/** 分配客户 */
@ -143,42 +137,36 @@ function handleDistributeForm() {
}
/** 客户放入公海 */
function handlePutPool(): Promise<boolean | undefined> {
return new Promise((resolve, reject) => {
confirm({
async function handlePutPool(): Promise<boolean | undefined> {
try {
await confirm({
content: `确定将客户【${customer.value.name}】放入公海吗?`,
})
.then(async () => {
//
await putCustomerPool(customerId.value);
//
message.success('放入公海成功');
resolve(true);
})
.catch(() => {
reject(new Error('取消操作'));
});
});
});
} catch {
return false;
}
//
await putCustomerPool(customerId.value);
//
message.success('放入公海成功');
return true;
}
/** 更新成交状态操作 */
async function handleUpdateDealStatus(): Promise<boolean | undefined> {
return new Promise((resolve, reject) => {
const dealStatus = !customer.value.dealStatus;
confirm({
const dealStatus = !customer.value.dealStatus;
try {
await confirm({
content: `确定更新成交状态为【${dealStatus ? '已成交' : '未成交'}】吗?`,
})
.then(async () => {
//
await updateCustomerDealStatus(customerId.value, dealStatus);
//
message.success('更新成交状态成功');
resolve(true);
})
.catch(() => {
reject(new Error('取消操作'));
});
});
});
} catch {
return false;
}
//
await updateCustomerDealStatus(customerId.value, dealStatus);
//
message.success('更新成交状态成功');
return true;
}
/** 加载数据 */

View File

@ -94,32 +94,28 @@ function handleEdit() {
}
/** 删除团队成员 */
function handleDelete() {
async function handleDelete() {
if (checkedRows.value.length === 0) {
message.error('请先选择团队成员后操作!');
return;
}
return new Promise((resolve, reject) => {
confirm({
try {
await confirm({
content: `你要将${checkedRows.value.map((item) => item.nickname).join(',')}移出团队吗?`,
})
.then(async () => {
const res = await deletePermissionBatch(
checkedRows.value.map((item) => item.id!),
);
if (res) {
//
message.success($t('ui.actionMessage.operationSuccess'));
handleRefresh();
resolve(true);
} else {
reject(new Error('移出失败'));
}
})
.catch(() => {
reject(new Error('取消操作'));
});
});
});
} catch {
return false;
}
const res = await deletePermissionBatch(
checkedRows.value.map((item) => item.id!),
);
if (!res) {
throw new Error('移出失败');
}
//
message.success($t('ui.actionMessage.operationSuccess'));
handleRefresh();
return true;
}
/** 退出团队 */

View File

@ -65,23 +65,20 @@ async function handleDefaultStatusChange(
newStatus: boolean,
row: ErpAccountApi.Account,
): Promise<boolean | undefined> {
return new Promise((resolve, reject) => {
const text = newStatus ? '设置' : '取消';
confirm({
const text = newStatus ? '设置' : '取消';
try {
await confirm({
content: `确认要${text}"${row.name}"默认吗?`,
})
.then(async () => {
//
await updateAccountDefaultStatus(row.id!, newStatus);
//
message.success(`${text}默认成功`);
handleRefresh();
resolve(true);
})
.catch(() => {
reject(new Error('取消操作'));
});
});
});
} catch {
return false;
}
//
await updateAccountDefaultStatus(row.id!, newStatus);
//
message.success(`${text}默认成功`);
handleRefresh();
return true;
}
const [Grid, gridApi] = useVbenVxeGrid({

View File

@ -10,8 +10,11 @@ import { getSupplierSimpleList } from '#/api/erp/purchase/supplier';
import { getSimpleUserList } from '#/api/system/user';
import { getRangePickerDefaultProps } from '#/utils';
/** 表单类型 */
export type FormType = 'create' | 'detail' | 'edit';
/** 表单的配置项 */
export function useFormSchema(formType: string): VbenFormSchema[] {
export function useFormSchema(formType: FormType): VbenFormSchema[] {
return [
{
fieldName: 'id',

View File

@ -42,12 +42,12 @@ async function handleExport() {
/** 新增付款单 */
function handleCreate() {
formModalApi.setData({ type: 'create' }).open();
formModalApi.setData({ formType: 'create' }).open();
}
/** 编辑付款单 */
function handleEdit(row: ErpFinancePaymentApi.FinancePayment) {
formModalApi.setData({ type: 'edit', id: row.id }).open();
formModalApi.setData({ formType: 'edit', id: row.id }).open();
}
/** 删除付款单 */
@ -94,7 +94,7 @@ function handleRowCheckboxChange({
/** 查看详情 */
function handleDetail(row: ErpFinancePaymentApi.FinancePayment) {
formModalApi.setData({ type: 'detail', id: row.id }).open();
formModalApi.setData({ formType: 'detail', id: row.id }).open();
}
const [Grid, gridApi] = useVbenVxeGrid({

View File

@ -1,4 +1,6 @@
<script lang="ts" setup>
import type { FormType } from '../data';
import type { ErpFinancePaymentApi } from '#/api/erp/finance/payment';
import { computed, ref } from 'vue';
@ -40,7 +42,7 @@ const formData = ref<
status: 0,
});
const formType = ref(''); // 'create' | 'edit' | 'detail'
const formType = ref<FormType>('create'); // 'create' | 'edit' | 'detail'
const itemFormRef = ref<InstanceType<typeof ItemForm>>();
const getTitle = computed(() => {
@ -145,8 +147,8 @@ const [Modal, modalApi] = useVbenModal({
return;
}
//
const data = modalApi.getData<{ id?: number; type: string }>();
formType.value = data.type;
const data = modalApi.getData<{ formType: FormType; id?: number }>();
formType.value = data.formType;
formApi.setDisabled(formType.value === 'detail');
formApi.updateSchema(useFormSchema(formType.value));
if (!data || !data.id) {

View File

@ -10,8 +10,11 @@ import { getCustomerSimpleList } from '#/api/erp/sale/customer';
import { getSimpleUserList } from '#/api/system/user';
import { getRangePickerDefaultProps } from '#/utils';
/** 表单类型 */
export type FormType = 'create' | 'detail' | 'edit';
/** 表单的配置项 */
export function useFormSchema(formType: string): VbenFormSchema[] {
export function useFormSchema(formType: FormType): VbenFormSchema[] {
return [
{
fieldName: 'id',

View File

@ -42,12 +42,12 @@ async function handleExport() {
/** 新增收款单 */
function handleCreate() {
formModalApi.setData({ type: 'create' }).open();
formModalApi.setData({ formType: 'create' }).open();
}
/** 编辑收款单 */
function handleEdit(row: ErpFinanceReceiptApi.FinanceReceipt) {
formModalApi.setData({ type: 'edit', id: row.id }).open();
formModalApi.setData({ formType: 'edit', id: row.id }).open();
}
/** 删除收款单 */
@ -94,7 +94,7 @@ function handleRowCheckboxChange({
/** 查看详情 */
function handleDetail(row: ErpFinanceReceiptApi.FinanceReceipt) {
formModalApi.setData({ type: 'detail', id: row.id }).open();
formModalApi.setData({ formType: 'detail', id: row.id }).open();
}
const [Grid, gridApi] = useVbenVxeGrid({

View File

@ -1,4 +1,6 @@
<script lang="ts" setup>
import type { FormType } from '../data';
import type { ErpFinanceReceiptApi } from '#/api/erp/finance/receipt';
import { computed, ref } from 'vue';
@ -40,7 +42,7 @@ const formData = ref<
status: 0,
});
const formType = ref(''); // 'create' | 'edit' | 'detail'
const formType = ref<FormType>('create'); // 'create' | 'edit' | 'detail'
const itemFormRef = ref<InstanceType<typeof ItemForm>>();
const getTitle = computed(() => {
@ -159,8 +161,8 @@ const [Modal, modalApi] = useVbenModal({
return;
}
//
const data = modalApi.getData<{ id?: number; type: string }>();
formType.value = data.type;
const data = modalApi.getData<{ formType: FormType; id?: number }>();
formType.value = data.formType;
formApi.setDisabled(formType.value === 'detail');
formApi.updateSchema(useFormSchema(formType.value));
if (!data || !data.id) {

View File

@ -13,8 +13,11 @@ import { getWarehouseSimpleList } from '#/api/erp/stock/warehouse';
import { getSimpleUserList } from '#/api/system/user';
import { getRangePickerDefaultProps } from '#/utils';
/** 表单类型 */
export type FormType = 'create' | 'detail' | 'edit';
/** 表单的配置项 */
export function useFormSchema(formType: string): VbenFormSchema[] {
export function useFormSchema(formType: FormType): VbenFormSchema[] {
return [
{
fieldName: 'id',

View File

@ -42,12 +42,12 @@ async function handleExport() {
/** 新增采购入库 */
function handleCreate() {
formModalApi.setData({ type: 'create' }).open();
formModalApi.setData({ formType: 'create' }).open();
}
/** 编辑采购入库 */
function handleEdit(row: ErpPurchaseInApi.PurchaseIn) {
formModalApi.setData({ type: 'edit', id: row.id }).open();
formModalApi.setData({ formType: 'edit', id: row.id }).open();
}
/** 删除采购入库 */
@ -94,7 +94,7 @@ function handleRowCheckboxChange({
/** 查看详情 */
function handleDetail(row: ErpPurchaseInApi.PurchaseIn) {
formModalApi.setData({ type: 'detail', id: row.id }).open();
formModalApi.setData({ formType: 'detail', id: row.id }).open();
}
const [Grid, gridApi] = useVbenVxeGrid({

View File

@ -1,4 +1,6 @@
<script lang="ts" setup>
import type { FormType } from '../data';
import type { ErpPurchaseInApi } from '#/api/erp/purchase/in';
import type { ErpPurchaseOrderApi } from '#/api/erp/purchase/order';
@ -46,7 +48,7 @@ const formData = ref<
otherPrice: 0,
items: [],
});
const formType = ref(''); // 'create' | 'edit' | 'detail'
const formType = ref<FormType>('create'); // 'create' | 'edit' | 'detail'
const itemFormRef = ref<InstanceType<typeof ItemForm>>();
const getTitle = computed(() => {
@ -175,8 +177,8 @@ const [Modal, modalApi] = useVbenModal({
return;
}
//
const data = modalApi.getData<{ id?: number; type: string }>();
formType.value = data.type;
const data = modalApi.getData<{ formType: FormType; id?: number }>();
formType.value = data.formType;
formApi.setDisabled(formType.value === 'detail');
formApi.updateSchema(useFormSchema(formType.value));
if (!data || !data.id) {

View File

@ -12,8 +12,11 @@ import { getSupplierSimpleList } from '#/api/erp/purchase/supplier';
import { getSimpleUserList } from '#/api/system/user';
import { getRangePickerDefaultProps } from '#/utils';
/** 表单类型 */
export type FormType = 'create' | 'detail' | 'edit';
/** 表单的配置项 */
export function useFormSchema(formType: string): VbenFormSchema[] {
export function useFormSchema(formType: FormType): VbenFormSchema[] {
return [
{
fieldName: 'id',

View File

@ -42,12 +42,12 @@ async function handleExport() {
/** 新增采购订单 */
function handleCreate() {
formModalApi.setData({ type: 'create' }).open();
formModalApi.setData({ formType: 'create' }).open();
}
/** 编辑采购订单 */
function handleEdit(row: ErpPurchaseOrderApi.PurchaseOrder) {
formModalApi.setData({ type: 'edit', id: row.id }).open();
formModalApi.setData({ formType: 'edit', id: row.id }).open();
}
/** 删除采购订单 */
@ -94,7 +94,7 @@ function handleRowCheckboxChange({
/** 查看详情 */
function handleDetail(row: ErpPurchaseOrderApi.PurchaseOrder) {
formModalApi.setData({ type: 'detail', id: row.id }).open();
formModalApi.setData({ formType: 'detail', id: row.id }).open();
}
const [Grid, gridApi] = useVbenVxeGrid({

View File

@ -1,4 +1,6 @@
<script lang="ts" setup>
import type { FormType } from '../data';
import type { ErpPurchaseOrderApi } from '#/api/erp/purchase/order';
import { computed, ref } from 'vue';
@ -21,7 +23,7 @@ import PurchaseOrderItemForm from './item-form.vue';
const emit = defineEmits(['success']);
const formData = ref<ErpPurchaseOrderApi.PurchaseOrder>();
const formType = ref(''); // 'create' | 'edit' | 'detail'
const formType = ref<FormType>('create'); // 'create' | 'edit' | 'detail'
const itemFormRef = ref<InstanceType<typeof PurchaseOrderItemForm>>();
const getTitle = computed(() => {
@ -124,8 +126,8 @@ const [Modal, modalApi] = useVbenModal({
return;
}
//
const data = modalApi.getData<{ id?: number; type: string }>();
formType.value = data.type;
const data = modalApi.getData<{ formType: FormType; id?: number }>();
formType.value = data.formType;
formApi.setDisabled(formType.value === 'detail');
formApi.updateSchema(useFormSchema(formType.value));
if (!data || !data.id) {

View File

@ -13,8 +13,11 @@ import { getWarehouseSimpleList } from '#/api/erp/stock/warehouse';
import { getSimpleUserList } from '#/api/system/user';
import { getRangePickerDefaultProps } from '#/utils';
/** 表单类型 */
export type FormType = 'create' | 'detail' | 'edit';
/** 表单的配置项 */
export function useFormSchema(formType: string): VbenFormSchema[] {
export function useFormSchema(formType: FormType): VbenFormSchema[] {
return [
{
fieldName: 'id',

View File

@ -45,17 +45,17 @@ function handleRowCheckboxChange({
/** 新增采购退货 */
function handleCreate() {
formModalApi.setData({ type: 'create' }).open();
formModalApi.setData({ formType: 'create' }).open();
}
/** 编辑采购退货 */
function handleEdit(row: ErpPurchaseReturnApi.PurchaseReturn) {
formModalApi.setData({ type: 'edit', id: row.id }).open();
formModalApi.setData({ formType: 'edit', id: row.id }).open();
}
/** 查看详情 */
function handleDetail(row: ErpPurchaseReturnApi.PurchaseReturn) {
formModalApi.setData({ type: 'detail', id: row.id }).open();
formModalApi.setData({ formType: 'detail', id: row.id }).open();
}
/** 删除采购退货 */

View File

@ -1,4 +1,6 @@
<script lang="ts" setup>
import type { FormType } from '../data';
import type { ErpPurchaseOrderApi } from '#/api/erp/purchase/order';
import type { ErpPurchaseReturnApi } from '#/api/erp/purchase/return';
@ -46,7 +48,7 @@ const formData = ref<
otherPrice: 0,
items: [],
});
const formType = ref(''); // 'create' | 'edit' | 'detail'
const formType = ref<FormType>('create'); // 'create' | 'edit' | 'detail'
const itemFormRef = ref<InstanceType<typeof ItemForm>>();
/* eslint-disable unicorn/no-nested-ternary */
@ -175,8 +177,8 @@ const [Modal, modalApi] = useVbenModal({
return;
}
//
const data = modalApi.getData<{ id?: number; type: string }>();
formType.value = data.type;
const data = modalApi.getData<{ formType: FormType; id?: number }>();
formType.value = data.formType;
formApi.setDisabled(formType.value === 'detail');
formApi.updateSchema(useFormSchema(formType.value));
if (!data || !data.id) {

View File

@ -12,8 +12,11 @@ import { getCustomerSimpleList } from '#/api/erp/sale/customer';
import { getSimpleUserList } from '#/api/system/user';
import { getRangePickerDefaultProps } from '#/utils';
/** 表单类型 */
export type FormType = 'create' | 'detail' | 'edit';
/** 表单的配置项 */
export function useFormSchema(formType: string): VbenFormSchema[] {
export function useFormSchema(formType: FormType): VbenFormSchema[] {
return [
{
fieldName: 'id',

View File

@ -42,12 +42,12 @@ async function handleExport() {
/** 新增销售订单 */
function handleCreate() {
formModalApi.setData({ type: 'create' }).open();
formModalApi.setData({ formType: 'create' }).open();
}
/** 编辑销售订单 */
function handleEdit(row: ErpSaleOrderApi.SaleOrder) {
formModalApi.setData({ type: 'edit', id: row.id }).open();
formModalApi.setData({ formType: 'edit', id: row.id }).open();
}
/** 删除销售订单 */
@ -94,7 +94,7 @@ function handleRowCheckboxChange({
/** 查看详情 */
function handleDetail(row: ErpSaleOrderApi.SaleOrder) {
formModalApi.setData({ type: 'detail', id: row.id }).open();
formModalApi.setData({ formType: 'detail', id: row.id }).open();
}
const [Grid, gridApi] = useVbenVxeGrid({

View File

@ -1,4 +1,6 @@
<script lang="ts" setup>
import type { FormType } from '../data';
import type { ErpSaleOrderApi } from '#/api/erp/sale/order';
import { computed, ref } from 'vue';
@ -21,7 +23,7 @@ import ItemForm from './item-form.vue';
const emit = defineEmits(['success']);
const formData = ref<ErpSaleOrderApi.SaleOrder>();
const formType = ref(''); // 'create' | 'edit' | 'detail'
const formType = ref<FormType>('create'); // 'create' | 'edit' | 'detail'
const itemFormRef = ref<InstanceType<typeof ItemForm>>();
const getTitle = computed(() => {
@ -114,8 +116,8 @@ const [Modal, modalApi] = useVbenModal({
return;
}
//
const data = modalApi.getData<{ id?: number; type: string }>();
formType.value = data.type;
const data = modalApi.getData<{ formType: FormType; id?: number }>();
formType.value = data.formType;
formApi.setDisabled(formType.value === 'detail');
formApi.updateSchema(useFormSchema(formType.value));
if (!data || !data.id) {

View File

@ -13,8 +13,11 @@ import { getWarehouseSimpleList } from '#/api/erp/stock/warehouse';
import { getSimpleUserList } from '#/api/system/user';
import { getRangePickerDefaultProps } from '#/utils';
/** 表单类型 */
export type FormType = 'create' | 'detail' | 'edit';
/** 表单的配置项 */
export function useFormSchema(formType: string): VbenFormSchema[] {
export function useFormSchema(formType: FormType): VbenFormSchema[] {
return [
{
fieldName: 'id',

View File

@ -42,12 +42,12 @@ async function handleExport() {
/** 新增销售出库 */
function handleCreate() {
formModalApi.setData({ type: 'create' }).open();
formModalApi.setData({ formType: 'create' }).open();
}
/** 编辑销售出库 */
function handleEdit(row: ErpSaleOutApi.SaleOut) {
formModalApi.setData({ type: 'edit', id: row.id }).open();
formModalApi.setData({ formType: 'edit', id: row.id }).open();
}
/** 删除销售出库 */
@ -91,7 +91,7 @@ function handleRowCheckboxChange({
/** 查看详情 */
function handleDetail(row: ErpSaleOutApi.SaleOut) {
formModalApi.setData({ type: 'detail', id: row.id }).open();
formModalApi.setData({ formType: 'detail', id: row.id }).open();
}
const [Grid, gridApi] = useVbenVxeGrid({

View File

@ -1,4 +1,6 @@
<script lang="ts" setup>
import type { FormType } from '../data';
import type { ErpSaleOrderApi } from '#/api/erp/sale/order';
import type { ErpSaleOutApi } from '#/api/erp/sale/out';
@ -42,7 +44,7 @@ const formData = ref<
otherPrice: 0,
items: [],
});
const formType = ref(''); // 'create' | 'edit' | 'detail'
const formType = ref<FormType>('create'); // 'create' | 'edit' | 'detail'
const itemFormRef = ref<InstanceType<typeof ItemForm>>();
/* eslint-disable unicorn/no-nested-ternary */
@ -170,8 +172,8 @@ const [Modal, modalApi] = useVbenModal({
return;
}
//
const data = modalApi.getData<{ id?: number; type: string }>();
formType.value = data.type;
const data = modalApi.getData<{ formType: FormType; id?: number }>();
formType.value = data.formType;
formApi.setDisabled(formType.value === 'detail');
formApi.updateSchema(useFormSchema(formType.value));
if (!data || !data.id) {

View File

@ -13,8 +13,11 @@ import { getWarehouseSimpleList } from '#/api/erp/stock/warehouse';
import { getSimpleUserList } from '#/api/system/user';
import { getRangePickerDefaultProps } from '#/utils';
/** 表单类型 */
export type FormType = 'create' | 'detail' | 'edit';
/** 表单的配置项 */
export function useFormSchema(formType: string): VbenFormSchema[] {
export function useFormSchema(formType: FormType): VbenFormSchema[] {
return [
{
fieldName: 'id',

View File

@ -42,12 +42,12 @@ async function handleExport() {
/** 新增销售退货 */
function handleCreate() {
formModalApi.setData({ type: 'create' }).open();
formModalApi.setData({ formType: 'create' }).open();
}
/** 编辑销售退货 */
function handleEdit(row: ErpSaleReturnApi.SaleReturn) {
formModalApi.setData({ type: 'edit', id: row.id }).open();
formModalApi.setData({ formType: 'edit', id: row.id }).open();
}
/** 删除销售退货 */
@ -94,7 +94,7 @@ function handleRowCheckboxChange({
/** 查看详情 */
function handleDetail(row: ErpSaleReturnApi.SaleReturn) {
formModalApi.setData({ type: 'detail', id: row.id }).open();
formModalApi.setData({ formType: 'detail', id: row.id }).open();
}
const [Grid, gridApi] = useVbenVxeGrid({

View File

@ -1,4 +1,6 @@
<script lang="ts" setup>
import type { FormType } from '../data';
import type { ErpSaleOrderApi } from '#/api/erp/sale/order';
import type { ErpSaleReturnApi } from '#/api/erp/sale/return';
@ -46,7 +48,7 @@ const formData = ref<
otherPrice: 0,
items: [],
});
const formType = ref(''); // 'create' | 'edit' | 'detail'
const formType = ref<FormType>('create'); // 'create' | 'edit' | 'detail'
const itemFormRef = ref<InstanceType<typeof ItemForm>>();
const getTitle = computed(() => {
@ -175,8 +177,8 @@ const [Modal, modalApi] = useVbenModal({
return;
}
//
const data = modalApi.getData<{ id?: number; type: string }>();
formType.value = data.type;
const data = modalApi.getData<{ formType: FormType; id?: number }>();
formType.value = data.formType;
formApi.setDisabled(formType.value === 'detail');
formApi.updateSchema(useFormSchema(formType.value));
if (!data || !data.id) {

View File

@ -9,8 +9,11 @@ import { getWarehouseSimpleList } from '#/api/erp/stock/warehouse';
import { getSimpleUserList } from '#/api/system/user';
import { getRangePickerDefaultProps } from '#/utils';
/** 表单类型 */
export type FormType = 'create' | 'detail' | 'edit';
/** 表单的配置项 */
export function useFormSchema(formType: string): VbenFormSchema[] {
export function useFormSchema(formType: FormType): VbenFormSchema[] {
return [
{
fieldName: 'id',

View File

@ -42,12 +42,12 @@ async function handleExport() {
/** 新增库存盘点单 */
function handleCreate() {
formModalApi.setData({ type: 'create' }).open();
formModalApi.setData({ formType: 'create' }).open();
}
/** 编辑库存盘点单 */
function handleEdit(row: ErpStockCheckApi.StockCheck) {
formModalApi.setData({ type: 'edit', id: row.id }).open();
formModalApi.setData({ formType: 'edit', id: row.id }).open();
}
/** 删除库存盘点单 */
@ -94,7 +94,7 @@ function handleRowCheckboxChange({
/** 查看详情 */
function handleDetail(row: ErpStockCheckApi.StockCheck) {
formModalApi.setData({ type: 'detail', id: row.id }).open();
formModalApi.setData({ formType: 'detail', id: row.id }).open();
}
const [Grid, gridApi] = useVbenVxeGrid({

View File

@ -1,4 +1,6 @@
<script lang="ts" setup>
import type { FormType } from '../data';
import type { ErpStockCheckApi } from '#/api/erp/stock/check';
import { computed, ref } from 'vue';
@ -20,7 +22,7 @@ import ItemForm from './item-form.vue';
const emit = defineEmits(['success']);
const formData = ref<ErpStockCheckApi.StockCheck>();
const formType = ref(''); // 'create' | 'edit' | 'detail'
const formType = ref<FormType>('create'); // 'create' | 'edit' | 'detail'
const itemFormRef = ref<InstanceType<typeof ItemForm>>();
const getTitle = computed(() => {
@ -93,8 +95,8 @@ const [Modal, modalApi] = useVbenModal({
return;
}
//
const data = modalApi.getData<{ id?: number; type: string }>();
formType.value = data.type;
const data = modalApi.getData<{ formType: FormType; id?: number }>();
formType.value = data.formType;
formApi.setDisabled(formType.value === 'detail');
formApi.updateSchema(useFormSchema(formType.value));
if (!data || !data.id) {

View File

@ -10,8 +10,11 @@ import { getWarehouseSimpleList } from '#/api/erp/stock/warehouse';
import { getSimpleUserList } from '#/api/system/user';
import { getRangePickerDefaultProps } from '#/utils';
/** 表单类型 */
export type FormType = 'create' | 'detail' | 'edit';
/** 表单的配置项 */
export function useFormSchema(formType: string): VbenFormSchema[] {
export function useFormSchema(formType: FormType): VbenFormSchema[] {
return [
{
fieldName: 'id',

View File

@ -42,12 +42,12 @@ async function handleExport() {
/** 新增其它入库单 */
function handleCreate() {
formModalApi.setData({ type: 'create' }).open();
formModalApi.setData({ formType: 'create' }).open();
}
/** 编辑其它入库单 */
function handleEdit(row: ErpStockInApi.StockIn) {
formModalApi.setData({ type: 'edit', id: row.id }).open();
formModalApi.setData({ formType: 'edit', id: row.id }).open();
}
/** 删除其它入库单 */
@ -91,7 +91,7 @@ function handleRowCheckboxChange({
/** 查看详情 */
function handleDetail(row: ErpStockInApi.StockIn) {
formModalApi.setData({ type: 'detail', id: row.id }).open();
formModalApi.setData({ formType: 'detail', id: row.id }).open();
}
const [Grid, gridApi] = useVbenVxeGrid({

View File

@ -1,4 +1,6 @@
<script lang="ts" setup>
import type { FormType } from '../data';
import type { ErpStockInApi } from '#/api/erp/stock/in';
import { computed, ref } from 'vue';
@ -16,7 +18,7 @@ import ItemForm from './item-form.vue';
const emit = defineEmits(['success']);
const formData = ref<ErpStockInApi.StockIn>();
const formType = ref(''); // 'create' | 'edit' | 'detail'
const formType = ref<FormType>('create'); // 'create' | 'edit' | 'detail'
const itemFormRef = ref<InstanceType<typeof ItemForm>>();
const getTitle = computed(() => {
@ -89,8 +91,8 @@ const [Modal, modalApi] = useVbenModal({
return;
}
//
const data = modalApi.getData<{ id?: number; type: string }>();
formType.value = data.type;
const data = modalApi.getData<{ formType: FormType; id?: number }>();
formType.value = data.formType;
formApi.setDisabled(formType.value === 'detail');
formApi.updateSchema(useFormSchema(formType.value));
if (!data || !data.id) {

View File

@ -9,8 +9,11 @@ import { getWarehouseSimpleList } from '#/api/erp/stock/warehouse';
import { getSimpleUserList } from '#/api/system/user';
import { getRangePickerDefaultProps } from '#/utils';
/** 表单类型 */
export type FormType = 'create' | 'detail' | 'edit';
/** 表单的配置项 */
export function useFormSchema(formType: string): VbenFormSchema[] {
export function useFormSchema(formType: FormType): VbenFormSchema[] {
return [
{
fieldName: 'id',

View File

@ -42,12 +42,12 @@ async function handleExport() {
/** 新增库存调拨单 */
function handleCreate() {
formModalApi.setData({ type: 'create' }).open();
formModalApi.setData({ formType: 'create' }).open();
}
/** 编辑库存调拨单 */
function handleEdit(row: ErpStockMoveApi.StockMove) {
formModalApi.setData({ type: 'edit', id: row.id }).open();
formModalApi.setData({ formType: 'edit', id: row.id }).open();
}
/** 删除库存调拨单 */
@ -94,7 +94,7 @@ function handleRowCheckboxChange({
/** 查看详情 */
function handleDetail(row: ErpStockMoveApi.StockMove) {
formModalApi.setData({ type: 'detail', id: row.id }).open();
formModalApi.setData({ formType: 'detail', id: row.id }).open();
}
const [Grid, gridApi] = useVbenVxeGrid({

View File

@ -1,4 +1,6 @@
<script lang="ts" setup>
import type { FormType } from '../data';
import type { ErpStockMoveApi } from '#/api/erp/stock/move';
import { computed, ref } from 'vue';
@ -20,7 +22,7 @@ import ItemForm from './item-form.vue';
const emit = defineEmits(['success']);
const formData = ref<ErpStockMoveApi.StockMove>();
const formType = ref(''); // 'create' | 'edit' | 'detail'
const formType = ref<FormType>('create'); // 'create' | 'edit' | 'detail'
const itemFormRef = ref<InstanceType<typeof ItemForm>>();
const getTitle = computed(() => {
@ -93,8 +95,8 @@ const [Modal, modalApi] = useVbenModal({
return;
}
//
const data = modalApi.getData<{ id?: number; type: string }>();
formType.value = data.type;
const data = modalApi.getData<{ formType: FormType; id?: number }>();
formType.value = data.formType;
formApi.setDisabled(formType.value === 'detail');
formApi.updateSchema(useFormSchema(formType.value));
if (!data || !data.id) {

View File

@ -10,8 +10,11 @@ import { getWarehouseSimpleList } from '#/api/erp/stock/warehouse';
import { getSimpleUserList } from '#/api/system/user';
import { getRangePickerDefaultProps } from '#/utils';
/** 表单类型 */
export type FormType = 'create' | 'detail' | 'edit';
/** 表单的配置项 */
export function useFormSchema(formType: string): VbenFormSchema[] {
export function useFormSchema(formType: FormType): VbenFormSchema[] {
return [
{
fieldName: 'id',

View File

@ -42,12 +42,12 @@ async function handleExport() {
/** 新增其它出库单 */
function handleCreate() {
formModalApi.setData({ type: 'create' }).open();
formModalApi.setData({ formType: 'create' }).open();
}
/** 编辑其它出库单 */
function handleEdit(row: ErpStockOutApi.StockOut) {
formModalApi.setData({ type: 'edit', id: row.id }).open();
formModalApi.setData({ formType: 'edit', id: row.id }).open();
}
/** 删除其它出库单 */
@ -94,7 +94,7 @@ function handleRowCheckboxChange({
/** 查看详情 */
function handleDetail(row: ErpStockOutApi.StockOut) {
formModalApi.setData({ type: 'detail', id: row.id }).open();
formModalApi.setData({ formType: 'detail', id: row.id }).open();
}
const [Grid, gridApi] = useVbenVxeGrid({

View File

@ -1,4 +1,6 @@
<script lang="ts" setup>
import type { FormType } from '../data';
import type { ErpStockOutApi } from '#/api/erp/stock/out';
import { computed, ref } from 'vue';
@ -20,7 +22,7 @@ import ItemForm from './item-form.vue';
const emit = defineEmits(['success']);
const formData = ref<ErpStockOutApi.StockOut>();
const formType = ref(''); // 'create' | 'edit' | 'detail'
const formType = ref<FormType>('create'); // 'create' | 'edit' | 'detail'
const itemFormRef = ref<InstanceType<typeof ItemForm>>();
const getTitle = computed(() => {
@ -93,8 +95,8 @@ const [Modal, modalApi] = useVbenModal({
return;
}
//
const data = modalApi.getData<{ id?: number; type: string }>();
formType.value = data.type;
const data = modalApi.getData<{ formType: FormType; id?: number }>();
formType.value = data.formType;
formApi.setDisabled(formType.value === 'detail');
formApi.updateSchema(useFormSchema(formType.value));
if (!data || !data.id) {

View File

@ -63,23 +63,20 @@ async function handleDefaultStatusChange(
newStatus: boolean,
row: ErpWarehouseApi.Warehouse,
): Promise<boolean | undefined> {
return new Promise((resolve, reject) => {
const text = newStatus ? '设置' : '取消';
confirm({
const text = newStatus ? '设置' : '取消';
try {
await confirm({
content: `确认要${text}"${row.name}"默认吗?`,
})
.then(async () => {
//
await updateWarehouseDefaultStatus(row.id!, newStatus);
//
message.success(`${text}默认成功`);
handleRefresh();
resolve(true);
})
.catch(() => {
reject(new Error('取消操作'));
});
});
});
} catch {
return false;
}
//
await updateWarehouseDefaultStatus(row.id!, newStatus);
//
message.success(`${text}默认成功`);
handleRefresh();
return true;
}
const [FormModal, formModalApi] = useVbenModal({

View File

@ -62,13 +62,27 @@ export function useGridFormSchema(): VbenFormSchema[] {
label: '设备',
component: 'ApiSelect',
componentProps: {
api: getSimpleDeviceList,
api: (params?: { productId?: number }) =>
getSimpleDeviceList(undefined, params?.productId),
labelField: 'deviceName',
valueField: 'id',
placeholder: '请选择设备',
allowClear: true,
showSearch: true,
},
dependencies: {
triggerFields: ['productId'],
componentProps: (values) => {
return {
params: { productId: values.productId },
};
},
trigger: (values, formApi) => {
if (values.deviceId !== undefined) {
void formApi.setFieldValue('deviceId', undefined);
}
},
},
},
{
fieldName: 'processStatus',

View File

@ -45,10 +45,6 @@ function handleProcess(row: AlertRecordApi.AlertRecord) {
}),
]),
async onOk() {
if (!processRemark.value) {
message.warning('请输入处理原因');
throw new Error('请输入处理原因');
}
const hideLoading = message.loading({
content: '正在处理...',
duration: 0,

View File

@ -79,10 +79,18 @@ export function useAdvancedFormSchema(): VbenFormSchema[] {
},
rules: z
.string()
.min(4, '备注名称长度限制为 4~64 个字符')
.max(64, '备注名称长度限制为 4~64 个字符')
.regex(
/^[\u4E00-\u9FA5\u3040-\u30FF\w]+$/,
.refine(
(value) => {
const length = value.replaceAll(
/[\u4E00-\u9FA5\u3040-\u30FF]/g,
'aa',
).length;
return length >= 4 && length <= 64;
},
'备注名称长度限制为 4~64 个字符,中文及日文算 2 个字符',
)
.refine(
(value) => /^[\u4E00-\u9FA5\u3040-\u30FF\w]+$/.test(value),
'备注名称只能包含中文、英文字母、日文、数字和下划线_',
)
.optional()
@ -276,6 +284,7 @@ export function useGridColumns(): VxeTableGridOptions<IotDeviceApi.Device>['colu
field: 'deviceName',
title: 'DeviceName',
minWidth: 150,
slots: { default: 'deviceName' },
},
{
field: 'nickname',

View File

@ -97,7 +97,7 @@ onMounted(async () => {
<Tabs v-model:active-key="activeTab" class="mt-4">
<Tabs.TabPane key="info" tab="设备信息">
<DeviceDetailsInfo
v-if="activeTab === 'info'"
v-if="activeTab === 'info' && device.id"
:device="device"
:product="product"
/>
@ -127,7 +127,7 @@ onMounted(async () => {
</Tabs.TabPane>
<Tabs.TabPane key="simulator" tab="模拟设备">
<DeviceDetailsSimulator
v-if="activeTab === 'simulator'"
v-if="activeTab === 'simulator' && device.id"
:device="device"
:product="product"
:thing-model-list="thingModelList"
@ -135,7 +135,7 @@ onMounted(async () => {
</Tabs.TabPane>
<Tabs.TabPane key="config" tab="设备配置">
<DeviceDetailConfig
v-if="activeTab === 'config'"
v-if="activeTab === 'config' && device.id"
:device="device"
@success="() => getDeviceData(id)"
/>
@ -151,7 +151,7 @@ onMounted(async () => {
tab="Modbus 配置"
>
<DeviceModbusConfig
v-if="activeTab === 'modbus'"
v-if="activeTab === 'modbus' && device.id"
:device="device"
:product="product"
:thing-model-list="thingModelList"

View File

@ -36,9 +36,9 @@ const authInfo = ref<IotDeviceApi.DeviceAuthInfoRespVO>(
);
const mapDialogRef = ref<InstanceType<typeof MapDialog>>();
/** 是否有位置信息 */
/** 是否有位置信息(合法经纬度 0 不应视为空) */
const hasLocation = computed(() => {
return !!(props.device.longitude && props.device.latitude);
return props.device.longitude != null && props.device.latitude != null;
});
/** 打开地图弹窗 */

View File

@ -31,6 +31,7 @@ const queryParams = reactive({
const autoRefresh = ref(false); //
let autoRefreshTimer: any = null; //
let refreshTimer: ReturnType<typeof setTimeout> | undefined; //
/** 消息方法选项 */
const methodOptions = computed(() => {
@ -150,6 +151,10 @@ onBeforeUnmount(() => {
clearInterval(autoRefreshTimer);
autoRefreshTimer = null;
}
if (refreshTimer) {
clearTimeout(refreshTimer);
refreshTimer = undefined;
}
});
/** 初始化 */
@ -161,9 +166,14 @@ onMounted(() => {
/** 刷新消息列表 */
function refresh(delay = 0) {
if (refreshTimer) {
clearTimeout(refreshTimer);
refreshTimer = undefined;
}
if (delay > 0) {
setTimeout(() => {
refreshTimer = setTimeout(() => {
gridApi.query();
refreshTimer = undefined;
}, delay);
} else {
gridApi.query();

View File

@ -58,11 +58,13 @@ const [Form, formApi] = useVbenForm({
componentProps: {
placeholder: '请输入 Modbus 服务器 IP 地址',
},
// Client Server
dependencies: {
triggerFields: [''],
show: () => isClient.value, // Client IP
show: () => isClient.value,
rules: () =>
isClient.value ? z.string().min(1, '请输入 IP 地址') : null,
},
rules: z.string().min(1, '请输入 IP 地址').optional(),
},
{
fieldName: 'port',
@ -76,9 +78,12 @@ const [Form, formApi] = useVbenForm({
},
dependencies: {
triggerFields: [''],
show: () => isClient.value, // Client
show: () => isClient.value,
rules: () =>
isClient.value
? z.number({ message: '请输入端口' }).min(1).max(65_535)
: null,
},
rules: z.number().min(1).max(65_535).optional(),
defaultValue: 502,
},
{
@ -106,9 +111,12 @@ const [Form, formApi] = useVbenForm({
},
dependencies: {
triggerFields: [''],
show: () => isClient.value, // Client
show: () => isClient.value,
rules: () =>
isClient.value
? z.number({ message: '请输入连接超时时间' }).min(1000)
: null,
},
rules: z.number().min(1000).optional(),
defaultValue: 3000,
},
{
@ -123,9 +131,12 @@ const [Form, formApi] = useVbenForm({
},
dependencies: {
triggerFields: [''],
show: () => isClient.value, // Client
show: () => isClient.value,
rules: () =>
isClient.value
? z.number({ message: '请输入重试间隔' }).min(1000)
: null,
},
rules: z.number().min(1000).optional(),
defaultValue: 10_000,
},
{

View File

@ -14,7 +14,7 @@ import { computed, h, onMounted, ref } from 'vue';
import { confirm, useVbenModal } from '@vben/common-ui';
import { DICT_TYPE, ModbusFunctionCodeOptions } from '@vben/constants';
import { Button, message } from 'ant-design-vue';
import { message } from 'ant-design-vue';
import { ACTION_ICON, TableAction, useVbenVxeGrid } from '#/adapter/vxe-table';
import { getModbusConfig } from '#/api/iot/device/modbus/config';
@ -307,7 +307,16 @@ onMounted(async () => {
<!-- 连接配置区域 -->
<ConfigDescriptions :data="modbusConfig" class="mb-4">
<template #extra>
<Button type="primary" @click="handleEditConfig"></Button>
<TableAction
:actions="[
{
label: '编辑',
type: 'primary',
auth: ['iot:device:create'],
onClick: handleEditConfig,
},
]"
/>
</template>
</ConfigDescriptions>
@ -320,6 +329,7 @@ onMounted(async () => {
label: '新增点位',
type: 'primary',
icon: ACTION_ICON.ADD,
auth: ['iot:device:create'],
onClick: handleAddPoint,
},
]"
@ -331,12 +341,14 @@ onMounted(async () => {
{
label: '编辑',
type: 'link',
auth: ['iot:device:update'],
onClick: () => handleEditPoint(row),
},
{
label: '删除',
type: 'link',
danger: true,
auth: ['iot:device:delete'],
popConfirm: {
title: `确定要删除点位【${row.name}】吗?`,
confirm: () => handleDeletePoint(row),

View File

@ -246,10 +246,20 @@ const [Form, formApi] = useVbenForm({
if (option && option.registerCount > 0) {
await formApi.setFieldValue('registerCount', option.registerCount);
}
//
// rawDataType
// setValues
const byteOrderOptions = getByteOrderOptions(rawDataType);
if (byteOrderOptions.length > 0) {
await formApi.setFieldValue('byteOrder', byteOrderOptions[0]!.value);
const currentByteOrder = values.byteOrder;
const isCurrentValid =
!!currentByteOrder &&
byteOrderOptions.some((opt) => opt.value === currentByteOrder);
if (!isCurrentValid) {
await formApi.setFieldValue(
'byteOrder',
byteOrderOptions[0]!.value,
);
}
}
}
}

View File

@ -6,11 +6,12 @@ import type { IotDeviceApi } from '#/api/iot/device/device';
import type { IotProductApi } from '#/api/iot/product/product';
import type { ThingModelApi } from '#/api/iot/thingmodel';
import { computed, ref } from 'vue';
import { computed, ref, watch } from 'vue';
import { ContentWrap } from '@vben/common-ui';
import {
DeviceStateEnum,
IoTDataSpecsDataTypeEnum,
IotDeviceMessageMethodEnum,
IoTThingModelTypeEnum,
} from '@vben/constants';
@ -21,8 +22,10 @@ import {
Card,
Col,
Input,
InputNumber,
message,
Row,
Select,
Table,
Tabs,
Textarea,
@ -51,7 +54,7 @@ const debugCollapsed = ref(false); // 指令调试区域折叠状态
const messageCollapsed = ref(false); //
//
const formData = ref<Record<string, string>>({});
const formData = ref<Record<string, any>>({});
//
const getFilteredThingModelList = (type: number) => {
@ -184,21 +187,101 @@ const serviceColumns = [
//
function getFormValue(identifier: string) {
return formData.value[identifier] || '';
return formData.value[identifier] ?? '';
}
//
function setFormValue(identifier: string, value: string) {
function setFormValue(identifier: string, value: any) {
formData.value[identifier] = value;
}
/** 获取属性数据类型 */
function getPropertyDataType(row: ThingModelApi.ThingModel) {
return row.property?.dataType;
}
/** 判断属性是否为数值类型 */
function isNumberProperty(row: ThingModelApi.ThingModel) {
return [
IoTDataSpecsDataTypeEnum.DOUBLE,
IoTDataSpecsDataTypeEnum.FLOAT,
IoTDataSpecsDataTypeEnum.INT,
].includes(getPropertyDataType(row) as any);
}
/** 判断属性是否使用下拉选项 */
function isSelectProperty(row: ThingModelApi.ThingModel) {
return [
IoTDataSpecsDataTypeEnum.BOOL,
IoTDataSpecsDataTypeEnum.ENUM,
].includes(getPropertyDataType(row) as any);
}
/** 获取属性选项 */
function getPropertyOptions(row: ThingModelApi.ThingModel) {
const list = row.property?.dataSpecsList || [];
if (list.length > 0) {
return list.map((item: any) => ({
label: item.name || item.label || String(item.value),
value: String(item.value),
}));
}
if (getPropertyDataType(row) === IoTDataSpecsDataTypeEnum.BOOL) {
return [
{ label: '真 (true)', value: 'true' },
{ label: '假 (false)', value: 'false' },
];
}
return [];
}
/** 获取物模型选项原始值 */
function getMatchedPropertyOption(row: ThingModelApi.ThingModel, value: any) {
return row.property?.dataSpecsList?.find(
(item: any) => String(item.value) === String(value),
);
}
/** 按物模型数据类型转换属性值 */
function normalizePropertyValue(row: ThingModelApi.ThingModel, value: any) {
if (value === undefined || value === null || value === '') {
return undefined;
}
const dataType = getPropertyDataType(row);
if (isNumberProperty(row)) {
return Number(value);
}
if (
[IoTDataSpecsDataTypeEnum.BOOL, IoTDataSpecsDataTypeEnum.ENUM].includes(
dataType as any,
)
) {
const option = getMatchedPropertyOption(row, value);
if (option) {
return option.value;
}
}
if (dataType === IoTDataSpecsDataTypeEnum.BOOL) {
if (String(value) === 'true') {
return true;
}
if (String(value) === 'false') {
return false;
}
}
return value;
}
//
async function handlePropertyPost() {
try {
const params: Record<string, any> = {};
propertyList.value.forEach((item) => {
const value = formData.value[item.identifier!];
if (value) {
const value = normalizePropertyValue(
item,
formData.value[item.identifier!],
);
if (value !== undefined) {
params[item.identifier!] = value;
}
});
@ -229,13 +312,15 @@ async function handleEventPost(row: ThingModelApi.ThingModel) {
const valueStr = formData.value[row.identifier!];
let eventValue: any;
if (valueStr) {
try {
eventValue = JSON.parse(valueStr);
} catch {
message.error('事件参数格式错误请输入有效的JSON格式');
return;
}
if (valueStr === undefined || valueStr === null || valueStr === '') {
message.warning('请输入事件参数');
return;
}
try {
eventValue = JSON.parse(valueStr);
} catch {
message.error('事件参数格式错误请输入有效的JSON格式');
return;
}
// IotDeviceEventPostReqDTO { identifier, value, time }
@ -281,8 +366,11 @@ async function handlePropertySet() {
try {
const params: Record<string, any> = {};
propertyList.value.forEach((item) => {
const value = formData.value[item.identifier!];
if (value) {
const value = normalizePropertyValue(
item,
formData.value[item.identifier!],
);
if (value !== undefined) {
params[item.identifier!] = value;
}
});
@ -313,13 +401,23 @@ async function handleServiceInvoke(row: ThingModelApi.ThingModel) {
const valueStr = formData.value[row.identifier!];
let inputParams: any = {};
if (valueStr) {
try {
inputParams = JSON.parse(valueStr);
} catch {
message.error('服务参数格式错误请输入有效的JSON格式');
return;
}
if (valueStr === undefined || valueStr === null || valueStr === '') {
message.warning('请输入服务参数');
return;
}
try {
inputParams = JSON.parse(valueStr);
} catch {
message.error('服务参数格式错误请输入有效的JSON格式');
return;
}
if (
typeof inputParams !== 'object' ||
inputParams === null ||
Array.isArray(inputParams)
) {
message.error('服务参数必须是 JSON 对象');
return;
}
// IotDeviceServiceInvokeReqDTO { identifier, inputParams }
@ -340,6 +438,11 @@ async function handleServiceInvoke(row: ThingModelApi.ThingModel) {
console.error(error);
}
}
/** 切换调试方法时清空输入,避免不同方法之间串台提交 */
watch([activeTab, upstreamTab, downstreamTab], () => {
formData.value = {};
});
</script>
<template>
@ -392,7 +495,29 @@ async function handleServiceInvoke(row: ThingModelApi.ThingModel) {
<DataDefinition :data="record" />
</template>
<template v-else-if="column.key === 'value'">
<InputNumber
v-if="isNumberProperty(record)"
:value="getFormValue(record.identifier)"
placeholder="输入值"
size="small"
class="w-full"
@update:value="
setFormValue(record.identifier, $event)
"
/>
<Select
v-else-if="isSelectProperty(record)"
:value="getFormValue(record.identifier)"
:options="getPropertyOptions(record)"
placeholder="请选择值"
size="small"
class="w-full"
@update:value="
setFormValue(record.identifier, $event)
"
/>
<Input
v-else
:value="getFormValue(record.identifier)"
placeholder="输入值"
size="small"
@ -514,7 +639,29 @@ async function handleServiceInvoke(row: ThingModelApi.ThingModel) {
<DataDefinition :data="record" />
</template>
<template v-else-if="column.key === 'value'">
<InputNumber
v-if="isNumberProperty(record)"
:value="getFormValue(record.identifier)"
placeholder="输入值"
size="small"
class="w-full"
@update:value="
setFormValue(record.identifier, $event)
"
/>
<Select
v-else-if="isSelectProperty(record)"
:value="getFormValue(record.identifier)"
:options="getPropertyOptions(record)"
placeholder="请选择值"
size="small"
class="w-full"
@update:value="
setFormValue(record.identifier, $event)
"
/>
<Input
v-else
:value="getFormValue(record.identifier)"
placeholder="输入值"
size="small"

View File

@ -317,6 +317,7 @@ watch(
label: '添加子设备',
type: 'primary',
icon: ACTION_ICON.ADD,
auth: ['iot:device:update'],
onClick: openAddModal,
},
{
@ -324,6 +325,7 @@ watch(
type: 'primary',
danger: true,
icon: ACTION_ICON.DELETE,
auth: ['iot:device:update'],
disabled: isEmpty(checkedIds),
onClick: handleUnbindBatch,
},
@ -342,6 +344,7 @@ watch(
label: '解绑',
type: 'link',
danger: true,
auth: ['iot:device:update'],
onClick: () => handleUnbind(row),
},
]"

View File

@ -3,7 +3,7 @@
import type { VxeTableGridOptions } from '#/adapter/vxe-table';
import type { ThingModelApi } from '#/api/iot/thingmodel';
import { computed, onMounted, reactive, watch } from 'vue';
import { computed, onBeforeUnmount, onMounted, reactive, watch } from 'vue';
import { Page } from '@vben/common-ui';
import {
@ -29,6 +29,7 @@ const queryParams = reactive({
identifier: '',
times: undefined as [string, string] | undefined,
});
let refreshTimer: ReturnType<typeof setTimeout> | undefined; //
/** 事件类型的物模型数据 */
const eventThingModels = computed(() => {
@ -153,8 +154,15 @@ function parseParams(params: string) {
/** 刷新列表 */
function refresh(delay = 0) {
if (refreshTimer) {
clearTimeout(refreshTimer);
refreshTimer = undefined;
}
if (delay > 0) {
setTimeout(() => gridApi.query(), delay);
refreshTimer = setTimeout(() => {
gridApi.query();
refreshTimer = undefined;
}, delay);
} else {
gridApi.query();
}
@ -177,6 +185,14 @@ onMounted(() => {
}
});
/** 组件卸载时清除延迟刷新定时器 */
onBeforeUnmount(() => {
if (refreshTimer) {
clearTimeout(refreshTimer);
refreshTimer = undefined;
}
});
/** 暴露方法给父组件 */
defineExpose({
refresh,

View File

@ -33,7 +33,7 @@ defineProps<{ deviceId: number }>();
const dialogVisible = ref(false); //
const loading = ref(false);
const viewMode = ref<'chart' | 'list'>('chart'); //
const list = ref<IotDeviceApi.DevicePropertyDetail[]>([]); //
const list = ref<Array<IotDeviceApi.DeviceProperty & { _rowKey: string }>>([]); //
const total = ref(0); //
const thingModelDataType = ref<string>(''); //
const propertyIdentifier = ref<string>(''); //
@ -137,23 +137,15 @@ const tableColumns = computed(() => [
},
]); //
const paginationConfig = computed(() => ({
current: 1,
pageSize: 10,
total: total.value,
showSizeChanger: true,
showQuickJumper: true,
pageSizeOptions: ['10', '20', '50', '100'],
showTotal: (total: number) => `${total} 条数据`,
})); //
/** 获得设备历史数据 */
async function getList() {
loading.value = true;
try {
//
const data = await getHistoryDevicePropertyList(queryParams);
list.value = (data || []) as IotDeviceApi.DevicePropertyDetail[];
list.value = (data || []).map((item, idx) => ({
...item,
_rowKey: `${item.updateTime ?? ''}-${idx}`, // value/updateTime _rowKey
}));
total.value = list.value.length;
//
@ -436,9 +428,9 @@ defineExpose({ open }); // 提供 open 方法,用于打开弹窗
<Table
:columns="tableColumns"
:data-source="list"
:pagination="paginationConfig"
:pagination="false"
:scroll="{ y: 500 }"
row-key="updateTime"
row-key="_rowKey"
size="small"
>
<template #bodyCell="{ column, record }">

View File

@ -207,6 +207,13 @@ function handleQuery() {
}
}
/** 搜索关键词变化 */
function handleKeywordChange(event: Event) {
if (!(event.target as HTMLInputElement).value) {
handleQuery();
}
}
/** 视图切换 */
async function handleViewModeChange(mode: 'card' | 'list') {
if (viewMode.value === mode) {
@ -281,6 +288,7 @@ onBeforeUnmount(() => {
allow-clear
placeholder="请输入属性名称、标识符"
style="width: 240px"
@change="handleKeywordChange"
@press-enter="handleQuery"
/>
<Switch

View File

@ -3,7 +3,7 @@
import type { VxeTableGridOptions } from '#/adapter/vxe-table';
import type { ThingModelApi } from '#/api/iot/thingmodel';
import { computed, onMounted, reactive, watch } from 'vue';
import { computed, onBeforeUnmount, onMounted, reactive, watch } from 'vue';
import { Page } from '@vben/common-ui';
import {
@ -29,6 +29,7 @@ const queryParams = reactive({
identifier: '',
times: undefined as [string, string] | undefined,
});
let refreshTimer: ReturnType<typeof setTimeout> | undefined; //
/** 服务类型的物模型数据 */
const serviceThingModels = computed(() => {
@ -167,8 +168,15 @@ function parseParams(params: string) {
/** 刷新列表 */
function refresh(delay = 0) {
if (refreshTimer) {
clearTimeout(refreshTimer);
refreshTimer = undefined;
}
if (delay > 0) {
setTimeout(() => gridApi.query(), delay);
refreshTimer = setTimeout(() => {
gridApi.query();
refreshTimer = undefined;
}, delay);
} else {
gridApi.query();
}
@ -191,6 +199,14 @@ onMounted(() => {
}
});
/** 组件卸载时清除延迟刷新定时器 */
onBeforeUnmount(() => {
if (refreshTimer) {
clearTimeout(refreshTimer);
refreshTimer = undefined;
}
});
/** 暴露方法给父组件 */
defineExpose({
refresh,

View File

@ -9,7 +9,7 @@ import type { IotProductApi } from '#/api/iot/product/product';
import { nextTick, onMounted, ref } from 'vue';
import { useRoute, useRouter } from 'vue-router';
import { Page, useVbenModal } from '@vben/common-ui';
import { confirm, Page, useVbenModal } from '@vben/common-ui';
import { DICT_TYPE } from '@vben/constants';
import { getDictOptions } from '@vben/hooks';
import { IconifyIcon } from '@vben/icons';
@ -169,6 +169,7 @@ async function handleDeleteBatch() {
message.warning('请选择要删除的设备');
return;
}
await confirm($t('ui.actionMessage.deleteBatchConfirm'));
const hideLoading = message.loading({
content: $t('ui.actionMessage.deletingBatch'),
duration: 0,
@ -214,6 +215,9 @@ const [Grid, gridApi] = useVbenVxeGrid({
columns: useGridColumns(),
height: 'auto',
keepSource: true,
pagerConfig: {
pageSize: 12,
},
proxyConfig: {
ajax: {
query: async ({
@ -429,6 +433,11 @@ onMounted(async () => {
<!-- 列表视图 -->
<Grid table-title="" v-show="viewMode === 'list'">
<template #deviceName="{ row }">
<a class="cursor-pointer text-primary" @click="openDetail(row.id!)">
{{ row.deviceName }}
</a>
</template>
<template #product="{ row }">
<a
class="cursor-pointer text-primary"
@ -465,7 +474,7 @@ onMounted(async () => {
{
label: '日志',
type: 'link',
auth: ['iot:device:message-query'],
auth: ['iot:device:query'],
onClick: openModel.bind(null, row.id!),
},
{

Some files were not shown because too many files have changed in this diff Show More