BasicInfo.vue 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301
  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="流程图标" prop="icon" 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"
  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-option label="均不可提交" :value="2" />
  81. </el-select>
  82. <div v-if="modelData.startUserType === 1" class="mt-2 flex flex-wrap gap-2">
  83. <div
  84. v-for="user in selectedStartUsers"
  85. :key="user.id"
  86. class="bg-gray-100 h-35px rounded-3xl flex items-center pr-8px dark:color-gray-600 position-relative"
  87. >
  88. <el-avatar class="!m-5px" :size="28" v-if="user.avatar" :src="user.avatar" />
  89. <el-avatar class="!m-5px" :size="28" v-else>
  90. {{ user.nickname.substring(0, 1) }}
  91. </el-avatar>
  92. {{ user.nickname }}
  93. <Icon
  94. icon="ep:close"
  95. class="ml-2 cursor-pointer hover:text-red-500"
  96. @click="handleRemoveStartUser(user)"
  97. />
  98. </div>
  99. <el-button type="primary" link @click="openStartUserSelect">
  100. <Icon icon="ep:plus" />选择人员
  101. </el-button>
  102. </div>
  103. </el-form-item>
  104. <el-form-item label="流程管理员" prop="managerUserType" class="mb-20px">
  105. <el-select
  106. v-model="modelData.managerUserType"
  107. placeholder="请选择流程管理员"
  108. @change="handleManagerUserTypeChange"
  109. >
  110. <el-option label="全员" :value="0" />
  111. <el-option label="指定人员" :value="1" />
  112. <el-option label="均不可提交" :value="2" />
  113. </el-select>
  114. <div v-if="modelData.managerUserType === 1" class="mt-2 flex flex-wrap gap-2">
  115. <div
  116. v-for="user in selectedManagerUsers"
  117. :key="user.id"
  118. class="bg-gray-100 h-35px rounded-3xl flex items-center pr-8px dark:color-gray-600 position-relative"
  119. >
  120. <el-avatar class="!m-5px" :size="28" v-if="user.avatar" :src="user.avatar" />
  121. <el-avatar class="!m-5px" :size="28" v-else>
  122. {{ user.nickname.substring(0, 1) }}
  123. </el-avatar>
  124. {{ user.nickname }}
  125. <Icon
  126. icon="ep:close"
  127. class="ml-2 cursor-pointer hover:text-red-500"
  128. @click="handleRemoveManagerUser(user)"
  129. />
  130. </div>
  131. <el-button type="primary" link @click="openManagerUserSelect">
  132. <Icon icon="ep:plus" />选择人员
  133. </el-button>
  134. </div>
  135. </el-form-item>
  136. </el-form>
  137. <!-- 用户选择弹窗 -->
  138. <UserSelectForm ref="userSelectFormRef" @confirm="handleUserSelectConfirm" />
  139. </template>
  140. <script lang="ts" setup>
  141. import { DICT_TYPE, getBoolDictOptions, getIntDictOptions } from '@/utils/dict'
  142. import { UserVO } from '@/api/system/user'
  143. const props = defineProps({
  144. modelValue: {
  145. type: Object,
  146. required: true
  147. },
  148. categoryList: {
  149. type: Array,
  150. required: true
  151. },
  152. userList: {
  153. type: Array,
  154. required: true
  155. }
  156. })
  157. const emit = defineEmits(['update:modelValue'])
  158. const formRef = ref()
  159. const selectedStartUsers = ref<UserVO[]>([])
  160. const selectedManagerUsers = ref<UserVO[]>([])
  161. const userSelectFormRef = ref()
  162. const currentSelectType = ref<'start' | 'manager'>('start')
  163. const rules = {
  164. name: [{ required: true, message: '流程名称不能为空', trigger: 'blur' }],
  165. key: [{ required: true, message: '流程标识不能为空', trigger: 'blur' }],
  166. category: [{ required: true, message: '流程分类不能为空', trigger: 'blur' }],
  167. icon: [{ required: true, message: '流程图标不能为空', trigger: 'blur' }],
  168. type: [{ required: true, message: '是否可见不能为空', trigger: 'blur' }],
  169. visible: [{ required: true, message: '是否可见不能为空', trigger: 'blur' }],
  170. managerUserIds: [{ required: true, message: '流程管理员不能为空', trigger: 'blur' }]
  171. }
  172. // 创建本地数据副本
  173. const modelData = computed({
  174. get: () => props.modelValue,
  175. set: (val) => emit('update:modelValue', val)
  176. })
  177. // 初始化选中的用户
  178. watch(
  179. () => props.modelValue,
  180. (newVal) => {
  181. if (newVal.startUserIds?.length) {
  182. selectedStartUsers.value = props.userList.filter((user: UserVO) =>
  183. newVal.startUserIds.includes(user.id)
  184. ) as UserVO[]
  185. }
  186. if (newVal.managerUserIds?.length) {
  187. selectedManagerUsers.value = props.userList.filter((user: UserVO) =>
  188. newVal.managerUserIds.includes(user.id)
  189. ) as UserVO[]
  190. }
  191. },
  192. { immediate: true }
  193. )
  194. /** 打开发起人选择 */
  195. const openStartUserSelect = () => {
  196. currentSelectType.value = 'start'
  197. userSelectFormRef.value.open(0, selectedStartUsers.value)
  198. }
  199. /** 打开管理员选择 */
  200. const openManagerUserSelect = () => {
  201. currentSelectType.value = 'manager'
  202. userSelectFormRef.value.open(0, selectedManagerUsers.value)
  203. }
  204. /** 处理用户选择确认 */
  205. const handleUserSelectConfirm = (_, users: UserVO[]) => {
  206. if (currentSelectType.value === 'start') {
  207. selectedStartUsers.value = users
  208. emit('update:modelValue', {
  209. ...modelData.value,
  210. startUserIds: users.map((u) => u.id)
  211. })
  212. } else {
  213. selectedManagerUsers.value = users
  214. emit('update:modelValue', {
  215. ...modelData.value,
  216. managerUserIds: users.map((u) => u.id)
  217. })
  218. }
  219. }
  220. /** 处理发起人类型变化 */
  221. const handleStartUserTypeChange = (value: number) => {
  222. if (value !== 1) {
  223. selectedStartUsers.value = []
  224. emit('update:modelValue', {
  225. ...modelData.value,
  226. startUserIds: []
  227. })
  228. }
  229. }
  230. /** 处理管理员类型变化 */
  231. const handleManagerUserTypeChange = (value: number) => {
  232. if (value !== 1) {
  233. selectedManagerUsers.value = []
  234. emit('update:modelValue', {
  235. ...modelData.value,
  236. managerUserIds: []
  237. })
  238. }
  239. }
  240. /** 移除发起人 */
  241. const handleRemoveStartUser = (user: UserVO) => {
  242. selectedStartUsers.value = selectedStartUsers.value.filter((u) => u.id !== user.id)
  243. emit('update:modelValue', {
  244. ...modelData.value,
  245. startUserIds: modelData.value.startUserIds.filter((id: number) => id !== user.id)
  246. })
  247. }
  248. /** 移除管理员 */
  249. const handleRemoveManagerUser = (user: UserVO) => {
  250. selectedManagerUsers.value = selectedManagerUsers.value.filter((u) => u.id !== user.id)
  251. emit('update:modelValue', {
  252. ...modelData.value,
  253. managerUserIds: modelData.value.managerUserIds.filter((id: number) => id !== user.id)
  254. })
  255. }
  256. /** 表单校验 */
  257. const validate = async () => {
  258. await formRef.value?.validate()
  259. }
  260. defineExpose({
  261. validate
  262. })
  263. </script>
  264. <style lang="scss" scoped>
  265. .bg-gray-100 {
  266. background-color: #f5f7fa;
  267. transition: all 0.3s;
  268. &:hover {
  269. background-color: #e6e8eb;
  270. }
  271. .ep-close {
  272. font-size: 14px;
  273. color: #909399;
  274. transition: color 0.3s;
  275. &:hover {
  276. color: #f56c6c;
  277. }
  278. }
  279. }
  280. </style>