国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

一個(gè)開源的汽修r(nóng)bac后臺(tái)管理系統(tǒng)項(xiàng)目,基于若依框架,實(shí)現(xiàn)了activiti工作流,附源碼

這篇具有很好參考價(jià)值的文章主要介紹了一個(gè)開源的汽修r(nóng)bac后臺(tái)管理系統(tǒng)項(xiàng)目,基于若依框架,實(shí)現(xiàn)了activiti工作流,附源碼。希望對(duì)大家有所幫助。如果存在錯(cuò)誤或未考慮完全的地方,請(qǐng)大家不吝賜教,您也可以點(diǎn)擊"舉報(bào)違法"按鈕提交疑問。

前言&源碼

為了更加熟悉activiti工作流的使用和實(shí)戰(zhàn)而改造的項(xiàng)目,歡迎大家參考和提出問題建議一起學(xué)習(xí)~

源碼gitee倉庫地址:Yuzaki-NASA / Activiti7_test_car_rbac
master分支是穩(wěn)定版,dev分支是后來加了個(gè)新的并行審核流程和客戶管理,個(gè)人測(cè)了多遍沒啥問題,建議拉dev的代碼。
sql文件在caro2o-business下的resources/sql里,啟動(dòng)項(xiàng)目前記得先添加一下sql

原模板源碼gitee倉庫地址:Yuzaki-NASA / activiti7-caro2o-template
這個(gè)是參考的模板,功能除去一些被我優(yōu)化過的地方以外大多一致,還寫了很多注釋,便于對(duì)照理解學(xué)習(xí)

項(xiàng)目參考圖:

  • 養(yǎng)修預(yù)約-服務(wù)項(xiàng)crud(很多頁面都類似,就不一一例舉了)

rbac項(xiàng)目源碼,開源,項(xiàng)目實(shí)例,Activiti,開源,spring boot,后端,vue,Activiti

  • 養(yǎng)修預(yù)約-結(jié)算單明細(xì)

rbac項(xiàng)目源碼,開源,項(xiàng)目實(shí)例,Activiti,開源,spring boot,后端,vue,Activiti

  • 流程管理-流程定義明細(xì)

rbac項(xiàng)目源碼,開源,項(xiàng)目實(shí)例,Activiti,開源,spring boot,后端,vue,Activiti

  • 套餐審核-我的已辦

rbac項(xiàng)目源碼,開源,項(xiàng)目實(shí)例,Activiti,開源,spring boot,后端,vue,Activiti

  • 套餐審核-我的待辦-進(jìn)度查看

rbac項(xiàng)目源碼,開源,項(xiàng)目實(shí)例,Activiti,開源,spring boot,后端,vue,Activiti


項(xiàng)目總結(jié):
(源碼中的caro2o-ui下的src/assets路徑下也有總結(jié)的pdf文件)

e店邦O2O平臺(tái)項(xiàng)目總結(jié)

一、springboot

1.1、springboot自動(dòng)配置原理

用自己的大白話來總結(jié)就是:

自動(dòng)配置簡(jiǎn)單來說就是自動(dòng)去把第三方組件的Bean裝載到IOC容器中,不需要開發(fā)人員再去寫B(tài)ean相關(guān)的配置。在SpringBoot應(yīng)用里只需要在啟動(dòng)類上加@SpringBootApplication注解就可以實(shí)現(xiàn)自動(dòng)配置。
@SpringBootApplication注解是一個(gè)復(fù)合注解,真正去實(shí)現(xiàn)自動(dòng)配置的注解是它里面的@EnableAutoConfiguration這樣一個(gè)注解。自動(dòng)配置的實(shí)現(xiàn)主要依靠三個(gè)核心的關(guān)鍵技術(shù):

①、第一個(gè),引入Starter

rbac項(xiàng)目源碼,開源,項(xiàng)目實(shí)例,Activiti,開源,spring boot,后端,vue,Activiti

啟動(dòng)依賴組件的時(shí)候,這個(gè)組件里必須要包含一個(gè)@Configuration配置類,而在這個(gè)配置類里面我們需要通過@Bean這個(gè)注解去聲明需要裝配到IOC容器里面的Bean對(duì)象。

②、第二個(gè),這個(gè)配置類是放在第三方的jar包里面,然后通過SpringBoot中約定優(yōu)于配置的這樣一個(gè)理念,使用Spring里擁有的SpringFactoriesLoader(Spring的一種加載方式,在Spring的底層非常常見)去把這個(gè)配置類的全限定名(路徑)放在classpath:/META-INF/spring.factories文件里面,這樣SpringBoot就可以知道第三方j(luò)ar包里面這個(gè)配置類的位置。

約定優(yōu)于配置理念:
維基百科解釋如下:
約定優(yōu)于配置(convention over configuration),也稱作按約定編程,是一種軟件設(shè)計(jì)范式,旨在減少軟件開發(fā)人員需做出決定的數(shù)量,活得簡(jiǎn)單的好處,而又不失靈活性。
本質(zhì)上是說,開發(fā)人員僅需要規(guī)定應(yīng)用中不符約定的部分,例如,如果模型中有個(gè)名為 Sale 的類,那么數(shù)據(jù)庫中對(duì)應(yīng)的表就會(huì)默認(rèn)命名為 sales。只有偏離這一約定時(shí),例如將該表命名為“products_sold”,才需寫有關(guān)這個(gè)名字的配置。
如果您所用工具的約定與你的期望相符,便可省去配置;反之,你可以配置來達(dá)到你所期待的方式。

/META-INF/spring.factories文件以key-value鍵值對(duì)作為內(nèi)容,其中有一個(gè)Key為EnableAutoConfiguration且Value為各個(gè)第三方j(luò)ar包的Configuration全限定名,而@EnableAutoConfiguration注解就是通過這里自動(dòng)加載到所有符合要求的第三方依賴。例如我們項(xiàng)目中用到的Avitiviti依賴包

rbac項(xiàng)目源碼,開源,項(xiàng)目實(shí)例,Activiti,開源,spring boot,后端,vue,Activiti

③、第三個(gè),SpringBoot拿到所有第三方j(luò)ar包里面聲明的配置類以后,再通過Spring提供的ImportSelector這樣一個(gè)接口來實(shí)現(xiàn)對(duì)這些配置類的動(dòng)態(tài)加載,從而去完成自動(dòng)配置這樣一個(gè)動(dòng)作。

在我看來,Springboot是約定優(yōu)于配置這一理念下的一個(gè)產(chǎn)物,所以在很多地方都能看到這一類的思想,它的出現(xiàn)讓開發(fā)人員可以更加聚焦(集中注意)在業(yè)務(wù)代碼的編寫上,而不需要去關(guān)心和業(yè)務(wù)無關(guān)的配置。

拓展:其實(shí)自動(dòng)配置的思想在SpringFramework3.x版本里面的@Enable注解就已經(jīng)有了實(shí)現(xiàn)的一個(gè)雛形,@Enable注解是一個(gè)模塊驅(qū)動(dòng)的意思,也就是說我們只需要增加@Enable注解就能自動(dòng)打開某個(gè)功能,而不需要針對(duì)這個(gè)功能去做Bean的配置,@Enable注解的底層也是去幫我們自動(dòng)去完成這樣一個(gè)模塊相關(guān)Bean的注入的,然后基于這一理念有了后來的SpringBoot自動(dòng)配置。

rbac項(xiàng)目源碼,開源,項(xiàng)目實(shí)例,Activiti,開源,spring boot,后端,vue,Activiti

1.2、springboot優(yōu)缺點(diǎn)

優(yōu)點(diǎn):

  1. 創(chuàng)建獨(dú)立Spring應(yīng)用
  2. 內(nèi)嵌web服務(wù)器(如tomcat等)
  3. 自動(dòng)starter依賴,簡(jiǎn)化構(gòu)建配置
  4. 自動(dòng)配置Spring以及第三方功能
  5. 提供生產(chǎn)級(jí)別的監(jiān)控、健康檢查以及外部?jī)?yōu)化配置
  6. 無代碼生成、無需編寫XML

缺點(diǎn):

  1. 迭代快
  2. 封裝太深,內(nèi)部原理復(fù)雜,不容易精通
1.3、springboot注解

rbac項(xiàng)目源碼,開源,項(xiàng)目實(shí)例,Activiti,開源,spring boot,后端,vue,Activiti

springboot常見注解可以參考這個(gè):https://zhuanlan.zhihu.com/p/593053050?utm_id=0

