NewTabButton.vue 13 KB

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