BasicInfo.vue 9.2 KB

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