來說一下caro2o項(xiàng)目中一些比較常用和重要的注解:

  • @RestController:

    • @RestController是@Controller和 @ResponseBody 的結(jié)合體,兩個(gè)標(biāo)注合并起來的作用。@RestController類中的所有方法只能返回String、Object、Json等實(shí)體對(duì)象,不能跳轉(zhuǎn)到模版頁面。
    • 如果只是使用@RestController注解Controller,則Controller中的方法無法返回jsp頁面,或者h(yuǎn)tml,配置的視圖解析器 InternalResourceViewResolver不起作用,返回的內(nèi)容就是Return 里的內(nèi)容。
    • 如果需要返回到指定頁面,則需要用 @Controller配合視圖解析器InternalResourceViewResolver才行。如果需要返回JSON,XML或自定義mediaType內(nèi)容到頁面,則需要在對(duì)應(yīng)的方法上加上@ResponseBody注解。
  • @PathVariable:

    • @PathVariable 映射 URL 綁定的占位符,通過 @PathVariable 可以將 URL 中占位符參數(shù)綁定到控制器處理方法的入?yún)⒅校篣RL 中的 {xxx} 占位符可以通過@PathVariable(“xxx”) 綁定到操作方法的入?yún)⒅?。單個(gè)變量或數(shù)組都可以。

    •     /**
           * 獲取養(yǎng)修信息預(yù)約詳細(xì)信息
           */
          @PreAuthorize("@ss.hasPermi('business:appointment:query')")
          @GetMapping(value = "/{id}")
          public AjaxResult getInfo(@PathVariable("id") Long id)
          {
              return AjaxResult.success(busAppointmentService.selectBusAppointmentById(id));
          }
      
          /**
           * 刪除養(yǎng)修信息預(yù)約(真刪除)
           */
          @PreAuthorize("@ss.hasPermi('business:appointment:remove')")
          @Log(title = "養(yǎng)修信息預(yù)約", businessType = BusinessType.DELETE)
      	@DeleteMapping("/{ids}")
          public AjaxResult remove(@PathVariable Long[] ids)
          {
              return toAjax(busAppointmentService.deleteBusAppointmentByIds(ids));
          }
      
          /**
           * 刪除養(yǎng)修信息預(yù)約(假刪除)
           */
          @PreAuthorize("@ss.hasPermi('business:appointment:remove')")
          @Log(title = "刪除養(yǎng)修信息預(yù)約", businessType = BusinessType.UPDATE)
          @PutMapping("/delete/{ids}")
          public AjaxResult updateDel(@PathVariable Long[] ids)
          {
              busAppointmentService.updateDel(ids);
              return AjaxResult.success();
          }
      
          /**
           * 刪除養(yǎng)修信息預(yù)約(假刪除)
           */
          @PreAuthorize("@ss.hasPermi('business:appointment:generate')")
          @Log(title = "養(yǎng)修信息預(yù)約", businessType = BusinessType.INSERT)
          @PostMapping("/generate/{appointmentId}")
          public AjaxResult generate(@PathVariable Long appointmentId)
          {
              return AjaxResult.success(busAppointmentService.generate(appointmentId));
          }
      
  • @RequestBody:Controller中接收的入?yún)⑹菍?duì)象的Json格式時(shí)貼,下面代碼塊中的POST和PUT方法都有用到,不多贅述了。

  • @Validated:是Spring Validation框架提供的參數(shù)驗(yàn)證功能,貼在controller類里方法的入?yún)⑶伴_啟參數(shù)校驗(yàn)功能,比較常貼在POST和PUT方法上:

    •     /**
           * 新增養(yǎng)修信息預(yù)約
           */
          @PreAuthorize("@ss.hasPermi('business:appointment:add')")
          @Log(title = "養(yǎng)修信息預(yù)約", businessType = BusinessType.INSERT)
          @PostMapping
          public AjaxResult add(@Validated @RequestBody BusAppointment busAppointment)
          {
              return toAjax(busAppointmentService.insertBusAppointment(busAppointment));
          }
      
          /**
           * 修改養(yǎng)修信息預(yù)約
           */
          @PreAuthorize("@ss.hasPermi('business:appointment:edit')")
          @Log(title = "養(yǎng)修信息預(yù)約", businessType = BusinessType.UPDATE)
          @PutMapping
          public AjaxResult edit(@Validated @RequestBody BusAppointment busAppointment)
          {
              return toAjax(busAppointmentService.updateBusAppointment(busAppointment));
          }
      
    • 在domain的類里的get方法上貼相關(guān)校驗(yàn)注解,如@NotBlank(貼在字符串成員上,表示不能為空或空字符串)、@NotNull(不能為Null)、@Size(限制字符串長度)等等

      •  	@NotBlank(message = "客戶姓名不能為空")
            @Size(min = 0, max = 64, message = "客戶姓名長度不能超過64個(gè)字符")
            public String getCustomerName() 
            {
                return customerName;
            }
            public void setCustomerPhone(String customerPhone) 
            {
                this.customerPhone = customerPhone;
            }
        
        @NotNull(message = "預(yù)約時(shí)間不能為空")
        public Date getAppointmentTime() 
        {
            return appointmentTime;
        }
        public void setActualArrivalTime(Date actualArrivalTime) 
        {
            this.actualArrivalTime = actualArrivalTime;
        }
        
        
        
  • @JsonFormat:在Jackson中定義的一個(gè)注解,是一個(gè)時(shí)間格式化注解。此注解用于屬性上,作用是把DATE類型的數(shù)據(jù)轉(zhuǎn)化成為我們想要的格式。

    • // 例如
      @JsonFormat(pattern = "yyyy-MM-dd")
      @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
      @JsonFormat(pattern = "yyyy年MM月dd日 HH時(shí)mm分ss秒")
      
  • @Param:在Mapper類中使用,這個(gè)注解是為SQL語句中參數(shù)賦值而服務(wù)的。

    • @Param的作用就是給參數(shù)命名,比如在mapper里面某方法A(int id),當(dāng)添加注解后A(@Param(“userId”) int id),也就是說外部想要取出傳入的id值,只需要取它的參數(shù)名userId就可以了。將參數(shù)值傳如SQL語句中,通過#{userId}進(jìn)行取值給SQL的參數(shù)賦值。
    • Mapper類中的方法參數(shù)不為基本數(shù)據(jù)類型或者有多個(gè)參數(shù)時(shí),使用該注解。
  • @Transactional:在service層開啟事務(wù),防止執(zhí)行途中出錯(cuò)而造成的數(shù)據(jù)混亂。

  • 其余還有一些若依自己封裝的注解類似@PreAuthorize(權(quán)限)、@Log(打印日志)、@Excel(導(dǎo)出文件相關(guān)注解)就不展開說明了,不同項(xiàng)目會(huì)封裝不同的自定義注解,這些都需要自己去研究其作用與實(shí)現(xiàn)。

二、rbac

2.1、概括

RBAC是一種基于角色實(shí)現(xiàn)訪問控制的權(quán)限管理機(jī)制,通過定義角色和權(quán)限、用戶和角色、角色和角色之間的關(guān)系,實(shí)現(xiàn)多層次、細(xì)粒度、可復(fù)用的權(quán)限管理系統(tǒng)。

基本模型有三個(gè)元素:用戶、角色和權(quán)限。模型設(shè)計(jì)基于“多對(duì)多”原則,即多個(gè)用戶可以具有相同的角色,一個(gè)用戶可以具有多個(gè)角色。同樣,您可以將同一權(quán)限分配給多個(gè)角色,也可以將同一角色分配給多個(gè)權(quán)限。

更詳細(xì)解釋見:https://zhuanlan.zhihu.com/p/513142061

2.2、三個(gè)元素的理解

用戶信息需要確保安全性,不能泄露。

角色關(guān)系到用戶和權(quán)限,需要設(shè)計(jì)合理。

權(quán)限字段應(yīng)在前端與后端都有校驗(yàn):前端通過菜單或按鈕的顯示與否體現(xiàn)對(duì)不同角色權(quán)限的控制,但前端可能會(huì)被用戶惡意修改視圖去顯示出因沒有權(quán)限而過濾掉的功能菜單或按鈕,此時(shí)在后端也要增加權(quán)限校驗(yàn),在該用戶沒擁有該權(quán)限時(shí),發(fā)起的請(qǐng)求返回403錯(cuò)誤,彈框提示該用戶缺少對(duì)應(yīng)權(quán)限。

三、數(shù)據(jù)字典

3.1、概括與作用

數(shù)據(jù)字典是整個(gè)平臺(tái)中數(shù)據(jù)描述的有效機(jī)制。通過界面進(jìn)行可視化的操作和維護(hù),能快速錄入和修改平臺(tái)上統(tǒng)一的字典數(shù)據(jù)。有效提高了數(shù)據(jù)的重復(fù)利用率和產(chǎn)品、項(xiàng)目的開發(fā)效率。整個(gè)數(shù)據(jù)字典數(shù)據(jù)為框架平臺(tái)所共享,用戶可以更好地對(duì)系統(tǒng)進(jìn)行自定義管理,以滿足自己的個(gè)性化需求。

3.2、怎么設(shè)計(jì)

參考:https://www.python100.com/html/82651.html

3.3、若依中使用字典

1、js中引入方法

import { getDicts } from "@/api/system/dict/data";

2、加載數(shù)據(jù)字典

