OrganizationEditPanel.vue 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688
  1. <template>
  2. <header>
  3. <h3 style="margin: 0px; padding: 5px 0px 9px 0px">
  4. {{ $t("lang.OrganizationEditPanel.departmentManagement") }}
  5. </h3>
  6. <a-divider style="margin: 0px" />
  7. </header>
  8. <div style="margin-top: 8px">
  9. <a-button type="primary" @click="editOrganization(true)">
  10. {{ $t("lang.OrganizationEditPanel.newDepartment") }}
  11. </a-button>
  12. <a-button type="dashed" style="margin-left: 8px" @click="refreshData">
  13. {{ $t("lang.OrganizationEditPanel.refresh") }}
  14. </a-button>
  15. <a-select
  16. v-model:value="clientIdStr"
  17. show-search
  18. option-filter-prop="label"
  19. style="width: 50%; margin-left: 16px"
  20. placeholder="请选择公司"
  21. :options="companies.map((item) => ({ value: item.id, label: item.name }))"
  22. @change="getClientId"
  23. />
  24. <a-button type="primary" style="margin-left: 8px" @click="editClient">
  25. 编辑公司
  26. </a-button>
  27. </div>
  28. <a-table
  29. style="margin-top: 6px"
  30. :columns="columns"
  31. :data-source="dataSource"
  32. :pagination="false"
  33. :scroll="{ y: 440 }"
  34. filter-search
  35. >
  36. <template #bodyCell="{ column, record }">
  37. <template v-if="column.dataIndex === 'operation'">
  38. <div class="editable-row-operations">
  39. <span>
  40. <a @click="editOrganization(false, record.key)">{{
  41. $t("lang.OrganizationEditPanel.edit")
  42. }}</a>
  43. </span>
  44. <span>
  45. <a-popconfirm
  46. title="确定删除吗!"
  47. ok-text="确定"
  48. cancel-text="取消"
  49. @confirm="deleteOrganization(record.key)"
  50. >
  51. <a style="color: red">删除</a>
  52. </a-popconfirm>
  53. </span>
  54. </div>
  55. </template>
  56. </template>
  57. </a-table>
  58. <a-drawer
  59. v-model:open="editVisible"
  60. :title="drawerTitle"
  61. :width="500"
  62. placement="right"
  63. >
  64. <div class="form-group">
  65. <label>{{ $t("lang.OrganizationEditPanel.corporateName") }}</label>
  66. <a-input v-model:value="organization.clientName" disabled />
  67. </div>
  68. <div class="form-group">
  69. <label>{{ $t("lang.OrganizationEditPanel.departmentNumber") }}</label>
  70. <a-input v-model:value="organization.no" />
  71. </div>
  72. <div class="form-group">
  73. <label>{{ $t("lang.OrganizationEditPanel.departmentName") }}</label>
  74. <a-input v-model:value="organization.name" />
  75. </div>
  76. <div class="form-group">
  77. <label>{{ $t("lang.OrganizationEditPanel.superiorDepartment") }}</label>
  78. <a-tree-select
  79. v-model:value="organization.parentId"
  80. show-search
  81. allow-clear
  82. style="width: 100%"
  83. :tree-data="organizations"
  84. tree-node-filter-prop="label"
  85. :dropdown-style="{ maxHeight: '300px', overflow: 'auto' }"
  86. @change="parentOrganizationValueChanged"
  87. />
  88. <!-- <SearchWidget
  89. info-window-no="20220420_233656"
  90. :field-value="parentOrganizationFieldValue"
  91. :title-name="$t('lang.OrganizationEditPanel.departmentInquiry')"
  92. display-name="name"
  93. :where-clause-source="parentOrganizationAdditionHql"
  94. @value-changed="parentOrganizationValueChanged"
  95. /> -->
  96. </div>
  97. <div class="form-group">
  98. <label>{{ $t("lang.OrganizationEditPanel.departmentProfile") }}</label>
  99. <textarea
  100. v-model="organization.description"
  101. class="form-control"
  102. rows="3"
  103. />
  104. </div>
  105. <div class="form-group">
  106. <label>{{ $t("lang.OrganizationEditPanel.departmentManager") }}</label>
  107. <div>
  108. <a-select
  109. v-model:value="organization.userIds"
  110. style="width: 100%"
  111. mode="multiple"
  112. :filter-option="false"
  113. :field-names="{ label: 'text', value: 'id' }"
  114. :not-found-content="fetching ? undefined : null"
  115. :options="userList"
  116. show-search
  117. @search="fetchUser"
  118. @change="getOrgUsers"
  119. >
  120. <template v-if="fetching" #notFoundContent>
  121. <a-spin size="small" />
  122. </template>
  123. </a-select>
  124. </div>
  125. </div>
  126. <template #footer>
  127. <a-button v-if="isCreate" type="primary" @click="createNew(organization)">
  128. 创建
  129. </a-button>
  130. <a-button
  131. v-else
  132. type="primary"
  133. @click="updateOrganization(organization.id)"
  134. >
  135. {{ $t("lang.OrganizationEditPanel.save") }}
  136. </a-button>
  137. <a-button
  138. v-if="!isCreate"
  139. danger
  140. style="margin-left: 8px"
  141. @click="hiddenDepartment(organization)"
  142. >
  143. 隐藏部门
  144. </a-button>
  145. </template>
  146. </a-drawer>
  147. <a-drawer
  148. v-model:open="isEditClient"
  149. title="编辑公司"
  150. :width="500"
  151. placement="right"
  152. >
  153. <div class="form-group">
  154. <label>公司ID</label>
  155. <a-input v-model:value="client.id" disabled />
  156. </div>
  157. <div class="form-group">
  158. <label>{{ $t("lang.OrganizationEditPanel.corporateName") }}</label>
  159. <a-input v-model:value="client.name" />
  160. </div>
  161. <div class="form-group">
  162. <label>{{ $t("lang.OrganizationEditPanel.companyNumber") }}</label>
  163. <a-input v-model:value="client.no" />
  164. </div>
  165. <div class="form-group">
  166. <label>公司简介</label>
  167. <textarea v-model="client.description" class="form-control" rows="3" />
  168. </div>
  169. <div class="form-group">
  170. <label>{{ $t("lang.OrganizationEditPanel.departmentManager") }}</label>
  171. <div>
  172. <a-select
  173. v-model:value="client.userIds"
  174. style="width: 100%"
  175. mode="multiple"
  176. :filter-option="false"
  177. :field-names="{ label: 'text', value: 'id' }"
  178. :not-found-content="fetching ? undefined : null"
  179. :options="userList"
  180. show-search
  181. @search="fetchUser"
  182. @change="getClientUsers"
  183. >
  184. <template v-if="fetching" #notFoundContent>
  185. <a-spin size="small" />
  186. </template>
  187. </a-select>
  188. </div>
  189. </div>
  190. <template #footer>
  191. <a-button type="primary" @click="updateClient(client.id)">
  192. {{ $t("lang.OrganizationEditPanel.save") }}
  193. </a-button>
  194. </template>
  195. </a-drawer>
  196. </template>
  197. <script setup>
  198. import Common from '../common/Common.js';
  199. import { Notify } from 'pc-component-v3';
  200. import { ref, onMounted, getCurrentInstance } from 'vue';
  201. import {
  202. columns,
  203. create,
  204. update,
  205. getCompony,
  206. getClientInfo,
  207. getUsersByName,
  208. updateClientInfo,
  209. loadOrganization,
  210. deleteDepartment,
  211. getAllOrganization,
  212. } from '../api/department/index';
  213. import { message } from 'ant-design-vue';
  214. import { TreeSelect } from 'ant-design-vue';
  215. const SHOW_PARENT = TreeSelect.SHOW_PARENT;
  216. const clientId = ref(''); //公司id
  217. const id = ref(''); //公司id
  218. const companies = ref([]); //所有公司
  219. const clientIdStr = ref(undefined);
  220. const userList = ref([]); // 用户清单
  221. const isCreate = ref(false); // 是否新建
  222. const isEditClient = ref(false); // 编辑公司
  223. const dataSource = ref([]); // 表格部门
  224. const drawerTitle = ref(''); //抽屉标题
  225. const organization = ref({}); // 部门详情
  226. const client = ref({}); // 公司详情
  227. const editVisible = ref(false); // 抽屉开关
  228. const organizationId = ref(''); // 所选部门ID
  229. const clientNameStr = ref('');
  230. const { proxy } = getCurrentInstance(); //访问this
  231. const superiorDepartment = ref('');
  232. const organizations = ref([]);
  233. const oldParentId = ref('');
  234. const oldParentName = ref('');
  235. const fetching = ref(false);
  236. onMounted(() => {
  237. getComponyInfo();
  238. });
  239. const fetchUser = Common.debounce(value => {
  240. userList.value = [];
  241. fetching.value = true;
  242. fetchUserList(value);
  243. }, 500);
  244. const getOrgUsers = (_, list) => {
  245. organization.value.managerUsers = list;
  246. };
  247. const getClientUsers = (_, list) => {
  248. client.value.managerUsers = list;
  249. };
  250. // 获取公司名称id
  251. const getComponyInfo = () => {
  252. companies.value = [];
  253. getCompony().then(
  254. success => {
  255. if (success.errorCode == 0) {
  256. if (success.datas && success.datas.length > 0) {
  257. getALLClient(success.datas);
  258. }
  259. } else {
  260. message.error(success.errorMessage);
  261. }
  262. },
  263. err => {
  264. Common.processException(err);
  265. },
  266. );
  267. };
  268. // 展示子公司数据
  269. const getALLClient = datas => {
  270. datas.forEach(item => {
  271. companies.value.push({ id: item.id, name: item.name });
  272. if (item.childrenClients && item.childrenClients.length > 0) {
  273. getALLClient(item.childrenClients);
  274. }
  275. });
  276. };
  277. // 编辑公司(获取公司信息)
  278. const editClient = () => {
  279. if (clientNameStr.value) {
  280. isEditClient.value = true;
  281. getClientInfo(clientId.value).then(
  282. success => {
  283. if (success.errorCode == 0) {
  284. fetchUserList();
  285. client.value = success.data;
  286. client.value.userIds = [];
  287. success.data.managerUsers.forEach(user => {
  288. client.value.userIds.push(user.id);
  289. });
  290. } else {
  291. message.error(success.errorMessage);
  292. }
  293. },
  294. error => {
  295. Common.processException(error);
  296. },
  297. );
  298. } else {
  299. message.warning('请选择公司');
  300. }
  301. };
  302. // 更新公司信息
  303. const updateClient = () => {
  304. const clientValue = JSON.parse(JSON.stringify(client.value));
  305. const { id, name, no } = clientValue;
  306. if (!id || !name || !no) {
  307. return;
  308. }
  309. updateClientInfo(clientValue).then(
  310. success => {
  311. isEditClient.value = false;
  312. if (success.errorCode == 0) {
  313. getComponyInfo();
  314. client.value = {};
  315. message.success(proxy.$t('lang.OrganizationEditPanel.describe6'));
  316. } else {
  317. message.error(success.errorMessage);
  318. }
  319. },
  320. err => {
  321. Common.processException(err);
  322. },
  323. );
  324. };
  325. // 获取所选公司id 名字
  326. const getClientId = (value, client) => {
  327. id.value = value;
  328. clientId.value = value;
  329. clientNameStr.value = client.label;
  330. getOrganization();
  331. };
  332. // 新建部门
  333. const createOrganization = () => {
  334. organization.value = {};
  335. organization.value.clientName = clientNameStr.value;
  336. organization.value.parentId = null;
  337. organization.value.parentName = null;
  338. };
  339. // 隐藏部门
  340. const hiddenDepartment = info => {
  341. $.ajax({
  342. url: Common.getApiURL('organizationResource/concealOrganization'),
  343. type: 'post',
  344. beforeSend: function (request) {
  345. Common.addTokenToRequest(request);
  346. },
  347. data: JSON.stringify(info),
  348. contentType: 'application/json; charset=utf-8',
  349. processData: false,
  350. success: function (data) {
  351. editVisible.value = false;
  352. message.success(`${info.name}隐藏成功。`);
  353. refreshData();
  354. },
  355. error: function (XMLHttpRequest, textStatus, errorThrown) {
  356. Common.processException(XMLHttpRequest, textStatus, errorThrown);
  357. },
  358. });
  359. };
  360. // 创建按钮
  361. const createNew = organization => {
  362. organization.clientId = id.value;
  363. create(organization).then(
  364. success => {
  365. if (success.errorCode == 0) {
  366. message.success('新建部门成功');
  367. getOrganization();
  368. editVisible.value = false;
  369. } else {
  370. message.error(success.errorMessage);
  371. }
  372. },
  373. err => {
  374. Common.processException(err);
  375. },
  376. );
  377. };
  378. //刷新数据
  379. const refreshData = () => {
  380. getComponyInfo();
  381. getOrganization();
  382. };
  383. // 获取所有部门
  384. const getOrganization = () => {
  385. dataSource.value = [];
  386. const datas = [];
  387. const id = clientId.value;
  388. getAllOrganization(id).then(
  389. success => {
  390. if (success.errorCode == 0) {
  391. success.datas.forEach(item => {
  392. datas.push(item.childrenOrganizations);
  393. });
  394. traversalTree(datas.flat(1), dataSource.value);
  395. clientOrganizations(dataSource.value);
  396. }
  397. // loadAllSubClients();
  398. },
  399. err => {
  400. Common.processException(err);
  401. },
  402. );
  403. };
  404. // 处理上级部门数据
  405. const clientOrganizations = datas => {
  406. datas.forEach(item => {
  407. item.value = item.id;
  408. item.label = item.name;
  409. if (item.children && item.children.length > 0) {
  410. clientOrganizations(item.children);
  411. }
  412. });
  413. organizations.value = datas;
  414. };
  415. // 编辑部门(获取部门信息)
  416. const editOrganization = (flag, id) => {
  417. organizationId.value = id;
  418. if (flag) {
  419. if (clientNameStr.value !== '') {
  420. editVisible.value = true;
  421. drawerTitle.value = '新建部门';
  422. createOrganization();
  423. fetchUserList();
  424. isCreate.value = true;
  425. } else {
  426. message.warning('请选择公司');
  427. }
  428. } else {
  429. editVisible.value = true;
  430. drawerTitle.value = '编辑部门';
  431. loadOrganization(id).then(
  432. success => {
  433. organization.value = success.data;
  434. organization.value.userIds = [];
  435. if (success.errorCode == 0) {
  436. success.data.managerUsers.forEach(user => {
  437. organization.value.userIds.push(user.id);
  438. });
  439. oldParentName.value = success.data.parentName;
  440. oldParentId.value = success.data.parentId;
  441. fetchUserList();
  442. } else {
  443. message.error(success.errorMessage);
  444. }
  445. },
  446. err => {
  447. Common.processException(err);
  448. },
  449. (isCreate.value = false),
  450. );
  451. }
  452. };
  453. //保存事件
  454. const updateOrganization = () => {
  455. const organizationValue = JSON.parse(JSON.stringify(organization.value));
  456. const { clientId, name, no } = organizationValue;
  457. if (!clientId || !name || !no) {
  458. Notify.error(
  459. proxy.$t('lang.Notify.error'),
  460. proxy.$t('lang.OrganizationEditPanel.describe5'),
  461. true,
  462. );
  463. return;
  464. }
  465. update(organizationValue).then(
  466. success => {
  467. if (success.errorCode == 0) {
  468. if (success.data) {
  469. message.success(proxy.$t('lang.OrganizationEditPanel.describe6'));
  470. organization.value = {};
  471. getOrganization();
  472. }
  473. } else {
  474. message.error(success.errorMessage);
  475. }
  476. editVisible.value = false;
  477. },
  478. err => {
  479. Common.processException(err);
  480. },
  481. );
  482. };
  483. // 删除部门
  484. const deleteOrganization = id => {
  485. loadOrganization(id).then(
  486. success => {
  487. const organization = success.data;
  488. if (organization == undefined) {
  489. Notify.error(
  490. proxy.$t('lang.Notify.error'),
  491. proxy.$t('lang.OrganizationEditPanel.describe4'),
  492. true,
  493. );
  494. return;
  495. }
  496. const params = {
  497. id: organization.id,
  498. no: organization.no,
  499. name: organization.name,
  500. };
  501. deleteDepartment(params).then(
  502. success => {
  503. if (success.errorCode == 0) {
  504. message.success(proxy.$t('lang.OrganizationEditPanel.describe3'));
  505. organization.value = undefined;
  506. getOrganization();
  507. } else {
  508. message.error(success.errorMessage);
  509. }
  510. },
  511. err => {
  512. Common.processException(err);
  513. },
  514. );
  515. },
  516. err => {
  517. Common.processException(err);
  518. },
  519. );
  520. };
  521. // 部门管理员输入的过滤条件发生改变
  522. const fetchUserList = value => {
  523. const params = {
  524. range: {
  525. start: 0,
  526. length: 1000,
  527. },
  528. conditional: value,
  529. };
  530. getUsersByName(params).then(
  531. successData => {
  532. if (successData && successData.resultList) {
  533. successData.resultList.forEach(function (user) {
  534. if (user.no) {
  535. user.text = user.name + '(' + user.no + ')';
  536. if (user.organizations && user.organizations.length > 0) {
  537. user.organizations.forEach(item => {
  538. user.text = user.text + '(' + item.organizationName + ')';
  539. });
  540. }
  541. } else {
  542. user.text = user.name;
  543. }
  544. });
  545. userList.value = successData.resultList;
  546. } else {
  547. userList.value = [];
  548. }
  549. fetching.value = false;
  550. },
  551. errorData => {
  552. fetching.value = false;
  553. Common.processException(errorData);
  554. },
  555. );
  556. // if (loading != null) {
  557. // loading(true);
  558. // }
  559. // let searchQueryParam = {
  560. // conditional: search,
  561. // range: {
  562. // start: 0,
  563. // length: 100,
  564. // },
  565. // };
  566. // getUsersByName(searchQueryParam).then(
  567. // (successData) => {
  568. // if (loading != null) {
  569. // loading(false);
  570. // }
  571. // userList.value = successData.resultList;
  572. // },
  573. // (errorData) => {
  574. // if (loading != null) {
  575. // loading(false);
  576. // }
  577. // Common.processException(errorData);
  578. // }
  579. // );
  580. };
  581. // 上级部门change事件
  582. const parentOrganizationValueChanged = (value, label) => {
  583. if (!value && label.length == 0) {
  584. organization.value.parentId = null;
  585. organization.value.parentName = null;
  586. return;
  587. }
  588. if (organizationId.value == value) {
  589. message.warning('不能将自己作为上级部门!');
  590. organization.value.parentId = oldParentId.value;
  591. organization.value.parentName = oldParentName.value;
  592. } else {
  593. organization.value.parentId = value;
  594. organization.value.parentName = label[0];
  595. }
  596. };
  597. // 递归将childrenOrganizations赋值给children
  598. const traversalTree = (array, target) => {
  599. array.map((item, index) => {
  600. target.push({
  601. id: item.id,
  602. no: item.no,
  603. key: item.id,
  604. children: [],
  605. type: item.type,
  606. name: item.name,
  607. description: item.description,
  608. });
  609. if (
  610. item.childrenOrganizations !== null &&
  611. item.childrenOrganizations.length !== 0
  612. ) {
  613. traversalTree(item.childrenOrganizations, target[index].children);
  614. } else {
  615. delete target[index].children;
  616. }
  617. });
  618. };
  619. // 获取所有子部门
  620. /**
  621. const loadAllSubClients = () => {
  622. var rootClientId = null;
  623. for (let i = 0; i < dataSource.value.length; i++) {
  624. var clientOrganization = dataSource.value[i];
  625. if (clientOrganization.children == null) {
  626. rootClientId = clientOrganization.key;
  627. }
  628. }
  629. loadSubClients(rootClientId).then(
  630. success => {
  631. if (success.errorCode == 0) {
  632. if (success.datas) {
  633. clientAdditionHql.value = ' ct.id in (' + success.join(',') + ')';
  634. } else {
  635. clientAdditionHql.value = {
  636. customerDataDimensions: [
  637. {
  638. fieldName: 'ct.id',
  639. dataDimensionTypeNo: '202201191757',
  640. defaultDataDimensionTypeValueNo: '1',
  641. },
  642. ],
  643. };
  644. parentOrganizationAdditionHql.value = {
  645. customerDataDimensions: [
  646. {
  647. fieldName: 'organization.id',
  648. dataDimensionTypeNo: '202201191700',
  649. defaultDataDimensionTypeValueNo: '1',
  650. },
  651. ],
  652. };
  653. }
  654. } else {
  655. message.error(success.errorMessage);
  656. }
  657. },
  658. err => {
  659. Common.processException(err);
  660. },
  661. );
  662. };*/
  663. </script>
  664. <style scoped>
  665. .editable-row-operations a {
  666. margin-right: 8px;
  667. }
  668. </style>