Commit fabdccd981c442823dad0a376dfda453ce8ccc8f
1 parent
62a86fdf
bpm:流程分配任务的列表 50%
Showing
4 changed files
with
378 additions
and
2 deletions
yudao-ui-admin-vue3/package.json
| @@ -52,6 +52,7 @@ | @@ -52,6 +52,7 @@ | ||
| 52 | "vue-i18n": "9.2.2", | 52 | "vue-i18n": "9.2.2", |
| 53 | "vue-router": "^4.1.6", | 53 | "vue-router": "^4.1.6", |
| 54 | "vue-types": "^5.0.2", | 54 | "vue-types": "^5.0.2", |
| 55 | + "vue3-treeselect": "^0.1.10", | ||
| 55 | "vxe-table": "^4.3.9", | 56 | "vxe-table": "^4.3.9", |
| 56 | "web-storage-cache": "^1.1.1", | 57 | "web-storage-cache": "^1.1.1", |
| 57 | "xe-utils": "^3.5.7" | 58 | "xe-utils": "^3.5.7" |
yudao-ui-admin-vue3/src/router/modules/remaining.ts
| @@ -177,6 +177,39 @@ const remainingRouter: AppRouteRecordRaw[] = [ | @@ -177,6 +177,39 @@ const remainingRouter: AppRouteRecordRaw[] = [ | ||
| 177 | title: '500', | 177 | title: '500', |
| 178 | noTagsView: true | 178 | noTagsView: true |
| 179 | } | 179 | } |
| 180 | + }, | ||
| 181 | + { | ||
| 182 | + path: '/bpm', | ||
| 183 | + component: Layout, | ||
| 184 | + name: 'bpm', | ||
| 185 | + meta: { | ||
| 186 | + hidden: true | ||
| 187 | + }, | ||
| 188 | + children: [ | ||
| 189 | + { | ||
| 190 | + path: '/manager/definition', | ||
| 191 | + component: () => import('@/views/bpm/definition/index.vue'), | ||
| 192 | + name: 'BpmProcessDefinitionList', | ||
| 193 | + meta: { | ||
| 194 | + noCache: true, | ||
| 195 | + hidden: true, | ||
| 196 | + canTo: true, | ||
| 197 | + title: '流程定义', | ||
| 198 | + activeMenu: 'bpm/definition/index' | ||
| 199 | + } | ||
| 200 | + }, | ||
| 201 | + { | ||
| 202 | + path: '/manager/task-assign-rule', | ||
| 203 | + component: () => import('@/views/bpm/taskAssignRule/index.vue'), | ||
| 204 | + name: 'BpmTaskAssignRuleList', | ||
| 205 | + meta: { | ||
| 206 | + noCache: true, | ||
| 207 | + hidden: true, | ||
| 208 | + canTo: true, | ||
| 209 | + title: '任务分配规则' | ||
| 210 | + } | ||
| 211 | + } | ||
| 212 | + ] | ||
| 180 | } | 213 | } |
| 181 | ] | 214 | ] |
| 182 | 215 |
yudao-ui-admin-vue3/src/views/bpm/taskAssignRule/index.vue
| 1 | <template> | 1 | <template> |
| 2 | - <div>index</div> | 2 | + <ContentWrap> |
| 3 | + <!-- 列表 --> | ||
| 4 | + <XTable @register="registerTable"> | ||
| 5 | + <template #options_default="{ row }"> | ||
| 6 | + <el-tag :key="option" v-for="option in row.options"> | ||
| 7 | + {{ getAssignRuleOptionName(row.type, option) }} | ||
| 8 | + </el-tag> | ||
| 9 | + </template> | ||
| 10 | + <!-- 操作 --> | ||
| 11 | + <template #actionbtns_default="{ row }" v-if="modelId"> | ||
| 12 | + <vxe-button | ||
| 13 | + type="text" | ||
| 14 | + status="primary" | ||
| 15 | + content="修改" | ||
| 16 | + icon="vxe-icon-edit" | ||
| 17 | + @click="handleUpdate(row)" | ||
| 18 | + /> | ||
| 19 | + </template> | ||
| 20 | + </XTable> | ||
| 21 | + | ||
| 22 | + <!-- 添加/修改弹窗 --> | ||
| 23 | + <XModal v-model="openVisible" title="修改任务规则" width="800" height="35%" resize> | ||
| 24 | + <el-form | ||
| 25 | + ref="xForm" | ||
| 26 | + :model="formData" | ||
| 27 | + :rules="formRules" | ||
| 28 | + label-width="120px" | ||
| 29 | + class="demo-ruleForm" | ||
| 30 | + size="default" | ||
| 31 | + status-icon | ||
| 32 | + > | ||
| 33 | + <el-form-item label="任务名称" prop="taskDefinitionName"> | ||
| 34 | + <el-input -model="formData.taskDefinitionName" placeholder="请输入流标标识" disabled /> | ||
| 35 | + </el-form-item> | ||
| 36 | + <el-form-item label="任务标识" prop="taskDefinitionKey"> | ||
| 37 | + <el-input v-model="formData.taskDefinitionKey" placeholder="请输入任务标识" disabled /> | ||
| 38 | + </el-form-item> | ||
| 39 | + <el-form-item label="规则类型" prop="type"> | ||
| 40 | + <el-select v-model="formData.type" clearable style="width: 100%"> | ||
| 41 | + <el-option | ||
| 42 | + v-for="dict in taskAssignRuleTypeDictDatas" | ||
| 43 | + :key="parseInt(dict.value)" | ||
| 44 | + :label="dict.label" | ||
| 45 | + :value="parseInt(dict.value)" | ||
| 46 | + /> | ||
| 47 | + </el-select> | ||
| 48 | + </el-form-item> | ||
| 49 | + <el-form-item v-if="formData.type === 10" label="指定角色" prop="roleIds"> | ||
| 50 | + <el-select v-model="formData.roleIds" multiple clearable style="width: 100%"> | ||
| 51 | + <el-option | ||
| 52 | + v-for="item in roleOptions" | ||
| 53 | + :key="parseInt(item.id)" | ||
| 54 | + :label="item.name" | ||
| 55 | + :value="parseInt(item.id)" | ||
| 56 | + /> | ||
| 57 | + </el-select> | ||
| 58 | + </el-form-item> | ||
| 59 | + <el-form-item | ||
| 60 | + label="指定部门" | ||
| 61 | + prop="deptIds" | ||
| 62 | + span="24" | ||
| 63 | + v-if="formData.type === 20 || formData.type === 21" | ||
| 64 | + > | ||
| 65 | + <treeselect | ||
| 66 | + v-model="formData.deptIds" | ||
| 67 | + :options="deptTreeOptions" | ||
| 68 | + multiple | ||
| 69 | + flat | ||
| 70 | + :defaultExpandLevel="3" | ||
| 71 | + placeholder="请选择指定部门" | ||
| 72 | + :normalizer="normalizer" | ||
| 73 | + /> | ||
| 74 | + </el-form-item> | ||
| 75 | + <el-form-item label="指定岗位" prop="postIds" span="24" v-if="formData.type === 22"> | ||
| 76 | + <el-select v-model="formData.postIds" multiple clearable style="width: 100%"> | ||
| 77 | + <el-option | ||
| 78 | + v-for="item in postOptions" | ||
| 79 | + :key="parseInt(item.id)" | ||
| 80 | + :label="item.name" | ||
| 81 | + :value="parseInt(item.id)" | ||
| 82 | + /> | ||
| 83 | + </el-select> | ||
| 84 | + </el-form-item> | ||
| 85 | + <el-form-item | ||
| 86 | + label="指定用户" | ||
| 87 | + prop="userIds" | ||
| 88 | + span="24" | ||
| 89 | + v-if="formData.type === 30 || formData.type === 31 || formData.type === 32" | ||
| 90 | + > | ||
| 91 | + <el-select v-model="formData.userIds" multiple clearable style="width: 100%"> | ||
| 92 | + <el-option | ||
| 93 | + v-for="item in userOptions" | ||
| 94 | + :key="parseInt(item.id)" | ||
| 95 | + :label="item.nickname" | ||
| 96 | + :value="parseInt(item.id)" | ||
| 97 | + /> | ||
| 98 | + </el-select> | ||
| 99 | + </el-form-item> | ||
| 100 | + <el-form-item label="指定用户组" prop="userGroupIds" v-if="formData.type === 40"> | ||
| 101 | + <el-select v-model="formData.userGroupIds" multiple clearable style="width: 100%"> | ||
| 102 | + <el-option | ||
| 103 | + v-for="item in userGroupOptions" | ||
| 104 | + :key="parseInt(item.id)" | ||
| 105 | + :label="item.name" | ||
| 106 | + :value="parseInt(item.id)" | ||
| 107 | + /> | ||
| 108 | + </el-select> | ||
| 109 | + </el-form-item> | ||
| 110 | + <el-form-item label="指定脚本" prop="scripts" v-if="formData.type === 50"> | ||
| 111 | + <el-select v-model="formData.scripts" multiple clearable style="width: 100%"> | ||
| 112 | + <el-option | ||
| 113 | + v-for="dict in taskAssignScriptDictDatas" | ||
| 114 | + :key="parseInt(dict.value)" | ||
| 115 | + :label="dict.label" | ||
| 116 | + :value="parseInt(dict.value)" | ||
| 117 | + /> | ||
| 118 | + </el-select> | ||
| 119 | + </el-form-item> | ||
| 120 | + </el-form> | ||
| 121 | + <template #footer> | ||
| 122 | + <XButton type="primary" title="保存" :loading="loading" @click="submitEvent(xForm)" /> | ||
| 123 | + <XButton title="关闭" @click="resetEvent(xForm)" /> | ||
| 124 | + </template> | ||
| 125 | + </XModal> | ||
| 126 | + </ContentWrap> | ||
| 3 | </template> | 127 | </template> |
| 4 | -<script setup lang="ts" name="TaskAssignRule"></script> | 128 | +<script setup lang="ts" name="TaskAssignRule"> |
| 129 | +// 全局相关的 import | ||
| 130 | +import { onMounted, reactive, ref } from 'vue' | ||
| 131 | +import { ElInput, ElTag, ElOption, ElSelect, ElForm, ElFormItem } from 'element-plus' | ||
| 132 | +import type { FormInstance } from 'element-plus' | ||
| 133 | + | ||
| 134 | +// 业务相关的 import | ||
| 135 | +import Treeselect from 'vue3-treeselect' | ||
| 136 | +import 'vue3-treeselect/dist/vue3-treeselect.css' | ||
| 137 | +import { useXTable } from '@/hooks/web/useXTable' | ||
| 138 | +import { allSchemas } from './taskAssignRule.data' | ||
| 139 | +import * as TaskAssignRuleApi from '@/api/bpm/taskAssignRule' | ||
| 140 | +import { listSimpleRolesApi } from '@/api/system/role' | ||
| 141 | +import { handleTree } from '@/utils/tree' | ||
| 142 | +import { listSimplePostsApi } from '@/api/system/post' | ||
| 143 | +import { getListSimpleUsersApi } from '@/api/system/user' | ||
| 144 | +import { listSimpleUserGroupsApi } from '@/api/bpm/userGroup' | ||
| 145 | +import { listSimpleDeptApi } from '@/api/system/dept' | ||
| 146 | +import { DICT_TYPE, getDictOptions } from '@/utils/dict' | ||
| 147 | +// import {useI18n} from "@/hooks/web/useI18n"; | ||
| 148 | +// import {useMessage} from "@/hooks/web/useMessage"; | ||
| 149 | +import { useRoute } from 'vue-router' | ||
| 150 | + | ||
| 151 | +// const { t } = useI18n() // 国际化 | ||
| 152 | +// const message = useMessage() // 消息弹窗 | ||
| 153 | +// const router = useRouter() // 路由 | ||
| 154 | +const { query } = useRoute() | ||
| 155 | + | ||
| 156 | +// ========== 列表相关 ========== | ||
| 157 | + | ||
| 158 | +// 流程模型的编号。如果 modelId 非空,则用于流程模型的查看与配置 | ||
| 159 | +const modelId = query.modelId | ||
| 160 | +// 流程定义的编号。如果 processDefinitionId 非空,则用于流程定义的查看,不支持配置 | ||
| 161 | +const processDefinitionId = query.processDefinitionId | ||
| 162 | +// 查询参数 | ||
| 163 | +const queryParams = reactive({ | ||
| 164 | + modelId: modelId, | ||
| 165 | + processDefinitionId: processDefinitionId | ||
| 166 | +}) | ||
| 167 | +const [registerTable] = useXTable({ | ||
| 168 | + allSchemas: allSchemas, | ||
| 169 | + params: queryParams, | ||
| 170 | + getListApi: TaskAssignRuleApi.getTaskAssignRuleList, | ||
| 171 | + isList: false // TODO 如果 isList 改成 true 时,进入页面不会加载数据 | ||
| 172 | +}) | ||
| 173 | +// 修改任务责任表单 | ||
| 174 | +const xForm = ref<FormInstance>() | ||
| 175 | +const formData = ref() | ||
| 176 | +const formRules = reactive({ | ||
| 177 | + type: [{ required: true, message: '规则类型不能为空', trigger: 'change' }], | ||
| 178 | + roleIds: [{ required: true, message: '指定角色不能为空', trigger: 'change' }], | ||
| 179 | + deptIds: [{ required: true, message: '指定部门不能为空', trigger: 'change' }], | ||
| 180 | + postIds: [{ required: true, message: '指定岗位不能为空', trigger: 'change' }], | ||
| 181 | + userIds: [{ required: true, message: '指定用户不能为空', trigger: 'change' }], | ||
| 182 | + userGroupIds: [{ required: true, message: '指定用户组不能为空', trigger: 'change' }], | ||
| 183 | + scripts: [{ required: true, message: '指定脚本不能为空', trigger: 'change' }] | ||
| 184 | +}) | ||
| 185 | +const loading = ref(false) | ||
| 186 | + | ||
| 187 | +const roleOptions = ref() // 角色列表 | ||
| 188 | +const deptOptions = ref() // 部门列表 | ||
| 189 | +const deptTreeOptions = ref() | ||
| 190 | +const postOptions = ref() // 岗位列表 | ||
| 191 | +const userOptions = ref() // 用户列表 | ||
| 192 | +const userGroupOptions = ref() // 用户组列表 | ||
| 193 | +const taskAssignScriptDictDatas = getDictOptions(DICT_TYPE.BPM_TASK_ASSIGN_SCRIPT) | ||
| 194 | +const taskAssignRuleTypeDictDatas = getDictOptions(DICT_TYPE.BPM_TASK_ASSIGN_RULE_TYPE) | ||
| 195 | + | ||
| 196 | +// 修改任务分配规则 | ||
| 197 | +const openVisible = ref(false) | ||
| 198 | + | ||
| 199 | +// 添加修改弹窗提交修改 | ||
| 200 | +const submitEvent = async (formEl: FormInstance | undefined) => { | ||
| 201 | + console.log('确认') | ||
| 202 | + if (!formEl) return | ||
| 203 | + loading.value = true | ||
| 204 | + await formEl.validate((valid, fields) => { | ||
| 205 | + if (valid) { | ||
| 206 | + console.log('submit!') | ||
| 207 | + loading.value = false | ||
| 208 | + openVisible.value = false | ||
| 209 | + } else { | ||
| 210 | + console.log('error submit!', fields) | ||
| 211 | + loading.value = false | ||
| 212 | + } | ||
| 213 | + }) | ||
| 214 | +} | ||
| 215 | + | ||
| 216 | +const resetEvent = (formEl: FormInstance | undefined) => { | ||
| 217 | + if (!formEl) return | ||
| 218 | + formEl.resetFields() | ||
| 219 | + openVisible.value = false | ||
| 220 | +} | ||
| 221 | + | ||
| 222 | +// 修改任务分配规则 | ||
| 223 | +const handleUpdate = (row) => { | ||
| 224 | + console.log(row, '修改i数据') | ||
| 225 | + openVisible.value = true | ||
| 226 | + formData.value = { ...row } | ||
| 227 | +} | ||
| 228 | +// 类型字典 | ||
| 229 | +const getAssignRuleOptionName = (type, option) => { | ||
| 230 | + if (type === 10) { | ||
| 231 | + for (const roleOption of roleOptions.value) { | ||
| 232 | + if (roleOption.id === option) { | ||
| 233 | + return roleOption.name | ||
| 234 | + } | ||
| 235 | + } | ||
| 236 | + } else if (type === 20 || type === 21) { | ||
| 237 | + for (const deptOption of deptOptions.value) { | ||
| 238 | + if (deptOption.id === option) { | ||
| 239 | + return deptOption.name | ||
| 240 | + } | ||
| 241 | + } | ||
| 242 | + } else if (type === 22) { | ||
| 243 | + for (const postOption of postOptions.value) { | ||
| 244 | + if (postOption.id === option) { | ||
| 245 | + return postOption.name | ||
| 246 | + } | ||
| 247 | + } | ||
| 248 | + } else if (type === 30 || type === 31 || type === 32) { | ||
| 249 | + for (const userOption of userOptions.value) { | ||
| 250 | + if (userOption.id === option) { | ||
| 251 | + return userOption.nickname | ||
| 252 | + } | ||
| 253 | + } | ||
| 254 | + } else if (type === 40) { | ||
| 255 | + for (const userGroupOption of userGroupOptions.value) { | ||
| 256 | + if (userGroupOption.id === option) { | ||
| 257 | + return userGroupOption.name | ||
| 258 | + } | ||
| 259 | + } | ||
| 260 | + } else if (type === 50) { | ||
| 261 | + option = option + '' // 转换成 string | ||
| 262 | + for (const dictData of taskAssignScriptDictDatas) { | ||
| 263 | + if (dictData.value === option) { | ||
| 264 | + return dictData.label | ||
| 265 | + } | ||
| 266 | + } | ||
| 267 | + } | ||
| 268 | + return '未知(' + option + ')' | ||
| 269 | +} | ||
| 270 | +// 格式化部门的下拉框 | ||
| 271 | +const normalizer = (node) => { | ||
| 272 | + return { | ||
| 273 | + id: node.id, | ||
| 274 | + label: node.name, | ||
| 275 | + children: node.children | ||
| 276 | + } | ||
| 277 | +} | ||
| 278 | + | ||
| 279 | +// ========== 初始化 ========== | ||
| 280 | +onMounted(() => { | ||
| 281 | + // 获得角色列表 | ||
| 282 | + roleOptions.value = [] | ||
| 283 | + listSimpleRolesApi().then((data) => { | ||
| 284 | + roleOptions.value.push(...data) | ||
| 285 | + }) | ||
| 286 | + // 获得部门列表 | ||
| 287 | + deptOptions.value = [] | ||
| 288 | + deptTreeOptions.value = [] | ||
| 289 | + listSimpleDeptApi().then((data) => { | ||
| 290 | + deptOptions.value.push(...data) | ||
| 291 | + deptTreeOptions.value.push(...handleTree(data, 'id')) | ||
| 292 | + }) | ||
| 293 | + // 获得岗位列表 | ||
| 294 | + postOptions.value = [] | ||
| 295 | + listSimplePostsApi().then((data) => { | ||
| 296 | + postOptions.value.push(...data) | ||
| 297 | + }) | ||
| 298 | + // 获得用户列表 | ||
| 299 | + userOptions.value = [] | ||
| 300 | + getListSimpleUsersApi().then((data) => { | ||
| 301 | + userOptions.value.push(...data) | ||
| 302 | + }) | ||
| 303 | + // 获得用户组列表 | ||
| 304 | + userGroupOptions.value = [] | ||
| 305 | + listSimpleUserGroupsApi().then((data) => { | ||
| 306 | + userGroupOptions.value.push(...data) | ||
| 307 | + }) | ||
| 308 | +}) | ||
| 309 | +</script> |
yudao-ui-admin-vue3/src/views/bpm/taskAssignRule/taskAssignRule.data.ts
0 → 100644
| 1 | +import { reactive } from 'vue' | ||
| 2 | +import { VxeCrudSchema, useVxeCrudSchemas } from '@/hooks/web/useVxeCrudSchemas' | ||
| 3 | +import { DICT_TYPE } from '@/utils/dict' | ||
| 4 | + | ||
| 5 | +// CrudSchema | ||
| 6 | +const crudSchemas = reactive<VxeCrudSchema>({ | ||
| 7 | + primaryKey: 'id', | ||
| 8 | + primaryType: null, | ||
| 9 | + action: true, | ||
| 10 | + actionWidth: '200px', | ||
| 11 | + columns: [ | ||
| 12 | + { | ||
| 13 | + title: '任务名', | ||
| 14 | + field: 'taskDefinitionName' | ||
| 15 | + }, | ||
| 16 | + { | ||
| 17 | + title: '任务标识', | ||
| 18 | + field: 'taskDefinitionKey' | ||
| 19 | + }, | ||
| 20 | + { | ||
| 21 | + title: '规则类型', | ||
| 22 | + field: 'category', | ||
| 23 | + dictType: DICT_TYPE.BPM_TASK_ASSIGN_RULE_TYPE, | ||
| 24 | + dictClass: 'number' | ||
| 25 | + }, | ||
| 26 | + { | ||
| 27 | + title: '规则范围', | ||
| 28 | + field: 'options', | ||
| 29 | + table: { | ||
| 30 | + slots: { | ||
| 31 | + default: 'options_default' | ||
| 32 | + } | ||
| 33 | + } | ||
| 34 | + } | ||
| 35 | + ] | ||
| 36 | +}) | ||
| 37 | +export const { allSchemas } = useVxeCrudSchemas(crudSchemas) |