Browse Source

流程配置模块

master
xueyinfei 2 months ago
parent
commit
e65399d373
  1. 20
      vue-fastapi-backend/module_admin/controller/approval_controller.py
  2. 27
      vue-fastapi-backend/module_admin/dao/approval_dao.py
  3. 14
      vue-fastapi-backend/module_admin/entity/do/approval_do.py
  4. 21
      vue-fastapi-backend/module_admin/entity/vo/approval_vo.py
  5. 17
      vue-fastapi-backend/module_admin/service/approval_service.py
  6. 40
      vue-fastapi-backend/module_admin/service/user_service.py
  7. 24
      vue-fastapi-frontend/src/api/flow/flow.js
  8. 87
      vue-fastapi-frontend/src/views/system/flow/conf.vue
  9. 2
      vue-fastapi-frontend/src/views/system/flow/index.vue

20
vue-fastapi-backend/module_admin/controller/approval_controller.py

@ -5,7 +5,7 @@ from fastapi import APIRouter, Depends, Request, UploadFile, File, Form
from sqlalchemy.ext.asyncio import AsyncSession
from config.get_db import get_db
from module_admin.entity.vo.user_vo import CurrentUserModel
from module_admin.entity.vo.approval_vo import ApplyModel, OperateModel, ApprovalQueryObject
from module_admin.entity.vo.approval_vo import ApplyModel, OperateModel, ApprovalQueryObject, SaveConfModel
from module_admin.service.login_service import LoginService
from module_admin.service.approval_service import ApprovalService
from utils.log_util import logger
@ -55,3 +55,21 @@ async def cancel_apply(request: Request,
current_user: CurrentUserModel = Depends(LoginService.get_current_user)):
operate_result = await ApprovalService.cancel_apply_services(query_db, flow_id, current_user)
return ResponseUtil.success(msg=operate_result.message)
@approvalController.get("/conf/list")
async def get_conf_list(request: Request,
module: str,
query_db: AsyncSession = Depends(get_db),
current_user: CurrentUserModel = Depends(LoginService.get_current_user)):
meta_query_result = await ApprovalService.get_conf_list_services(module, query_db, current_user)
return ResponseUtil.success(data=meta_query_result)
@approvalController.post("/conf/save")
async def save_flow_config(
saveConfModel: SaveConfModel,
query_db: AsyncSession = Depends(get_db),
):
operate_result = await ApprovalService.save_flow_config_services(query_db, saveConfModel)
return ResponseUtil.success(msg=operate_result.message)

27
vue-fastapi-backend/module_admin/dao/approval_dao.py

@ -1,6 +1,6 @@
from sqlalchemy import desc, delete, func, select, update
from sqlalchemy.ext.asyncio import AsyncSession
from module_admin.entity.do.approval_do import FlowApproval
from module_admin.entity.do.approval_do import FlowApproval, FlowConfig
from module_admin.entity.vo.approval_vo import ApprovalQueryObject
from module_admin.entity.vo.user_vo import CurrentUserModel
from sqlalchemy import select, text, cast, Integer, and_, or_, outerjoin, func, join
@ -76,3 +76,28 @@ class ApprovalDao:
.first()
)
return result
@classmethod
async def get_conf_list(cls, db: AsyncSession, module: str):
result = (
(
await db.execute(select(FlowConfig).where(
FlowConfig.module == module
))
).scalars().all()
)
return result
@classmethod
async def add_flow_config(cls, db: AsyncSession, conf: dict):
db_conf = FlowConfig(**conf)
db.add(db_conf)
await db.flush()
return conf
@classmethod
async def delete_flow_by_module(cls, module: str, db: AsyncSession):
await db.execute(delete(FlowConfig).where(FlowConfig.module == module))

14
vue-fastapi-backend/module_admin/entity/do/approval_do.py

