ruoyi-nbcio-plus基于vue3的flowable的自定义业务显示历史信息组件的升级修改

更多ruoyi-nbcio功能请看演示系统

gitee源代码地址

前后端代码: https://gitee.com/nbacheng/ruoyi-nbcio

演示地址:RuoYi-Nbcio后台管理系统 http://122.227.135.243:9666/

更多nbcio-boot功能请看演示系统 

gitee源代码地址

后端代码: https://gitee.com/nbacheng/nbcio-boot

前端代码:https://gitee.com/nbacheng/nbcio-vue.git

在线演示(包括H5) : http://122.227.135.243:9888

1、原先 vue的HistoricDetail.vue代码如下:

<style lang="less">
</style>
<template>
  <div class="search">
    <el-tabs tab-position="top" v-model="activeName" :value="processed === true ? 'approval' : 'form'" @tab-click="changeTab">
      <el-tab-pane label="表单信息" name="form">
        <div v-if="customForm.visible"> <!-- 自定义表单 -->
            <component ref="refCustomForm" :disabled="customForm.disabled" v-bind:is="customForm.formComponent" :model="customForm.model"
                        :customFormData="customForm.customFormData" :isNew = "customForm.isNew"></component>
        </div>
        <div style="margin-left:10%;margin-bottom: 30px">
           <!--对上传文件进行显示处理,临时方案 add by nbacheng 2022-07-27 -->
           <el-upload action="#" :on-preview="handleFilePreview" :file-list="fileList" v-if="fileDisplay" />
        </div>
      </el-tab-pane >

      <el-tab-pane label="流转记录" name="record">
        <el-card class="box-card" shadow="never">
          <el-col :span="20" :offset="2">
            <div class="block">
              <el-timeline>
                <el-timeline-item v-for="(item,index) in historyProcNodeList" :key="index" :icon="setIcon(item.endTime)" :color="setColor(item.endTime)">
                  <p style="font-weight: 700">{{ item.activityName }}</p>
                  <el-card v-if="item.activityType === 'startEvent'" class="box-card" shadow="hover">
                    {{ item.assigneeName }} 在 {{ item.createTime }} 发起流程
                  </el-card>
                  <el-card v-if="item.activityType === 'userTask'" class="box-card" shadow="hover">
                    <el-descriptions :column="5" :labelStyle="{'font-weight': 'bold'}">
                      <el-descriptions-item label="实际办理">{{ item.assigneeName || '-'}}</el-descriptions-item>
                      <el-descriptions-item label="候选办理">{{ item.candidate || '-'}}</el-descriptions-item>
                      <el-descriptions-item label="接收时间">{{ item.createTime || '-'}}</el-descriptions-item>
                      <el-descriptions-item label="办结时间">{{ item.endTime || '-' }}</el-descriptions-item>
                      <el-descriptions-item label="耗时">{{ item.duration || '-'}}</el-descriptions-item>
                    </el-descriptions>
                    <div v-if="item.commentList && item.commentList.length > 0">
                      <div v-for="(comment, index) in item.commentList" :key="index">
                        <el-divider content-position="left">
                          <el-tag :type="approveTypeTag(comment.type)" size="mini">{{ commentType(comment.type) }}</el-tag>
                          <el-tag type="info" effect="plain" size="mini">{{ comment.time }}</el-tag>
                        </el-divider>
                        <span>{{ comment.fullMessage }}</span>
                      </div>
                    </div>
                  </el-card>
                  <el-card v-if="item.activityType === 'endEvent'" class="box-card" shadow="hover">
                    {{ item.createTime }} 结束流程
                  </el-card>
                </el-timeline-item>
              </el-timeline>
            </div>
          </el-col>
        </el-card>
      </el-tab-pane>

      <el-tab-pane label="流程跟踪" name="track">
        <el-card class="box-card" shadow="never">
          <process-viewer :key="`designer-${loadIndex}`" :style="'height:' + height" :xml="xmlData"
                          :finishedInfo="finishedInfo" :allCommentList="historyProcNodeList"
          />
        </el-card>
      </el-tab-pane>
    </el-tabs>
  </div>
</template>

<script>
import {detailProcessByDataId} from "@/api/workflow/process";
import ProcessViewer from '@/components/ProcessViewer'
import {
    flowableMixin
  } from '@/views/workflow/mixins/flowableMixin'