export default {
  data() {
    return {
      xxxxxOptions: [],
      .....
...

created() {
  this.getDicts("字典類型").then(response => {
    this.xxxxxOptions = response.data;
  });
},

3、讀取數(shù)據(jù)字典

<uni-data-select
  v-for="dict in xxxxxOptions"
  :key="dict.dictValue"
  :text="dict.dictLabel"
  :value="dict.dictValue"
/>

四、工作流——Activiti7

4.1、概念

沒有?作流引擎之前如果要控制業(yè)務(wù)流程我們可能通過改變某個(gè)字段的狀態(tài)來實(shí)現(xiàn),這會(huì)帶來?旦我們流程發(fā)?變化的時(shí)候我們就需要去同步修改代碼。??流程引擎它??內(nèi)置可25張表,我們只要讀取它??的表就可以了,與表對(duì)應(yīng)的它還提供?系列可操作表的接?。核??個(gè)類是ProcessEngine,通過它能獲取?系列的service接?。

4.2、如何使?

部署?作流引擎,其實(shí)就是jar包api

流程定義:.bpmn?件,是?個(gè)xml?件定義了流程信息

流程定義部署

啟動(dòng)?個(gè)流程實(shí)例

?戶查詢代辦任務(wù),?個(gè)instance有多個(gè)task

?戶辦理任務(wù)

流程結(jié)束

4.3、優(yōu)點(diǎn)缺點(diǎn)

優(yōu)點(diǎn)
1、 最大的優(yōu)點(diǎn)就是免費(fèi)開源,這也是很多人選擇的原因
2、 小項(xiàng)目中應(yīng)用簡(jiǎn)單的串行并行流轉(zhuǎn)基本能滿足需求。
缺點(diǎn)
1、節(jié)點(diǎn)定義概念不同
2、缺乏可“追溯”性
3、擴(kuò)展需要與很多的Event來實(shí)現(xiàn)
4、二次開發(fā)難度大,門檻高

4.4、常用操作步驟
【Deployment】 (創(chuàng)建并部署一個(gè)新的流程定義)

獲取方式:
repositoryService.createDeployment().deploy();
對(duì)應(yīng)的表:act_re_deployment

用于存儲(chǔ)流程部署的相關(guān)信息。該表記錄了每個(gè)流程部署的唯一標(biāo)識(shí)符(ID)、名稱(NAME)、類別(CATEGORY)、租戶標(biāo)識(shí)符(TENANT_ID)、鍵(KEY)以及部署時(shí)間(DEPLOY_TIME)等信息。

核心字段:
id、name、deployementTime、category、key、tenantid


【ProcessDefinition】 (查詢流程定義對(duì)象)

獲取方式:
repositoryService.createProcessDefinitionQuery()
.deploymentId(“流程部署id”)
.processDefinitionId(“流程定義id”)
.processDefinitionKey(“流程定義的key”)
.processDefinitionName(“流程定義的name”)
.singleResult();
對(duì)應(yīng)的表:act_re_procdef

用于存儲(chǔ)流程定義的相關(guān)信息。該表記錄了每個(gè)流程定義的ID、名稱、版本號(hào)、資源文件和圖片文件等信息。

通過查詢act_re_procdef表,您可以獲得以下信息:

  • 流程定義ID(id):這是每個(gè)流程定義的唯一標(biāo)識(shí)符。
  • 流程定義名稱(name):這是流程定義的名稱。
  • 版本號(hào)(version):這是流程定義的版本號(hào)。
  • 資源文件(resource_name):這是與流程定義關(guān)聯(lián)的資源文件名稱。
  • 圖片文件(image_name):這是與流程定義關(guān)聯(lián)的圖片文件名稱。

act_re_procdef表與act_ge_bytearray表之間存在多對(duì)一的關(guān)系,即一個(gè)流程定義對(duì)應(yīng)多個(gè)資源文件和圖片文件。在Activiti中,每個(gè)流程定義都會(huì)在act_re_procdef表中增加一條記錄,同時(shí)也會(huì)在act_ge_bytearray表中存在相應(yīng)的資源記錄。

通過查詢act_re_procdef表,您可以了解流程定義的相關(guān)信息,包括其名稱、版本號(hào)以及與之關(guān)聯(lián)的資源文件和圖片文件。這對(duì)于管理和維護(hù)業(yè)務(wù)流程非常有用。

核心字段:
id、name、key、description、resourceName、deploymentId、tenantId、engineVersion


【ProcessInstance】 (查詢流程實(shí)例對(duì)象)

獲取方式:
方式1:runtimeService.startProcessInstanceByKey(processDefinitionKey);
方式2:
runtimeService.createProcessInstanceQuery()
.processInstanceId(“流程實(shí)例id”)
.processDefinitionId(“流程定義id”)
.processDefinitionKey(“流程定義的key”)
.deploymentId(“流程部署id”)
.processDefinitionName(“流程定義的name”)
.processInstanceBusinessKey(“流程實(shí)例業(yè)務(wù)key”)
.singleResult();

對(duì)應(yīng)的表:act_hi_procinst

用于存儲(chǔ)流程實(shí)例的歷史信息。該表記錄了每個(gè)流程實(shí)例的ID、名稱、業(yè)務(wù)鍵、狀態(tài)以及相關(guān)的其他信息。

通過查詢act_hi_procinst表,您可以獲得以下信息:

  • 流程實(shí)例ID(proc_id):這是每個(gè)流程實(shí)例的唯一標(biāo)識(shí)符。
  • 流程實(shí)例名稱(proc_name):這是流程實(shí)例的名稱。
  • 業(yè)務(wù)鍵(business_key):這是與流程實(shí)例關(guān)聯(lián)的業(yè)務(wù)鍵,通常用于標(biāo)識(shí)業(yè)務(wù)流程的唯一性。
  • 狀態(tài)(state):這是流程實(shí)例的狀態(tài),例如已啟動(dòng)、已完成、已暫停等。
  • 其他相關(guān)信息:act_hi_procinst表還包含其他與流程實(shí)例相關(guān)的信息,例如創(chuàng)建時(shí)間、更新時(shí)間、所屬組織等。

通過查詢act_hi_procinst表,您可以了解流程實(shí)例的歷史記錄,包括其狀態(tài)變化、執(zhí)行路徑以及相關(guān)的其他信息。這對(duì)于分析和優(yōu)化業(yè)務(wù)流程非常有用。

核心字段:
name、businessKey、deploymentId、descriptionName、processDefinitionId、processDefinitionKey、processDefinitionName、startTime、startTimeUser、tenantId、activityId、 processInstanceId


【Task】 (查詢?nèi)蝿?wù)信息)

獲取方式:
taskService.createTaskQuery()
.taskId(“taskId”)
.taskAssignee(“節(jié)點(diǎn)任務(wù)負(fù)責(zé)人”)
.taskCandidateUser(“taskCandidateUser”)
.taskDefinitionKey(“taskDefinitionKey”)
.processDefinitionKey(“流程定義的key”)
.processInstanceId(“流程實(shí)例id”)
.deploymentId(“流程部署id”)
.singleResult();
對(duì)應(yīng)的表:act_ru_task

用于存儲(chǔ)正在執(zhí)行的任務(wù)信息。該表記錄了每個(gè)任務(wù)的ID、名稱、狀態(tài)、執(zhí)行路徑等信息。

通過查詢act_ru_task表,您可以獲得以下信息:

  • 任務(wù)ID(task_id):這是每個(gè)任務(wù)的唯一標(biāo)識(shí)符。
  • 任務(wù)名稱(name):這是任務(wù)的名稱。
  • 任務(wù)狀態(tài)(status):這是任務(wù)的狀態(tài),例如待辦、已完成、正在進(jìn)行中等。
  • 執(zhí)行路徑(execution_id):這是與任務(wù)關(guān)聯(lián)的流程實(shí)例的執(zhí)行路徑信息。
  • 其他相關(guān)信息:act_ru_task表還包含其他與任務(wù)相關(guān)的信息,例如創(chuàng)建時(shí)間、更新時(shí)間、任務(wù)節(jié)點(diǎn)類型等。

act_ru_task表與act_ge_bytearray表之間存在多對(duì)一的關(guān)系,即一個(gè)任務(wù)對(duì)應(yīng)多個(gè)附件文件。在Activiti中,每個(gè)任務(wù)都會(huì)在act_ru_task表中增加一條記錄,同時(shí)也會(huì)在act_ge_bytearray表中存在相應(yīng)的附件記錄。

通過查詢act_ru_task表,您可以了解正在執(zhí)行的任務(wù)的相關(guān)信息,包括其ID、名稱、狀態(tài)以及執(zhí)行路徑等。這對(duì)于跟蹤和管理業(yè)務(wù)流程中的任務(wù)非常有用。

核心字段:
name、description、priority、owner、assignee、delegationState、formKey、parentTaskId、
processInstanceId、executionId、processDefinitionId、processVariables


【HistoricActivityInstance】 (查詢歷史活動(dòng)實(shí)例信息)

獲取方式:
historyService.createHistoricActivityInstanceQuery()
.processDefinitionId(“流程定義id”)
.taskAssignee(“節(jié)點(diǎn)任務(wù)負(fù)責(zé)人”)
.processInstanceId(“流程實(shí)例id”)
.singleResult();
對(duì)應(yīng)的表:act_hi_actinst

是一個(gè)歷史節(jié)點(diǎn)表,用于存儲(chǔ)歷史流程實(shí)例的信息。該表記錄了每個(gè)歷史流程實(shí)例的ID、名稱、業(yè)務(wù)鍵、狀態(tài)以及相關(guān)的其他信息,包括開始時(shí)間、結(jié)束時(shí)間等。通過查詢 act_hi_actinst 表,您可以了解已經(jīng)執(zhí)行過的流程實(shí)例的歷史記錄,例如流程的執(zhí)行路徑、各個(gè)節(jié)點(diǎn)的執(zhí)行時(shí)間等信息。這對(duì)于分析和優(yōu)化業(yè)務(wù)流程非常有用,可以幫助企業(yè)更好地了解業(yè)務(wù)流程的執(zhí)行情況,從而進(jìn)行改進(jìn)和優(yōu)化。

核心字段:
id、activityId、activityName、activityType、processDefinitionId、processInstanceId、executionId、taskId、assignee、startTime、endTime、durationInMilli、tenantId


【Execution】(查詢執(zhí)行流數(shù)據(jù))

獲取方式:
runtimeService.createExecutionQuery()
.processDefinitionKey(“流程定義的key”)
.executionId(“executionId”)
.processDefinitionId(“流程定義id”)
.processInstanceId(“流程實(shí)例id”)
.processDefinitionKey(“流程定義的key”)
.singleResult();
對(duì)應(yīng)的表:act_ru_execution

是存儲(chǔ)運(yùn)行時(shí)數(shù)據(jù)的表,主要包含執(zhí)行過程中的活動(dòng)、任務(wù)、變量等數(shù)據(jù)。該表記錄了每個(gè)流程實(shí)例的執(zhí)行路徑信息,例如當(dāng)前執(zhí)行到哪個(gè)流程節(jié)點(diǎn)、哪些分支已經(jīng)被激活等。通過查詢 act_ru_execution 表,可以獲取流程實(shí)例的實(shí)時(shí)運(yùn)行狀態(tài)信息,例如哪個(gè)任務(wù)正在由哪個(gè)用戶執(zhí)行、執(zhí)行到哪個(gè)節(jié)點(diǎn)等。這對(duì)于跟蹤和管理業(yè)務(wù)流程中的實(shí)例非常有用。

核心字段:
id、activityId、processInstanceId、name、description


【IdentityLink】(查詢身份與流程數(shù)據(jù)的綁定關(guān)系)

獲取方式:
方式1:runtimeService.getIdentityLinksForProcessInstance(processInstanceId)
方式2:repositoryService.getIdentityLinksForProcessDefinition(ProcessDefinitionId)
方式3:taskService.getIdentityLinksForTask(taskId)
對(duì)應(yīng)的表:act_ru_identitylink

存儲(chǔ)了用戶或用戶組與流程數(shù)據(jù)之間的綁定關(guān)系。該表記錄了用戶或用戶組與流程實(shí)例、流程任務(wù)等數(shù)據(jù)的關(guān)聯(lián)信息。通過查詢 act_ru_identitylink 表,可以獲取用戶或用戶組與流程實(shí)例、流程任務(wù)等數(shù)據(jù)的綁定關(guān)系,例如哪個(gè)用戶或用戶組執(zhí)行了哪個(gè)流程任務(wù)、哪些流程任務(wù)被指定給了哪些用戶或用戶組等。這對(duì)于了解業(yè)務(wù)流程的執(zhí)行情況、進(jìn)行權(quán)限管理和任務(wù)分配等操作非常有用。

核心字段:
type、userId、taskId、processDefinitionId、processInstanceId

4.5、項(xiàng)目怎么用,怎么設(shè)計(jì)表
4.5.1、流程定義明細(xì)模塊:
  1. 設(shè)置一個(gè)流程管理模塊,數(shù)據(jù)庫創(chuàng)建一張流程定義明細(xì)表bus_bpmn_info和與之對(duì)應(yīng)的查詢頁面,表中要有processKey和version這兩個(gè)字段,在該頁面增加一個(gè)流程文件部署功能,需要選擇審核類型、上傳bpmn流程文件、添加備注(描述信息,可不填),然后通過repositoryService服務(wù)的deploy部署一個(gè)新流程,部署后就可以在act_re_procdef表里查到剛才部署的流程定義了。將流程定義的所需信息存放到我們自己建的bpmnInfo流程定義明細(xì)表中,在查詢頁面顯示出來我們新建過的流程定義。

        @Override
        public void deploy(DeployVO vo) throws IOException {
            //參數(shù)判斷--文件大小--文件后綴
            if(vo == null){
                throw new ServiceException("參數(shù)異常");
            }
            MultipartFile file = vo.getFile();
            if(file == null || file.getSize() == 0){
                throw new ServiceException("必需選擇一個(gè)流程文件");
            }
            String ext = FileUploadUtils.getExtension(file);
            if(!"bpmn".equalsIgnoreCase(ext)){
                throw new ServiceException("文件格式必須為 bpmn 格式");
            }
            //流程部署
            Deployment deployment = repositoryService.createDeployment()
                    .addInputStream(vo.getBpmnLabel(), file.getInputStream())
                    .deploy();
            //流程類-解下流程文件, 獲取流程文件所有信息封裝對(duì)象-ProcessDefinition---act_re_procdef
            ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery()
                    .deploymentId(deployment.getId()).singleResult();
            //保存流程信息對(duì)象: BpmnInfo
            BpmnInfo bpmnInfo = new BpmnInfo();
            bpmnInfo.setInfo(vo.getInfo());
            bpmnInfo.setBpmnLabel(vo.getBpmnLabel());
            bpmnInfo.setBpmnType(vo.getBpmnType());
    
            bpmnInfo.setDeployTime(deployment.getDeploymentTime());
            bpmnInfo.setVersion(processDefinition.getVersion());
            bpmnInfo.setProcessDefinitionKey(processDefinition.getKey());
    
            bpmnInfoMapper.insertBpmnInfo(bpmnInfo);
    
        }
    
  2. 在流程定義明細(xì)頁面中可以查看流程文件或流程圖,具體實(shí)現(xiàn)代碼:

        @Override
        public InputStream getResource(String type, Long id) {
            BpmnInfo bpmnInfo = bpmnInfoMapper.selectBpmnInfoById(id);
    
            if (bpmnInfo==null||!("xml".equalsIgnoreCase(type)||"png".equalsIgnoreCase(type))) {
                throw new ServiceException("參數(shù)異?;蛭募袷疆惓?);
            }
    
            InputStream inputStream = null;
    
            ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery()
                    .processDefinitionKey(bpmnInfo.getProcessDefinitionKey())
                    .processDefinitionVersion(bpmnInfo.getVersion())
                    .singleResult();
            if("xml".equalsIgnoreCase(type)){
                inputStream = repositoryService
                        .getResourceAsStream(processDefinition.getDeploymentId(), bpmnInfo.getBpmnLabel());
            }else if("png".equalsIgnoreCase(type)){
                DefaultProcessDiagramGenerator processDiagramGenerator = new DefaultProcessDiagramGenerator();
                BpmnModel bpmnModel = repositoryService.getBpmnModel(processDefinition.getId());
                /**
                 * 第一個(gè)參數(shù): 流程定義模型
                 * 第二個(gè)參數(shù): 高亮節(jié)點(diǎn)集合
                 * 第三個(gè)參數(shù): 高亮連線集合
                 */
                inputStream = processDiagramGenerator.generateDiagram(bpmnModel,
                        Collections.emptyList(),
                        Collections.emptyList(),
                        "宋體",
                        "宋體",
                        "宋體");
            }
            return inputStream;
        }
    
  3. 流程定義的撤銷:

        /**
         * 批量撤銷流程定義明細(xì)
         *
         * @param ids 需要?jiǎng)h除的流程定義明細(xì)主鍵
         * @return 結(jié)果
         */
        @Override
        public int deleteBpmnInfoByIds(Long[] ids) {
            if (ids==null||ids.length<1) {
                throw new ServiceException("參數(shù)異常");
            }
    
            for (Long id : ids) {
                BpmnInfo bpmnInfo = bpmnInfoMapper.selectBpmnInfoById(id);
                if (bpmnInfo==null) {
                    throw new ServiceException("參數(shù)異常");
                }
    
                ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery()
                        .processDefinitionKey(bpmnInfo.getProcessDefinitionKey())
                        .processDefinitionVersion(bpmnInfo.getVersion())
                        .singleResult();
    
                if (processDefinition==null) {
                    throw new ServiceException("存在撤銷項(xiàng)參數(shù)異常");
                }
    
                repositoryService.deleteDeployment(processDefinition.getDeploymentId(),true);
    
                bpmnInfoMapper.deleteBpmnInfoById(id);
            }
            return 1;
        }
    
4.5.2、發(fā)起/提交審核模塊:

? 發(fā)起審核的彈框里需要用戶從前端傳入所有所需的參數(shù),如審核人等。并且前端和后端都要添加狀態(tài)判斷——該業(yè)務(wù)處在什么狀態(tài)下才允許發(fā)起審核、該業(yè)務(wù)的某些條件是否影響審核節(jié)點(diǎn)等。

	@Transactional
    @Override
    public void startAudit(AuditVO vo) {

        //參數(shù)判斷
        ServiceItem serviceItem = serviceItemMapper.selectServiceItemById(vo.getId());
        if(serviceItem == null){
            throw new ServiceException("參數(shù)異常");
        }

        if(!ServiceItem.CARPACKAGE_YES.equals(serviceItem.getCarPackage())){
            throw new ServiceException("必須是套餐才允許審核");
        }
        if(!(ServiceItem.AUDITSTATUS_INIT.equals(serviceItem.getAuditStatus())
                || ServiceItem.AUDITSTATUS_REPLY.equals(serviceItem.getAuditStatus()))){
            throw new ServiceException("必須是初始化或者審核拒絕狀態(tài)才可以進(jìn)行審核");
        }
        //審核信息保存
        CarPackageAudit audit = new CarPackageAudit();

        audit.setInfo(vo.getInfo());
        audit.setServiceItemId(vo.getId());
        audit.setServiceItemName(serviceItem.getName());
        audit.setServiceItemInfo(serviceItem.getInfo());
        audit.setServiceItemPrice(serviceItem.getDiscountPrice());
        audit.setCreatorId(SecurityUtils.getUserId().toString());
        audit.setStatus(CarPackageAudit.STATUS_IN_ROGRESS);
        audit.setCreateTime(new Date());
        carPackageAuditMapper.insertCarPackageAudit(audit);

        BpmnInfo bpmnInfo = bpmnInfoMapper.selectLastByType(CarPackageAudit.FLOW_AUDIT_TYPE);
        //流程啟動(dòng)---businesskey   map(審核流程涉及參數(shù))

        String businessKey = audit.getId().toString();
        String processDefinitionKey = bpmnInfo.getProcessDefinitionKey();
        Map<String, Object> map = new HashMap<>();

        //設(shè)置節(jié)點(diǎn)審核人:財(cái)務(wù)
        if(vo.getFinanceId() != null){
            map.put("financeId", vo.getFinanceId());
        }
        //設(shè)置節(jié)點(diǎn)審核人:店長
        if(vo.getShopOwnerId() != null){
            map.put("shopOwnerId", vo.getShopOwnerId());
        }
        // 流程圖中不支持BigDecimal 校驗(yàn), 轉(zhuǎn)換long類型
        map.put("disCountPrice", serviceItem.getDiscountPrice().longValue());

        ProcessInstance instance = runtimeService.startProcessInstanceByKey(processDefinitionKey, businessKey, map);

        //audit.setInstanceId(instance.getProcessInstanceId());  //流程實(shí)例id
        audit.setInstanceId(instance.getId());  //流程實(shí)例id
        carPackageAuditMapper.updateCarPackageAudit(audit);

        //套餐項(xiàng)狀態(tài)--審核中
        serviceItem.setAuditStatus(ServiceItem.AUDITSTATUS_AUDITING);
        serviceItemMapper.updateServiceItem(serviceItem);

    }
4.5.3、套餐審核信息模塊:
  1. 每一個(gè)開啟審核的業(yè)務(wù)對(duì)應(yīng)一個(gè)執(zhí)行的流程實(shí)例,我們要?jiǎng)?chuàng)建一個(gè)業(yè)務(wù)表bus_car_package_audit,表中要擁有關(guān)聯(lián)服務(wù)項(xiàng)表的字段service_item_id(為了頁面回顯效果也可以將name、info、price字段加上)、關(guān)聯(lián)流程實(shí)例的字段instance_id,還可以將關(guān)聯(lián)流程定義的字段process_key也加上,還有一些狀態(tài)status和創(chuàng)建者id和創(chuàng)建時(shí)間create_time等。

    CREATE TABLE `bus_car_package_audit` (
      `id` bigint NOT NULL AUTO_INCREMENT COMMENT '主鍵',
      `service_item_id` bigint DEFAULT NULL COMMENT '服務(wù)單項(xiàng)id',
      `service_item_name` varchar(100) DEFAULT NULL COMMENT '服務(wù)項(xiàng)名稱',
      `service_item_info` varchar(255) DEFAULT NULL COMMENT '服務(wù)單項(xiàng)備注',
      `service_item_price` decimal(10,2) DEFAULT NULL COMMENT '服務(wù)單項(xiàng)審核價(jià)格',
      `instance_id` varchar(64) DEFAULT NULL COMMENT '流程實(shí)例id',
      `creator_id` varchar(20) DEFAULT NULL COMMENT '創(chuàng)建者',
      `info` varchar(255) DEFAULT NULL COMMENT '備注',
      `status` int DEFAULT NULL COMMENT '狀態(tài)【審核中0/審核拒絕1/審核通過2/審核撤銷3】',
      `create_time` datetime DEFAULT NULL COMMENT '創(chuàng)建時(shí)間',
      PRIMARY KEY (`id`) USING BTREE
    ) ENGINE=InnoDB  DEFAULT CHARSET=utf8mb3 COMMENT='套餐審核';
    
  2. 審核歷史按鈕功能:查看該條審核的審批操作歷史。使用對(duì)應(yīng)的流程實(shí)例id通過historyService.createHistoricTaskInstanceQuery()可查詢到該實(shí)例的每一條審批節(jié)點(diǎn)記錄,

        @Override
        public List<HistoryVO> queryHistory(Long instanceId) {
    
            if(instanceId == null){
                throw new ServiceException("參數(shù)異常");
            }
            BpmnInfo bpmnInfo = bpmnInfoMapper.selectLastByType(CarPackageAudit.FLOW_AUDIT_TYPE);
    
            //原生的activit7返回domain對(duì)象 不一定滿足頁面的要求, 所以:一般將元素activiti對(duì)象進(jìn)行二次加工
            List<HistoricTaskInstance> list = historyService.createHistoricTaskInstanceQuery()
                    .processInstanceId(instanceId.toString())  //
                    .processDefinitionKey(bpmnInfo.getProcessDefinitionKey())  //套餐審核節(jié)點(diǎn)
                    .finished()  //要求節(jié)點(diǎn)執(zhí)行審核操作
                    .list();
            
            //思考: 怎么查詢歷史??
            List<HistoryVO> vos = new ArrayList<>();
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            for (HistoricTaskInstance task : list) {
                HistoryVO vo = new HistoryVO();
                vo.setTaskName(task.getName());
                // 將Date類型轉(zhuǎn)成對(duì)應(yīng)格式的String
                vo.setEndTime(sdf.format(task.getEndTime()));
                vo.setStartTime(sdf.format(task.getStartTime()));
                //間隔時(shí)間: 花費(fèi)時(shí)間:  endTime-startTime
                // 格式是 毫秒 ---> xx年 xx天 xxx月xxx日 xx時(shí)
                vo.setDurationInMillis(task.getDurationInMillis() / 1000 + "s");
                //審核備注
                //查詢節(jié)點(diǎn)審核備注信息?
                //由于可能存在并行網(wǎng)關(guān),有多條審核備注,所以要拼接在一起
                List<Comment> comments = taskService.getTaskComments(task.getId());
                if(comments != null || comments.size() > 0){
                    StringBuilder sb = new StringBuilder(80);
                    for (Comment comment : comments) {
                        //節(jié)點(diǎn)備注信息
                        sb.append(comment.getFullMessage());
                    }
                    vo.setComment(sb.toString());
                }
                vos.add(vo);
            }
            return vos;
        }
    
  3. 進(jìn)度查看按鈕功能:查看流程進(jìn)行到哪,在流程圖png中將進(jìn)行到的節(jié)點(diǎn)用紅框高亮的方式顯示出來。

        @Override
        public InputStream getProcessImg(Long id) {
            BpmnInfo bpmnInfo = bpmnInfoMapper.selectLastByType(CarPackageAudit.FLOW_AUDIT_TYPE);
            ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery()
                    .processDefinitionKey(bpmnInfo.getProcessDefinitionKey())
                    .processDefinitionVersion(bpmnInfo.getVersion())  //指定版本
                    .singleResult();//???
    
            CarPackageAudit audit = carPackageAuditMapper.selectCarPackageAuditById(id);
            List<String> activeActivityIds = new ArrayList<>();
            if(audit.getStatus().equals(CarPackageAudit.STATUS_IN_ROGRESS)){
                //高亮顯示當(dāng)前流程所在節(jié)點(diǎn)-坐標(biāo)
                activeActivityIds = runtimeService.getActiveActivityIds(audit.getInstanceId());
            }else{
                activeActivityIds = Collections.emptyList();
            }
            //圖片
            DefaultProcessDiagramGenerator processDiagramGenerator = new DefaultProcessDiagramGenerator();
            BpmnModel bpmnModel = repositoryService.getBpmnModel(processDefinition.getId());
            /**
             * 第一個(gè)參數(shù): 流程定義模型
             * 第二個(gè)參數(shù): 高亮節(jié)點(diǎn)集合---當(dāng)前流程推進(jìn)到哪個(gè)節(jié)點(diǎn)了---傳的是節(jié)點(diǎn)坐標(biāo)
             * 第三個(gè)參數(shù): 高亮連線集合
             */
            InputStream inputStream = processDiagramGenerator.generateDiagram(bpmnModel,
                    activeActivityIds,
                    Collections.emptyList(),
                    "宋體",
                    "宋體",
                    "宋體");
            return inputStream;
        }
    
  4. 撤銷審核按鈕功能:顧名思義。先校驗(yàn)該流程狀態(tài)是否允許被撤銷,撤銷時(shí)需要完成三個(gè)步驟——服務(wù)套餐狀態(tài)置為初始化、審核信息記錄狀態(tài)置為審核撤銷、將運(yùn)行流程實(shí)例(關(guān)聯(lián)到的幾個(gè)表)執(zhí)行撤銷方法runtimeService.deleteProcessInstance()

        @Override
        public void auditCancel(Long id) {
            //參數(shù)校驗(yàn)
            CarPackageAudit audit = carPackageAuditMapper.selectCarPackageAuditById(id);
            if(audit == null){
                throw new ServiceException("參數(shù)異常");
            }
            if(!CarPackageAudit.STATUS_IN_ROGRESS.equals(audit.getStatus())){
                throw new ServiceException("只有在審核中狀態(tài)才允許撤銷操作");
            }
            //服務(wù)套餐--狀態(tài)-初始化
            ServiceItem serviceItem = serviceItemMapper.selectServiceItemById(audit.getServiceItemId());
            serviceItem.setAuditStatus(ServiceItem.AUDITSTATUS_INIT);
            serviceItemMapper.updateServiceItem(serviceItem);
    
            //審核信息記錄--狀態(tài)--撤銷
            audit.setStatus(CarPackageAudit.STATUS_CANCEL);
            carPackageAuditMapper.updateCarPackageAudit(audit);
    
            //流程--流程結(jié)束--刪除
            runtimeService.deleteProcessInstance(audit.getInstanceId(), "審核被撤銷了");
        }
    
