allen 1 giorno fa
parent
commit
38f53c04b0

+ 131 - 0
ips-admin/src/main/java/com/ips/system/controller/AttributeIdentificationtController.java

@@ -0,0 +1,131 @@
+package com.ips.system.controller;
+
+import java.util.List;
+import javax.servlet.http.HttpServletResponse;
+
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.ips.common.utils.StringUtils;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.PutMapping;
+import org.springframework.web.bind.annotation.DeleteMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+import com.ips.common.annotation.Log;
+import com.ips.common.core.controller.BaseController;
+import com.ips.common.core.domain.AjaxResult;
+import com.ips.common.enums.BusinessType;
+import com.ips.system.domain.AttributeIdentificationt;
+import com.ips.system.service.IAttributeIdentificationtService;
+import com.ips.common.utils.poi.ExcelUtil;
+import com.ips.common.core.page.TableDataInfo;
+
+/**
+ * 属性识别Controller
+ * 
+ * @author Allen
+ * @date 2025-07-02
+ */
+@RestController
+@RequestMapping("/biz/identificationt")
+public class AttributeIdentificationtController extends BaseController
+{
+    @Autowired
+    private IAttributeIdentificationtService attributeIdentificationtService;
+
+    /**
+     * 查询属性识别列表
+     */
+    @PreAuthorize("@ss.hasPermi('biz:identificationt:list')")
+    @GetMapping("/list")
+    public TableDataInfo list(AttributeIdentificationt attributeIdentificationt)
+    {
+        startPage();
+        List<AttributeIdentificationt> list = attributeIdentificationtService.selectAttributeIdentificationtList(attributeIdentificationt);
+        return getDataTable(list);
+    }
+
+    /**
+     * 导出属性识别列表
+     */
+    @PreAuthorize("@ss.hasPermi('biz:identificationt:export')")
+    @Log(title = "属性识别", businessType = BusinessType.EXPORT)
+    @PostMapping("/export")
+    public void export(HttpServletResponse response, AttributeIdentificationt attributeIdentificationt)
+    {
+        List<AttributeIdentificationt> list = attributeIdentificationtService.selectAttributeIdentificationtList(attributeIdentificationt);
+        ExcelUtil<AttributeIdentificationt> util = new ExcelUtil<AttributeIdentificationt>(AttributeIdentificationt.class);
+        util.exportExcel(response, list, "属性识别数据");
+    }
+
+    /**
+     * 获取属性识别详细信息
+     */
+    @PreAuthorize("@ss.hasPermi('biz:identificationt:query')")
+    @GetMapping(value = "/{id}")
+    public AjaxResult getInfo(@PathVariable("id") Long id)
+    {
+        return success(attributeIdentificationtService.selectAttributeIdentificationtById(id));
+    }
+
+    /**
+     * 新增属性识别
+     */
+    @PreAuthorize("@ss.hasPermi('biz:identificationt:add')")
+    @Log(title = "属性识别", businessType = BusinessType.INSERT)
+    @PostMapping
+    public AjaxResult add(@RequestBody AttributeIdentificationt attributeIdentificationt)
+    {
+        return toAjax(attributeIdentificationtService.insertAttributeIdentificationt(attributeIdentificationt));
+    }
+
+    /**
+     * 修改属性识别
+     */
+    @PreAuthorize("@ss.hasPermi('biz:identificationt:edit')")
+    @Log(title = "属性识别", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public AjaxResult edit(@RequestBody AttributeIdentificationt attributeIdentificationt)
+    {
+        return toAjax(attributeIdentificationtService.updateAttributeIdentificationt(attributeIdentificationt));
+    }
+
+    /**
+     * 删除属性识别
+     */
+    @PreAuthorize("@ss.hasPermi('biz:identificationt:remove')")
+    @Log(title = "属性识别", businessType = BusinessType.DELETE)
+	@DeleteMapping("/{ids}")
+    public AjaxResult remove(@PathVariable Long[] ids)
+    {
+        return toAjax(attributeIdentificationtService.deleteAttributeIdentificationtByIds(ids));
+    }
+
+
+    /**
+     * 运行算法模型
+     * @param id
+     * @return
+     * @throws JsonProcessingException
+     */
+    @PreAuthorize("@ss.hasPermi('biz:identificationt:add')")
+    @GetMapping(value = "/run/{id}")
+    public AjaxResult run(@PathVariable("id") Long id) throws JsonProcessingException {
+        String errorMsg = attributeIdentificationtService.run(id);
+        if(StringUtils.isEmpty(errorMsg)){
+            return success(errorMsg);
+        } else {
+            return error(errorMsg);
+        }
+    }
+
+    @PreAuthorize("@ss.hasPermi('biz:identificationt:add')")
+    @GetMapping(value = "/getTaskStatusIsChanged/{id}")
+    public AjaxResult getTaskStatusIsChanged(@PathVariable("id") Long id){
+        return success(attributeIdentificationtService.getTaskStatusIsChanged(id));
+    }
+}

+ 61 - 0
ips-admin/src/main/java/com/ips/system/domain/AttributeIdentificationt.java

@@ -0,0 +1,61 @@
+package com.ips.system.domain;
+
+import java.util.Date;
+import com.fasterxml.jackson.annotation.JsonFormat;
+import com.ips.common.annotation.Excel;
+import com.ips.common.core.domain.BaseEntity;
+import lombok.Data;
+
+/**
+ * 属性识别对象 biz_attribute_identificationt
+ * 
+ * @author Allen
+ * @date 2025-07-02
+ */
+@Data
+public class AttributeIdentificationt extends BaseEntity
+{
+    private static final long serialVersionUID = 1L;
+
+    /** 编号 */
+    private Long id;
+
+    /** 任务名称 */
+    @Excel(name = "任务名称")
+    private String taskName;
+
+    /** 算法 */
+    @Excel(name = "算法")
+    private Long algorithmId;
+
+    /** 模型pth */
+    private String modelPath;
+
+    /** 模型pkl */
+    private String modelPklPath;
+
+    /** 输入路径 */
+    private String inputPath;
+
+    /** 输出路径 */
+    private String outputPath;
+
+    /** 算法参数 */
+    private String algorithmParams;
+
+    /** 状态 */
+    @Excel(name = "状态")
+    private String status;
+
+    /** 开始时间 */
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    @Excel(name = "开始时间", width = 30, dateFormat = "yyyy-MM-dd HH:mm:ss")
+    private Date startTime;
+
+    /** 结束时间 */
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    @Excel(name = "结束时间", width = 30, dateFormat = "yyyy-MM-dd HH:mm:ss")
+    private Date endTime;
+
+    private String algorithmName;
+}

+ 63 - 0
ips-admin/src/main/java/com/ips/system/mapper/AttributeIdentificationtMapper.java

@@ -0,0 +1,63 @@
+package com.ips.system.mapper;
+
+import java.util.List;
+import com.ips.system.domain.AttributeIdentificationt;
+
+/**
+ * 属性识别Mapper接口
+ * 
+ * @author Allen
+ * @date 2025-07-02
+ */
+public interface AttributeIdentificationtMapper 
+{
+    /**
+     * 查询属性识别
+     * 
+     * @param id 属性识别主键
+     * @return 属性识别
+     */
+    public AttributeIdentificationt selectAttributeIdentificationtById(Long id);
+
+    /**
+     * 查询属性识别列表
+     * 
+     * @param attributeIdentificationt 属性识别
+     * @return 属性识别集合
+     */
+    public List<AttributeIdentificationt> selectAttributeIdentificationtList(AttributeIdentificationt attributeIdentificationt);
+
+    /**
+     * 新增属性识别
+     * 
+     * @param attributeIdentificationt 属性识别
+     * @return 结果
+     */
+    public int insertAttributeIdentificationt(AttributeIdentificationt attributeIdentificationt);
+
+    /**
+     * 修改属性识别
+     * 
+     * @param attributeIdentificationt 属性识别
+     * @return 结果
+     */
+    public int updateAttributeIdentificationt(AttributeIdentificationt attributeIdentificationt);
+
+    /**
+     * 删除属性识别
+     * 
+     * @param id 属性识别主键
+     * @return 结果
+     */
+    public int deleteAttributeIdentificationtById(Long id);
+
+    /**
+     * 批量删除属性识别
+     * 
+     * @param ids 需要删除的数据主键集合
+     * @return 结果
+     */
+    public int deleteAttributeIdentificationtByIds(Long[] ids);
+
+    Boolean getTaskStatusIsChanged(Long id);
+}

+ 68 - 0
ips-admin/src/main/java/com/ips/system/service/IAttributeIdentificationtService.java

@@ -0,0 +1,68 @@
+package com.ips.system.service;
+
+import java.util.List;
+
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.ips.system.domain.AttributeIdentificationt;
+import com.ips.system.domain.BizTraining;
+
+/**
+ * 属性识别Service接口
+ * 
+ * @author Allen
+ * @date 2025-07-02
+ */
+public interface IAttributeIdentificationtService 
+{
+    /**
+     * 查询属性识别
+     * 
+     * @param id 属性识别主键
+     * @return 属性识别
+     */
+    public AttributeIdentificationt selectAttributeIdentificationtById(Long id);
+
+    /**
+     * 查询属性识别列表
+     * 
+     * @param attributeIdentificationt 属性识别
+     * @return 属性识别集合
+     */
+    public List<AttributeIdentificationt> selectAttributeIdentificationtList(AttributeIdentificationt attributeIdentificationt);
+
+    /**
+     * 新增属性识别
+     * 
+     * @param attributeIdentificationt 属性识别
+     * @return 结果
+     */
+    public int insertAttributeIdentificationt(AttributeIdentificationt attributeIdentificationt);
+
+    /**
+     * 修改属性识别
+     * 
+     * @param attributeIdentificationt 属性识别
+     * @return 结果
+     */
+    public int updateAttributeIdentificationt(AttributeIdentificationt attributeIdentificationt);
+
+    /**
+     * 批量删除属性识别
+     * 
+     * @param ids 需要删除的属性识别主键集合
+     * @return 结果
+     */
+    public int deleteAttributeIdentificationtByIds(Long[] ids);
+
+    /**
+     * 删除属性识别信息
+     * 
+     * @param id 属性识别主键
+     * @return 结果
+     */
+    public int deleteAttributeIdentificationtById(Long id);
+
+    String run(Long id) throws JsonProcessingException;
+
+    Boolean getTaskStatusIsChanged(Long id);
+}

+ 183 - 0
ips-admin/src/main/java/com/ips/system/service/impl/AttributeIdentificationtServiceImpl.java

@@ -0,0 +1,183 @@
+package com.ips.system.service.impl;
+
+import java.util.Date;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.CompletableFuture;
+
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.core.type.TypeReference;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.ips.common.utils.DateUtils;
+import com.ips.common.utils.StringUtils;
+import com.ips.system.domain.AlgorithmConfig;
+import com.ips.system.domain.BizTraining;
+import com.ips.system.dto.AlgorithmParamsDto;
+import com.ips.system.mapper.BizTrainingMapper;
+import com.ips.system.service.IAlgorithmConfigService;
+import com.ips.system.utils.AlgorithmCaller;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import com.ips.system.mapper.AttributeIdentificationtMapper;
+import com.ips.system.domain.AttributeIdentificationt;
+import com.ips.system.service.IAttributeIdentificationtService;
+
+/**
+ * 属性识别Service业务层处理
+ * 
+ * @author Allen
+ * @date 2025-07-02
+ */
+@Service
+public class AttributeIdentificationtServiceImpl implements IAttributeIdentificationtService
+{
+
+    protected final Logger logger = LoggerFactory.getLogger(this.getClass());
+    @Autowired
+    private AttributeIdentificationtMapper attributeIdentificationtMapper;
+
+    @Autowired
+    private IAlgorithmConfigService algorithmConfigService;
+
+    /**
+     * 查询属性识别
+     * 
+     * @param id 属性识别主键
+     * @return 属性识别
+     */
+    @Override
+    public AttributeIdentificationt selectAttributeIdentificationtById(Long id)
+    {
+        return attributeIdentificationtMapper.selectAttributeIdentificationtById(id);
+    }
+
+    /**
+     * 查询属性识别列表
+     * 
+     * @param attributeIdentificationt 属性识别
+     * @return 属性识别
+     */
+    @Override
+    public List<AttributeIdentificationt> selectAttributeIdentificationtList(AttributeIdentificationt attributeIdentificationt)
+    {
+        return attributeIdentificationtMapper.selectAttributeIdentificationtList(attributeIdentificationt);
+    }
+
+    /**
+     * 新增属性识别
+     * 
+     * @param attributeIdentificationt 属性识别
+     * @return 结果
+     */
+    @Override
+    public int insertAttributeIdentificationt(AttributeIdentificationt attributeIdentificationt)
+    {
+        attributeIdentificationt.setCreateTime(DateUtils.getNowDate());
+        return attributeIdentificationtMapper.insertAttributeIdentificationt(attributeIdentificationt);
+    }
+
+    /**
+     * 修改属性识别
+     * 
+     * @param attributeIdentificationt 属性识别
+     * @return 结果
+     */
+    @Override
+    public int updateAttributeIdentificationt(AttributeIdentificationt attributeIdentificationt)
+    {
+        attributeIdentificationt.setUpdateTime(DateUtils.getNowDate());
+        return attributeIdentificationtMapper.updateAttributeIdentificationt(attributeIdentificationt);
+    }
+
+    /**
+     * 批量删除属性识别
+     * 
+     * @param ids 需要删除的属性识别主键
+     * @return 结果
+     */
+    @Override
+    public int deleteAttributeIdentificationtByIds(Long[] ids)
+    {
+        return attributeIdentificationtMapper.deleteAttributeIdentificationtByIds(ids);
+    }
+
+    /**
+     * 删除属性识别信息
+     * 
+     * @param id 属性识别主键
+     * @return 结果
+     */
+    @Override
+    public int deleteAttributeIdentificationtById(Long id)
+    {
+        return attributeIdentificationtMapper.deleteAttributeIdentificationtById(id);
+    }
+
+    @Override
+    public String run(Long id) throws JsonProcessingException {
+        AttributeIdentificationt attributeIdentificationt = attributeIdentificationtMapper.selectAttributeIdentificationtById(id);
+        if (attributeIdentificationt == null || attributeIdentificationt.getAlgorithmId() == null) {
+            return "无法找到该任务,id:" + id;
+        }
+        Long algorithmId = attributeIdentificationt.getAlgorithmId();
+        AlgorithmConfig algorithmConfig = algorithmConfigService.selectAlgorithmConfigById(algorithmId);
+        attributeIdentificationt.setStartTime(new Date());
+        attributeIdentificationt.setStatus("1");
+        this.updateAttributeIdentificationt(attributeIdentificationt);
+        CompletableFuture.runAsync(() -> {
+            // 异步逻辑
+            doRun(algorithmConfig, attributeIdentificationt);
+        });
+        return null;
+    }
+
+    private void doRun(AlgorithmConfig algorithmConfig, AttributeIdentificationt attributeIdentificationt) {
+        String algorithmPath = algorithmConfig.getAlgorithmPath();
+
+        // 组装json
+        String inputPath = attributeIdentificationt.getInputPath();
+        String outputPath = attributeIdentificationt.getOutputPath();
+        ObjectMapper objectMapper = new ObjectMapper();
+        Map<String, Object> params = new HashMap<>(2);
+
+        String errorMsg = "";
+        try {
+            if (StringUtils.isNotEmpty(attributeIdentificationt.getAlgorithmParams())) {
+
+                params = objectMapper.readValue(
+                        attributeIdentificationt.getAlgorithmParams(),
+                        new TypeReference<Map<String, Object>>() {
+                        }
+                );
+            }
+            params.put("model", attributeIdentificationt.getModelPath());
+            params.put("mode_pkl", attributeIdentificationt.getModelPklPath());
+            AlgorithmParamsDto algorithmParamsDto = new AlgorithmParamsDto(algorithmConfig.getAlgorithmName(), inputPath, outputPath, params);
+            // 对象 → JSON 字符串
+            String json = objectMapper.writeValueAsString(algorithmParamsDto);
+            // 处理算法
+            errorMsg = AlgorithmCaller.executeAlgorithm(algorithmConfig.getAlgorithmName(),algorithmPath, json);
+        } catch (JsonProcessingException e) {
+            logger.error("格式化失败", e);
+            errorMsg = "格式化失败";
+        }
+        //处理结果
+        attributeIdentificationt.setRemark(StringUtils.substring(errorMsg,0,100));
+        if (StringUtils.isEmpty(errorMsg)) {
+            attributeIdentificationt.setStatus("2");
+        } else {
+            logger.error("算法调用失败,错误原因:{}", errorMsg);
+            attributeIdentificationt.setStatus("3");
+        }
+        attributeIdentificationt.setEndTime(new Date());
+        this.updateAttributeIdentificationt(attributeIdentificationt);
+    }
+
+    @Override
+    public Boolean getTaskStatusIsChanged(Long id) {
+        return attributeIdentificationtMapper.getTaskStatusIsChanged(id);
+    }
+}

+ 5 - 5
ips-admin/src/main/resources/application-druid.yml

@@ -6,12 +6,12 @@ spring:
         druid:
             # 主库数据源
             master:
-                url: jdbc:mysql://localhost:3306/nwpu-ips?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
-                username: root
-                password: 123456
-#                url: jdbc:mysql://101.126.133.7:9006/nwpu-ips?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
+#                url: jdbc:mysql://localhost:3306/nwpu-ips?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
 #                username: root
-#                password: 404cf3eae29df38f
+#                password: 123456
+                url: jdbc:mysql://101.126.133.7:9006/nwpu-ips?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
+                username: root
+                password: 404cf3eae29df38f
             # 从库数据源
             slave:
                 # 从数据源开关/默认关闭

+ 3 - 3
ips-admin/src/main/resources/application.yml

@@ -66,14 +66,14 @@ spring:
   # redis 配置
   redis:
     # 地址
-#    host: 101.126.133.7
-    host: 127.0.0.1
+    host: 101.126.133.7
+#    host: 127.0.0.1
     # 端口,默认为6379
     port: 6379
     # 数据库索引
     database: 0
     # 密码 Z;G4AS:Vor'YF#p?
-    password:
+    password: Z;G4AS:Vor'YF#p?
     # 连接超时时间
     timeout: 10s
     jedis:

+ 1 - 0
ips-admin/src/main/resources/mapper/biz/AlgorithmConfigMapper.xml

@@ -27,6 +27,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
             <if test="algorithmName != null "> and algorithm_name like concat('%', #{algorithmName}, '%')</if>
             <if test="algorithmType != null  and algorithmType != ''"> and algorithm_type = #{algorithmType}</if>
         </where>
+        order by id desc
     </select>
     
     <select id="selectAlgorithmConfigById" parameterType="Long" resultMap="AlgorithmConfigResult">

+ 142 - 0
ips-admin/src/main/resources/mapper/biz/AttributeIdentificationtMapper.xml

@@ -0,0 +1,142 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE mapper
+PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
+"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.ips.system.mapper.AttributeIdentificationtMapper">
+    
+    <resultMap type="AttributeIdentificationt" id="AttributeIdentificationtResult">
+        <result property="id"    column="id"    />
+        <result property="taskName"    column="task_name"    />
+        <result property="algorithmId"    column="algorithm_id"    />
+        <result property="modelPath"    column="model_path"    />
+        <result property="modelPklPath"    column="model_pkl_path"    />
+        <result property="inputPath"    column="input_path"    />
+        <result property="outputPath"    column="output_path"    />
+        <result property="algorithmParams"    column="algorithm_params"    />
+        <result property="status"    column="status"    />
+        <result property="startTime"    column="start_time"    />
+        <result property="endTime"    column="end_time"    />
+        <result property="remark"    column="remark"    />
+        <result property="createBy"    column="create_by"    />
+        <result property="createTime"    column="create_time"    />
+        <result property="updateBy"    column="update_by"    />
+        <result property="updateTime"    column="update_time"    />
+        <result property="algorithmName"    column="algorithm_name"    />
+    </resultMap>
+
+    <sql id="selectAttributeIdentificationtVo">
+        SELECT
+            ai.id,
+            ai.task_name,
+            ai.algorithm_id,
+            ai.model_path,
+            ai.model_pkl_path,
+            ai.input_path,
+            ai.output_path,
+            ai.algorithm_params,
+            ai.STATUS,
+            ai.start_time,
+            ai.end_time,
+            ai.remark,
+            ai.create_by,
+            ai.create_time,
+            ai.update_by,
+            ai.update_time,
+            bac.algorithm_name
+        FROM
+            biz_attribute_identificationt ai
+            LEFT JOIN biz_algorithm_config bac ON bac.id = ai.algorithm_id
+    </sql>
+
+    <select id="selectAttributeIdentificationtList" parameterType="AttributeIdentificationt" resultMap="AttributeIdentificationtResult">
+        <include refid="selectAttributeIdentificationtVo"/>
+        <where>  
+            <if test="taskName != null  and taskName != ''"> and ai.task_name like concat('%', #{taskName}, '%')</if>
+            <if test="algorithmId != null "> and ai.algorithm_id = #{algorithmId}</if>
+            <if test="status != null  and status != ''"> and ai.status = #{status}</if>
+        </where>
+        order by ai.id desc
+    </select>
+    
+    <select id="selectAttributeIdentificationtById" parameterType="Long" resultMap="AttributeIdentificationtResult">
+        <include refid="selectAttributeIdentificationtVo"/>
+        where ai.id = #{id}
+    </select>
+
+    <insert id="insertAttributeIdentificationt" parameterType="AttributeIdentificationt" useGeneratedKeys="true" keyProperty="id">
+        insert into biz_attribute_identificationt
+        <trim prefix="(" suffix=")" suffixOverrides=",">
+            <if test="taskName != null">task_name,</if>
+            <if test="algorithmId != null">algorithm_id,</if>
+            <if test="modelPath != null">model_path,</if>
+            <if test="modelPklPath != null">model_pkl_path,</if>
+            <if test="inputPath != null">input_path,</if>
+            <if test="outputPath != null">output_path,</if>
+            <if test="algorithmParams != null">algorithm_params,</if>
+            <if test="status != null">status,</if>
+            <if test="startTime != null">start_time,</if>
+            <if test="endTime != null">end_time,</if>
+            <if test="remark != null">remark,</if>
+            <if test="createBy != null">create_by,</if>
+            <if test="createTime != null">create_time,</if>
+            <if test="updateBy != null">update_by,</if>
+            <if test="updateTime != null">update_time,</if>
+         </trim>
+        <trim prefix="values (" suffix=")" suffixOverrides=",">
+            <if test="taskName != null">#{taskName},</if>
+            <if test="algorithmId != null">#{algorithmId},</if>
+            <if test="modelPath != null">#{modelPath},</if>
+            <if test="modelPklPath != null">#{modelPklPath},</if>
+            <if test="inputPath != null">#{inputPath},</if>
+            <if test="outputPath != null">#{outputPath},</if>
+            <if test="algorithmParams != null">#{algorithmParams},</if>
+            <if test="status != null">#{status},</if>
+            <if test="startTime != null">#{startTime},</if>
+            <if test="endTime != null">#{endTime},</if>
+            <if test="remark != null">#{remark},</if>
+            <if test="createBy != null">#{createBy},</if>
+            <if test="createTime != null">#{createTime},</if>
+            <if test="updateBy != null">#{updateBy},</if>
+            <if test="updateTime != null">#{updateTime},</if>
+         </trim>
+    </insert>
+
+    <update id="updateAttributeIdentificationt" parameterType="AttributeIdentificationt">
+        update biz_attribute_identificationt
+        <trim prefix="SET" suffixOverrides=",">
+            <if test="taskName != null">task_name = #{taskName},</if>
+            <if test="algorithmId != null">algorithm_id = #{algorithmId},</if>
+            <if test="modelPath != null">model_path = #{modelPath},</if>
+            <if test="modelPklPath != null">model_pkl_path = #{modelPklPath},</if>
+            <if test="inputPath != null">input_path = #{inputPath},</if>
+            <if test="outputPath != null">output_path = #{outputPath},</if>
+            <if test="algorithmParams != null">algorithm_params = #{algorithmParams},</if>
+            <if test="status != null">status = #{status},</if>
+            <if test="startTime != null">start_time = #{startTime},</if>
+            <if test="endTime != null">end_time = #{endTime},</if>
+            <if test="remark != null">remark = #{remark},</if>
+            <if test="createBy != null">create_by = #{createBy},</if>
+            <if test="createTime != null">create_time = #{createTime},</if>
+            <if test="updateBy != null">update_by = #{updateBy},</if>
+            <if test="updateTime != null">update_time = #{updateTime},</if>
+        </trim>
+        where id = #{id}
+    </update>
+
+    <delete id="deleteAttributeIdentificationtById" parameterType="Long">
+        delete from biz_attribute_identificationt where id = #{id}
+    </delete>
+
+    <delete id="deleteAttributeIdentificationtByIds" parameterType="String">
+        delete from biz_attribute_identificationt where id in 
+        <foreach item="id" collection="array" open="(" separator="," close=")">
+            #{id}
+        </foreach>
+    </delete>
+
+    <select id="getTaskStatusIsChanged" parameterType="Long" resultType="boolean">
+        SELECT status != '1' AS isChanged
+        FROM biz_attribute_identificationt
+        WHERE id = #{id}
+    </select>
+</mapper>

+ 60 - 0
ips-ui/src/api/biz/identificationt.js

@@ -0,0 +1,60 @@
+import request from '@/utils/request'
+
+// 查询属性识别列表
+export function listIdentificationt(query) {
+  return request({
+    url: '/biz/identificationt/list',
+    method: 'get',
+    params: query
+  })
+}
+
+// 查询属性识别详细
+export function getIdentificationt(id) {
+  return request({
+    url: '/biz/identificationt/' + id,
+    method: 'get'
+  })
+}
+
+// 新增属性识别
+export function addIdentificationt(data) {
+  return request({
+    url: '/biz/identificationt',
+    method: 'post',
+    data: data
+  })
+}
+
+// 修改属性识别
+export function updateIdentificationt(data) {
+  return request({
+    url: '/biz/identificationt',
+    method: 'put',
+    data: data
+  })
+}
+
+// 删除属性识别
+export function delIdentificationt(id) {
+  return request({
+    url: '/biz/identificationt/' + id,
+    method: 'delete'
+  })
+}
+
+// 运行分类测试
+export function run(id) {
+  return request({
+    url: "/biz/identificationt/run/" + id,
+    method: "get",
+  });
+}
+
+// 获取运行结果详情
+export function getTaskStatusIsChanged(id) {
+  return request({
+    url: "/biz/identificationt/getTaskStatusIsChanged/" + id,
+    method: "get",
+  });
+}

+ 1 - 1
ips-ui/src/background.js

@@ -31,7 +31,7 @@ async function createWindow() {
   win.maximize();
   //  win.show();
   // 打开控制台
-  // win.webContents.openDevTools();
+   win.webContents.openDevTools();
   ipcMain.on("getPrinterList", (event) => {
     //主线程获取打印机列表
     win.webContents.getPrintersAsync().then((data) => {

+ 17 - 0
ips-ui/src/layout/components/TagsView/index.vue

@@ -1,5 +1,22 @@
 <template>
   <div id="tags-view-container" class="tags-view-container">
+    <scroll-pane ref="scrollPane" class="tags-view-wrapper" @scroll="handleScroll" v-show="false">
+      <router-link
+        v-for="tag in visitedViews"
+        ref="tag"
+        :key="tag.path"
+        :class="isActive(tag)?'active':''"
+        :to="{ path: tag.path, query: tag.query, fullPath: tag.fullPath }"
+        tag="span"
+        class="tags-view-item"
+        :style="activeStyle(tag)"
+        @click.middle.native="!isAffix(tag)?closeSelectedTag(tag):''"
+        @contextmenu.prevent.native="openMenu(tag,$event)"
+      >
+        {{ tag.title }}
+        <span v-if="!isAffix(tag)" class="el-icon-close" @click.prevent.stop="closeSelectedTag(tag)" />
+      </router-link>
+    </scroll-pane>
     <ul v-show="visible" :style="{left:left+'px',top:top+'px'}" class="contextmenu">
       <li @click="refreshSelectedTag(selectedTag)"><i class="el-icon-refresh-right"></i> 刷新页面</li>
       <li v-if="!isAffix(selectedTag)" @click="closeSelectedTag(selectedTag)"><i class="el-icon-close"></i> 关闭当前</li>

+ 19 - 0
ips-ui/src/views/biz/features/index.vue

@@ -219,6 +219,14 @@
           >
             日志
           </el-button>
+          <el-button
+            size="mini"
+            type="text"
+            icon="el-icon-info"
+            @click="openFolder(scope.row)"
+            v-hasPermi="['biz:features:add']"
+            >打开结果</el-button
+          >
           <el-button
             size="mini"
             type="text"
@@ -609,6 +617,17 @@ export default {
         this.runningTask = {};
       }
     },
+    openFolder(row) {
+      try {
+        shell.openPath(row.outputPath).then((result) => {
+          if (result) {
+            this.$message.error(`打开文件夹失败: ${result}`);
+          }
+        });
+      } catch (error) {
+        this.$message.error(`打开文件夹出错: ${error.message}`);
+      }
+    },
   },
 };
 </script>

+ 482 - 0
ips-ui/src/views/biz/identificationt/index.vue

@@ -0,0 +1,482 @@
+<template>
+  <div class="app-container">
+    <el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="68px">
+      <el-form-item label="任务名称" prop="taskName">
+        <el-input
+          v-model="queryParams.taskName"
+          placeholder="请输入任务名称"
+          clearable
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="算法" prop="algorithmId">
+        <el-select
+          v-model="queryParams.algorithmId"
+          placeholder="请选择算法"
+          @keyup.enter.native="handleQuery"
+          clearable
+        >
+          <el-option
+            v-for="option in configOptions"
+            :key="option.id"
+            :label="option.name"
+            :value="option.id"
+          />
+        </el-select>
+      </el-form-item>
+      <el-form-item label="状态" prop="status">
+        <el-select v-model="queryParams.status" placeholder="请选择状态" clearable>
+          <el-option
+            v-for="dict in dict.type.biz_status"
+            :key="dict.value"
+            :label="dict.label"
+            :value="dict.value"
+          />
+        </el-select>
+      </el-form-item>
+      <el-form-item>
+        <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
+        <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
+      </el-form-item>
+    </el-form>
+
+    <el-row :gutter="10" class="mb8">
+      <el-col :span="1.5">
+        <el-button
+          type="primary"
+          plain
+          icon="el-icon-plus"
+          size="mini"
+          @click="handleAdd"
+          v-hasPermi="['biz:identificationt:add']"
+        >新增</el-button>
+      </el-col>
+      <el-col :span="1.5">
+        <el-button
+          type="success"
+          plain
+          icon="el-icon-edit"
+          size="mini"
+          :disabled="single"
+          @click="handleUpdate"
+          v-hasPermi="['biz:identificationt:edit']"
+        >修改</el-button>
+      </el-col>
+      <el-col :span="1.5">
+        <el-button
+          type="danger"
+          plain
+          icon="el-icon-delete"
+          size="mini"
+          :disabled="multiple"
+          @click="handleDelete"
+          v-hasPermi="['biz:identificationt:remove']"
+        >删除</el-button>
+      </el-col>
+      <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
+    </el-row>
+
+    <el-table v-loading="loading" :data="identificationtList" @selection-change="handleSelectionChange">
+      <el-table-column type="selection" width="55" align="center" />
+      <el-table-column label="任务名称" align="center" prop="taskName" />
+      <el-table-column label="算法" align="center" prop="algorithmName" />
+      <el-table-column label="状态" align="center" prop="status">
+        <template slot-scope="scope">
+          <dict-tag :options="dict.type.biz_status" :value="scope.row.status"/>
+        </template>
+      </el-table-column>
+      <el-table-column label="开始时间" align="center" prop="startTime" width="180">
+        <template slot-scope="scope">
+          <span>{{ parseTime(scope.row.startTime)}}</span>
+        </template>
+      </el-table-column>
+      <el-table-column label="结束时间" align="center" prop="endTime" width="180">
+        <template slot-scope="scope">
+          <span>{{ parseTime(scope.row.endTime)}}</span>
+        </template>
+      </el-table-column>
+      <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
+        <template slot-scope="scope">
+          <el-button
+            size="mini"
+            type="text"
+            icon="el-icon-video-play"
+            @click="handleRun(scope.row)"
+            v-hasPermi="['biz:identificationt:add']"
+            >运行</el-button
+          >
+          <el-button
+            type="text"
+            icon="el-icon-search"
+            @click="showLogViewer(scope.row)"
+          >
+            日志
+          </el-button>
+          <el-button
+            size="mini"
+            type="text"
+            icon="el-icon-edit"
+            @click="handleUpdate(scope.row)"
+            v-hasPermi="['biz:identificationt:edit']"
+          >修改</el-button>
+          <el-button
+            size="mini"
+            type="text"
+            icon="el-icon-delete"
+            @click="handleDelete(scope.row)"
+            v-hasPermi="['biz:identificationt:remove']"
+          >删除</el-button>
+        </template>
+      </el-table-column>
+    </el-table>
+
+    <pagination
+      v-show="total>0"
+      :total="total"
+      :page.sync="queryParams.pageNum"
+      :limit.sync="queryParams.pageSize"
+      @pagination="getList"
+    />
+
+    <!-- 添加或修改属性识别对话框 -->
+    <el-dialog :title="title" :visible.sync="open" width="500px" append-to-body>
+      <el-form ref="form" :model="form" :rules="rules" label-width="80px">
+        <el-form-item label="任务名称" prop="taskName">
+          <el-input v-model="form.taskName" placeholder="请输入任务名称" />
+        </el-form-item>
+        <el-form-item label="算法" prop="algorithmId">
+          <el-select
+            v-model="form.algorithmId"
+            placeholder="请选择算法"
+            @change="changeAlgorithmId"
+            clearable
+          >
+            <el-option
+              v-for="option in configOptions"
+              :key="option.id"
+              :label="option.name"
+              :value="option.id"
+            />
+          </el-select>
+        </el-form-item>
+        <el-form-item label="pth模型" prop="modelPath">
+          <file-folder-picker v-model="form.modelPath" />
+        </el-form-item>
+        <el-form-item label="pkl模型" prop="modelPklPath">
+          <file-folder-picker v-model="form.modelPklPath" />
+        </el-form-item>
+        <el-form-item label="输入路径" prop="inputPath">
+          <folder-picker v-model="form.inputPath" />
+        </el-form-item>
+        <el-form-item label="输出路径" prop="outputPath">
+          <folder-picker v-model="form.outputPath" />
+        </el-form-item>
+        <el-form-item label="算法参数" prop="algorithmParams">
+          <el-button @click="showParamsDialog = true">设置参数</el-button>
+          <dynamic-form-dialog
+            :json-str="form.algorithmParams"
+            :visible.sync="showParamsDialog"
+            @submit="handleConfigSubmit"
+          />
+        </el-form-item>
+        <el-form-item label="备注" prop="remark">
+          <el-input v-model="form.remark" placeholder="请输入备注" />
+        </el-form-item>
+      </el-form>
+      <div slot="footer" class="dialog-footer">
+        <el-button type="primary" @click="submitForm">确 定</el-button>
+        <el-button @click="cancel">取 消</el-button>
+      </div>
+    </el-dialog>
+    <log-viewer
+      :currentLogUrl="currentLogUrl"
+      :dialogTitle="dialogTitle"
+      :logDialogVisible="logDialogVisible"
+      @updateLogDiaLlogVisible="updateLogDiaLlogVisible"
+    />
+  </div>
+</template>
+
+<script>
+import { listIdentificationt, getIdentificationt, delIdentificationt, addIdentificationt, updateIdentificationt, run, getTaskStatusIsChanged, } from "@/api/biz/identificationt";
+import { getOptionsByType } from "@/api/biz/config";
+import FolderPicker from "@/components/FolderPicker";
+import FilePicker from "@/components/FilePicker";
+import FileFolderPicker from "@/components/FileFolderPicker";
+import DynamicFormDialog from "@/components/DynamicFormDialog";
+import LogViewer from "@/components/LogViewer";
+const { shell } = window.require("electron");
+
+export default {
+  name: "Identificationt",
+  dicts: ['biz_status'],
+  components: {
+    FolderPicker,
+    FilePicker,
+    DynamicFormDialog,
+    LogViewer,
+    FileFolderPicker,
+  },
+  data() {
+    return {
+      // 遮罩层
+      loading: true,
+      // 选中数组
+      ids: [],
+      // 非单个禁用
+      single: true,
+      // 非多个禁用
+      multiple: true,
+      // 显示搜索条件
+      showSearch: true,
+      // 总条数
+      total: 0,
+      // 属性识别表格数据
+      identificationtList: [],
+      // 弹出层标题
+      title: "",
+      // 是否显示弹出层
+      open: false,
+      // 查询参数
+      queryParams: {
+        pageNum: 1,
+        pageSize: 10,
+        taskName: null,
+        algorithmId: null,
+        status: null,
+      },
+      // 表单参数
+      form: {},
+      // 表单校验
+      rules: {},
+      configOptions: [],
+      resultDetails: {},
+      detailsOpen: false,
+      jsonResult: {},
+      selectFileName: "",
+      showParamsDialog: false,
+      // 日志查看器
+      logDialogVisible: false,
+      currentLogUrl: "",
+      dialogTitle: "",
+      runningTaskId: null,
+      taskPollingInterval: null,
+    };
+  },
+  created() {
+    this.getList();
+    this.getOptions();
+  },
+  activated() {
+    this.getList();
+    this.getOptions();
+  },
+  methods: {
+    /** 查询属性识别列表 */
+    getList() {
+      this.loading = true;
+      listIdentificationt(this.queryParams).then(response => {
+        this.identificationtList = response.rows;
+        this.total = response.total;
+        this.loading = false;
+      });
+    },
+    // 取消按钮
+    cancel() {
+      this.open = false;
+      this.reset();
+    },
+    // 表单重置
+    reset() {
+      this.form = {
+        id: null,
+        taskName: null,
+        algorithmId: null,
+        modelPath: null,
+        modelPklPath: null,
+        inputPath: null,
+        outputPath: null,
+        algorithmParams: null,
+        status: null,
+        startTime: null,
+        endTime: null,
+        remark: null,
+        createBy: null,
+        createTime: null,
+        updateBy: null,
+        updateTime: null
+      };
+      this.resetForm("form");
+    },
+    /** 搜索按钮操作 */
+    handleQuery() {
+      this.queryParams.pageNum = 1;
+      this.getList();
+    },
+    /** 重置按钮操作 */
+    resetQuery() {
+      this.resetForm("queryForm");
+      this.handleQuery();
+    },
+    // 多选框选中数据
+    handleSelectionChange(selection) {
+      this.ids = selection.map(item => item.id)
+      this.single = selection.length!==1
+      this.multiple = !selection.length
+    },
+    /** 新增按钮操作 */
+    handleAdd() {
+      this.reset();
+      this.open = true;
+      this.title = "添加属性识别";
+    },
+    /** 修改按钮操作 */
+    handleUpdate(row) {
+      this.reset();
+      const id = row.id || this.ids
+      getIdentificationt(id).then(response => {
+        this.form = response.data;
+        this.open = true;
+        this.title = "修改属性识别";
+      });
+    },
+    /** 提交按钮 */
+    submitForm() {
+      this.$refs["form"].validate(valid => {
+        if (valid) {
+          if (this.form.id != null) {
+            updateIdentificationt(this.form).then(response => {
+              this.$modal.msgSuccess("修改成功");
+              this.open = false;
+              this.getList();
+            });
+          } else {
+            addIdentificationt(this.form).then(response => {
+              this.$modal.msgSuccess("新增成功");
+              this.open = false;
+              this.getList();
+            });
+          }
+        }
+      });
+    },
+    /** 删除按钮操作 */
+    handleDelete(row) {
+      const ids = row.id || this.ids;
+      this.$modal.confirm('是否确认删除属性识别?').then(function() {
+        return delIdentificationt(ids);
+      }).then(() => {
+        this.getList();
+        this.$modal.msgSuccess("删除成功");
+      }).catch(() => {});
+    },
+    /** 导出按钮操作 */
+    handleExport() {
+      this.download('biz/identificationt/export', {
+        ...this.queryParams
+      }, `identificationt_${new Date().getTime()}.xlsx`)
+    },
+    getOptions() {
+      getOptionsByType("7").then((response) => {
+        this.configOptions = response.data;
+      });
+    },
+    changeAlgorithmId() {
+      const algorithmId = this.form.algorithmId;
+      const config = this.configOptions.find((item) => item.id === algorithmId);
+      if (config && config.params) {
+        this.form.algorithmParams = config.params;
+      } else {
+        this.form.algorithmParams = "";
+      }
+    },
+
+    handleConfigSubmit(modifiedJson) {
+      this.form.algorithmParams = modifiedJson;
+      // 这里可以添加处理配置更新的逻辑
+      console.log("更新后的配置:", JSON.parse(modifiedJson));
+    },
+    updateLogDiaLlogVisible(visiible) {
+      console.log("updateLogDiaLlogVisible", visiible);
+      this.logDialogVisible = visiible;
+    },
+    showLogViewer(row) {
+      this.currentLogUrl = row.outputPath + "\\" + "log.log";
+      this.dialogTitle = "日志";
+      this.logDialogVisible = true;
+    },
+    openFolder(row) {
+      try {
+        shell.openPath(row.outputPath).then((result) => {
+          if (result) {
+            this.$message.error(`打开文件夹失败: ${result}`);
+          }
+        });
+      } catch (error) {
+        this.$message.error(`打开文件夹出错: ${error.message}`);
+      }
+    },
+    // 运行任务并开始轮询状态
+    runTaskAndPollStatus(id) {
+      this.runningTaskId = id;
+      try {
+        // 开始轮询任务状态
+        this.startPollingTaskStatus(id);
+      } catch (error) {
+        console.error("运行任务失败:", error);
+        this.clearPollingInterval();
+        throw error;
+      }
+    },
+
+    // 开始轮询任务状态
+    startPollingTaskStatus(id) {
+      // 先清除可能存在的已有定时器
+      this.clearPollingInterval();
+
+      // 立即查询一次状态
+      this.checkTaskStatus(id);
+
+      // 设置定时器,每3秒查询一次
+      this.taskPollingInterval = setInterval(() => {
+        this.checkTaskStatus(id);
+      }, 3000);
+    },
+
+    // 查询任务状态
+    checkTaskStatus(id) {
+      try {
+        getTaskStatusIsChanged(id).then((response) => {
+          if (response.data) {
+            // 这里根据你的实际状态判断
+            // 状态变化,更新列表并停止轮询
+            this.getList();
+            this.clearPollingInterval();
+            alert("任务已完成!");
+          }
+        });
+      } catch (error) {
+        console.error("查询任务状态失败:", error);
+        this.clearPollingInterval();
+      }
+    },
+
+    // 清除轮询定时器
+    clearPollingInterval() {
+      if (this.taskPollingInterval) {
+        clearInterval(this.taskPollingInterval);
+        this.taskPollingInterval = null;
+        this.runningTask = {};
+      }
+    },
+    handleRun(row) {
+      const id = row.id;
+      run(id).then((response) => {
+        alert("任务开始运行!");
+      });
+      this.getList();
+      this.runTaskAndPollStatus(id);
+    },
+  }
+};
+</script>

+ 45 - 1
sql/biz.sql

@@ -164,6 +164,27 @@ create table biz_time_frequency_images(
 --  PRIMARY KEY (`page_id`)
 --) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='页面配置表';
 
+drop table if exists biz_attribute_identificationt;
+create table biz_attribute_identificationt (
+  id           bigint(20)      not null auto_increment    comment '编号',
+  task_name         varchar(50)      default ''                comment '任务名称',
+  algorithm_id      bigint(20)                                 comment '算法',
+  model_path        varchar(255)     default ''                comment '模型pth',
+  model_pkl_path        varchar(255)     default ''            comment '模型pkl',
+  input_path        varchar(255)     default ''                comment '输入路径',
+  output_path       varchar(255)     default ''                comment '输出路径',
+  algorithm_params  text                                       comment '算法参数',
+  status            char(1)          default '0'               comment '状态(0未运行,1运行中,2已完成,3失败)',
+  start_time        datetime                                   comment '开始时间',
+  end_time          datetime                                   comment '结束时间',
+  remark            varchar(255)          default ''           comment '备注',
+  create_by         varchar(64)     default ''                 comment '创建者',
+  create_time 	    datetime                                   comment '创建时间',
+  update_by         varchar(64)     default ''                 comment '更新者',
+  update_time       datetime                                   comment '更新时间',
+  primary key (id)
+) engine=innodb comment = '属性识别表';
+
 
 -- 菜单 SQL
 insert into sys_menu (menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, update_by, update_time, remark)
@@ -325,4 +346,27 @@ insert into sys_menu (menu_name, parent_id, order_num, path, component, is_frame
 values('时频图生成删除', @parentId, '4',  '#', '', 1, 0, 'F', '0', '0', 'biz:images:remove',       '#', 'admin', sysdate(), '', null, '');
 
 insert into sys_menu (menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, update_by, update_time, remark)
-values('时频图生成导出', @parentId, '5',  '#', '', 1, 0, 'F', '0', '0', 'biz:images:export',       '#', 'admin', sysdate(), '', null, '');
+values('时频图生成导出', @parentId, '5',  '#', '', 1, 0, 'F', '0', '0', 'biz:images:export',       '#', 'admin', sysdate(), '', null, '');
+
+-- 菜单 SQL
+insert into sys_menu (menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, update_by, update_time, remark)
+values('属性识别', '2008', '1', 'identificationt', 'biz/identificationt/index', 1, 0, 'C', '0', '0', 'biz:identificationt:list', '#', 'admin', sysdate(), '', null, '属性识别菜单');
+
+-- 按钮父菜单ID
+SELECT @parentId := LAST_INSERT_ID();
+
+-- 按钮 SQL
+insert into sys_menu (menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, update_by, update_time, remark)
+values('属性识别查询', @parentId, '1',  '#', '', 1, 0, 'F', '0', '0', 'biz:identificationt:query',        '#', 'admin', sysdate(), '', null, '');
+
+insert into sys_menu (menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, update_by, update_time, remark)
+values('属性识别新增', @parentId, '2',  '#', '', 1, 0, 'F', '0', '0', 'biz:identificationt:add',          '#', 'admin', sysdate(), '', null, '');
+
+insert into sys_menu (menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, update_by, update_time, remark)
+values('属性识别修改', @parentId, '3',  '#', '', 1, 0, 'F', '0', '0', 'biz:identificationt:edit',         '#', 'admin', sysdate(), '', null, '');
+
+insert into sys_menu (menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, update_by, update_time, remark)
+values('属性识别删除', @parentId, '4',  '#', '', 1, 0, 'F', '0', '0', 'biz:identificationt:remove',       '#', 'admin', sysdate(), '', null, '');
+
+insert into sys_menu (menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, update_by, update_time, remark)
+values('属性识别导出', @parentId, '5',  '#', '', 1, 0, 'F', '0', '0', 'biz:identificationt:export',       '#', 'admin', sysdate(), '', null, '');

+ 43 - 0
sql/ips_update20250701.sql

@@ -0,0 +1,43 @@
+drop table if exists biz_attribute_identificationt;
+create table biz_attribute_identificationt (
+  id           bigint(20)      not null auto_increment    comment '编号',
+  task_name         varchar(50)      default ''                comment '任务名称',
+  algorithm_id      bigint(20)                                 comment '算法',
+  model_path        varchar(255)     default ''                comment '模型pth',
+  model_pkl_path        varchar(255)     default ''            comment '模型pkl',
+  input_path        varchar(255)     default ''                comment '输入路径',
+  output_path       varchar(255)     default ''                comment '输出路径',
+  algorithm_params  text                                       comment '算法参数',
+  status            char(1)          default '0'               comment '状态(0未运行,1运行中,2已完成,3失败)',
+  start_time        datetime                                   comment '开始时间',
+  end_time          datetime                                   comment '结束时间',
+  remark            varchar(255)          default ''           comment '备注',
+  create_by         varchar(64)     default ''                 comment '创建者',
+  create_time 	    datetime                                   comment '创建时间',
+  update_by         varchar(64)     default ''                 comment '更新者',
+  update_time       datetime                                   comment '更新时间',
+  primary key (id)
+) engine=innodb comment = '属性识别表';
+
+-- 菜单 SQL
+insert into sys_menu (menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, update_by, update_time, remark)
+values('属性识别', '2008', '1', 'identificationt', 'biz/identificationt/index', 1, 0, 'C', '0', '0', 'biz:identificationt:list', '#', 'admin', sysdate(), '', null, '属性识别菜单');
+
+-- 按钮父菜单ID
+SELECT @parentId := LAST_INSERT_ID();
+
+-- 按钮 SQL
+insert into sys_menu (menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, update_by, update_time, remark)
+values('属性识别查询', @parentId, '1',  '#', '', 1, 0, 'F', '0', '0', 'biz:identificationt:query',        '#', 'admin', sysdate(), '', null, '');
+
+insert into sys_menu (menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, update_by, update_time, remark)
+values('属性识别新增', @parentId, '2',  '#', '', 1, 0, 'F', '0', '0', 'biz:identificationt:add',          '#', 'admin', sysdate(), '', null, '');
+
+insert into sys_menu (menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, update_by, update_time, remark)
+values('属性识别修改', @parentId, '3',  '#', '', 1, 0, 'F', '0', '0', 'biz:identificationt:edit',         '#', 'admin', sysdate(), '', null, '');
+
+insert into sys_menu (menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, update_by, update_time, remark)
+values('属性识别删除', @parentId, '4',  '#', '', 1, 0, 'F', '0', '0', 'biz:identificationt:remove',       '#', 'admin', sysdate(), '', null, '');
+
+insert into sys_menu (menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, update_by, update_time, remark)
+values('属性识别导出', @parentId, '5',  '#', '', 1, 0, 'F', '0', '0', 'biz:identificationt:export',       '#', 'admin', sysdate(), '', null, '');