export default {
  name: 'HistoricDetail',
  mixins: [flowableMixin],
  components: {
    ProcessViewer,
  },
    props: {
    /**/
        dataId: {
            type: String,
            default: '',
            required: true
        }
    },
    computed: {
      commentType() {
        return val => {
          switch (val) {
            case '1': return '通过'
            case '2': return '退回'
            case '3': return '驳回'
            case '4': return '委派'
            case '5': return '转办'
            case '6': return '终止'
            case '7': return '撤回'
            case '8': return '拒绝'
            case '9': return '跳过'
            case '10': return '前加签'
            case '11': return '后加签'
            case '12': return '多实例加签'
            case '13': return '跳转'
            case '14': return '收回'
          }
        }
      },
      approveTypeTag() {
        return val => {
          switch (val) {
            case '1': return 'success'
            case '2': return 'warning'
            case '3': return 'danger'
            case '4': return 'primary'
            case '5': return 'success'
            case '6': return 'danger'
            case '7': return 'info'
          }
        }
      }
    },
    data() {
        return {
          height: document.documentElement.clientHeight - 205 + 'px;',
          // 模型xml数据
          loadIndex: 0,
          xmlData: undefined,
          finishedInfo: {
            finishedSequenceFlowSet: [],
            finishedTaskSet: [],
            unfinishedTaskSet: [],
            rejectedTaskSet: []
          },
          historyProcNodeList: [],
          processed: false,
          activeName:'form', //获取当然tabname
          customForm: { //自定义业务表单
            formId: '',
            title: '',
            disabled: false,
            visible: false,
            formComponent: null,
            model: {},
            /*流程数据*/
            customFormData: {},
            isNew: false,
            disableSubmit: true
          },
          fileDisplay: false, // formdesigner是否显示上传的文件控件
          fileList: [], //表单设计器上传的文件列表
        };
    },
    created() {
        this.init();
    },
    watch: {
      dataId: function(newval, oldName) {
            this.init();
        }
    },

    methods: {
      init() {
       // 获取流程变量
       this.detailProcesssByDataId(this.dataId);
      },
      detailProcesssByDataId(dataId) {
        const params = {dataId: dataId}
        detailProcessByDataId(params).then(res => {
          console.log("detailProcessByDataId res=",res);
          if (res.code === 200 && res.data != null) {
            const data = res.data;
            this.xmlData = data.bpmnXml;
            this.processFormList = data.processFormList;
            if(this.processFormList.length == 1 &&
               this.processFormList[0].formValues.hasOwnProperty('routeName')) {
               this.customForm.disabled = true;
               this.customForm.visible = true;
               this.customForm.formComponent = this.getFormComponent(this.processFormList[0].formValues.routeName).component;
               this.customForm.model = this.processFormList[0].formValues.formData;
               this.customForm.customFormData = this.processFormList[0].formValues.formData;
               console.log("detailProcess customForm",this.customForm);
            }
            this.historyProcNodeList = data.historyProcNodeList;
            this.finishedInfo = data.flowViewer;
          }
        })
      },
      changeTab(tab, event) {
        console.log("changeTab tab=",tab);
        if(tab.name === 'form') {
          console.log("changeTab this.processFormList=",this.processFormList);
          if(this.customForm.formId === "") {
            // 回填数据,这里主要是处理文件列表显示,临时解决,以后应该在formdesigner里完成
            this.processFormList.forEach((item, i) => {
              if (item.hasOwnProperty('list') && item.list != null) {
                this.fillFormData(item.list, item)
                // 更新表单
                this.key = +new Date().getTime()
              }
            });
          }
        }
      },
      setIcon(val) {
        if (val) {
          return "el-icon-check";
        } else {
          return "el-icon-time";
        }
      },
      setColor(val) {
        if (val) {
          return "#2bc418";
        } else {
          return "#b3bdbb";
        }
      },
      fillFormData(list, formConf) { // for formdesigner
        console.log("fillFormData list=",list);
        console.log("fillFormData formConf=",formConf);
        list.forEach((item, i) => {
          // 特殊处理el-upload,包括 回显图片
          if(formConf.formValues[item.id] != '') {
            const val = formConf.formValues[item.id];
            if (item.ele === 'el-upload') {
              console.log('fillFormData val=',val)
              if(item['list-type'] != 'text') {//图片
                this.fileList = []    //隐藏加的el-upload文件列表
                //item['file-list'] = JSON.parse(val)
                if(val != '') {
                  item['file-list'] = JSON.parse(val)
                }
              }
              else {  //列表
                console.log("列表fillFormData val",val)
                this.fileList = JSON.parse(val)
                item['file-list'] = [] //隐藏加的表单设计器的文件列表
              }
              // 回显图片
              this.fileDisplay = true
            }
          }

          if (Array.isArray(item.columns)) {
            this.fillFormData(item.columns, formConf)
          }
        })
      },
    }

};
</script>
<style lang="scss" scoped>
.clearfix:before,
.clearfix:after {
  display: table;
  content: "";
}
.clearfix:after {
  clear: both
}

