NewTabButton.vue 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580
  1. <template>
  2. <div class="button_list">
  3. <div v-if="leftTabButton.length === 0" />
  4. <a-breadcrumb v-if="leftTabButton && leftTabButton.length" separator="|">
  5. <a-breadcrumb-item v-for="(item, index) in leftTabButton" :key="index">
  6. <a-button
  7. v-if="item.action === 'CREATE'"
  8. :icon="h(PlusSquareTwoTone)"
  9. @click="create"
  10. >
  11. {{ item.name }}
  12. </a-button>
  13. <a-button v-else-if="item.action === 'EDIT'" :icon="h(EditTwoTone)">
  14. {{ item.name }}
  15. </a-button>
  16. <a-button
  17. v-else-if="item.action === 'DELETE'"
  18. :icon="h(DeleteTwoTone)"
  19. @click="deleteData"
  20. >
  21. {{ item.name }}
  22. </a-button>
  23. <a-button
  24. v-else-if="item.action === 'RUN_PROCESS_REPORT'"
  25. :icon="h(ControlTwoTone)"
  26. >
  27. {{ item.name }}
  28. </a-button>
  29. <a-button
  30. v-else-if="item.action === 'OPEN_CUSTOMER_WINDOW'"
  31. :icon="h(BookTwoTone)"
  32. >
  33. {{ item.name }}
  34. </a-button>
  35. <a-button
  36. v-else-if="item.action === 'OPEN_HTML_WINDOW'"
  37. :icon="h(ContainerTwoTone)"
  38. >
  39. {{ item.name }}
  40. </a-button>
  41. <a-button
  42. v-else-if="item.action === 'EXPORT'"
  43. :icon="h(FileTextTwoTone)"
  44. @click="exportConfirm"
  45. >
  46. {{ item.name }}
  47. </a-button>
  48. <a-button
  49. v-else-if="item.action === 'REFRESH'"
  50. :icon="h(ReloadOutlined)"
  51. @click="refresh"
  52. >
  53. {{ item.name }}
  54. </a-button>
  55. <a-button v-else-if="item.action === 'NOTICE'" :icon="h(BellTwoTone)">
  56. {{ item.name }}
  57. </a-button>
  58. <a-button
  59. v-else-if="item.action === 'OPEN_REMOTE_COMPONENT_MODULE_IN_MODAL'"
  60. :icon="h(HddOutlined)"
  61. @click="openRemoteComponentModule(item)"
  62. >
  63. {{ item.name }}
  64. </a-button>
  65. <a-button v-else :icon="h(LayoutTwoTone)">{{ item.name }}</a-button>
  66. </a-breadcrumb-item>
  67. <!-- <a-breadcrumb-item>
  68. <GridColumnDef
  69. :window-no="windowNo"
  70. :tab-index="tabIndex"
  71. :tab-grid-fields="tabGridFields"
  72. @property-changed="propertyChanged($event)"
  73. />
  74. </a-breadcrumb-item> -->
  75. </a-breadcrumb>
  76. <a-breadcrumb separator="|">
  77. <a-breadcrumb-item v-for="(item, index) in rightTabButton" :key="index">
  78. <a-button
  79. v-if="item.action === 'CREATE'"
  80. :icon="h(PlusSquareTwoTone)"
  81. @click="create"
  82. >
  83. {{ item.name }}
  84. </a-button>
  85. <a-button v-else-if="item.action === 'EDIT'" :icon="h(EditTwoTone)">
  86. {{ item.name }}
  87. </a-button>
  88. <a-button
  89. v-else-if="item.action === 'DELETE'"
  90. :icon="h(DeleteTwoTone)"
  91. @click="deleteData"
  92. >
  93. {{ item.name }}
  94. </a-button>
  95. <a-button
  96. v-else-if="item.action === 'RUN_PROCESS_REPORT'"
  97. :icon="h(ControlTwoTone)"
  98. >
  99. {{ item.name }}
  100. </a-button>
  101. <a-button
  102. v-else-if="item.action === 'OPEN_CUSTOMER_WINDOW'"
  103. :icon="h(BookTwoTone)"
  104. >
  105. {{ item.name }}
  106. </a-button>
  107. <a-button
  108. v-else-if="item.action === 'OPEN_HTML_WINDOW'"
  109. :icon="h(ContainerTwoTone)"
  110. >
  111. {{ item.name }}
  112. </a-button>
  113. <a-button
  114. v-else-if="item.action === 'EXPORT'"
  115. :icon="h(FileTextTwoTone)"
  116. @click="exportConfirm"
  117. >
  118. {{ item.name }}
  119. </a-button>
  120. <a-button
  121. v-else-if="item.action === 'REFRESH'"
  122. :icon="h(ReloadOutlined)"
  123. @click="refresh"
  124. >
  125. {{ item.name }}
  126. </a-button>
  127. <a-button v-else-if="item.action === 'NOTICE'" :icon="h(BellTwoTone)">
  128. {{ item.name }}
  129. </a-button>
  130. <a-button
  131. v-else-if="item.action === 'OPEN_REMOTE_COMPONENT_MODULE_IN_MODAL'"
  132. :icon="h(HddOutlined)"
  133. @click="openRemoteComponentModule(item)"
  134. >
  135. {{ item.name }}
  136. </a-button>
  137. <a-button v-else :icon="h(LayoutTwoTone)">{{ item.name }}</a-button>
  138. </a-breadcrumb-item>
  139. </a-breadcrumb>
  140. </div>
  141. <Modal
  142. v-model:show="notificationModal"
  143. :show-canel-button="false"
  144. :show-ok-button="false"
  145. >
  146. <template #header>
  147. {{ $t("lang.tabButton.sendNotice") }}
  148. </template>
  149. <NotificationPanel ref="notificationPanel" />
  150. <template #footer>
  151. <button type="button" class="btn btn-default" @click="sendNotification">
  152. {{ $t("lang.tabButton.send") }}
  153. </button>
  154. <button type="button" class="btn btn-default" @click="cancelNotification">
  155. {{ $t("lang.tabButton.cancel") }}
  156. </button>
  157. </template>
  158. </Modal>
  159. <!-- <a-modal v-model:open="modal1Open"> -->
  160. <component :is="modal1Component" v-model:open="modal1Open" />
  161. <!-- </a-modal> -->
  162. </template>
  163. <script setup>
  164. import {
  165. ref,
  166. defineProps,
  167. defineEmits,
  168. watch,
  169. getCurrentInstance,
  170. defineAsyncComponent,
  171. h,
  172. } from 'vue';
  173. import Common from '../../common/Common';
  174. import DownloadService from '../../resource/file/DownloadService.js';
  175. import NotificationPanel from '../../customer/NotificationPanel.vue';
  176. import dayjs from 'dayjs';
  177. import GridColumnDefUtil from '../tabGridView/GridColumnDef.js';
  178. import GridColumnDef from '../tabGridView/GridColumnDef.vue';
  179. import { Spin as ASpin, Empty as AEmpty } from 'ant-design-vue';
  180. import { CssUtil } from 'pc-component-v3';
  181. import {
  182. PlusSquareTwoTone,
  183. DeleteTwoTone,
  184. EditTwoTone,
  185. BookTwoTone,
  186. BellTwoTone,
  187. HddOutlined,
  188. FileTextTwoTone,
  189. ContainerTwoTone,
  190. ControlTwoTone,
  191. ReloadOutlined,
  192. LayoutTwoTone,
  193. } from '@ant-design/icons-vue';
  194. const props = defineProps({
  195. window: {
  196. type: Object,
  197. default: () => ({}),
  198. },
  199. nowTab: {
  200. type: String,
  201. default: '',
  202. },
  203. curdWindowFunctionAccess: {
  204. type: Object,
  205. default: function () {
  206. return null;
  207. },
  208. },
  209. modelDatas: {
  210. type: Object,
  211. default: function () {
  212. return null;
  213. },
  214. },
  215. showTabDto: {
  216. type: Object,
  217. default: function () {
  218. return null;
  219. },
  220. },
  221. simpleFilterParams: {
  222. type: String,
  223. default: null,
  224. },
  225. complexFilterParams: {
  226. type: Array,
  227. default: () => {
  228. return [];
  229. },
  230. },
  231. viewType: {
  232. type: String,
  233. default: null,
  234. },
  235. uuid: {
  236. type: String,
  237. default: null,
  238. },
  239. });
  240. const emit = defineEmits([
  241. 'createRecordInWindowEdit',
  242. 'deleteRecords',
  243. 'refreshDatas',
  244. 'judgeIsHaveButtons',
  245. ]);
  246. const tabButtons = ref([]);
  247. const leftTabButton = ref([]);
  248. const rightTabButton = ref([]);
  249. const notificationModal = ref(false);
  250. const notificationPanel = ref(null);
  251. // 模态框的打开状态
  252. const modal1Open = ref(false);
  253. // 模态框的组件
  254. const modal1Component = ref(null);
  255. const { proxy } = getCurrentInstance(); //访问this
  256. // 新建数据
  257. const create = () => {
  258. emit('createRecordInWindowEdit');
  259. };
  260. // 删除数据
  261. const deleteData = () => {
  262. emit('deleteRecords');
  263. };
  264. // 刷新
  265. const refresh = () => {
  266. emit('refreshDatas', false);
  267. };
  268. const closeModal = () => {
  269. modal1Open.value = false;
  270. };
  271. /**
  272. * 导出确认
  273. */
  274. const exportConfirm = () => {
  275. if (
  276. props.curdWindowFunctionAccess.canExport != null &&
  277. props.curdWindowFunctionAccess.canExport === true
  278. ) {
  279. BootstrapDialog.show({
  280. title: proxy.$t('lang.TabButton.dataExport'), //title
  281. message: proxy.$t('lang.TabButton.DataExport'),
  282. buttons: [
  283. {
  284. label: proxy.$t('lang.TabButton.exportMasterTableData'),
  285. action: function (dialog) {
  286. exportData(false);
  287. dialog.close();
  288. },
  289. },
  290. {
  291. label: proxy.$t('lang.TabButton.exportAllData'),
  292. action: function (dialog) {
  293. exportData(true);
  294. dialog.close();
  295. },
  296. },
  297. {
  298. label: proxy.$t('lang.TabButton.cancel'),
  299. action: function (dialog) {
  300. dialog.close();
  301. },
  302. },
  303. ],
  304. });
  305. } else {
  306. Notify.error(
  307. proxy.$t('lang.tabButton.describe4'),
  308. proxy.$t('lang.tabButton.describe5'),
  309. false,
  310. );
  311. }
  312. };
  313. const exportData = exportSubTabData => {
  314. var token = localStorage.getItem('#token');
  315. var windowNo = props.window.no;
  316. var recordId = null;
  317. if (props.modelDatas != undefined) {
  318. recordId = props.modelDatas.id;
  319. }
  320. var obj = {
  321. windowNo: windowNo,
  322. tabIndex: props.showTabDto.tabIndex,
  323. recordId: recordId,
  324. token: token,
  325. simpleFilterCondition: props.simpleFilterParams,
  326. filterParams: props.complexFilterParams,
  327. };
  328. let url = null;
  329. if (recordId == null) {
  330. url = Common.getApiURL('exportResource/exportWindowData');
  331. } else {
  332. url = Common.getApiURL('exportResource/exportSingleWindowData');
  333. }
  334. url += '?exportSubTabData=' + exportSubTabData;
  335. let formParameterName = 'exportQueryParamStr';
  336. let formParameterValue = JSON.stringify(obj);
  337. var data = formParameterName + '=' + formParameterValue;
  338. var timeStr = dayjs().format('_YYYYMMDD_hhmmss');
  339. var fileName =
  340. props.showTabDto == null
  341. ? '导出数据' + timeStr + '.xlsx'
  342. : props.showTabDto.name + timeStr + '.xlsx';
  343. DownloadService.postDownloadFile(url, data, fileName);
  344. };
  345. // 发送通知
  346. const sendNotification = () => {
  347. var notification = notificationPanel.value.getNotification();
  348. var recordIds = [];
  349. if (props.viewType == 'Grid') {
  350. if (props.modelDatas && props.modelDatas.length > 0) {
  351. props.modelDatas.forEach(function (item) {
  352. if (item.select) {
  353. recordIds.push(item.id);
  354. }
  355. });
  356. }
  357. }
  358. if (recordIds.length == 0) {
  359. Notify.error(
  360. proxy.$t('lang.Notify.error'),
  361. proxy.$t('lang.tabButton.describe7'),
  362. true,
  363. );
  364. return;
  365. }
  366. if (notification.userIds == null || notification.userIds.length == 0) {
  367. Notify.error(
  368. proxy.$t('lang.Notify.error'),
  369. proxy.$t('lang.tabButton.describe8'),
  370. true,
  371. );
  372. return;
  373. }
  374. if (notification.theme == null || notification.theme.trim() == '') {
  375. Notify.error(
  376. proxy.$t('lang.Notify.error'),
  377. proxy.$t('lang.tabButton.describe9'),
  378. true,
  379. );
  380. return;
  381. }
  382. if (notification.content == null || notification.content.trim() == '') {
  383. Notify.error(
  384. proxy.$t('lang.Notify.error'),
  385. proxy.$t('lang.tabButton.describe10'),
  386. true,
  387. );
  388. return;
  389. }
  390. var windowNo = props.window.no;
  391. var tabIndex = props.showTabDto.tabIndex;
  392. notification.windowNo = windowNo;
  393. notification.tabIndex = tabIndex;
  394. notification.recordIds = recordIds;
  395. notification.className = props.showTabDto.className;
  396. $.ajax({
  397. url: Common.getApiURL('notificationResource/send'),
  398. type: 'post',
  399. beforeSend: function (request) {
  400. Common.addTokenToRequest(request);
  401. },
  402. contentType: 'application/json',
  403. data: JSON.stringify(notification),
  404. success: function (data) {
  405. notificationModal.value = false;
  406. Notify.success(
  407. proxy.$t('lang.tabButton.describe11'),
  408. proxy.$t('lang.tabButton.describe12'),
  409. true,
  410. );
  411. },
  412. error: function (XMLHttpRequest, textStatus, errorThrown) {
  413. Common.processException(XMLHttpRequest, textStatus, errorThrown);
  414. },
  415. });
  416. };
  417. // 取消发送
  418. const cancelNotification = () => {
  419. notificationModal.value = false;
  420. };
  421. // 获取表头按钮分组值,如果没有分组则使用页签按钮
  422. watch(
  423. () => props.window,
  424. newVal => {
  425. if (newVal.tabs && newVal.tabs.length) {
  426. const mapTabButtonDtos = JSON.parse(
  427. JSON.stringify(newVal.tabs[0].tabGridView.mapTabButtonDtos),
  428. );
  429. if (isEmpty(mapTabButtonDtos)) {
  430. tabButtons.value = newVal.tabs[0].tabGridView.tabButtons;
  431. tabButtonsHandler();
  432. } else {
  433. tabButtons.value = newVal.tabs[0].tabGridView.mapTabButtonDtos;
  434. }
  435. }
  436. },
  437. { deep: true, immediate: true },
  438. );
  439. watch(
  440. () => props.nowTab,
  441. (newVal, oldVal) => {
  442. if (newVal !== oldVal) {
  443. let nowTabButtons;
  444. if (tabButtons.value) {
  445. for (let key in tabButtons.value) {
  446. if (key === newVal) {
  447. nowTabButtons = tabButtons.value[key];
  448. tabButtonsHandler(nowTabButtons);
  449. }
  450. }
  451. }
  452. }
  453. },
  454. { deep: true, immediate: true },
  455. );
  456. const tabButtonsHandler = nowTabButtons => {
  457. let buttons;
  458. if (nowTabButtons) {
  459. buttons = JSON.parse(JSON.stringify(nowTabButtons));
  460. } else {
  461. buttons = JSON.parse(JSON.stringify(tabButtons.value));
  462. }
  463. rightTabButton.value = [];
  464. leftTabButton.value = [];
  465. buttons.forEach(item => {
  466. if (item.buttonLocation === 'TABLE_HEADER_RIGHT') {
  467. rightTabButton.value.push(item);
  468. } else {
  469. leftTabButton.value.push(item);
  470. }
  471. });
  472. if (leftTabButton.value.length > 0 && rightTabButton.value.length > 0) {
  473. emit('judgeIsHaveButtons', true);
  474. } else {
  475. emit('judgeIsHaveButtons', false);
  476. }
  477. };
  478. // 用来判断分组的表头按钮是否有值
  479. const isEmpty = obj => {
  480. if (typeof obj !== 'object' || obj === null) {
  481. return true;
  482. }
  483. if (Object.keys(obj).length === 0) {
  484. return true;
  485. }
  486. };
  487. /**
  488. * 获取字符串的哈希值
  489. * @param input
  490. */
  491. const getHash = function (input) {
  492. let hash = 0;
  493. if (input.length === 0) {
  494. return hash;
  495. }
  496. for (let i = 0; i < input.length; i++) {
  497. const char = input.charCodeAt(i);
  498. hash = (hash << 5) - hash + char;
  499. hash = hash & hash; // 确保返回值是一个32位有符号整数
  500. }
  501. return Math.abs(hash).toString();
  502. };
  503. /**
  504. * 远程加载ES VUE组件模块,并在模态框中打开。
  505. * @param jsUrl js路径
  506. * @param cssUrl css路径
  507. */
  508. const openRemoteComponentModule = async function (tabButton) {
  509. let jsUrl = tabButton.remoteComponentModuleJsUrl;
  510. let cssUrl = tabButton.remoteComponentModuleCssUrl;
  511. // 显示模态框
  512. // 异步的加载js组件
  513. //let jsUrl = './static/client-eam-module-v3/dist/AssetCheckCreate.js';
  514. //let cssUrl = './static/client-eam-module-v3/dist/AssetCheckCreate.css';
  515. if (cssUrl != null && cssUrl.length > 0) {
  516. let cssUrlHash = getHash(cssUrl);
  517. CssUtil.dynamicLoadCss(cssUrl, cssUrlHash);
  518. }
  519. // webpackIgnore:设置为 true 时,禁用动态导入解析。
  520. // const testAsyncRemoteComponent = await import(/* webpackIgnore: true */ jsUrl);
  521. // console.log(testAsyncRemoteComponent);
  522. if (jsUrl != null && jsUrl.length > 0) {
  523. const testAsyncRemoteComponent = defineAsyncComponent({
  524. // 加载函数
  525. loader: () => {
  526. return import(/* webpackIgnore: true */ jsUrl);
  527. },
  528. // 加载异步组件时使用的组件
  529. loadingComponent: ASpin,
  530. // 展示加载组件前的延迟时间,默认为 200ms
  531. delay: 200,
  532. // 加载失败后展示的组件
  533. errorComponent: AEmpty,
  534. // 如果提供了一个 timeout 时间限制,并超时了
  535. // 也会显示这里配置的报错组件,默认值是:Infinity
  536. timeout: 3000,
  537. });
  538. modal1Component.value = testAsyncRemoteComponent;
  539. modal1Open.value = true;
  540. console.log(modal1Component.value);
  541. }
  542. };
  543. </script>
  544. <style scoped>
  545. .button_list {
  546. display: flex;
  547. justify-content: space-between;
  548. align-items: center;
  549. margin-right: 6px;
  550. }
  551. .ant-btn {
  552. padding: 4px 10px;
  553. }
  554. </style>