4.5.4、我的待辦、我的已辦模塊:
  1. 前端代碼可以直接拷貝套餐審核信息模塊的vue文件,因?yàn)椴樵兊亩际菢I(yè)務(wù)表bus_car_package_audit。不同的是該兩個(gè)模塊只負(fù)責(zé)流程的推動(dòng)和審批,故沒有撤銷按鈕功能,而我的待辦模塊會(huì)多一個(gè)“審批”功能,即分配給當(dāng)前用戶的審批流程可以通過該操作選擇同意或拒絕來推動(dòng)流程進(jìn)行。

  2. 查詢功能參數(shù)需要添加當(dāng)前用戶條件,因?yàn)橹荒懿榈疆?dāng)前登錄用戶自己負(fù)責(zé)的審核流程。若依有自帶的SecurityUtils工具類獲取當(dāng)前登錄用戶的id、name等信息,再通過taskService.createTaskQuery().taskAssignee(SecurityUtils.getUserId().toString()).list();拿到當(dāng)前尚在推動(dòng)流程階段(未結(jié)束)的用戶自己負(fù)責(zé)的流程實(shí)例,獲取到流程實(shí)例id,即可在業(yè)務(wù)表bus_car_package_audit查詢到對(duì)應(yīng)的審核業(yè)務(wù)數(shù)據(jù)。上述說的是我的待辦模塊,而在我的已辦模塊,只需將查詢未結(jié)束的流程換成查詢?nèi)苛鞒蹋◤膆istory表中查)即可,List list = historyService.createHistoricTaskInstanceQuery().taskAssignee(SecurityUtils.getUserId().toString()).list();

  3. 這里提供一個(gè)更為直觀的多表聯(lián)查方法:我們一開始就能用SecurityUtils拿到用戶id,在對(duì)應(yīng)的表通過ASSIGNEE_字段篩選出當(dāng)前登錄用戶所負(fù)責(zé)的流程實(shí)例(待辦則查act_ru_task表,已辦則查act_hi_taskinst表),再通過拿到的流程實(shí)例id的字符串集合去業(yè)務(wù)表bus_car_package_audit獲取到最終自己負(fù)責(zé)的業(yè)務(wù)數(shù)據(jù)。

    // mapper接口方法,注意因?yàn)楸绕胀ú樵兌嗔藆serId條件,所以需要加@Param注解給多個(gè)參數(shù)命名,傳CarPackageAudit對(duì)象是為了頁面上的條件查詢,即通過審核狀態(tài)與創(chuàng)建時(shí)間篩選數(shù)據(jù)。最后傳的字符串tableName是查詢的表名,因?yàn)榇k與已辦的sql只有一個(gè)表名之差,所以復(fù)用一下,在動(dòng)態(tài)sql里使用${}替換字符串,因?yàn)椴皇峭ㄟ^參數(shù)傳入的字段,所以不會(huì)有動(dòng)態(tài)sql注入的風(fēng)險(xiǎn)。
    List<CarPackageAudit> selectHisByUserId(@Param("userId") Long userId, @Param("carPackageAudit") CarPackageAudit carPackageAudit, @Param("tableName") String tableName);
    
    	<!-- mapper.xml里的sql -->
        <select id="selectHisByUserId" resultMap="CarPackageAuditResult">
            select c.* from bus_car_package_audit c LEFT JOIN ${tableName} a ON a.PROC_INST_ID_ = c.instance_id
            <where>
                a.ASSIGNEE_ = #{userId}
                <if test="carPackageAudit.params.beginCreateTime != null and carPackageAudit.params.beginCreateTime != '' and carPackageAudit.params.endCreateTime != null and carPackageAudit.params.endCreateTime != ''">
                    and c.create_time between #{carPackageAudit.params.beginCreateTime} and #{carPackageAudit.params.endCreateTime}
                </if>
                <if test="carPackageAudit.status != null"> and c.status = #{carPackageAudit.status}</if>
            </where>
        </select>
    
    // service中的方法:
    // 已辦
    List<CarPackageAudit> list = carPackageAuditMapper.selectHisByUserId(SecurityUtils.getUserId(),carPackageAudit,"act_ru_task");
    
    // 待辦
    List<CarPackageAudit> list = carPackageAuditMapper.selectHisByUserId(SecurityUtils.getUserId(),carPackageAudit,"act_hi_taskinst");
    
    
  4. 我的已辦中的審批功能:首先校驗(yàn)狀態(tài)是否能進(jìn)行審核。然后taskService.createTaskQuery().processInstanceId(audit.getInstanceId())查詢?nèi)蝿?wù),判斷是否為null(因?yàn)槿羰褂门潘W(wǎng)關(guān),可能其他人先一步審核通過了,若為null,則什么也不做直接return),然后根據(jù)是否審核通過添加備注信息:taskService.addComment(task.getId(), audit.getInstanceId().toString(), message); 然后新建一個(gè)map存放節(jié)點(diǎn)條件,key為條件字段的變量名value為布爾值(同意or拒絕),然后任務(wù)處理taskService.complete(task.getId(), map);。隨后業(yè)務(wù)線推進(jìn),若審核通過,判斷是否還有下一個(gè)節(jié)點(diǎn):若有則什么也不做(等待流程到下個(gè)節(jié)點(diǎn)繼續(xù)推動(dòng)),若沒有則代表當(dāng)前流程正常結(jié)束,即可修改套餐狀態(tài)和業(yè)務(wù)信息狀態(tài)。若審核拒絕,則直接修改套餐狀態(tài)和業(yè)務(wù)信息狀態(tài)。

    @Override
        public void audit(PackageAuditVO vo) {
    
            //審核條件
            //id != null
            //狀態(tài) 為審核中
            if(vo == null){
                throw new ServiceException("參數(shù)異常");
            }
            CarPackageAudit audit = carPackageAuditMapper.selectCarPackageAuditById(vo.getId());
            if(audit == null || !CarPackageAudit.STATUS_IN_ROGRESS.equals(audit.getStatus())){
                throw new ServiceException("參數(shù)異常或者狀態(tài)異常");
            }
            //流程推進(jìn): 節(jié)點(diǎn)審核
            //查詢?nèi)蝿?wù)
            Task task = taskService.createTaskQuery()
                    .processInstanceId(audit.getInstanceId())
                    .singleResult();
            if(task == null){
                return;
            }
            //審核備注
            String message = "";
            if(CarPackageAudit.STATUS_PASS.equals(vo.getAuditStatus())){
                //通過
                message = "審批人:" + SecurityUtils.getUsername() + "通過, 審核備注:[" + vo.getAuditInfo() + "]";
            }else{
                //拒絕
                message = "審批人:" + SecurityUtils.getUsername() + "拒絕, 審核備注:[" + vo.getAuditInfo() + "]";
            }
            taskService.addComment(task.getId(), audit.getInstanceId().toString(), message);
    
            Map<String, Object> map = new HashMap<>();
            map.put("shopOwner", CarPackageAudit.STATUS_PASS.equals(vo.getAuditStatus()));
            //處理
            taskService.complete(task.getId(), map);
    
    
            ServiceItem serviceItem = serviceItemMapper.selectServiceItemById(audit.getServiceItemId());
    
            //業(yè)務(wù)線推進(jìn)
            if(CarPackageAudit.STATUS_PASS.equals(vo.getAuditStatus())){
                //審核通過
                Task nextTask = taskService.createTaskQuery()
                        .processInstanceId(audit.getInstanceId())
                        .singleResult();
                //判斷是否有下一個(gè)節(jié)點(diǎn)
                if(nextTask == null){
                    //  沒有: 當(dāng)前流程正常結(jié)束
                    //       1:服務(wù)套餐--審核通過
                    serviceItem.setAuditStatus(ServiceItem.AUDITSTATUS_APPROVED);
                    serviceItemMapper.updateServiceItem(serviceItem);
                    //       2:審核流程信息--審核通過
                    audit.setStatus(CarPackageAudit.STATUS_PASS);
                    carPackageAuditMapper.updateCarPackageAudit(audit);
                }
                //有: 當(dāng)前流程還在繼續(xù) -- 啥都不做
            }else {
                //審核拒絕
                //1:服務(wù)套餐--審核拒絕
                serviceItem.setAuditStatus(ServiceItem.AUDITSTATUS_REPLY);
                serviceItemMapper.updateServiceItem(serviceItem);
                //2:審核流程信息--審核拒絕
                audit.setStatus(CarPackageAudit.STATUS_REJECT);
                carPackageAuditMapper.updateCarPackageAudit(audit);
                //3:流程--流程正常結(jié)束
            }
        }
    