.box-card {
  width: 100%;
  margin-bottom: 20px;
}

.el-tag + .el-tag {
  margin-left: 10px;
}

.el-row {
  margin-bottom: 20px;
  &:last-child {
    margin-bottom: 0;
  }
}
.el-col {
  border-radius: 4px;
}

.button-new-tag {
  margin-left: 10px;
}
</style>

2、修改成vue3后的代码如下:

<style lang="less">
</style>
<template>
  <div class="search">
    <el-tabs tab-position="top" v-model="activeName" :value="processed === true ? 'approval' : 'form'" @tab-click="changeTab">
      <el-tab-pane label="表单信息" name="form">
        <div v-if="customForm.visible"> <!-- 自定义表单 -->
            <component ref="refCustomForm" :disabled="customForm.disabled" :is="customForm.formComponent" :model="customForm.model"
                        :customFormData="customForm.customFormData" :isNew = "customForm.isNew"></component>
        </div>
        <div style="margin-left:10%;margin-bottom: 30px">
           <!--对上传文件进行显示处理,临时方案 add by nbacheng 2022-07-27 -->
           <el-upload action="#" :on-preview="handleFilePreview" :file-list="fileList" v-if="fileDisplay" />
        </div>
      </el-tab-pane >

      <el-tab-pane label="流转记录" name="record">
        <el-card class="box-card" shadow="never">
          <el-col :span="20" :offset="2">
            <div class="block">
              <el-timeline>
                <el-timeline-item v-for="(item,index) in historyProcNodeList" :key="index" :icon="setIcon(item.endTime)" :color="setColor(item.endTime)">
                  <p style="font-weight: 700">{{ item.activityName }}</p>
                  <el-card v-if="item.activityType === 'startEvent'" class="box-card" shadow="hover">
                    {{ item.assigneeName }} 在 {{ item.createTime }} 发起流程
                  </el-card>
                  <el-card v-if="item.activityType === 'userTask'" class="box-card" shadow="hover">
                    <el-descriptions :column="5" :labelStyle="{'font-weight': 'bold'}">
                      <el-descriptions-item label="实际办理">{{ item.assigneeName || '-'}}</el-descriptions-item>
                      <el-descriptions-item label="候选办理">{{ item.candidate || '-'}}</el-descriptions-item>
                      <el-descriptions-item label="接收时间">{{ item.createTime || '-'}}</el-descriptions-item>
                      <el-descriptions-item label="办结时间">{{ item.endTime || '-' }}</el-descriptions-item>
                      <el-descriptions-item label="耗时">{{ item.duration || '-'}}</el-descriptions-item>
                    </el-descriptions>
                    <div v-if="item.commentList && item.commentList.length > 0">
                      <div v-for="(comment, index) in item.commentList" :key="index">
                        <el-divider content-position="left">
                          <el-tag :type="approveTypeTag(comment.type)" size="small">{{ commentType(comment.type) }}</el-tag>
                          <el-tag type="info" effect="plain" size="small">{{ comment.time }}</el-tag>
                        </el-divider>
                        <span>{{ comment.fullMessage }}</span>
                      </div>
                    </div>
                  </el-card>
                  <el-card v-if="item.activityType === 'endEvent'" class="box-card" shadow="hover">
                    {{ item.createTime }} 结束流程
                  </el-card>
                </el-timeline-item>
              </el-timeline>
            </div>
          </el-col>
        </el-card>
      </el-tab-pane>

      <el-tab-pane label="流程跟踪" name="track">
        <el-card class="box-card" shadow="never">
          <process-viewer :key="`designer-${loadIndex}`" :style="'height:' + height" :xml="xmlData"
                          :finishedInfo="finishedInfo" :allCommentList="historyProcNodeList"
          />
        </el-card>
      </el-tab-pane>
    </el-tabs>
  </div>
</template>

