jiazx0107
2025-12-30 c106cce63d27889807111bad4dbc6f89b738f716
新增工单流程配置页面
已删除1个文件
已添加7个文件
已修改9个文件
1539 ■■■■■ 文件已修改
fzzy-igdss-core/src/main/java/com/fzzy/work/data/WorkBizType.java 41 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
fzzy-igdss-core/src/main/java/com/fzzy/work/domain/WorkOrderConf.java 80 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
fzzy-igdss-core/src/main/java/com/fzzy/work/mapper/WorkOrderConfMapper.java 10 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
fzzy-igdss-core/src/main/java/com/fzzy/work/service/WorkOrderConfService.java 61 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
fzzy-igdss-core/src/main/java/com/fzzy/work/service/WorkOrderService.java 33 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
fzzy-igdss-view/src/main/java/com/fzzy/igds/ConfByDept.view.xml 16 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
fzzy-igdss-view/src/main/java/com/fzzy/igds/InoutNoticeIn.view.xml 8 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
fzzy-igdss-view/src/main/java/com/fzzy/igds/SelectDeptPR.java 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
fzzy-igdss-view/src/main/java/com/fzzy/igds/SnapConfPR.java 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
fzzy-igdss-view/src/main/java/com/fzzy/work/WorkOrderConf.view.xml 279 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
fzzy-igdss-view/src/main/java/com/fzzy/work/WorkOrderPR.java 89 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
fzzy-igdss-view/src/main/java/com/fzzy/work/WorkProcess.view.xml 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
fzzy-igdss-view/src/main/java/com/fzzy/work/WorkProcessPR.java 33 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
fzzy-igdss-web/src/main/java/com/fzzy/work/WorkOrderController.java 25 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
fzzy-igdss-web/src/main/resources/d7/common.css 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
fzzy-igdss-web/src/main/resources/templates/test/flow.html 499 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
fzzy-igdss-web/src/main/resources/templates/work/flow-conf.html 359 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
fzzy-igdss-core/src/main/java/com/fzzy/work/data/WorkBizType.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,41 @@
package com.fzzy.work.data;
/**
 * @Desc: å·¥å•业务分类枚举类
 * @Author: Andy.jia
 * @Date: 2025/12/18
 */
public enum WorkBizType {
    TYPE_10("10", "入库通知单流程"),
    TYPE_20("20", "出库通知单流程"),
    TYPE_30("30", "AI事件"),
    TYPE_40("40", "预警/警告"),
    TYPE_99("99", "其他");
    private String code;
    private String msg;
    WorkBizType(String code, String msg) {
        this.code = code;
        this.msg = msg;
    }
    public String getCode() {
        return code;
    }
    public String getMsg() {
        return msg;
    }
    public static String getMsg(String code) {
        if(null == code) return null;
        if(WorkBizType.TYPE_10.getCode().equals(code)) return WorkBizType.TYPE_10.getMsg();
        if(WorkBizType.TYPE_20.getCode().equals(code)) return WorkBizType.TYPE_20.getMsg();
        if(WorkBizType.TYPE_30.getCode().equals(code)) return WorkBizType.TYPE_30.getMsg();
        if(WorkBizType.TYPE_40.getCode().equals(code)) return WorkBizType.TYPE_40.getMsg();
        if(WorkBizType.TYPE_99.getCode().equals(code)) return WorkBizType.TYPE_99.getMsg();
        return code;
    }
}
fzzy-igdss-core/src/main/java/com/fzzy/work/domain/WorkOrderConf.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,80 @@
package com.fzzy.work.domain;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.fzzy.igds.constant.Constant;
import com.fzzy.igds.domain.BizBaseEntity;
import lombok.Data;
import lombok.EqualsAndHashCode;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;
import java.io.Serializable;
/**
 * @Desc: å·¥å•配置类
 * @Author: Andy.jia
 * @Date: 2025/12/29
 */
@Data
@Entity
@Table(name = "work_order_conf")
@TableName("work_order_conf")
@EqualsAndHashCode(callSuper = false)
public class WorkOrderConf extends BizBaseEntity implements Serializable {
    /**
     *
     */
    private static final long serialVersionUID = 1L;
    @Id
    @Column(name = "id", columnDefinition = "varchar(40) COMMENT '主键'")
    @TableId(value = "id", type = IdType.NONE)
    @TableField("id")
    private String id;
    @Column(name = "dept_id", columnDefinition = "varchar(40) COMMENT '所属库区'")
    @TableField("dept_id")
    private String deptId;
    @Column(name = "biz_type", columnDefinition = "varchar(20) COMMENT '业务分类'")
    @TableField("biz_type")
    private String bizType;
    @Column(name = "val_tag", columnDefinition = "varchar(2) COMMENT '是有启用'")
    @TableField("val_tag")
    private String valTag = Constant.YN_Y;
    @Column(name = "node_name1", columnDefinition = "varchar(30) COMMENT '节点名称'")
    @TableField("node_name1")
    private String nodeName1 = "库区审批";
    @Column(name = "node_val1", columnDefinition = "varchar(2) COMMENT '是否有效'")
    @TableField("node_val1")
    private String nodeVal1 = Constant.YN_N;
    @Column(name = "node_name2", columnDefinition = "varchar(30) COMMENT '节点名称'")
    @TableField("node_name2")
    private String nodeName2 = "监管审批";
    @Column(name = "node_val2", columnDefinition = "varchar(2) COMMENT '是否有效'")
    @TableField("node_val2")
    private String nodeVal2 = Constant.YN_Y;
    @Column(name = "node_name3", columnDefinition = "varchar(30) COMMENT '节点名称'")
    @TableField("node_name3")
    private String nodeName3 = "银行审批";
    @Column(name = "node_val3", columnDefinition = "varchar(2) COMMENT '是否有效'")
    @TableField("node_val3")
    private String nodeVal3 = Constant.YN_Y;
    @Column(name = "remark", columnDefinition = "varchar(200) COMMENT '备注信息'")
    @TableField("remark")
    private String remark;
}
fzzy-igdss-core/src/main/java/com/fzzy/work/mapper/WorkOrderConfMapper.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,10 @@
package com.fzzy.work.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.fzzy.work.domain.WorkOrderConf;
import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface WorkOrderConfMapper extends BaseMapper<WorkOrderConf> {
}
fzzy-igdss-core/src/main/java/com/fzzy/work/service/WorkOrderConfService.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,61 @@
package com.fzzy.work.service;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.fzzy.igds.data.BaseResp;
import com.fzzy.igds.utils.ContextUtil;
import com.fzzy.work.domain.WorkOrderConf;
import com.fzzy.work.mapper.WorkOrderConfMapper;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.Date;
import java.util.List;
/**
 * @Desc:
 * @Author: Andy.jia
 * @Date: 2025/12/29
 */