4.6、思考總結(jié):
  • 熟悉activiti重要的那些表,及對(duì)應(yīng)的service操作。

rbac項(xiàng)目源碼,開源,項(xiàng)目實(shí)例,Activiti,開源,spring boot,后端,vue,Activiti

  • 設(shè)計(jì)業(yè)務(wù)表時(shí)想清楚需要哪些字段去關(guān)聯(lián)哪些activiti的表和哪些其他業(yè)務(wù),還有需要顯示的數(shù)據(jù),表設(shè)計(jì)得好則代碼寫起來就能簡(jiǎn)便很多。
  • 使用工作流實(shí)現(xiàn)某個(gè)功能時(shí),從最后需要拿到的數(shù)據(jù)往前推,最后的數(shù)據(jù)有哪些對(duì)應(yīng)的字段可以和哪些表關(guān)聯(lián),建立每張表的聯(lián)系,最后聯(lián)系到我們提供的參數(shù)數(shù)據(jù),即可搭建好這座參數(shù)與返回值連接的橋梁,完成需求。

五、若依腳手架

5.1、概念

腳手架(scaffolding)指的是創(chuàng)建項(xiàng)目時(shí),自動(dòng)完成的創(chuàng)建初始文件等初始化工作。這些工作往往是每次新建工程都要進(jìn)行的重復(fù)性工作。如創(chuàng)建Maven 項(xiàng)目時(shí)使用的原型(archetype)等。腳手架是一種由一些 model–view–controller 框架支持的技術(shù),程序員可以在其中指定應(yīng)用程序數(shù)據(jù)庫的使用方式。