<script setup lang="ts">
  import {detailProcessByDataId} from "@/api/workflow/process";
  import ProcessViewer from '@/components/ProcessViewer'
  import {
      useFlowable
  } from '@/views/workflow/hooks/useFlowable'

  defineOptions({ name: 'HistoricDetail' })
  const props = defineProps({
    dataId: {
        type: String,
        default: '',
        required: true
    }
  })
  const commentType = computed(() => {
    return val => {
      switch (val) {
        case '1': return '通过'
        case '2': return '退回'
        case '3': return '驳回'
        case '4': return '委派'
        case '5': return '转办'
        case '6': return '终止'
        case '7': return '撤回'
        case '8': return '拒绝'
        case '9': return '跳过'
        case '10': return '前加签'
        case '11': return '后加签'
        case '12': return '多实例加签'
        case '13': return '跳转'
        case '14': return '收回'
      }
    }
  })

  const approveTypeTag = computed(() => {
    return val => {
      switch (val) {
        case '1': return 'success'
        case '2': return 'warning'
        case '3': return 'danger'
        case '4': return 'primary'
        case '5': return 'success'
        case '6': return 'danger'
        case '7': return 'info'
      }
    }
  })

  const { getFormComponent } = useFlowable()
  const height = ref(document.documentElement.clientHeight - 205 + 'px;')
  // 模型xml数据
  const loadIndex = ref(0)
  const xmlData = ref(null)
  const finishedInfo = ref({
    finishedSequenceFlowSet: [],
    finishedTaskSet: [],
    unfinishedTaskSet: [],
    rejectedTaskSet: []
  })
  const historyProcNodeList = ref<any>([])
  const processed = ref(false)
  const activeName = ref('form') //获取当然tabname
  const processFormList = ref<any>([])
  const customForm =  ref({ //自定义业务表单
    formId: '',
    title: '',
    disabled: false,
    visible: false,
    formComponent: null,
    model: {},
    /*流程数据*/
    customFormData: {},
    isNew: false,
    disableSubmit: true
  })
  const fileDisplay = ref(false) // formdesigner是否显示上传的文件控件
  const fileList = ref<any>([]) //表单设计器上传的文件列表
  const key = ref<any>()

  const init = () => {
   // 获取流程变量
   detailProcesssByDataId(props.dataId);
  }
  const detailProcesssByDataId = (dataId) => {
    const params = {dataId: dataId}
    detailProcessByDataId(params).then(res => {
      console.log("detailProcessByDataId res=",res);
      if (res.code === 200 && res.data != null) {
        const data = res.data;
        xmlData.value = data.bpmnXml;
        processFormList.value = data.processFormList;
        if(processFormList.value.length == 1 &&
           processFormList.value[0].formValues.hasOwnProperty('routeName')) {
           customForm.value.disabled = true;
           customForm.value.visible = true;
           customForm.value.formComponent = getFormComponent(processFormList.value[0].formValues.routeName).component;
           customForm.value.model = processFormList.value[0].formValues.formData;
           customForm.value.customFormData = processFormList.value[0].formValues.formData;
           console.log("detailProcess customForm.value",customForm.value);
        }
        historyProcNodeList.value = data.historyProcNodeList;
        finishedInfo.value = data.flowViewer;
      }
    })
  }
  const changeTab = (tab, event) => {
    console.log("changeTab tab=",tab);
    const tabname = toRaw(tab);
    if(tabname.paneName.value === 'form') {
      console.log("changeTab processFormList.value=",processFormList.value);
      if(customForm.value.formId === "") {
        // 回填数据,这里主要是处理文件列表显示,临时解决,以后应该在formdesigner里完成
        processFormList.value.forEach((item, i) => {
          if (item.hasOwnProperty('list') && item.list != null) {
            fillFormData(item.list, item)
            // 更新表单
            key.value = +new Date().getTime()
          }
        });
      }
    }
  }
  const setIcon = (val) => {
    if (val) {
      return "el-icon-check";
    } else {
      return "el-icon-time";
    }
  }
  const setColor = (val) => {
    if (val) {
      return "#2bc418";
    } else {
      return "#b3bdbb";
    }
  }
  const fillFormData = (list, formConf) => { // for formdesigner
    console.log("fillFormData list=",list);
    console.log("fillFormData formConf=",formConf);
    list.forEach((item, i) => {
      // 特殊处理el-upload,包括 回显图片
      if(formConf.formValues[item.id] != '') {
        const val = formConf.formValues[item.id];
        if (item.ele === 'el-upload') {
          console.log('fillFormData val=',val)
          if(item['list-type'] != 'text') {//图片
            fileList.value = []    //隐藏加的el-upload文件列表
            //item['file-list'] = JSON.parse(val)
            if(val != '') {
              item['file-list'] = JSON.parse(val)
            }
          }
          else {  //列表
            console.log("列表fillFormData val",val)
            fileList.value = JSON.parse(val)
            item['file-list'] = [] //隐藏加的表单设计器的文件列表
          }
          // 回显图片
          fileDisplay.value = true
        }
      }

      if (Array.isArray(item.columns)) {
        fillFormData(item.columns, formConf)
      }
    })
  }
  onMounted(() => {
    init();
  });