@Service
public class WorkOrderConfService {
    @Resource
    private WorkOrderConfMapper mapper;
    public List<WorkOrderConf> queryList(String deptId) {
        if (StringUtils.isEmpty(deptId)) return null;
        QueryWrapper<WorkOrderConf> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("dept_id", deptId);
        return mapper.selectList(queryWrapper);
    }
    public WorkOrderConf selectById(String id) {
        if (StringUtils.isEmpty(id)) return null;
        return mapper.selectById(id);
    }
    public void insertConf(WorkOrderConf data) {
        data.setId(ContextUtil.generateId());
        data.setCreateBy(ContextUtil.getLoginUserName());
        data.setCreateTime(new Date());
        data.setUpdateBy(ContextUtil.getLoginUserName());
        data.setUpdateTime(new Date());
        if(null == data.getCompanyId()) data.setCompanyId(ContextUtil.getCompanyId());
        mapper.insert(data);
    }
    public void updateConf(WorkOrderConf data) {
        data.setUpdateBy(ContextUtil.getLoginUserName());
        data.setUpdateTime(new Date());
        mapper.updateById(data);
    }
    public BaseResp deleteConf(WorkOrderConf data) {
        if (null == data.getId()) return BaseResp.success();
        return mapper.deleteById(data.getId()) > 0 ? BaseResp.success() : BaseResp.error("删除失败");
    }
}
fzzy-igdss-core/src/main/java/com/fzzy/work/service/WorkOrderService.java
@@ -5,6 +5,7 @@
import com.fzzy.igds.utils.ContextUtil;
import com.fzzy.igds.utils.DateUtil;
import com.fzzy.work.data.OrderStatus;
import com.fzzy.work.data.WorkBizType;
import com.fzzy.work.data.WorkOrderParam;
import com.fzzy.work.domain.WorkOrder;
import com.fzzy.work.mapper.WorkOrderMapper;
@@ -36,7 +37,7 @@
            param = new WorkOrderParam();
        }
        if(null == param.getCompanyId())param.setCompanyId(ContextUtil.getCompanyId());
        if (null == param.getCompanyId()) param.setCompanyId(ContextUtil.getCompanyId());
        queryWrapper.eq("company_id", param.getCompanyId());