5.2、如何快速掌握腳手架
  • 看官方文檔
  • 使用腳手架創(chuàng)建項(xiàng)目后看代碼并實(shí)際上手操作
  • 問有經(jīng)驗(yàn)的老前輩
5.3、如何通過腳手架快速復(fù)制出一個(gè)curd操作流程

有官方文檔就按照官方文檔操作一遍,沒有就自己搗鼓或問別人。

5.4、其他

工作中很大概率不會(huì)使用若依這樣的腳手架,則拿到腳手架后的改造就要自己操作了,注意哪些文件夾和類名要改,pom里依賴的坐標(biāo)名、版本等,最后再全局替換一下需要替換的字段,啟動(dòng)項(xiàng)目看看有沒有問題。最好是公司的腳手架已配置好初始化信息。

六、項(xiàng)目——操作

6.1、開發(fā)意識(shí)
  1. 產(chǎn)品是開發(fā)給用戶用的,一些功能和需求多站在用戶角度考慮,寫代碼前先整體想好該怎么開發(fā),想得細(xì)致入微一些,考慮得周全一些,把要實(shí)現(xiàn)的步驟盡可能明細(xì)地列舉出來,能畫出業(yè)務(wù)流程原型圖最好,覺得不合理或有更優(yōu)方案的地方及時(shí)和經(jīng)理或上級(jí)溝通交流,確定好最終方案,再開始開發(fā),事半功倍。
  2. 設(shè)計(jì)一張表的時(shí)候,先把頁面列表要什么字段加進(jìn)去,其次再考慮每個(gè)字段可能要關(guān)聯(lián)的其他字段(例如頁面只顯示用戶姓名,但我們要把用戶id的字段也加上,因?yàn)閕d才是可以唯一識(shí)別的主鍵),其次再考慮該表會(huì)關(guān)聯(lián)到的其他表需要通過什么字段關(guān)聯(lián)起來或者建立起什么關(guān)系,最后考慮該表的應(yīng)用場(chǎng)景應(yīng)該再加些什么字段去豐富它(經(jīng)驗(yàn)積累,如創(chuàng)建時(shí)間create_time,狀態(tài)status,軟刪除is_delete,創(chuàng)建人user_id等等)??紤]好每個(gè)字段用什么數(shù)據(jù)類型,是否要采用字典(常用于可選項(xiàng)較少的下拉框選項(xiàng))。
  3. 添加時(shí)彈窗需要回顯什么,如果是要封裝的數(shù)據(jù)則在后端包裝一個(gè)VO類去傳,后端接收前端傳來的入?yún)⑿枰b時(shí)也同理。編輯和刪除操作時(shí)多考慮除了對(duì)應(yīng)的數(shù)據(jù)改變以外,其他數(shù)據(jù)和表的狀態(tài)是否要一起改變,不要漏掉關(guān)聯(lián)的邏輯。
  4. 寫業(yè)務(wù)需求時(shí)還是要多多思考多多溝通,盡善盡美。
6.2、修改bug能力

后端:

  • 先看拋出的異常類型,鎖定bug產(chǎn)生的原因。通過報(bào)錯(cuò)信息定位到報(bào)錯(cuò)位置,仔細(xì)排查解決。
  • 看看是不是哪個(gè)注解漏貼了,哪里有可能造成空指針了,包import導(dǎo)入的對(duì)不對(duì)、是不是你要用的那個(gè)依賴的包。
  • mapper.xml里的sql先在sql工具中的查詢頁面運(yùn)行一遍,沒報(bào)錯(cuò)再粘貼過去。
  • debug模式打斷點(diǎn)看執(zhí)行時(shí)數(shù)據(jù)是否正常。

前端:

  • 多用console.log查看數(shù)據(jù)是否有問題。
  • 注意漏加this的問題
  • 異步數(shù)據(jù)沒獲取到的問題
  • 箭頭函數(shù)造成的作用域問題,使得this指向有誤,解決方法:在箭頭函數(shù)外寫let that = this,箭頭函數(shù)中使用that來指向this。

七、項(xiàng)目——技術(shù)上

