NewTabButton.vue 15 KB

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