</script>
<style lang="scss" scoped>
.clearfix:before,
.clearfix:after {
  display: table;
  content: "";
}
.clearfix:after {
  clear: both
}

.box-card {
  width: 100%;
  margin-bottom: 20px;
}

.el-tag + .el-tag {
  margin-left: 10px;
}

.el-row {
  margin-bottom: 20px;
  &:last-child {
    margin-bottom: 0;
  }
}
.el-col {
  border-radius: 4px;
}

.button-new-tag {
  margin-left: 10px;
}
</style>

3、效果图如下:

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/538750.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

多 线 程

1&#xff0e;什么是多线程? 有了多线程&#xff0c;我们就可以让程序同时做多件事情 2.多线程的作用? 提高效率 3&#xff0e;多线程的应用场景? 只要你想让多个事情同时运行就需要用到多线程 比如:软件中的耗时操作、所有的聊天软件、所有的服务器 1.进程和线程【理解】 …

mybiats-puls-插入测试以及雪花算法

一&#xff0c;测试 /* * 插入测试 * */ Test public void test01() {User user new User();/** 自动帮我们生成id* */user.setName("kuku");user.setAge(3);user.setEmail("2983394967qq.com");final int insert mapper.insert(user);System.out.print…

OceanMind海睿思入选《2024 中国MarTech行业生态图》

「Morketing研究院」正式发布《2024 中国MarTech行业生态图》&#xff0c;中新赛克海睿思作为国内数据治理优秀厂商&#xff0c;成功入选「数据与分析」板块「数据管理平台」子类&#xff0c;占据Martech领域关键节点。 ◎《2024中国MarTech行业生态图》 关于MarTech生态图 《…

【Django开发】前后端分离美多商城项目第7篇:登录,使用登录的流程【附代码文档】

美多商城项目4.0文档完整教程&#xff08;附代码资料&#xff09;主要内容讲述&#xff1a;美多商城&#xff0c;项目准备1.B2B--企业对企业,2.C2C--个人对个人,3.B2C--企业对个人,4.C2B--个人对企业,5.O2O--线上到线下,6.F2C--工厂到个人。项目准备&#xff0c;配置1. 修改set…

记录一次Java中使用P12证书访问https,nginx返回403的问题

目录 1、先使用浏览器导入证书访问&#xff0c;测试证书和密钥是否正确2、编写初始java代码3、结果响应 403 Forbidden4、解决方案 1、先使用浏览器导入证书访问&#xff0c;测试证书和密钥是否正确 成功返回&#xff0c;说明p12证书和密钥是没问题的。 2、编写初始java代码 …

智慧公厕是公共厕所信息化向高端发展的必然

现代社会的发展离不开科技的加持&#xff0c;公共厕所作为城市基础设施之一&#xff0c;也在不断引入智慧化的概念&#xff0c;实现信息化、智慧化和数字化的使用和管理。智慧公厕通过物联网、大数据、云计算、网络通信和自动化控制技术的应用&#xff0c;成为了高级的社会公共…

【vue】watchEffect 自动侦听器

watchEffect&#xff1a;自动监听值的变化 获取旧值时&#xff0c;不是很方便&#xff0c;建议用watch <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><meta name"viewport" content"widthdevic…

哪些被Asterisk 21版本暴砍的功能有多少是你常用的?我指的是chan_alsa

目录 江湖再无NoCDRapp_macro也不见了常用的还有哪些&#xff1f; Asterisk 21.0版本的发布&#xff0c;主打一个剪刀手。 正如社区官方傲慢、粗鲁&毫不遮掩的说法&#xff1a; Asterisk 21 saw fewer new additions than previous versions. Many of the changes are actu…

element table 使用了表格固定height高度和表格属性fixed属性出现了高度错乱bug

问题描述&#xff1a;因为使用了表格固定height高度所以 使用表格属性fixed属性出现了高度错乱bug知识点&#xff1a;使用element table 里提供的doLayout 方法 代码 // template <el-table ref"test" ></el-table>//js// 查询数据getList(obj{}) {get…

