sd-dep-picker.vue 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314
  1. <template>
  2. <span :class="$style.wapper">
  3. <sd-value-picker
  4. :render="renderList"
  5. :modal-props="{ class: $style.userpicker }"
  6. v-bind="$props"
  7. option-value="code"
  8. :single-column="false"
  9. @change="change"
  10. >
  11. <template v-slot="scope">
  12. <SdPickerUsersByGroup
  13. title="按部门"
  14. icon="apartment"
  15. v-bind="scope"
  16. :render="renderList"
  17. :root-node="rootNode"
  18. :hierarchical="hierarchical"
  19. :secret-level="secretLevel"
  20. />
  21. <SdPickerUsersByUsergroup
  22. ref="SdPickerUsersByUsergroup"
  23. title="个人群组"
  24. icon="user"
  25. v-bind="scope"
  26. :render="renderList"
  27. :secret-level="secretLevel"
  28. />
  29. <SdPickerUsersByDepgroup
  30. title="部门群组"
  31. icon="apartment"
  32. v-bind="scope"
  33. :render="renderList"
  34. :root-node="rootNode"
  35. :hierarchical="hierarchical"
  36. :secret-level="secretLevel"
  37. />
  38. <sd-picker-source-list
  39. v-if="webflow.flowData"
  40. title="流程参与人"
  41. icon="user"
  42. :load-list-data="() => participant()"
  43. v-bind="scope"
  44. :show-search="false"
  45. />
  46. </template>
  47. <template v-slot:targetListHeader="{ targetKeys, targetValues }">
  48. <a-button type="link" icon="save" title="保存群组" @click="userGroupClick(targetValues)" />
  49. </template>
  50. <a-icon v-if="!readOnly" slot="suffixIcon" type="user" />
  51. </sd-value-picker>
  52. <a-modal
  53. ok-text="保存"
  54. cancel-text="退出"
  55. :mask="true"
  56. destroy-tooltip-on-hide
  57. :visible="confirm.confirmvisible"
  58. @ok="saveconfirm"
  59. @cancel="cancelconfirm"
  60. >
  61. <a-form-model ref="ruleForm" :model="confirm.form" :rules="confirm.rules">
  62. <a-form-model-item ref="groupName" label="群组名称" prop="groupName">
  63. <a-input v-model="confirm.form.groupName" />
  64. </a-form-model-item>
  65. </a-form-model>
  66. </a-modal>
  67. </span>
  68. </template>
  69. <script>
  70. // eslint-disable-next-line filenames/match-regex
  71. import AddressBook from '@/addressbook/group-user-service'
  72. import PageService from '@/common/services/page-service'
  73. import axios from '@/common/services/axios-instance'
  74. import { Modal, Message } from 'ant-design-vue'
  75. import sdUserinfoCard from '@/common/components/sd-user-item/sd-userinfo-card'
  76. import { sdLocalStorage } from '@/common/services/storage-service'
  77. import pickerMixin from '@/common/components/sd-picker/picker-mixin'
  78. import SdPickerUsersByGroup from '@/common/components/sd-picker/sd-picker-users-by-group.vue'
  79. import components from '@/common/components/_import-components/sd-user-picker-import'
  80. import SdPickerUsersByUsergroup from '@/common/components/sd-picker/sd-picker-users-by-usergroup.vue'
  81. import SdPickerUsersByDepgroup from '@/common/components/sd-picker/sd-picker-users-by-depgroup.vue'
  82. let saveValues
  83. export default {
  84. name: 'SdDepPicker',
  85. components: {
  86. ...components,
  87. SdPickerUsersByGroup,SdPickerUsersByUsergroup,SdPickerUsersByDepgroup
  88. },
  89. mixins: [pickerMixin],
  90. metaInfo: {
  91. title: 'SdUsersPicker',
  92. },
  93. props: {
  94. rootNode: {
  95. type: [Object, Array],
  96. default: undefined,
  97. },
  98. /**
  99. * 当开启分级授权时,是否过滤掉启用分级授权的子公司,true时过滤,false时不过滤
  100. *
  101. */
  102. hierarchical: {
  103. type: Boolean,
  104. default: undefined,
  105. },
  106. /**
  107. * 密级,开启等分保功能后,可按密级过滤人员
  108. * @since 0.17
  109. */
  110. secretLevel: {
  111. type: String,
  112. default: '',
  113. },
  114. },
  115. data() {
  116. return {
  117. confirm: {
  118. confirmvisible: false,
  119. pageflowId: '',
  120. pagePath: '',
  121. groupData: [],
  122. form: {
  123. groupName: '',
  124. },
  125. rules: {
  126. groupName: [{ required: true, message: '请输入群组名称', trigger: ['change', 'blur'] }],
  127. },
  128. },
  129. }
  130. },
  131. inject: {
  132. webflow: { default: () => ({}) },
  133. },
  134. methods: {
  135. // 获取流程参与人
  136. participant() {
  137. const params = {}
  138. if (this.secretLevel) {
  139. params.securityLevel = this.secretLevel
  140. }
  141. return axios
  142. .get(
  143. `api/framework/v1/user-manager/instance/${this.webflow.FlowData?.instId || 0}/processors`,
  144. {
  145. params,
  146. }
  147. )
  148. .then((res) => {
  149. return (res.data || []).map((item) => {
  150. return {
  151. id: item.id,
  152. code: item.props.account,
  153. name: item.text,
  154. props: item.props,
  155. type: item.props?.type?.startsWith('G') ? 'Group' : 'User',
  156. }
  157. })
  158. })
  159. .catch(() => {
  160. Message.error('获取流程参与人失败')
  161. return []
  162. })
  163. },
  164. renderList(item) {
  165. return [
  166. <span class={this.$style.label}>{item.name}</span>,
  167. <sdUserinfoCard account={item.code} />,
  168. ]
  169. },
  170. // 打开保存个人组
  171. userGroupClick(targetValues) {
  172. if (targetValues.length < 1) {
  173. Message.warning('请选择人员')
  174. return
  175. }
  176. saveValues = targetValues
  177. this.confirm.form.groupName = ''
  178. PageService.get({}, 'personal/usergroup/personalUserGroup').then((res) => {
  179. if (res.status === 200) {
  180. this.confirm.groupData = res.data
  181. this.confirm.confirmvisible = true
  182. }
  183. })
  184. },
  185. // 关闭组
  186. cancelconfirm() {
  187. this.confirm.confirmvisible = false
  188. },
  189. // 保存个人组
  190. saveconfirm() {
  191. this.$refs.ruleForm.validate((valid) => {
  192. if (valid) {
  193. const groupName = this.confirm.form.groupName
  194. // 检查群组名是否存在
  195. AddressBook.checkExistGroupByName(groupName).then((res) => {
  196. if (res.data === true) {
  197. Message.warn('已存在群组名[' + groupName + '],请重新输入!')
  198. return false
  199. } else {
  200. const resJson = this.confirm.groupData
  201. resJson.pageFormData.pageFieldInfos.forEach((item) => {
  202. if (item.name === 'groupName') {
  203. item.value = this.confirm.form.groupName
  204. }
  205. if (item.name === 'members') {
  206. item.value = JSON.stringify(saveValues)
  207. }
  208. })
  209. const params = {
  210. eventId: 'save',
  211. inputs: resJson.pageFormData.pageFieldInfos.map((v) => ({
  212. name: v.name,
  213. value: v.value,
  214. })),
  215. pageFlowId: resJson.attrs.pageflowId,
  216. pagePath: resJson.attrs.pagePath,
  217. }
  218. PageService.save(params)
  219. .then((res) => {
  220. Message.success('保存成功')
  221. this.confirm.confirmvisible = false
  222. this.$refs.SdPickerUsersByUsergroup?.updateTree()
  223. })
  224. .catch((err) => {
  225. Modal.error({
  226. title: '保存失败',
  227. content: err.response?.data?.message?.split(':')[1] || '保存失败',
  228. })
  229. })
  230. }
  231. })
  232. } else {
  233. return false
  234. }
  235. })
  236. },
  237. change(users) {
  238. // 常用选择人
  239. let recentUser = JSON.parse(sdLocalStorage.getItem('deprecentUser') || '[]')
  240. users.forEach((item) => {
  241. if (!recentUser.find((user) => user.code === item.code)) {
  242. recentUser.unshift(item)
  243. }
  244. })
  245. recentUser = recentUser.slice(0, 100)
  246. sdLocalStorage.setItem('deprecentUser', JSON.stringify(recentUser))
  247. this.$emit(
  248. 'change',
  249. users?.map((item) => {
  250. return {
  251. name: item.name,
  252. code: item.code,
  253. type: item.type,
  254. }
  255. })
  256. )
  257. },
  258. },
  259. }
  260. </script>
  261. <style module lang="scss">
  262. @use '@/common/design' as *;
  263. .userpicker {
  264. :global(.ant-tabs-tabpane):nth-child(1) {
  265. margin-left: 270px;
  266. }
  267. :global(.ant-tabs-tabpane):nth-child(2) {
  268. margin-left: 270px;
  269. }
  270. :global(.ant-tabs-tabpane):nth-child(3) {
  271. margin-left: 270px;
  272. :global(.ant-transfer-list):first-child {
  273. top: 250px;
  274. height: 250px;
  275. }
  276. :global(.source-list-header_sd-value-picker_common) button {
  277. top: 250px;
  278. }
  279. }
  280. :global(.ant-transfer-list-body-customize-wrapper) {
  281. > div {
  282. height: 100%;
  283. }
  284. }
  285. div[mask='true'] {
  286. display: inline-block;
  287. }
  288. a {
  289. display: none;
  290. }
  291. :global(.ant-transfer-list-content-item:not(.ant-transfer-list-content-item-disabled):hover) {
  292. a {
  293. display: inline;
  294. }
  295. }
  296. :global(.ant-tabs-left-content) {
  297. height: 500px;
  298. }
  299. }
  300. .label {
  301. display: inline-block;
  302. width: calc(100% - 42px);
  303. min-width: 120px;
  304. overflow: hidden;
  305. text-overflow: ellipsis;
  306. vertical-align: top;
  307. }
  308. .wapper {
  309. width: 100%;
  310. }
  311. </style>