BasicInfo.vue 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272
  1. <template>
  2. <el-form ref="formRef" :model="modelData" :rules="rules" label-width="120px" class="mt-20px">
  3. <el-form-item label="流程标识" prop="key" class="mb-20px">
  4. <div class="flex items-center">
  5. <el-input
  6. class="!w-440px"
  7. v-model="modelData.key"
  8. :disabled="!!modelData.id"
  9. placeholder="请输入流标标识"
  10. />
  11. <el-tooltip
  12. class="item"
  13. :content="modelData.id ? '流程标识不可修改!' : '新建后,流程标识不可修改!'"
  14. effect="light"
  15. placement="top"
  16. >
  17. <Icon icon="ep:question-filled" class="ml-5px" />
  18. </el-tooltip>
  19. </div>
  20. </el-form-item>
  21. <el-form-item label="流程名称" prop="name" class="mb-20px">
  22. <el-input
  23. v-model="modelData.name"
  24. :disabled="!!modelData.id"
  25. clearable
  26. placeholder="请输入流程名称"
  27. />
  28. </el-form-item>
  29. <el-form-item label="流程分类" prop="category" class="mb-20px">
  30. <el-select
  31. class="!w-full"
  32. v-model="modelData.category"
  33. clearable
  34. placeholder="请选择流程分类"
  35. >
  36. <el-option
  37. v-for="category in categoryList"
  38. :key="category.code"
  39. :label="category.name"
  40. :value="category.code"
  41. />
  42. </el-select>
  43. </el-form-item>
  44. <el-form-item label="流程图标" class="mb-20px">
  45. <UploadImg v-model="modelData.icon" :limit="1" height="64px" width="64px" />
  46. </el-form-item>
  47. <el-form-item label="流程描述" prop="description" class="mb-20px">
  48. <el-input v-model="modelData.description" clearable type="textarea" />
  49. </el-form-item>
  50. <el-form-item label="流程类型" prop="type" class="mb-20px">
  51. <el-radio-group v-model="modelData.type">
  52. <el-radio
  53. v-for="dict in getIntDictOptions(DICT_TYPE.BPM_MODEL_TYPE)"
  54. :key="dict.value"
  55. :value="dict.value"
  56. >
  57. {{ dict.label }}
  58. </el-radio>
  59. </el-radio-group>
  60. </el-form-item>
  61. <el-form-item label="是否可见" prop="visible" class="mb-20px">
  62. <el-radio-group v-model="modelData.visible">
  63. <el-radio
  64. v-for="dict in getBoolDictOptions(DICT_TYPE.INFRA_BOOLEAN_STRING)"
  65. :key="dict.value as string"
  66. :value="dict.value"
  67. >
  68. {{ dict.label }}
  69. </el-radio>
  70. </el-radio-group>
  71. </el-form-item>
  72. <el-form-item label="谁可以发起" prop="startUserType" class="mb-20px">
  73. <el-select
  74. v-model="modelData.startUserType"
  75. placeholder="请选择谁可以发起"
  76. @change="handleStartUserTypeChange"
  77. >
  78. <el-option label="全员" :value="0" />
  79. <el-option label="指定人员" :value="1" />
  80. </el-select>
  81. <div v-if="modelData.startUserType === 1" class="mt-2 flex flex-wrap gap-2">
  82. <div
  83. v-for="user in selectedStartUsers"
  84. :key="user.id"
  85. class="bg-gray-100 h-35px rounded-3xl flex items-center pr-8px dark:color-gray-600 position-relative"
  86. >
  87. <el-avatar class="!m-5px" :size="28" v-if="user.avatar" :src="user.avatar" />
  88. <el-avatar class="!m-5px" :size="28" v-else>
  89. {{ user.nickname.substring(0, 1) }}
  90. </el-avatar>
  91. {{ user.nickname }}
  92. <Icon
  93. icon="ep:close"
  94. class="ml-2 cursor-pointer hover:text-red-500"
  95. @click="handleRemoveStartUser(user)"
  96. />
  97. </div>
  98. <el-button type="primary" link @click="openStartUserSelect">
  99. <Icon icon="ep:plus" /> 选择人员
  100. </el-button>
  101. </div>
  102. </el-form-item>
  103. <el-form-item label="流程管理员" prop="managerUserIds" class="mb-20px">
  104. <div class="flex flex-wrap gap-2">
  105. <div
  106. v-for="user in selectedManagerUsers"
  107. :key="user.id"
  108. class="bg-gray-100 h-35px rounded-3xl flex items-center pr-8px dark:color-gray-600 position-relative"
  109. >
  110. <el-avatar class="!m-5px" :size="28" v-if="user.avatar" :src="user.avatar" />
  111. <el-avatar class="!m-5px" :size="28" v-else>
  112. {{ user.nickname.substring(0, 1) }}
  113. </el-avatar>
  114. {{ user.nickname }}
  115. <Icon
  116. icon="ep:close"
  117. class="ml-2 cursor-pointer hover:text-red-500"
  118. @click="handleRemoveManagerUser(user)"
  119. />
  120. </div>
  121. <el-button type="primary" link @click="openManagerUserSelect">
  122. <Icon icon="ep:plus" />选择人员
  123. </el-button>
  124. </div>
  125. </el-form-item>
  126. </el-form>
  127. <!-- 用户选择弹窗 -->
  128. <UserSelectForm ref="userSelectFormRef" @confirm="handleUserSelectConfirm" />
  129. </template>
  130. <script lang="ts" setup>
  131. import { DICT_TYPE, getBoolDictOptions, getIntDictOptions } from '@/utils/dict'
  132. import { UserVO } from '@/api/system/user'
  133. import { CategoryVO } from '@/api/bpm/category'
  134. const props = defineProps({
  135. categoryList: {
  136. type: Array as PropType<CategoryVO[]>,
  137. required: true
  138. },
  139. userList: {
  140. type: Array,
  141. required: true
  142. }
  143. })
  144. const formRef = ref()
  145. const selectedStartUsers = ref<UserVO[]>([])
  146. const selectedManagerUsers = ref<UserVO[]>([])
  147. const userSelectFormRef = ref()
  148. const currentSelectType = ref<'start' | 'manager'>('start')
  149. const rules = {
  150. name: [{ required: true, message: '流程名称不能为空', trigger: 'blur' }],
  151. key: [{ required: true, message: '流程标识不能为空', trigger: 'blur' }],
  152. category: [{ required: true, message: '流程分类不能为空', trigger: 'blur' }],
  153. type: [{ required: true, message: '是否可见不能为空', trigger: 'blur' }],
  154. visible: [{ required: true, message: '是否可见不能为空', trigger: 'blur' }],
  155. managerUserIds: [{ required: true, message: '流程管理员不能为空', trigger: 'blur' }]
  156. }
  157. // 创建本地数据副本
  158. const modelData = defineModel<any>()
  159. // 初始化选中的用户
  160. watch(
  161. () => modelData.value,
  162. (newVal) => {
  163. if (newVal.startUserIds?.length) {
  164. selectedStartUsers.value = props.userList.filter((user: UserVO) =>
  165. newVal.startUserIds.includes(user.id)
  166. ) as UserVO[]
  167. } else {
  168. selectedStartUsers.value = []
  169. }
  170. if (newVal.managerUserIds?.length) {
  171. selectedManagerUsers.value = props.userList.filter((user: UserVO) =>
  172. newVal.managerUserIds.includes(user.id)
  173. ) as UserVO[]
  174. } else {
  175. selectedManagerUsers.value = []
  176. }
  177. },
  178. {
  179. immediate: true
  180. }
  181. )
  182. /** 打开发起人选择 */
  183. const openStartUserSelect = () => {
  184. currentSelectType.value = 'start'
  185. userSelectFormRef.value.open(0, selectedStartUsers.value)
  186. }
  187. /** 打开管理员选择 */
  188. const openManagerUserSelect = () => {
  189. currentSelectType.value = 'manager'
  190. userSelectFormRef.value.open(0, selectedManagerUsers.value)
  191. }
  192. /** 处理用户选择确认 */
  193. const handleUserSelectConfirm = (_, users: UserVO[]) => {
  194. if (currentSelectType.value === 'start') {
  195. modelData.value = {
  196. ...modelData.value,
  197. startUserIds: users.map((u) => u.id)
  198. }
  199. } else {
  200. modelData.value = {
  201. ...modelData.value,
  202. managerUserIds: users.map((u) => u.id)
  203. }
  204. }
  205. }
  206. /** 处理发起人类型变化 */
  207. const handleStartUserTypeChange = (value: number) => {
  208. if (value !== 1) {
  209. modelData.value = {
  210. ...modelData.value,
  211. startUserIds: []
  212. }
  213. }
  214. }
  215. /** 移除发起人 */
  216. const handleRemoveStartUser = (user: UserVO) => {
  217. modelData.value = {
  218. ...modelData.value,
  219. startUserIds: modelData.value.startUserIds.filter((id: number) => id !== user.id)
  220. }
  221. }
  222. /** 移除管理员 */
  223. const handleRemoveManagerUser = (user: UserVO) => {
  224. modelData.value = {
  225. ...modelData.value,
  226. managerUserIds: modelData.value.managerUserIds.filter((id: number) => id !== user.id)
  227. }
  228. }
  229. /** 表单校验 */
  230. const validate = async () => {
  231. await formRef.value?.validate()
  232. }
  233. defineExpose({
  234. validate
  235. })
  236. </script>
  237. <style lang="scss" scoped>
  238. .bg-gray-100 {
  239. background-color: #f5f7fa;
  240. transition: all 0.3s;
  241. &:hover {
  242. background-color: #e6e8eb;
  243. }
  244. .ep-close {
  245. font-size: 14px;
  246. color: #909399;
  247. transition: color 0.3s;
  248. &:hover {
  249. color: #f56c6c;
  250. }
  251. }
  252. }
  253. </style>