@ -18,3 +18,17 @@ class FlowApproval(Base):
nextStep = Column(Integer, default=None, comment="下一步编号")
status = Column(String(10), default=None, comment='状态')
approvalFlow = Column(Text, default=None, comment='审批流') # [{审批人:‘’,审批时间:‘’,'审批结果':‘’,审批意见:''},{}]数组
class FlowConfig(Base):
__tablename__ = 'flow_config'
id = Column(String(50), primary_key=True, comment='id')
code = Column(String(50), default='', comment='节点代码')
text = Column(String(255), default='', comment='节点名称')
type = Column(String(50), default=None, comment='节点类型,Role/User')
module = Column(String(50), default=None, comment='所属模块')
step = Column(Integer, default=None, comment='步骤')
x = Column(Integer, default=None, comment='节点位置x')
y = Column(Integer, default=None, comment='节点位置y')
parent = Column(Text, default=None, comment="父节点")

21
vue-fastapi-backend/module_admin/entity/vo/approval_vo.py

@ -32,3 +32,24 @@ class EditObjectModel(BaseModel):
approver: Optional[str] = None
nextStep: Optional[int] = None
approvalFlow: Optional[str] = None
class FlowConfModel(BaseModel):
id: Optional[str]
code: Optional[str]
text: Optional[str]
type: Optional[str]
module: Optional[str]
step: Optional[int]
x: Optional[int]
y: Optional[int]
parent: Optional[str]
class SaveConfModel(BaseModel):
module: Optional[str]
confList: Optional[List[Union[FlowConfModel, None]]]

17
vue-fastapi-backend/module_admin/service/approval_service.py

@ -4,7 +4,7 @@ import uuid
from typing import Optional
from sqlalchemy.ext.asyncio import AsyncSession
from module_admin.entity.vo.common_vo import CrudResponseModel
from module_admin.entity.vo.approval_vo import ApplyModel, OperateModel, ApprovalQueryObject, EditObjectModel
from module_admin.entity.vo.approval_vo import ApplyModel, OperateModel, ApprovalQueryObject, EditObjectModel, SaveConfModel
from module_admin.entity.vo.user_vo import CurrentUserModel
from module_admin.entity.do.approval_do import FlowApproval
from exceptions.exception import ServiceException, ServiceWarning
@ -119,3 +119,18 @@ class ApprovalService:
flow.status = 'canceled'
await ApprovalDao.edit_flow_approval(query_db, flow)
return CrudResponseModel(is_success=True, message='操作成功')
@classmethod
async def get_conf_list_services(cls, module: str, query_db: AsyncSession, current_user: CurrentUserModel):
result = await ApprovalDao.get_conf_list(query_db, module)
return result
@classmethod
async def save_flow_config_services(cls, query_db: AsyncSession, saveConfModel: SaveConfModel):
await ApprovalDao.delete_flow_by_module(saveConfModel.module, query_db)
for item in saveConfModel.confList:
confDict = item.model_dump(exclude_unset=True)
await ApprovalDao.add_flow_config(query_db, confDict)
await query_db.commit()
return CrudResponseModel(is_success=True, message='操作成功')

40
vue-fastapi-backend/module_admin/service/user_service.py