7.1、基礎(chǔ):
  • 使用腳手架添加菜單和生成代碼時(shí),務(wù)必注意模塊名和路徑這類敏感信息不要寫錯(cuò)。善用數(shù)據(jù)字典。

  • 善用各種工具類,例如驗(yàn)證手機(jī)號(hào)和驗(yàn)證車牌號(hào),能省很多事

    // 驗(yàn)證是否非法手機(jī)號(hào)
    boolean phoneLegal = RegexUtils.isPhoneLegal(busAppointment.getCustomerPhone());
    Assert.isTrue(phoneLegal, "非法手機(jī)號(hào)碼");
    
    // 驗(yàn)證是否非法車牌號(hào)
    VehiclePlateNoUtil.VehiclePlateNoEnum vehiclePlateNo = VehiclePlateNoUtil.getVehiclePlateNo(busAppointment.getLicensePlate());
    Assert.notNull(vehiclePlateNo, "非法車牌號(hào)");
    
    // 獲取當(dāng)前登錄用戶信息
    Long userId = SecurityUtils.getUserId();
    String username = SecurityUtils.getUsername();
    
    // 將Date數(shù)據(jù)轉(zhuǎn)成想要的格式的String字符串
    SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    vo.setEndTime(sdf.format(task.getEndTime()));
    vo.setStartTime(sdf.format(task.getStartTime()));
    
  • domain中有用到數(shù)據(jù)字典字段的類,在類里加上靜態(tài)常量,避免手寫出錯(cuò)或后期要修改時(shí)造成的各種麻煩

        public static final Integer FLOW_AUDIT_TYPE = 0;//服務(wù)套餐審核類型
        public static final Integer FLOW_PERSONAL_LEAVE = 1;//事假審核類型
        public static final Integer FLOW_SICK_LEAVE = 2;//病假審核類型
    
        public static final Integer STATUS_IN_ROGRESS = 0;//審核中
        public static final Integer STATUS_REJECT = 1;//審核拒絕(拒絕)
        public static final Integer STATUS_PASS = 2;//審核通過(同意)
        public static final Integer STATUS_CANCEL = 3;//審核撤銷
    
        public static final Integer IS_DELETE_YES = 1; // 已刪除
        public static final Integer IS_DELETE_NO = 0; // 未刪除
    
  • 添加目錄、二級(jí)菜單、菜單下的按鈕時(shí),若需要添加權(quán)限字段,則記得統(tǒng)一添加(前端v-hasPermi,后端controller的方法上@PreAuthorize(“@ss.hasPermi(‘business:appointment:add’)”),腳手架頁面的菜單權(quán)限字段上),前端權(quán)限控制是否顯示,后端權(quán)限控制當(dāng)前用戶是否有權(quán)執(zhí)行該請(qǐng)求。

    	// 后端
        @PreAuthorize("@ss.hasPermi('business:appointment:add')")
        @Log(title = "新增養(yǎng)修信息預(yù)約", businessType = BusinessType.INSERT)
        @PostMapping
        public AjaxResult add(@Validated @RequestBody BusAppointment busAppointment)
        {
            return toAjax(busAppointmentService.insertBusAppointment(busAppointment));
        }
    
          <!-- 前端 -->
    	  <el-col :span="1.5">
            <el-button
              type="primary"
              plain
              icon="el-icon-plus"
              size="mini"
              @click="handleAdd"
              v-hasPermi="['business:appointment:add']"
              >新增</el-button
            >
          </el-col>
    

    // 頁面:

    rbac項(xiàng)目源碼,開源,項(xiàng)目實(shí)例,Activiti,開源,spring boot,后端,vue,Activiti

  • 寫動(dòng)態(tài)sql或條件查詢語句時(shí)注意代碼書寫格式,批量操作的數(shù)組用where xxx in (xxx),時(shí)間范圍用between,善用<include refid="xxx"/>

    	<sql id="selectBusStatementVo">
            select id,
                   customer_name,
                   ...
                   is_delete
            from bus_statement
        </sql>
    
        <select id="selectBusStatementList" parameterType="BusStatement" resultMap="BusStatementResult">
            <include refid="selectBusStatementVo"/>
            <where>
                <if test="params.beginActualArrivalTime != null and params.beginActualArrivalTime != '' and params.endActualArrivalTime != null and params.endActualArrivalTime != ''">
                    and actual_arrival_time between #{params.beginActualArrivalTime} and #{params.endActualArrivalTime}
                </if>
                <if test="isDelete != null "> and is_delete = #{isDelete}</if>
            </where>
        </select>
    
        <delete id="deleteBusStatementByIds" parameterType="String">
            delete from bus_statement where id in
            <foreach item="id" collection="array" open="(" separator="," close=")">
                #{id}
            </foreach>
        </delete>
    
  • 軟刪除時(shí)記得修改一些邏輯上相關(guān)的sql,因?yàn)檐泟h除數(shù)據(jù)還存在,要加上is_delete = #{isDelete}的條件

  • 使用postman測(cè)試接口:

    • 通過驗(yàn)證碼請(qǐng)求http://localhost:8080/captchaImage獲取到驗(yàn)證碼的uuid和code

    • 登錄請(qǐng)求http://localhost:8080/login,body通過raw-JSON格式帶上uuid、code、username、password。

      {
      	"uuid": "b9896c01fb814f128d4f6bb47d5fb99f",
      	"username": "admin",
      	"password": "admin123",
      	"code": "14"
      }
      
    • 登錄成功后,后續(xù)在需要測(cè)試的接口請(qǐng)求頭帶上Content-Type和Authorization,Content-Type固定填入application/json,Authorization填入剛才登錄接口返回的token

      rbac項(xiàng)目源碼,開源,項(xiàng)目實(shí)例,Activiti,開源,spring boot,后端,vue,Activiti

    • 可在若依框架里系統(tǒng)管理-參數(shù)設(shè)置中關(guān)閉驗(yàn)證碼

      rbac項(xiàng)目源碼,開源,項(xiàng)目實(shí)例,Activiti,開源,spring boot,后端,vue,Activiti

7.2、拓展:
  • 預(yù)約單超時(shí)取消:采用若依自帶的定時(shí)任務(wù)功能。因是個(gè)人項(xiàng)目不需要考慮表數(shù)據(jù)量過大,設(shè)置的是每小時(shí)執(zhí)行一次定時(shí)任務(wù)。若定時(shí)任務(wù)需要遍歷的表數(shù)據(jù)量過大,則應(yīng)錯(cuò)峰執(zhí)行定時(shí)任務(wù),如每天凌晨執(zhí)行。

    /**
     * 定時(shí)任務(wù)調(diào)度測(cè)試
     *
     * @author ruoyi
     */
    @Component("appointmentTask")
    public class AppointmentTask {
        @Autowired
        private BusAppointmentMapper appointmentMapper;
    
        /**
         * 預(yù)約超時(shí)取消
         */
        public void AppointmentOvertime() {
            List<Integer> status = new ArrayList<>();
            status.add(BusAppointment.STATUS_APPOINTMENT);
    
            List<BusAppointment> list = appointmentMapper.selectByStatus(status, BusAppointment.IS_DEL);
    
            for (BusAppointment busAppointment : list) {
                Calendar calendar = Calendar.getInstance();
                calendar.setTime(busAppointment.getAppointmentTime());
                calendar.add(Calendar.HOUR_OF_DAY, 6);
                Date overTime = calendar.getTime();
    
                if (overTime.before(new Date())) {
                    appointmentMapper.updateStatus(busAppointment.getId(), BusAppointment.STATUS_OVERTIME);
    //                System.out.println(busAppointment.getCustomerName() + "已超時(shí)");
                }
            }
        }
    }
    

    前端定時(shí)任務(wù)頁面:

    rbac項(xiàng)目源碼,開源,項(xiàng)目實(shí)例,Activiti,開源,spring boot,后端,vue,Activiti

    拓拓展:Calendar類的入門使用

  • 結(jié)算單明細(xì)頁面,數(shù)據(jù)無論做任何修改后,在執(zhí)行保存前都不允許操作支付按鈕。給支付按鈕標(biāo)簽加:disabled=“canPay”,初始值為true,任何修改操作的方法里都將該值置為true,執(zhí)行保存方法后該值置為false。

  • 客戶管理-拜訪記錄-回訪顧客下拉框,首先在create生命周期里查詢獲取到bus_customer表里的全顧客列表customerList,然后將customerList放入el-select下的el-option作為v-for遍歷的數(shù)組,key和value為item.id,lable為item.name

    	 <el-form-item label="回訪客戶" prop="customerId">
            <el-select
              v-model="queryParams.customerId"
              placeholder="請(qǐng)選擇"
              clearable
            >
              <el-option
                v-for="item in customerList"
                :key="item.id"
                :label="item.customerName"
                :value="item.id"
              />
            </el-select>
          </el-form-item>
    
     created() {
        this.getUserList();
        this.getCustomerList();
      },
      
      methods: {
        getCustomerList() {
          listCustomer().then((response) => {
            this.customerList = response.rows;
            console.log(this.customerList);
          });
        },
      }
    
  • 增加了并行網(wǎng)關(guān)的工作流流程審核:

    • 先在IDEA19制定一張并行網(wǎng)關(guān)的bpmn
      rbac項(xiàng)目源碼,開源,項(xiàng)目實(shí)例,Activiti,開源,spring boot,后端,vue,Activiti

    • 要改動(dòng)的地方不多,前端加一個(gè)發(fā)起并行審核的按鈕

      •       <el-col :span="1.5">
                <el-button
                  type="success"
                  plain
                  icon="el-icon-edit"
                  size="mini"
                  :disabled="!canAudit"
                  @click="handleParallelAudit"
                  v-hasPermi="['business:serviceItem:edit']"
                  >發(fā)起并行審核</el-button
                >
              </el-col>
          	  <!-- 審核窗口復(fù)制一個(gè)之前的,只是多一欄下拉框供給并行的選擇第二個(gè)店長,然后綁定另一個(gè)值v-model="shopOwnerId2 -->
                <el-form-item
                  label="審核人(店長):"
                  prop="shopOwners"
                  v-if="isParallel"
                >
                  <el-select size="medium" v-model="shopOwnerId2">
                    <el-option
                      v-for="item in auditInfo.shopOwners"
                      :key="item.userId"
                      :label="item.nickName"
                      :value="item.userId"
                    >
                    </el-option>
                  </el-select>
                </el-form-item>
        
      • data() {
            shopOwnerId2: null,
            // 是否是并行審核
            isParallel: false,
        }
         
        methods:{
            /** 發(fā)起并行審核彈窗 */
            handleParallelAudit() {
              if (!this.canAudit) {
                return;
              }
              getAuditInfo(this.id).then((res) => {
                this.resetAudit();
                console.log(res);
                this.auditInfo = res.data;
                this.isParallel = true;
                this.auditOpen = true;
              });
            },
                
            /** 確認(rèn)發(fā)起審核 */
            auditSubmit() {
              let param = {
                id: this.id,
                shopOwnerId: this.shopOwnerId,
                shopOwnerId2: this.shopOwnerId2,
                financeId: this.financeId,
                info: this.info,
              };
              // 開始審核
              if (this.isParallel) {
                startParallelAudit(param).then((res) => {
                  this.getList();
                  this.$modal.msgSuccess("發(fā)起審核成功!");
                  this.isParallel = false;
                  this.auditOpen = false;
                })
                .catch(() => {});
              } else {
                startAudit(param).then((res) => {
                  this.getList();
                  this.$modal.msgSuccess("發(fā)起審核成功!");
                  this.isParallel = false;
                  this.auditOpen = false;
                });
              }
            },
        }
        
    • 后端新增一個(gè)接口接收并行工作流的審核提交,新建一個(gè)vo類,因?yàn)槎嗔藗€(gè)shopOwnerId2參數(shù)要接收。服務(wù)層也可以復(fù)制之前的再修改調(diào)整,改一下校驗(yàn)邏輯,注意在并行網(wǎng)關(guān)時(shí)雙店長審核有一個(gè)審核拒絕,另一個(gè)在activiti里并不會(huì)自動(dòng)刪除(結(jié)束流程)而是還在ru_task里,需要手動(dòng)結(jié)束其他并行流程,提供一個(gè)思路

      • else {
            		// else里寫審核拒絕邏輯
        	// 拿到當(dāng)前審核流程實(shí)例下的其他并行流程
                    List<Task> list = taskService.createTaskQuery()
                            .processInstanceId(audit.getInstanceId()).list();
                    if (list != null && list.size() > 0) {
                        for (Task otherTask : list) {
                            taskService.complete(otherTask.getId(), map);
                            taskService.addComment(otherTask.getId(), audit.getInstanceId().toString(), "其余審核人已拒絕");
                        }
                    }
                    serviceItemMapper.updateServiceItemStatus(audit.getServiceItemId(), BusServiceItem.AUDITSTATUS_REPLY);
                    audit.setStatus(CarPackageAudit.STATUS_REJECT);
                    carPackageAuditMapper.updateCarPackageAudit(audit);
                }
        
    • 一些可能不會(huì)報(bào)錯(cuò)的bug:流程走向有問題,先看看bpmn有沒有寫對(duì),使用文本編輯看看每個(gè)節(jié)點(diǎn)的參數(shù)和連接下個(gè)節(jié)點(diǎn)是否正確。然后看代碼,很可能是服務(wù)層寫錯(cuò)了,比如我遇到一個(gè)問題是兩個(gè)店長都審核完了,結(jié)果走財(cái)務(wù)審核時(shí)又跳到了一個(gè)店長角色審核,一看才發(fā)現(xiàn)是添加條件map時(shí)財(cái)務(wù)節(jié)點(diǎn)的value復(fù)制錯(cuò)了vo.getshowOnerId。