电焰灶十大品牌:华火电燃灶怎么样?

随着科技的发展和人们生活品质的提升&#xff0c;传统燃气灶具已无法满足现代家庭对于高效、环保、安全的需求。在这一背景下&#xff0c;电焰灶作为一种新型的厨房设备逐渐崭露头角。在众多电焰灶品牌中&#xff0c;华火电燃灶凭借其卓越的性能和创新的技术&#xff0c;成功跻…

【MATLAB第104期】基于MATLAB的xgboost的敏感性分析/特征值排序计算(针对多输入单输出回归预测模型)

【MATLAB第104期】基于MATLAB的xgboost的敏感性分析/特征值排序计算&#xff08;针对多输入单输出回归预测模型&#xff09; 因matlab的xgboost训练模型不含敏感性分析算法&#xff0c;本文通过使用single算法&#xff0c;即单特征因素对输出影响进行分析&#xff0c;得出不同…

NAPI 类对象导出及其生命周期管理(下)

4. 样例工程源码剖析 工程的模板是Native C,模型是Stage。源码剖析主要围绕以下几个文件 4.1. NAPI导出对象和生命周期管理具体实现 4.1.1. 定义NapiTest类及方法 Napi.h文件内容如下&#xff1a; #ifndef __NAPI_TEST_H__ #define __NAPI_TEST_H__#include "napi/nat…

集群监控原理

3.1.2.集群监控原理 Sentinel基于心跳机制监测服务状态&#xff0c;每隔1秒向集群的每个实例发送ping命令&#xff1a; •主观下线&#xff1a;如果某sentinel节点发现某实例未在规定时间响应&#xff0c;则认为该实例主观下线。 •客观下线&#xff1a;若超过指定数量&…

华为远程登陆管理配置:轻松掌握核心要点

实验拓扑及需求 实验步骤 A、配置相关地址及连通性测试 R1&#xff1a; [R1]int GigabitEthernet 0/0/0 [R1-GigabitEthernet0/0/0]ip address 192.168.12.1 24 R2&#xff1a; [R2]int gi 0/0/0 [R2-GigabitEthernet0/0/0]ip add 192.168.12.2 24 [R2]int gi 0/0/1 […

使用 Docker 部署 Linux-Command 命令搜索工具

1&#xff09;介绍 Linux-Command GitHub&#xff1a;https://github.com/jaywcjlove/linux-command Linux-Command 仓库搜集了 580 多个 Linux 命令&#xff0c;是一个非盈利性的仓库&#xff0c;生成了一个 Web 网站方便使用&#xff0c;目前网站没有任何广告&#xff0c;内…

阿里云4核16G服务器可以用来做什么?

阿里云4核16G服务器可以用来做什么&#xff1f;可用来搭建游戏服务器&#xff0c;阿里云4核16G服务器10M带宽30元1个月、90元3个月&#xff0c;优惠活动 aliyunfuwuqi.com/go/youhui 阿里云4核16G服务器可以用来做什么&#xff1f;除了搭建游戏服务器&#xff0c;还可以用来哪…

阿里云短信服务对接流程

阿里云短信服务是阿里巴巴集团推出的一款通讯服务产品&#xff0c;支持发送短信到手机、验证码短信、语音短信等多种短信场景。通过阿里云短信服务&#xff0c;企业可以方便、快捷、安全地将消息发送给用户&#xff0c;提升用户体验和品牌形象。此外&#xff0c;阿里云短信服务…

各种拟合算法整理

各种拟合算法整理 1. 最小二乘法2. 霍夫变换3. RANSAC算法 本篇将介绍最小二乘法(Least Square)、霍夫变换(Hough Transform)和RANSAC(random sample consensus&#xff0c;随机抽样一致性算法)算法的原理、应用和代码。 如果已经知道了一组可靠的点&#xff0c;可以直接使用最…

QAT量化 demo

一、QAT量化基本流程 QAT过程可以分解为以下步骤&#xff1a; 定义模型&#xff1a;定义一个浮点模型&#xff0c;就像常规模型一样。定义量化模型&#xff1a;定义一个与原始模型结构相同但增加了量化操作&#xff08;如torch.quantization.QuantStub()&#xff09;和反量化…

【Canvas技法】四条C形色带填满一个圆/环形

【关键点】 通过三角函数计算控制点的位置。 【成果图】 【代码】 <!DOCTYPE html> <html lang"utf-8"> <meta http-equiv"Content-Type" content"text/html; charsetutf-8"/> <head><title>四条C形色带填满一个…