@@ -45,23 +46,31 @@
        queryWrapper.like(null != param.getName(), "title", param.getName());
        queryWrapper.eq(null != param.getStatus(), "status", param.getStatus());
        if(null != param.getStart()){
        if (null != param.getStart()) {
            queryWrapper.gt("create_time", DateUtil.getNextZero(param.getStart()));
        }
        if(null != param.getEnd()){
        if (null != param.getEnd()) {
            queryWrapper.lt("create_time", DateUtil.getCurZero(param.getEnd()));
        }
        workOrderMapper.selectPage(page, queryWrapper);
    }
    public List<SysDictData> triggerStatus() {
         List<SysDictData> list = new ArrayList<SysDictData>();
            for (OrderStatus w : OrderStatus.values()) {
                list.add(new SysDictData(w.getMsg(), w.getCode()));
            }
            return list;
    }
    public List<SysDictData> triggerStatus() {
        List<SysDictData> list = new ArrayList<SysDictData>();
        for (OrderStatus w : OrderStatus.values()) {
            list.add(new SysDictData(w.getMsg(), w.getCode()));
        }
        return list;
    }
    public List<SysDictData> triggerType() {
        List<SysDictData> list = new ArrayList<SysDictData>();
        for (WorkBizType w : WorkBizType.values()) {
            list.add(new SysDictData(w.getMsg(), w.getCode()));
        }
        return list;
    }
    /**
     * èŽ·å–ç”¨æˆ·å¾…å¤„ç†å·¥å•æ•°
@@ -72,7 +81,7 @@
    public Integer getNumByUser(String status, String userId) {
        QueryWrapper<WorkOrder> queryWrapper = new QueryWrapper<>();
        if(StringUtils.isBlank(userId) || StringUtils.isBlank(status)){
        if (StringUtils.isBlank(userId) || StringUtils.isBlank(status)) {
            return 0;
        }
@@ -81,4 +90,6 @@
        return workOrderMapper.selectCount(queryWrapper);
    }
}
fzzy-igdss-view/src/main/java/com/fzzy/igds/ConfByDept.view.xml
@@ -175,12 +175,26 @@
    }else{&#xD;
        $notify(&quot;请先选择库区……&quot;);&#xD;
    }
};
/**
* å·¥å•配置
*/
workOrderConf = function(){
    var cur = view.get(&quot;#dgMain&quot;).get(&quot;selection&quot;);
    if(cur){
        var deptId = cur.get(&quot;id&quot;);
        var url = &quot;/com.fzzy.work.WorkOrderConf.d?deptId=&quot;+ deptId;
        window.$openTab(&quot;工单配置&quot;, url);
    }else{
        $notify(&quot;请先选择库区……&quot;);
    }
};&#xD;
//操作&#xD;
renderCell1 = function(arg,self){&#xD;
    var data = arg.data;&#xD;
    var htm = &quot;&lt;a onClick='inoutConf()' class='a-btn1'>出入库配置&lt;/a>&amp;nbsp;|&amp;nbsp;&lt;a onClick='snapConf()' class='a-btn2'>抓拍配置&lt;/a>&amp;nbsp;|&amp;nbsp;&lt;a onClick='patrolConf()' class='a-btn4'>巡检配置&lt;/a>&quot;;&#xD;
    var htm = &quot;&lt;a onClick='inoutConf()' class='a-btn1'>出入库配置&lt;/a>&amp;nbsp;|&amp;nbsp;&lt;a onClick='snapConf()' class='a-btn2'>抓拍配置&lt;/a>&amp;nbsp;|&amp;nbsp;&lt;a onClick='patrolConf()' class='a-btn4'>巡检配置&lt;/a>&amp;nbsp;|&amp;nbsp;&lt;a onClick='workOrderConf()' class='a-btn2'>工单审批&lt;/a>&quot;;&#xD;
    arg.dom.innerHTML = htm;&#xD;
};&#xD;
&#xD;</ClientEvent>
fzzy-igdss-view/src/main/java/com/fzzy/igds/InoutNoticeIn.view.xml
@@ -34,11 +34,11 @@
          <Property name="mapValues">
            <Collection>
              <Entity>
                <Property name="name">库区通知单</Property>
                <Property name="name">库区自建通知单</Property>
                <Property name="code">10</Property>
              </Entity>
              <Entity>
                <Property name="name">监管通知单</Property>
                <Property name="name">质押监管通知单</Property>
                <Property name="code">20</Property>
              </Entity>
            </Collection>
@@ -310,7 +310,7 @@
        </ToolBarButton>
      </ToolBar>
      <DataGrid id="dataGridMain" layoutConstraint="padding:8">
        <ClientEvent name="onDataRowClick">view.get(&quot;#dataGridMain&quot;).set(&quot;selection&quot;,arg.data);</ClientEvent>
        <ClientEvent name="onDataRowClick">self.set(&quot;selection&quot;,arg.data);</ClientEvent>
        <Property name="dataSet">dsMain</Property>
        <Property name="readOnly">true</Property>
        <Property name="selectionMode">singleRow</Property>
@@ -452,7 +452,7 @@
            <AutoFormElement>
              <Property name="name">type</Property>
              <Property name="property">type</Property>
              <Property name="editorType">RadioGroup</Property>
              <Property name="trigger">autoMappingDropDown1</Property>
              <Editor/>
            </AutoFormElement>
            <AutoFormElement>
fzzy-igdss-view/src/main/java/com/fzzy/igds/SelectDeptPR.java
@@ -7,7 +7,6 @@
import com.fzzy.igds.service.CoreCompanyService;
import com.fzzy.igds.service.CoreDeptService;
import com.fzzy.igds.utils.ContextUtil;
import com.ruoyi.common.config.FrameworkConfig;
import com.ruoyi.common.core.domain.entity.SysUser;
import org.springframework.stereotype.Component;
fzzy-igdss-view/src/main/java/com/fzzy/igds/SnapConfPR.java
@@ -3,7 +3,6 @@
import com.bstek.dorado.annotation.DataProvider;
import com.bstek.dorado.annotation.DataResolver;
import com.bstek.dorado.annotation.Expose;
import com.fzzy.igds.data.BaseResp;
import com.fzzy.igds.domain.SnapConf;
import com.fzzy.igds.service.SnapConfService;
import com.fzzy.igds.utils.ContextUtil;
fzzy-igdss-view/src/main/java/com/fzzy/work/WorkOrderConf.view.xml
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,279 @@
<?xml version="1.0" encoding="UTF-8"?>
<ViewConfig>
  <Arguments/>
  <Context/>
  <Model>
    <DataType name="dtWorkConf">
      <Property name="creationType">com.fzzy.work.domain.WorkOrderConf</Property>
      <PropertyDef name="id">
        <Property/>
      </PropertyDef>
      <PropertyDef name="deptId">
        <Property/>
        <Property name="label">所属库区</Property>
        <Property name="required">true</Property>
      </PropertyDef>
      <PropertyDef name="bizType">
        <Property/>
        <Property name="label">业务类型</Property>
        <Property name="mapping">
          <Property name="mapValues">${dorado.getDataProvider(&quot;workOrderPR#triggerType&quot;).getResult()}</Property>
          <Property name="keyProperty">dictValue</Property>
          <Property name="valueProperty">dictLabel</Property>
        </Property>
        <Property name="required">true</Property>
      </PropertyDef>
      <PropertyDef name="valTag">
        <Property/>
        <Property name="label">启用流程</Property>
        <Property name="mapping">
          <Property name="mapValues">${dorado.getDataProvider(&quot;dicPR#triggerYN&quot;).getResult()}</Property>
          <Property name="keyProperty">dictValue</Property>
          <Property name="valueProperty">dictLabel</Property>
        </Property>
        <Property name="required">true</Property>
      </PropertyDef>
      <PropertyDef name="nodeName1">
        <Property/>
        <Property name="label">节点名称</Property>
      </PropertyDef>
      <PropertyDef name="nodeVal1">
        <Property/>
        <Property name="label">是否有效</Property>
      </PropertyDef>
      <PropertyDef name="nodeName2">
        <Property/>
        <Property name="label">节点名称</Property>
      </PropertyDef>
      <PropertyDef name="nodeVal2">
        <Property/>
        <Property name="label">是否有效</Property>
      </PropertyDef>
      <PropertyDef name="nodeName3">
        <Property/>
        <Property name="label">节点名称</Property>
      </PropertyDef>
      <PropertyDef name="nodeVal3">
        <Property/>
        <Property name="label">是否有效</Property>
      </PropertyDef>
      <PropertyDef name="remark">
        <Property/>
        <Property name="label">备注信息</Property>
      </PropertyDef>
      <PropertyDef name="companyId">
        <Property/>
      </PropertyDef>
      <PropertyDef name="createBy">
        <Property/>
        <Property name="label">创建人</Property>
      </PropertyDef>
      <PropertyDef name="createTime">
        <Property name="dataType">DateTime</Property>
        <Property name="label">创建时间</Property>
      </PropertyDef>
      <PropertyDef name="updateBy">
        <Property/>
        <Property name="label">修改人</Property>
      </PropertyDef>
      <PropertyDef name="updateTime">
        <Property name="dataType">DateTime</Property>
        <Property name="label">修改时间</Property>
      </PropertyDef>
    </DataType>
  </Model>
  <View layout="padding:10">
    <ClientEvent name="onReady">var deptId = &quot;${request.getParameter('deptId')}&quot;;&#xD;
&#xD;
query = function(){&#xD;
    view.get(&quot;#dsMain&quot;).set(&quot;parameter&quot;,deptId).flushAsync();&#xD;
}&#xD;
query();&#xD;
&#xD;
&#xD;
addData = function(){&#xD;
    view.get(&quot;#dsMain&quot;).insert({&#xD;
        deptId:deptId&#xD;
    });&#xD;
    &#xD;
    //流程图&#xD;
    view.get(&quot;#iFrameFlow&quot;).set(&quot;path&quot;,&quot;work/flow-conf?id=&quot;)&#xD;
    &#xD;
    &#xD;
    view.get(&quot;#dialogMain&quot;).show();&#xD;
}&#xD;
&#xD;
showDetail = function(){&#xD;
    var cur = view.get(&quot;#dsMain.data:#&quot;);&#xD;
    //流程图&#xD;
    view.get(&quot;#iFrameFlow&quot;).set(&quot;path&quot;,&quot;work/flow-conf?id=&quot;+cur.get(&quot;id&quot;));&#xD;
    &#xD;
    view.get(&quot;#dialogMain&quot;).show();&#xD;
}&#xD;
&#xD;
//流程图中节点启用禁用的方法&#xD;
onNodeValChange = function(nodes){&#xD;
    if(!nodes) return;&#xD;
    var cur = view.get(&quot;#dsMain.data:#&quot;);&#xD;
    nodes.forEach(function(node,index){&#xD;
        if(&quot;node1&quot; == node.node){&#xD;
            if(node.val){cur.set(&quot;nodeVal1&quot;,&quot;Y&quot;);} else{cur.set(&quot;nodeVal1&quot;,&quot;N&quot;);}&#xD;
            cur.set(&quot;nodeName1&quot;,node.name);&#xD;
        }&#xD;
        if(&quot;node2&quot; == node.node){&#xD;
            if(node.val){cur.set(&quot;nodeVal2&quot;,&quot;Y&quot;);} else{cur.set(&quot;nodeVal2&quot;,&quot;N&quot;);}&#xD;
            cur.set(&quot;nodeName2&quot;,node.name);&#xD;
        }&#xD;
        if(&quot;node3&quot; == node.node){&#xD;
            if(node.val){cur.set(&quot;nodeVal3&quot;,&quot;Y&quot;);} else{cur.set(&quot;nodeVal3&quot;,&quot;N&quot;);}&#xD;
            cur.set(&quot;nodeName3&quot;,node.name);&#xD;
        }&#xD;
    });&#xD;
}&#xD;
</ClientEvent>
    <Property name="packages">font-awesome,css-common</Property>
    <DataSet id="dsMain">
      <Property name="dataType">[dtWorkConf]</Property>
      <Property name="dataProvider">workOrderPR#confList</Property>
      <Property name="loadMode">manual</Property>
    </DataSet>
    <Container>
      <Property name="className">c-data</Property>
      <ToolBar>
        <ToolBarButton>
          <ClientEvent name="onClick">addData();</ClientEvent>
          <Property name="caption">新增</Property>
          <Property name="exClassName">btn1</Property>
          <Property name="width">100</Property>
          <Property name="iconClass">fa fa-plus</Property>
        </ToolBarButton>
        <ToolBarButton>
          <ClientEvent name="onClick">showDetail();</ClientEvent>
          <Property name="id">btnUpdate</Property>
          <Property name="caption">修改</Property>
          <Property name="exClassName">btn2</Property>
          <Property name="width">100</Property>
          <Property name="iconClass">fa fa-pencil-square-o</Property>
        </ToolBarButton>
        <ToolBarButton>
          <ClientEvent name="onClick">var data = view.get(&quot;#dsMian.data:#&quot;);
if (!data) {
    $alert(&quot;请选择数据&quot;);
    return;
}
view.get(&quot;#ajaxDelData&quot;).set(&quot;parameter&quot;, data).execute(function(result){
    if(&quot;200&quot;!=result.respCode){
        $alert(&quot;异常信息:&quot;+result.respMsg);
    }else{
        $notify(&quot;执行成功&quot;);
        query();
    }
});</ClientEvent>
          <Property name="caption">删除</Property>
          <Property name="exClassName">btn3</Property>
          <Property name="width">100</Property>
          <Property name="iconClass">fa fa-times</Property>
        </ToolBarButton>
      </ToolBar>
      <DataGrid id="dgMain" layoutConstraint="padding:8" selectionMode="singleRow">
        <ClientEvent name="onDataRowClick">self.set(&quot;selection&quot;, arg.data)</ClientEvent>
        <Property name="dataSet">dsMain</Property>
        <Property name="readOnly">true</Property>
        <RowSelectorColumn/>
        <RowNumColumn/>
        <DataColumn name="deptId">
          <Property name="property">deptId</Property>
        </DataColumn>
        <DataColumn name="bizType">
          <Property name="property">bizType</Property>
        </DataColumn>
        <DataColumn name="valTag">
          <Property name="property">valTag</Property>
        </DataColumn>
        <DataColumn name="updateBy">
          <Property name="property">updateBy</Property>
        </DataColumn>
        <DataColumn name="updateTime">
          <Property name="property">updateTime</Property>
        </DataColumn>
        <DataColumn name="remark">
          <Property name="property">remark</Property>
        </DataColumn>
      </DataGrid>
    </Container>
    <Dialog id="dialogMain">
      <Property name="width">1100</Property>
      <Property name="caption">工单审核配置</Property>
      <Property name="closeable">false</Property>
      <Property name="iconClass">fa fa-tasks</Property>
      <Buttons>
        <Button>
          <ClientEvent name="onClick">view.get(&quot;#saveAction&quot;).execute(function(){&#xD;
    self.get(&quot;parent&quot;).hide();&#xD;
});</ClientEvent>
          <Property name="caption">保存</Property>
          <Property name="iconClass">fa fa-check-circle</Property>
          <Property name="exClassName">btn1</Property>
          <Property name="width">120</Property>
        </Button>
        <Button>
          <ClientEvent name="onClick">view.get(&quot;#dsMain.data:#&quot;).cancel();&#xD;
self.get(&quot;parent&quot;).hide();</ClientEvent>
          <Property name="caption">取消</Property>
          <Property name="exClassName">btn3</Property>
          <Property name="iconClass">fa fa-times-circle</Property>
          <Property name="width">120</Property>
        </Button>
      </Buttons>
      <Children>
        <Container>
          <AutoForm layoutConstraint="padding:10">
            <Property name="cols">*,*,*</Property>
            <Property name="dataSet">dsMain</Property>
            <Property name="labelSeparator">:</Property>
            <Property name="labelAlign">right</Property>
            <Property name="labelWidth">120</Property>
            <AutoFormElement>
              <Property name="name">deptId</Property>
              <Property name="property">deptId</Property>
              <Editor/>
            </AutoFormElement>
            <AutoFormElement>
              <Property name="name">bizType</Property>
              <Property name="property">bizType</Property>
              <Editor/>
            </AutoFormElement>
            <AutoFormElement>
              <Property name="name">valTag</Property>
              <Property name="property">valTag</Property>
              <Editor/>
            </AutoFormElement>
            <AutoFormElement layoutConstraint="colSpan:3">
              <Property name="name">remark</Property>
              <Property name="property">remark</Property>
              <Property name="editorType">TextArea</Property>
              <Editor/>
            </AutoFormElement>
          </AutoForm>
        </Container>
        <IFrame id="iFrameFlow">
          <Property name="path">work/flow-conf</Property>
          <Property name="height">280</Property>
          <Property name="width">100%</Property>
        </IFrame>
      </Children>
      <Tools/>
    </Dialog>
    <UpdateAction id="saveAction">
      <Property name="dataResolver">workOrderPR#saveConf</Property>
      <UpdateItem>
        <Property name="dataSet">dsMain</Property>
        <Property name="dataPath">[#current]</Property>
      </UpdateItem>
    </UpdateAction>
    <AjaxAction id="ajaxDelData">
      <Property name="confirmMessage">确定要删除数据么?</Property>
      <Property name="service">workOrderPR#delConf</Property>
    </AjaxAction>
  </View>
</ViewConfig>
fzzy-igdss-view/src/main/java/com/fzzy/work/WorkOrderPR.java
@@ -1,14 +1,22 @@
package com.fzzy.work;
import com.bstek.dorado.annotation.DataProvider;
import com.bstek.dorado.annotation.DataResolver;
import com.bstek.dorado.annotation.Expose;
import com.bstek.dorado.data.provider.Page;
import com.fzzy.igds.data.BaseResp;
import com.fzzy.igds.utils.ContextUtil;
import com.fzzy.work.data.OrderStatus;
import com.fzzy.work.domain.WorkOrder;
import com.fzzy.work.data.WorkOrderParam;
import com.fzzy.work.domain.WorkOrderConf;
import com.fzzy.work.domain.WorkOrderProcess;
import com.fzzy.work.service.WorkOrderConfService;
import com.fzzy.work.service.WorkOrderProcessService;
import com.fzzy.work.service.WorkOrderService;
import com.ruoyi.common.core.domain.entity.SysDictData;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Component;
import java.util.List;
@@ -25,7 +33,10 @@
    @Resource
    private WorkOrderService workOrderService;
    @Resource
    private WorkOrderProcessService workOrderProcessService;
    @Resource
    private WorkOrderConfService workOrderConfService;
    /**
     *
@@ -71,8 +82,8 @@
        page.setEntities(corePage.getRecords());
        page.setEntityCount(Integer.parseInt(String.valueOf(corePage.getTotal())));
    }
    /**
     * å·¥å•状态
     * ${dorado.getDataProvider("workOrderPR#triggerStatus").getResult()}
@@ -83,4 +94,76 @@
    public List<SysDictData> triggerStatus() {
        return workOrderService.triggerStatus();
    }
    //--------------------工单审批历史信息查询--------------------
    /**
     *
     * workOrderPR#processList
     * ä¿¡æ¯åˆ—表
     * @param orderId å·¥å•ID
     */
    @DataProvider
    public List<WorkOrderProcess> processList(String orderId) {
        return workOrderProcessService.queryList(orderId);
    }
    //--------------------工单审批配置信息管理--------------------
    /**
     *
     * workOrderPR#confList
     * ä¿¡æ¯åˆ—表
     *
     */
    @DataProvider
    public List<WorkOrderConf> confList(String deptId) {
        return workOrderConfService.queryList(deptId);
    }
    /**
     *
     * workOrderPR#saveConf
     * ä¿¡æ¯åˆ—表
     *
     */
    @DataResolver
    public void saveConf(WorkOrderConf data) {
        WorkOrderConf newData = new WorkOrderConf();
        BeanUtils.copyProperties(data, newData);
        if (null == data.getId()) {
            workOrderConfService.insertConf(newData);
        } else {
            workOrderConfService.updateConf(newData);
        }
    }
    /**
     *
     * workOrderPR#deleteConf
     * ä¿¡æ¯åˆ—表
     *
     */
    @Expose
    public BaseResp deleteConf(WorkOrderConf data) {
        WorkOrderConf newData = new WorkOrderConf();
        BeanUtils.copyProperties(data, newData);
        return workOrderConfService.deleteConf(newData);
    }
    /**
     * å·¥å•业务类型
     * ${dorado.getDataProvider("workOrderPR#triggerType").getResult()}
     *
     * @return
     */
    @DataProvider
    public List<SysDictData> triggerType() {
        return workOrderService.triggerType();
    }
}
fzzy-igdss-view/src/main/java/com/fzzy/work/WorkProcess.view.xml
@@ -37,7 +37,7 @@
    <DataSet id="dsMain">
      <ClientEvent name="onLoadData">$notify(&quot;数据加载完成……&quot;);</ClientEvent>
      <Property name="dataType">[dtMain]</Property>
      <Property name="dataProvider">workProcessPR#queryList</Property>
      <Property name="dataProvider">workOrderPR#processList</Property>
      <Property name="parameter">${request.getParameter('orderId')}</Property>
    </DataSet>
    <Container>
fzzy-igdss-view/src/main/java/com/fzzy/work/WorkProcessPR.java
ÎļþÒÑɾ³ý
fzzy-igdss-web/src/main/java/com/fzzy/work/WorkOrderController.java
@@ -1,10 +1,15 @@
package com.fzzy.work;
import com.fzzy.work.domain.WorkOrderConf;
import com.fzzy.work.service.WorkOrderConfService;
import com.ruoyi.common.core.controller.BaseController;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import javax.annotation.Resource;
/**
 * å·¥å•管理
@@ -13,7 +18,11 @@
@RequestMapping("/work")
public class WorkOrderController extends BaseController {
    private static final String prefix = "work";
    @Resource
    private WorkOrderConfService workOrderConfService;
    /**
@@ -36,4 +45,20 @@
        return prefix + "/no-business";
    }
    /**
     * æ ¹æ®é…ç½®ID èŽ·å–åˆ°é…ç½®ä¿¡æ¯
     * å·¥å•流程图配置
     *
     */
    @GetMapping("/flow-conf")
    public String noBusiness(@RequestParam("id") String id, ModelMap mmap) {
        WorkOrderConf conf = workOrderConfService.selectById(id);
        if (null == conf) conf = new WorkOrderConf();
        mmap.put("data", conf);
        return prefix + "/flow-conf";
    }
}
fzzy-igdss-web/src/main/resources/d7/common.css
@@ -329,7 +329,7 @@
/**表单TITLE**/
.f-title{
    font: bold 30px Arial, sans-serif;
    font: bold 30px Georgia, serif;
    text-align: center;
}
.bar-title {
fzzy-igdss-web/src/main/resources/templates/test/flow.html
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,499 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>流程节点配置</title>
    <style>
        * {
            margin: 0;
            padding: 0;
            box-sizing: border-box;
            font-family: 'Segoe UI', 'Microsoft YaHei', sans-serif;
        }
        body {
            background-color: #f5f7fa;
            color: #333;
            line-height: 1.6;
            padding: 20px;
            min-height: 100vh;
        }
        .container {
            max-width: 1000px;
            margin: 0 auto;
            padding: 30px;
            background-color: white;
            border-radius: 12px;
            box-shadow: 0 5px 20px rgba(0, 0, 0, 0.08);
        }
        header {
            text-align: center;
            margin-bottom: 40px;
        }
        h1 {
            color: #2c3e50;
            margin-bottom: 10px;
            font-size: 28px;
        }
        .description {
            color: #7f8c8d;
            max-width: 600px;
            margin: 0 auto;
        }
        .process-container {
            position: relative;
            display: flex;
            justify-content: space-between;
            align-items: center;
            margin-bottom: 60px;
        }
        /* è¿žæŽ¥çº¿ */
        .process-line {
            position: absolute;
            top: 40px;
            left: 80px;
            right: 80px;
            height: 4px;
            background-color: #e0e0e0;
            z-index: 1;
        }
        .process-line.active {
            background-color: #3498db;
        }
        .node {
            position: relative;
            display: flex;
            flex-direction: column;
            align-items: center;
            width: 120px;
            z-index: 2;
        }
        .node-indicator {
            width: 80px;
            height: 80px;
            border-radius: 50%;
            display: flex;
            align-items: center;
            justify-content: center;
            font-size: 20px;
            font-weight: bold;
            color: white;
            margin-bottom: 15px;
            box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
            transition: all 0.3s ease;
            cursor: pointer;
        }
        .node-indicator.start {
            background: linear-gradient(135deg, #1abc9c, #16a085);
        }
        .node-indicator.manager {
            background: linear-gradient(135deg, #3498db, #2980b9);
        }
        .node-indicator.leader {
            background: linear-gradient(135deg, #9b59b6, #8e44ad);
        }
        .node-indicator.group {
            background: linear-gradient(135deg, #e67e22, #d35400);
        }
        .node-indicator.end {
            background: linear-gradient(135deg, #e74c3c, #c0392b);
        }
        .node-indicator.disabled {
            background: #bdc3c7;
            transform: scale(0.9);
            opacity: 0.7;
        }
        .node-label {
            font-weight: 600;
            margin-bottom: 8px;
            color: #2c3e50;
            text-align: center;
        }
        .toggle-container {
            display: flex;
            align-items: center;
            justify-content: center;
        }
        /* åˆ‡æ¢å¼€å…³æ ·å¼ */
        .toggle-switch {
            position: relative;
            display: inline-block;
            width: 50px;
            height: 24px;
        }
        .toggle-switch input {
            opacity: 0;
            width: 0;
            height: 0;
        }
        .toggle-slider {
            position: absolute;
            cursor: pointer;
            top: 0;
            left: 0;
            right: 0;
            bottom: 0;
            background-color: #ccc;
            transition: .4s;
            border-radius: 24px;
        }
        .toggle-slider:before {
            position: absolute;
            content: "";
            height: 18px;
            width: 18px;
            left: 3px;
            bottom: 3px;
            background-color: white;
            transition: .4s;
            border-radius: 50%;
        }
        input:checked + .toggle-slider {
            background-color: #2ecc71;
        }
        input:checked + .toggle-slider:before {
            transform: translateX(26px);
        }
        .toggle-label {
            margin-left: 8px;
            font-size: 14px;
            color: #7f8c8d;
        }
        .toggle-label.active {
            color: #2ecc71;
            font-weight: 600;
        }
        .toggle-label.inactive {
            color: #e74c3c;
        }
        .controls {
            display: flex;
            justify-content: center;
            gap: 20px;
            margin-top: 40px;
            padding-top: 30px;
            border-top: 1px solid #eee;
        }
        .btn {
            padding: 12px 30px;
            border: none;
            border-radius: 6px;
            font-size: 16px;
            font-weight: 600;
            cursor: pointer;
            transition: all 0.3s ease;
        }
        .btn-save {
            background-color: #3498db;
            color: white;
        }
        .btn-save:hover {
            background-color: #2980b9;
            transform: translateY(-2px);
        }
        .btn-reset {
            background-color: #ecf0f1;
            color: #34495e;
        }
        .btn-reset:hover {
            background-color: #d5dbdb;
        }
        .status-bar {
            background-color: #f8f9fa;
            padding: 15px 20px;
            border-radius: 8px;
            margin-top: 30px;
            border-left: 4px solid #3498db;
        }
        .status-text {
            font-size: 15px;
            color: #2c3e50;
        }
        .status-text .enabled-count {
            font-weight: bold;
            color: #27ae60;
        }
        .status-text .disabled-count {
            font-weight: bold;
            color: #e74c3c;
        }
        @media (max-width: 768px) {
            .process-container {
                flex-direction: column;
                align-items: center;
            }
            .node {
                margin-bottom: 30px;
                width: 100%;
            }
            .process-line {
                display: none;
            }
            .controls {
                flex-direction: column;
            }
        }
    </style>
</head>
<body>
<div class="container">
    <div class="process-container">
        <!-- è¿žæŽ¥çº¿ -->
        <div class="process-line" id="processLine"></div>
        <!-- å¼€å§‹èŠ‚ç‚¹ -->
        <div class="node">
            <div class="node-indicator start" id="node-start">开始</div>
            <div class="node-label">开始节点</div>
            <div class="toggle-container">
                <label class="toggle-switch">
                    <input type="checkbox" class="node-toggle" data-node="start" checked>
                    <span class="toggle-slider"></span>
                </label>
                <span class="toggle-label active" id="label-start">启用</span>
            </div>
        </div>
        <!-- ç»ç†å®¡æ‰¹èŠ‚ç‚¹ -->
        <div class="node">
            <div class="node-indicator manager" id="node-manager">经理</div>
            <div class="node-label">经理审批</div>
            <div class="toggle-container">
                <label class="toggle-switch">
                    <input type="checkbox" class="node-toggle" data-node="manager" checked>
                    <span class="toggle-slider"></span>
                </label>
                <span class="toggle-label active" id="label-manager">启用</span>
            </div>
        </div>
        <!-- é¢†å¯¼å®¡æ‰¹èŠ‚ç‚¹ -->
        <div class="node">
            <div class="node-indicator leader" id="node-leader">领导</div>
            <div class="node-label">领导审批</div>
            <div class="toggle-container">
                <label class="toggle-switch">
                    <input type="checkbox" class="node-toggle" data-node="leader" checked>
                    <span class="toggle-slider"></span>
                </label>
                <span class="toggle-label active" id="label-leader">启用</span>
            </div>
        </div>
        <!-- é›†å›¢å®¡æ‰¹èŠ‚ç‚¹ -->
        <div class="node">
            <div class="node-indicator group" id="node-group">集团</div>
            <div class="node-label">集团审批</div>
            <div class="toggle-container">
                <label class="toggle-switch">
                    <input type="checkbox" class="node-toggle" data-node="group" checked>
                    <span class="toggle-slider"></span>
                </label>
                <span class="toggle-label active" id="label-group">启用</span>
            </div>
        </div>
        <!-- ç»“束节点 -->
        <div class="node">
            <div class="node-indicator end" id="node-end">结束</div>
            <div class="node-label">结束节点</div>
            <div class="toggle-container">
                <label class="toggle-switch">
                    <input type="checkbox" class="node-toggle" data-node="end" checked disabled>
                    <span class="toggle-slider"></span>
                </label>
                <span class="toggle-label active" id="label-end">启用</span>
            </div>
        </div>
    </div>
    <div class="status-bar">
        <p class="status-text">当前状态:<span id="enabledCount" class="enabled-count">5</span>个节点已启用,<span id="disabledCount" class="disabled-count">0</span>个节点已禁用。<span id="statusDetail">所有节点均已启用,流程可正常执行。</span></p>
    </div>
    <div class="controls">
        <button class="btn btn-save" id="saveBtn">保存配置</button>
        <button class="btn btn-reset" id="resetBtn">重置为默认</button>
    </div>
</div>
<script>
    document.addEventListener('DOMContentLoaded', function() {
        // èŽ·å–æ‰€æœ‰èŠ‚ç‚¹åˆ‡æ¢å¼€å…³
        const nodeToggles = document.querySelectorAll('.node-toggle');
        const processLine = document.getElementById('processLine');
        // æ›´æ–°è¿žæŽ¥çº¿çŠ¶æ€
        function updateProcessLine() {
            const enabledNodes = [];
            nodeToggles.forEach(toggle => {
                if (toggle.checked) {
                    enabledNodes.push(toggle.dataset.node);
                }
            });
            // å¦‚果所有节点都启用,将连接线设置为激活状态
            if (enabledNodes.length === nodeToggles.length) {
                processLine.classList.add('active');
            } else {
                processLine.classList.remove('active');
            }
            // æ›´æ–°èŠ‚ç‚¹æŒ‡ç¤ºå™¨çŠ¶æ€
            nodeToggles.forEach(toggle => {
                const node = toggle.dataset.node;
                const nodeIndicator = document.getElementById(`node-${node}`);
                const label = document.getElementById(`label-${node}`);
                if (toggle.checked) {
                    nodeIndicator.classList.remove('disabled');
                    label.textContent = '启用';
                    label.className = 'toggle-label active';
                } else {
                    nodeIndicator.classList.add('disabled');
                    label.textContent = '禁用';
                    label.className = 'toggle-label inactive';
                }
            });
            // æ›´æ–°çŠ¶æ€æ 
            updateStatusBar();
        }
        // æ›´æ–°çŠ¶æ€æ ä¿¡æ¯
        function updateStatusBar() {
            const enabledCount = document.querySelectorAll('.node-toggle:checked').length;
            const disabledCount = nodeToggles.length - enabledCount;
            document.getElementById('enabledCount').textContent = enabledCount;
            document.getElementById('disabledCount').textContent = disabledCount;
            const statusDetail = document.getElementById('statusDetail');
            if (enabledCount === nodeToggles.length) {
                statusDetail.textContent = '所有节点均已启用,流程可正常执行。';
            } else if (disabledCount === nodeToggles.length) {
                statusDetail.textContent = '所有节点均已禁用,流程无法执行。';
            } else if (disabledCount === 1) {
                statusDetail.textContent = '有1个节点被禁用,流程将跳过该节点执行。';
            } else {
                statusDetail.textContent = `有${disabledCount}个节点被禁用,流程将跳过这些节点执行。`;
            }
        }
        // ä¸ºæ¯ä¸ªåˆ‡æ¢å¼€å…³æ·»åŠ äº‹ä»¶ç›‘å¬
        nodeToggles.forEach(toggle => {
            toggle.addEventListener('change', updateProcessLine);
        });
        // ä¿å­˜é…ç½®æŒ‰é’®
        document.getElementById('saveBtn').addEventListener('click', function() {
            const config = {};
            nodeToggles.forEach(toggle => {
                config[toggle.dataset.node] = toggle.checked;
            });
            // åœ¨å®žé™…应用中,这里会发送配置到服务器
            // çŽ°åœ¨åªæ˜¾ç¤ºä¸€ä¸ªæç¤º
            alert('配置已保存!\n\n当前配置:\n' +
                JSON.stringify(config, null, 2));
            // æ·»åŠ è§†è§‰åé¦ˆ
            this.textContent = '保存成功!';
            this.style.backgroundColor = '#2ecc71';
            setTimeout(() => {
                this.textContent = '保存配置';
                this.style.backgroundColor = '#3498db';
            }, 1500);
        });
        // é‡ç½®æŒ‰é’®
        document.getElementById('resetBtn').addEventListener('click', function() {
            if (confirm('确定要重置所有节点配置为默认状态吗?')) {
                nodeToggles.forEach(toggle => {
                    // ç»“束节点始终启用且不可更改
                    if (toggle.dataset.node === 'end') {
                        toggle.checked = true;
                        toggle.disabled = true;
                    } else {
                        toggle.checked = true;
                    }
                });
                updateProcessLine();
                // æ·»åŠ è§†è§‰åé¦ˆ
                this.textContent = '已重置!';
                this.style.backgroundColor = '#9b59b6';
                setTimeout(() => {
                    this.textContent = '重置为默认';
                    this.style.backgroundColor = '#ecf0f1';
                }, 1500);
            }
        });
        // ä¸ºèŠ‚ç‚¹æŒ‡ç¤ºå™¨æ·»åŠ ç‚¹å‡»åˆ‡æ¢åŠŸèƒ½
        document.querySelectorAll('.node-indicator').forEach(indicator => {
            // è·³è¿‡ç»“束节点,因为它不可禁用
            if (indicator.id === 'node-end') return;
            indicator.addEventListener('click', function() {
                const nodeId = this.id.replace('node-', '');
                const toggle = document.querySelector(`.node-toggle[data-node="${nodeId}"]`);
                if (toggle && !toggle.disabled) {
                    toggle.checked = !toggle.checked;
                    toggle.dispatchEvent(new Event('change'));
                }
            });
        });
        // åˆå§‹åŒ–状态
        updateProcessLine();
    });
</script>
</body>
</html>
fzzy-igdss-web/src/main/resources/templates/work/flow-conf.html
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,359 @@
<!DOCTYPE html>
<html lang="zh_CN" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>流程节点配置</title>
    <style>
        * {
            margin: 0;
            padding: 0;
            box-sizing: border-box;
            font-family: 'Segoe UI', 'Microsoft YaHei', sans-serif;
        }
        body {
            background-color: #FFF;
            color: #333;
            line-height: 1.6;
            overflow: hidden;
        }
        .container {
            max-width: 1000px;
            margin: 0 auto;
            padding: 10px;
        }
        .process-container {
            position: relative;
            display: flex;
            justify-content: space-between;
            align-items: center;
            margin-bottom: 25px;
        }
        /* è¿žæŽ¥çº¿ */
        .process-line {
            position: absolute;
            top: 40px;
            left: 80px;
            right: 80px;
            height: 4px;
            background-color: #e0e0e0;
            z-index: 1;
        }
        .process-line.active {
            background-color: #3498db;
        }
        .node {
            position: relative;
            display: flex;
            flex-direction: column;
            align-items: center;
            width: 120px;
            z-index: 2;
        }
        .node-indicator {
            width: 80px;
            height: 80px;
            border-radius: 50%;
            display: flex;
            align-items: center;
            justify-content: center;
            font-size: 20px;
            font-weight: bold;
            color: #FFF;
            margin-bottom: 15px;
            box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
            transition: all 0.3s ease;
            cursor: pointer;
        }
        .node-indicator.start {
            background: linear-gradient(135deg, #1abc9c, #16a085);
        }
        .node-indicator.node1 {
            background: linear-gradient(135deg, #3498db, #2980b9);
        }
        .node-indicator.node2 {
            background: linear-gradient(135deg, #9b59b6, #8e44ad);
        }
        .node-indicator.node3 {
            background: linear-gradient(135deg, #e67e22, #d35400);
        }
        .node-indicator.end {
            background: linear-gradient(135deg, #e74c3c, #c0392b);
        }
        .node-indicator.disabled {
            background: #bdc3c7;
            transform: scale(0.9);
            opacity: 0.7;
        }
        .node-label {
            font-weight: 600;
            margin-bottom: 8px;
            color: #2c3e50;
            text-align: center;
        }
        .toggle-container {
            display: flex;
            align-items: center;
            justify-content: center;
        }
        /* åˆ‡æ¢å¼€å…³æ ·å¼ */
        .toggle-switch {
            position: relative;
            display: inline-block;
            width: 50px;
            height: 24px;
        }
        .toggle-switch input {
            opacity: 0;
            width: 0;
            height: 0;
        }
        .toggle-slider {
            position: absolute;
            cursor: pointer;
            top: 0;
            left: 0;
            right: 0;
            bottom: 0;
            background-color: #ccc;
            transition: .4s;
            border-radius: 24px;
        }
        .toggle-slider:before {
            position: absolute;
            content: "";
            height: 18px;
            width: 18px;
            left: 3px;
            bottom: 3px;
            background-color: #FFF;
            transition: .4s;
            border-radius: 50%;
        }
        input:checked + .toggle-slider {
            background-color: #2ecc71;
        }
        input:checked + .toggle-slider:before {
            transform: translateX(26px);
        }
        .toggle-label {
            margin-left: 8px;
            font-size: 14px;
            color: #7f8c8d;
        }
        .toggle-label.active {
            color: #2ecc71;
            font-weight: 600;
        }
        .toggle-label.inactive {
            color: #e74c3c;
        }
        .status-bar {
            background-color: #f8f9fa;
            padding: 15px 15px;
            border-radius: 6px;
            margin-top: 15px;
            border-left: 4px solid #037d41;
        }
        .status-text {
            font-size: 13px;
            color: #2c3e50;
        }
        @media (max-width: 768px) {
            .process-container {
                flex-direction: column;
                align-items: center;
            }
            .node {
                margin-bottom: 15px;
                width: 100%;
            }
            .process-line {
                display: none;
            }
        }
    </style>
</head>
<body>
<div class="container">
    <div class="process-container">
        <!-- è¿žæŽ¥çº¿ -->
        <div class="process-line" id="processLine"></div>
        <!-- å¼€å§‹èŠ‚ç‚¹ -->
        <div class="node">
            <div class="node-indicator start" id="node-start">开始</div>
            <div class="node-label" id="name-start">开始节点</div>
            <div class="toggle-container">
                <label class="toggle-switch">
                    <input type="checkbox" class="node-toggle" data-node="start" checked disabled>
                    <span class="toggle-slider"></span>
                </label>
                <span class="toggle-label active" id="label-start">启用</span>
            </div>
        </div>
        <!-- åº“区审批 -->
        <div class="node">
            <div class="node-indicator node1" id="node-node1">库区</div>
            <div class="node-label" id="name-node1">库区领导审批</div>
            <div class="toggle-container">
                <label class="toggle-switch">
                    <input type="checkbox" class="node-toggle" data-node="node1" id="nodeVal1" th:checked="${data.nodeVal1=='Y'}" >
                    <span class="toggle-slider"></span>
                </label>
                <span class="toggle-label active" id="label-node1" th:text="${data.nodeVal1=='Y'?'启用':'禁用'}">启用</span>
            </div>
        </div>
        <!-- ç›‘管审批 -->
        <div class="node">
            <div class="node-indicator node2" id="node-node2">监管</div>
            <div class="node-label" id="name-node2">监管审批</div>
            <div class="toggle-container">
                <label class="toggle-switch">
                    <input type="checkbox" class="node-toggle" data-node="node2" id="nodeVal2" th:checked="${data.nodeVal2=='Y'}">
                    <span class="toggle-slider"></span>
                </label>
                <span class="toggle-label active" id="label-node2" th:text="${data.nodeVal2=='Y'?'启用':'禁用'}">启用</span>
            </div>
        </div>
        <!-- é“¶è¡Œå®¡æ‰¹ -->
        <div class="node">
            <div class="node-indicator node3" id="node-node3">银行</div>
            <div class="node-label" id="name-node3">银行审批</div>
            <div class="toggle-container">
                <label class="toggle-switch">
                    <input type="checkbox" class="node-toggle" data-node="node3" id="nodeVal3" th:checked="${data.nodeVal3=='Y'}">
                    <span class="toggle-slider"></span>
                </label>
                <span class="toggle-label active" id="label-node3" th:text="${data.nodeVal3=='Y'?'启用':'禁用'}">启用</span>
            </div>
        </div>
        <!-- ç»“束节点 -->
        <div class="node">
            <div class="node-indicator end" id="node-end">结束</div>
            <div class="node-label" id="name-end">结束节点</div>
            <div class="toggle-container">
                <label class="toggle-switch">
                    <input type="checkbox" class="node-toggle" data-node="end" checked disabled>
                    <span class="toggle-slider"></span>
                </label>
                <span class="toggle-label active" id="label-end">启用</span>
            </div>
        </div>
    </div>
    <div class="status-bar">
        <p class="status-text">
               æ³¨ï¼š1.启用流程=否,当前流程不使用,业务流程不配置对应业务不执行工单审批。<br>
           2.启用节点的有权限的任何人均可进行处理和审批,如工单指派人员,则仅处理人可以处理。
        </p>
    </div>
</div>
</body>
<script th:inline="javascript">
    const data = [[${data}]];
</script>
<script th:src="@{/js/jquery.min.js}"></script>
<script>
    $(function () {
        // èŽ·å–æ‰€æœ‰èŠ‚ç‚¹åˆ‡æ¢å¼€å…³
        const nodeToggles = document.querySelectorAll('.node-toggle');
        const processLine = document.getElementById('processLine');
        // æ›´æ–°è¿žæŽ¥çº¿çŠ¶æ€
        function updateProcessLine() {
            const nodes =[];
            const enabledNodes = [];
            nodeToggles.forEach(toggle => {
                if (toggle.checked) {
                    enabledNodes.push(toggle.dataset.node);
                }
            });
            // å¦‚果所有节点都启用,将连接线设置为激活状态
            if (enabledNodes.length === nodeToggles.length) {
                processLine.classList.add('active');
            } else {
               // processLine.classList.remove('active');
            }
            // æ›´æ–°èŠ‚ç‚¹æŒ‡ç¤ºå™¨çŠ¶æ€
            nodeToggles.forEach(toggle => {
                const node = toggle.dataset.node;
                const nodeIndicator = document.getElementById(`node-${node}`);
                const label = document.getElementById(`label-${node}`);
                const name = document.getElementById(`name-${node}`);
                if (toggle.checked) {
                    nodeIndicator.classList.remove('disabled');
                    label.textContent = '启用';
                    label.className = 'toggle-label active';
                } else {
                    nodeIndicator.classList.add('disabled');
                    label.textContent = '禁用';
                    label.className = 'toggle-label inactive';
                }
                //封装数据用于传递给后台
                nodes.push({
                    node: node,
                    val: toggle.checked,
                    name: name.textContent
                });
            });
            //console.log(nodes);
            //数据传输给上级页面
            window.parent.onNodeValChange(nodes);
        }
        // ä¸ºæ¯ä¸ªåˆ‡æ¢å¼€å…³æ·»åŠ äº‹ä»¶ç›‘å¬
        nodeToggles.forEach(toggle => {
            toggle.addEventListener('change', updateProcessLine);
        });
        // ä¸ºèŠ‚ç‚¹æŒ‡ç¤ºå™¨æ·»åŠ ç‚¹å‡»åˆ‡æ¢åŠŸèƒ½
        document.querySelectorAll('.node-indicator').forEach(indicator => {
            // è·³è¿‡ç»“束节点,因为它不可禁用
            if (indicator.id === 'node-end' || indicator.id === 'node-start') return;
            indicator.addEventListener('click', function () {
                const nodeId = this.id.replace('node-', '');
                const toggle = document.querySelector(`.node-toggle[data-node="${nodeId}"]`);
                if (toggle && !toggle.disabled) {
                    toggle.checked = !toggle.checked;
                    toggle.dispatchEvent(new Event('change'));
                }
            });
        });
        // åˆå§‹åŒ–状态
        updateProcessLine();
    });
</script>
</html>