@ -212,11 +212,14 @@ class UserService:
:return: 编辑用户校验结果
"""
edit_user = page_object.model_dump(exclude_unset=True, exclude={'admin'})
requestDs = True
if page_object.type != 'status' and page_object.type != 'avatar' and page_object.type != 'pwd':
del edit_user['role_ids']
del edit_user['post_ids']
del edit_user['role']
if page_object.type == 'status' or page_object.type == 'avatar' or page_object.type == 'pwd':
if page_object.type == 'status' or page_object.type == 'avatar':
requestDs = False
del edit_user['type']
user_info = await cls.user_detail_services(query_db, edit_user.get('user_id'))
if user_info.data and user_info.data.user_id:
@ -228,24 +231,25 @@ class UserService:
elif page_object.email and not await cls.check_email_unique_services(query_db, page_object):
raise ServiceException(message=f'修改用户{page_object.user_name}失败,邮箱账号已存在')
try:
payload = {
'id': -1,
'userName': user_info.data.user_name,
'userPassword': page_object.password if page_object.password else '',
'email': page_object.email if page_object.email else '',
'phone': page_object.phonenumber if page_object.phonenumber else '',
'tenantId': -1,
'state': 1 if (page_object.status is None or page_object.status == '0') else 0
}
headers = {'dashUserName': currentUserName, 'dashPassword': currentPassword}
response_post = requests.post(url=AppConfig.ds_server_url+'/dolphinscheduler/users/update',
params=payload,
headers=headers, verify=False)
if response_post.status_code != 200:
if response_post.status_code != 201:
raise Exception("服务异常,请确保各节点是否在线")
if not response_post.json().get('success'):
raise Exception(response_post.json().get('msg'))
if requestDs:
payload = {
'id': -1,
'userName': user_info.data.user_name,
'userPassword': page_object.password if page_object.password else '',
'email': page_object.email if page_object.email else '',
'phone': page_object.phonenumber if page_object.phonenumber else '',
'tenantId': -1,
'state': 1 if (page_object.status is None or page_object.status == '0') else 0
}
headers = {'dashUserName': currentUserName, 'dashPassword': currentPassword}
response_post = requests.post(url=AppConfig.ds_server_url+'/dolphinscheduler/users/update',
params=payload,
headers=headers, verify=False)
if response_post.status_code != 200:
if response_post.status_code != 201:
raise Exception("服务异常,请确保各节点是否在线")
if not response_post.json().get('success'):
raise Exception(response_post.json().get('msg'))
await UserDao.edit_user_dao(query_db, edit_user)
if page_object.type != 'status' and page_object.type != 'avatar' and page_object.type != 'pwd':
await UserDao.delete_user_role_dao(query_db, UserRoleModel(userId=page_object.user_id))

24
vue-fastapi-frontend/src/api/flow/flow.js

@ -9,14 +9,6 @@ export function getApprovalList(data) {
})
}
export function getflowList(data) {
return request({
url: '/default-api/approval/list',
method: 'get',
params: {module:data}
})
}
export function getWaitingFlowCount() {
return request({
url: '/default-api/approval/waitingTotal',
@ -30,4 +22,20 @@ export function operateProcess(data) {
method: 'post',
data: data
})
}
export function getFlowConfList(data) {
return request({
url: '/default-api/approval/conf/list',
method: 'get',
params: {module:data}
})
}
export function saveFlowConfig(data){
return request({
url: '/default-api/approval/conf/save',
method: 'post',
data: data
})
}

87
vue-fastapi-frontend/src/views/system/flow/conf.vue

@ -8,14 +8,9 @@
<i class="ri-save-3-line"></i> 保存
</el-button>
</div>
<div style="text-align: center;margin-top: 10px;" >
<el-button class="moduleButton" style="width: 50%;height: 100px;" :style="{background: checked ==='元数据'?'#ebf5ff':'none'}" @click="changeBackGround('元数据信息')">
元数据信息模块
</el-button>
</div>
<div style="text-align: center;margin-top: 10px">
<el-button class="moduleButton" style="width: 50%;height: 100px" :style="{background: checked ==='其他模块'?'#ebf5ff':'none'}" @click="changeBackGround('其他模块')">
其他模块----敬请期待
<div v-for="item in moduleList" style="text-align: center;margin-top: 10px;" >
<el-button class="moduleButton" style="width: 50%;height: 100px;" :style="{background: checked === item.module ?'#ebf5ff':'none'}" @click="changeBackGround(item.module)">
{{ item.text }}
</el-button>
</div>
</el-col>
@ -64,13 +59,14 @@ import { Selection } from '@antv/x6-plugin-selection'
import { Clipboard } from '@antv/x6-plugin-clipboard'
import { ref, nextTick, computed, watch, reactive, onMounted } from 'vue'
import { listRole } from "@/api/system/role";
import {getflowList } from "@/api/flow/flow";
import {getFlowConfList,saveFlowConfig } from "@/api/flow/flow";
const { proxy } = getCurrentInstance();
const moduleList = ref([{'module':'metaDataInfo','text':'元数据'},{'module':'other','text':'其他模块(敬请期待)'}])
let graph = null
const roleList = ref([])
const data = ref([])
const checked = ref('元数据')
const checked = ref('metaDataInfo')
const ports = ref({
groups: {
top: {
@ -230,7 +226,7 @@ function register(){
inherit: 'edge',
attrs: {
line: {
stroke: '#A2B1C3',
stroke: '#C71E1EFF',
strokeWidth: 2,
},
},
@ -239,14 +235,19 @@ function register(){
)
}
function changeBackGround(module){
if (module === '元数据信息'){
checked.value = '元数据'
}
if (module === '其他模块'){
checked.value = '其他模块'
}
getflowList(checked.value).then(res=>{
checked.value = module
searchFlowData()
}
function searchFlowData(){
getFlowConfList(checked.value).then(res=>{
let resData = res.data
if (resData.length > 0){
for (let i = 0; i < resData.length; i++) {
resData[i].parent = JSON.parse(resData[i].parent)
}
}
data.value = resData
loadGraphData()
})
}
function showAddDialog(){
@ -258,7 +259,6 @@ function showAddDialog(){
function save(){
let json = graph.toJSON()
let array = json.cells;
console.log(array)
let flows = []
if (array.length>0){
for (let i = 0; i < array.length; i++) {
@ -268,6 +268,7 @@ function save(){
id: cell.id,
code: cell.code,
text: cell.attrs.text.text,
module: checked.value,
type: cell.type,
x: cell.position.x,
y: cell.position.y,
@ -292,7 +293,36 @@ function save(){
}
}
}
console.log(flows)
if (flows.length>0){
for (let i = 0; i < flows.length; i++) {
flows[i].step = getNodeStep(flows[i],flows)
}
for (let i = 0; i < flows.length; i++) {
flows[i].parent = JSON.stringify(flows[i].parent)
}
let saveData = {
module: checked.value,
confList: flows
}
saveFlowConfig(saveData).then(res=>{
proxy.$modal.msgSuccess("操作成功");
})
}
}
function getNodeStep(node,array){
if(node.parent.length === 0){
return 1;
}else {
let step = 0;
node.parent.forEach(parentId=>{
let parentNode = array.find(item => item.id === parentId)
let parentStep = getNodeStep(parentNode,array)
if (step < (parentStep +1)){
step = parentStep + 1;
}
})
return step
}
}
function loadGraphData(){
let array = []
@ -302,6 +332,7 @@ function loadGraphData(){
code: item.code,
attrs: {text:{text: item.text}},
position:{x:item.x,y:item.y},
type: item.type,
width: 100,
height: 60,
shape: "activity"
@ -333,16 +364,8 @@ onMounted(re=>{
grid:true,
autoResize: true,
connecting: {
router: 'orth',
router: 'manhattan'
},
createEdge() {
return new Shape.Edge({
"id": uuid(),
"shape": "bpmn-edge",
"source": "7",
"target": "13"
});
}
})
graph.use(new Keyboard())
.use(
@ -375,7 +398,7 @@ onMounted(re=>{
const ports = container.querySelectorAll('.x6-port-body',)
showPorts(ports, false)
})
loadGraphData()
searchFlowData()
})
</script>

2
vue-fastapi-frontend/src/views/system/flow/index.vue

@ -74,7 +74,7 @@
</template>
<script setup>
import {getApprovalList, operateProcess } from "@/api/flow/flow.js"
import {getApprovalList, operateProcess } from "@/api/flow/flow"
const { proxy } = getCurrentInstance();
import { ref, nextTick, computed, watch, reactive, onMounted } from 'vue'
import {getWaitingFlowCount} from "../../../api/flow/flow.js";

Loading…
Cancel
Save