收工,后續(xù)有機(jī)會(huì)再迭代新功能。文章來源地址http://www.zghlxwxcb.cn/news/detail-842636.html

到了這里,關(guān)于一個(gè)開源的汽修r(nóng)bac后臺(tái)管理系統(tǒng)項(xiàng)目,基于若依框架,實(shí)現(xiàn)了activiti工作流,附源碼的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點(diǎn)僅代表作者本人,不代表本站立場(chǎng)。本站僅提供信息存儲(chǔ)空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請(qǐng)注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實(shí)不符,請(qǐng)點(diǎn)擊違法舉報(bào)進(jìn)行投訴反饋,一經(jīng)查實(shí),立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費(fèi)用

相關(guān)文章

  • 開源后臺(tái)管理系統(tǒng)Geekplus Admin

    開源后臺(tái)管理系統(tǒng)Geekplus Admin

    本系統(tǒng)采用前后端分離開發(fā)模式,后端采用springboot開發(fā)技術(shù)棧,mybatis持久層框架,redis緩存,shiro認(rèn)證授權(quán)框架,freemarker模版在線生成代碼,websocket消息推送等,后臺(tái)管理包含用戶管理,角色管理,菜單權(quán)限管理,部門組織管理,通知管理,日志管理,系統(tǒng)監(jiān)控,在線用戶,

    2024年02月12日
    瀏覽(27)
  • vue3開源后臺(tái)管理系統(tǒng)模板

    vue3開源后臺(tái)管理系統(tǒng)模板

    2022-08-28 推薦一些 Vue3 常用后臺(tái)管理系統(tǒng)模板。 Vue3 在今年2月份已成為新的默認(rèn)版本,本文收集了一些 Vue3 的后臺(tái)管理系統(tǒng)模板,分享給在座的仌 ??。 還是老規(guī)矩,按照 Github 星標(biāo)數(shù)量來依次介紹。 個(gè)人較推薦 vue-vben-admin、vue-pure-admin、naive-ui-admin、vue3-composition-admin、vue-

    2024年02月03日
    瀏覽(24)
  • 項(xiàng)目講解之火爆全網(wǎng)的開源后臺(tái)管理系統(tǒng)RuoYi

    項(xiàng)目講解之火爆全網(wǎng)的開源后臺(tái)管理系統(tǒng)RuoYi

    博主是在2018年中就接觸了 RuoYi 項(xiàng)目 這個(gè)項(xiàng)目,對(duì)于當(dāng)時(shí)國內(nèi)的開源后臺(tái)管理系統(tǒng)來說,RuoYi 算是一個(gè)完成度較高,易讀易懂、界面簡(jiǎn)潔美觀的前后端不分離項(xiàng)目。 對(duì)于當(dāng)時(shí)剛?cè)胄羞€在寫 jsp 模板的博主來說,RuoYi 項(xiàng)目在后臺(tái)基礎(chǔ)功能、模塊劃分、易用性和頁面美觀度上,對(duì)

    2024年02月02日
    瀏覽(41)
  • 免費(fèi)開源的vue+express搭建的后臺(tái)管理系統(tǒng)

    免費(fèi)開源的vue+express搭建的后臺(tái)管理系統(tǒng)

    此項(xiàng)目已開源 前端git地址:exp后臺(tái)管理系統(tǒng)前端: exp后臺(tái)管理系統(tǒng)前端 后端git地址:express后臺(tái)管理系統(tǒng): express后臺(tái)管理系統(tǒng) npm i yarn i 前端: npm run dev? |? yarn dev 后端: npm run start | yarn start 前端 后端 名稱 版本 名稱 版本 vue 2.6.11 node.js 16.13.0 vue-router 3.6.5 express 4.17.3 vuex 3.4.0

    2024年02月12日
    瀏覽(39)
  • 開源后臺(tái)管理系統(tǒng) (go-vue-admin)

    go-vue-admin 是一套基于go語言開源的后臺(tái)管理系統(tǒng)。功能參考諾依網(wǎng)站 ,前后端分離。 前端采用vue3、Element Plus 、RuoYi-Vue3 后端采用gofrome 框架、mysql、redis、Jwt 實(shí)現(xiàn)了一鍵生成前后端代碼,高效開發(fā)。 用戶管理:用戶是系統(tǒng)操作者,該功能主要完成系統(tǒng)用戶配置。 部門管理:

    2024年02月07日
    瀏覽(20)
  • 基于.NET6.0完全開源的MiniX后臺(tái)管理系統(tǒng),全端免費(fèi)開源

    介紹 基于.NET 6.0打造的成熟后臺(tái)管理系統(tǒng)框架,完全開源免費(fèi)免費(fèi),集成了LayUI,操作界面友好!已應(yīng)用到上百個(gè)項(xiàng)目,經(jīng)過多年的沉淀,開源給廣大用戶使用。 整套架構(gòu)包含后端\\\"miniAdmin\\\"+前端APP/小程序應(yīng)用“miniAPP”+PC端“miniPC”,全棧開源,永久免費(fèi)。 符合國家安全三級(jí)

    2024年02月11日
    瀏覽(29)
  • 開源項(xiàng)目 | 可二次開發(fā)的開源后臺(tái)、支持支付系統(tǒng)通用的支付、對(duì)賬、清算、賬戶管理、支付訂單管理等功能

    開源項(xiàng)目 | 可二次開發(fā)的開源后臺(tái)、支持支付系統(tǒng)通用的支付、對(duì)賬、清算、賬戶管理、支付訂單管理等功能

    在RuoYi項(xiàng)目基礎(chǔ)上改造,通過多模塊的方式整合其他經(jīng)常被用到的功能模塊,特別感謝RuoYi。基于SpringBoot2.0的開發(fā)的系統(tǒng) 易讀易懂、界面簡(jiǎn)潔美觀。具備支付系統(tǒng)通用的支付、對(duì)賬、清算、賬戶管理、支付訂單管理等功能;目前已接通微信支付渠道,應(yīng)用微信公眾號(hào)商城 在此

    2024年01月21日
    瀏覽(34)
  • 開源項(xiàng)目學(xué)習(xí):若依RuoYi-Vue后臺(tái)管理系統(tǒng)【環(huán)境搭建】

    開源項(xiàng)目學(xué)習(xí):若依RuoYi-Vue后臺(tái)管理系統(tǒng)【環(huán)境搭建】

    第一章 環(huán)境搭建 第二章 項(xiàng)目運(yùn)行 第三章 閱讀源碼:例子-新增用戶接口 第四章 基于ruoyi-vue開發(fā)新項(xiàng)目 本文盡量貼近零基礎(chǔ)入門,獻(xiàn)給初入門的學(xué)弟學(xué)妹們! 文章基本流程:環(huán)境配置→運(yùn)行項(xiàng)目→閱讀源碼 安裝環(huán)境時(shí)最好修改安裝路徑! Java開發(fā)必備! JDK下載:http://www

    2023年04月19日
    瀏覽(23)
  • React--》從零開始搭建一個(gè)文章后臺(tái)管理系統(tǒng)

    React--》從零開始搭建一個(gè)文章后臺(tái)管理系統(tǒng)

    目錄 項(xiàng)目準(zhǔn)備 項(xiàng)目搭建 scss預(yù)處理器的使用 配置基礎(chǔ)路由 組件庫antd的使用 開發(fā)者工具的安裝 登錄模塊 基本樣式搭建 創(chuàng)建表單結(jié)構(gòu) 獲取表單數(shù)據(jù)并進(jìn)行相關(guān)登錄操作 對(duì)登錄模塊的token進(jìn)行相關(guān)處理 路由鑒權(quán)實(shí)現(xiàn) 后臺(tái)頁面模塊 基本頁面結(jié)構(gòu)搭建 菜單高亮顯示 展示個(gè)人信

    2023年04月17日
    瀏覽(25)
  • 基于SpringBoot+VUE的寵物醫(yī)院后臺(tái)管理系統(tǒng)【源碼開源】【建議收藏】

    基于SpringBoot+VUE的寵物醫(yī)院后臺(tái)管理系統(tǒng)【源碼開源】【建議收藏】

    今天給大家開源一個(gè)基于SpringBoot+VUE的寵物醫(yī)院后臺(tái)管理系統(tǒng),系統(tǒng)基于腳手架工程,花了大概1周時(shí)間做出來的。 該系統(tǒng)完全開源。 系統(tǒng)完美運(yùn)行,無任何的bug,技術(shù)較多,可以當(dāng)做 面試的項(xiàng)目或者作為畢設(shè)的項(xiàng)目。 通過本項(xiàng)目你可以學(xué)到: 項(xiàng)目是怎樣前后端分離的 vue 是

    2024年02月07日
    瀏覽(23)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請(qǐng)作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包