usePopBiz.ts 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885
  1. import { reactive, ref, unref, defineAsyncComponent, toRaw, markRaw, isRef, watch, onUnmounted } from 'vue';
  2. import { httpGroupRequest } from '/@/components/Form/src/utils/GroupRequest';
  3. import { defHttp } from '/@/utils/http/axios';
  4. import { filterMultiDictText } from '/@/utils/dict/JDictSelectUtil.js';
  5. import { useMessage } from '/@/hooks/web/useMessage';
  6. import { OnlineColumn } from '/@/components/jeecg/OnLine/types/onlineConfig';
  7. import { h } from 'vue';
  8. import { useRouter, useRoute } from 'vue-router';
  9. import { useMethods } from '/@/hooks/system/useMethods';
  10. import { importViewsFile, _eval } from '/@/utils';
  11. export function usePopBiz(ob, tableRef?) {
  12. // update-begin--author:liaozhiyang---date:20230811---for:【issues/675】子表字段Popup弹框数据不更新
  13. let props: any;
  14. if (isRef(ob)) {
  15. props = ob.value;
  16. const stopWatch = watch(ob, (newVal) => {
  17. props = newVal;
  18. });
  19. onUnmounted(() => stopWatch());
  20. } else {
  21. props = ob;
  22. }
  23. // update-end--author:liaozhiyang---date:20230811---for:【issues/675】子表字段Popup弹框数据不更新
  24. const { createMessage } = useMessage();
  25. //弹窗可视状态
  26. const visible = ref(false);
  27. //表格加载
  28. const loading = ref(false);
  29. //cgRpConfigId
  30. const cgRpConfigId = ref('');
  31. //标题
  32. const title = ref('列表');
  33. // 排序字段,默认无排序
  34. const iSorter = ref<any>('');
  35. // 查询对象
  36. const queryInfo = ref([]);
  37. // 查询参数
  38. const queryParam = ref<any>({});
  39. // 动态参数
  40. const dynamicParam = ref<any>({});
  41. //字典配置项
  42. const dictOptions = ref({});
  43. //数据集
  44. const dataSource = ref<Array<object>>([]);
  45. //定义表格信息
  46. const columns = ref<Array<object>>([]);
  47. // 当前路由
  48. const route = useRoute();
  49. //定义请求url信息
  50. const configUrl = reactive({
  51. //列表页加载column和data
  52. getColumnsAndData: '/online/cgreport/api/getColumnsAndData/',
  53. getColumns: '/online/cgreport/api/getRpColumns/',
  54. getData: '/online/cgreport/api/getData/',
  55. getQueryInfo: '/online/cgreport/api/getQueryInfo/',
  56. export: '/online/cgreport/api/exportManySheetXls/',
  57. });
  58. //已选择的值
  59. const checkedKeys = ref<Array<string | number>>([]);
  60. //选择的行记录
  61. const selectRows = ref<Array<any>>([]);
  62. // 点击单元格选中行 popup需要 但是报表预览不需要
  63. let clickThenCheckFlag = true;
  64. if (props.clickToRowSelect === false) {
  65. clickThenCheckFlag = false;
  66. }
  67. /**
  68. * 选择列配置
  69. */
  70. const rowSelection = {
  71. fixed: true,
  72. selectedRowKeys: checkedKeys,
  73. selectionRows: selectRows,
  74. onChange: onSelectChange,
  75. };
  76. /**
  77. * 序号列配置
  78. */
  79. const indexColumnProps = {
  80. dataIndex: 'index',
  81. width: '15px',
  82. };
  83. /**
  84. * 分页配置
  85. */
  86. const pagination = reactive({
  87. current: 1,
  88. pageSize: 10,
  89. pageSizeOptions: ['10', '20', '30'],
  90. // showTotal: (total, range) => {
  91. // return range[0] + '-' + range[1] + ' 共' + total + '条'
  92. // },
  93. showQuickJumper: true,
  94. showSizeChanger: true,
  95. total: 0,
  96. // 合计逻辑 [待优化 3.0]
  97. showTotal: (total) => onShowTotal(total),
  98. realPageSize: 10,
  99. realTotal: 0,
  100. // 是否有合计列,默认为"",在第一次获取到数据之后会设计为ture或者false
  101. isTotal: <string | boolean>'',
  102. onShowSizeChange: (current, pageSize) => onSizeChange(current, pageSize),
  103. });
  104. /**
  105. * 表格选择事件
  106. * @param selectedRowKeys
  107. * @param selectRow
  108. */
  109. function onSelectChange(selectedRowKeys: (string | number)[]) {
  110. // update-begin--author:liaozhiyang---date:20230919---for:【QQYUN-4263】跨页选择导出问题
  111. if (!selectedRowKeys || selectedRowKeys.length == 0) {
  112. selectRows.value = [];
  113. checkedKeys.value = [];
  114. } else {
  115. if (selectRows.value.length > selectedRowKeys.length) {
  116. // 取消
  117. selectRows.value.forEach((item, index) => {
  118. const rowKey = combineRowKey(item);
  119. if (!selectedRowKeys.find((key) => key === rowKey)) {
  120. selectRows.value.splice(index, 1);
  121. }
  122. });
  123. } else {
  124. // 新增
  125. const append: any = [];
  126. const beforeRowKeys = selectRows.value.map((item) => combineRowKey(item));
  127. selectedRowKeys.forEach((key) => {
  128. if (!beforeRowKeys.find((item) => item === key)) {
  129. // 那就是新增选中的行
  130. const row = getRowByKey(key);
  131. row && append.push(row);
  132. }
  133. });
  134. selectRows.value = [...selectRows.value, ...append];
  135. }
  136. checkedKeys.value = [...selectedRowKeys];
  137. }
  138. // update-end--author:liaozhiyang---date:20230919---for:【QQYUN-4263】跨页选择导出问题
  139. }
  140. /**
  141. * 过滤没用选项
  142. * @param selectedRowKeys
  143. */
  144. function filterUnuseSelect() {
  145. selectRows.value = unref(selectRows).filter((item) => {
  146. const combineKey = combineRowKey(item);
  147. return unref(checkedKeys).indexOf(combineKey) >= 0;
  148. });
  149. }
  150. /**
  151. * 根据key获取row信息
  152. * @param key
  153. */
  154. function getRowByKey(key) {
  155. const row = unref(dataSource).filter((record) => combineRowKey(record) === key);
  156. return row && row.length > 0 ? row[0] : '';
  157. }
  158. /**
  159. * 加载rowKey
  160. */
  161. function combineRowKey(record) {
  162. let res = record?.id || '';
  163. Object.keys(record).forEach((key) => {
  164. res = key == 'rowIndex' ? record[key] + res : res + record[key];
  165. });
  166. res = res.length > 50 ? res.substring(0, 50) : res;
  167. return res;
  168. }
  169. /**
  170. * 加载列信息
  171. */
  172. function loadColumnsInfo() {
  173. const url = `${configUrl.getColumns}${props.code}`;
  174. //缓存key
  175. const groupIdKey = props.groupId ? `${props.groupId}${url}` : '';
  176. httpGroupRequest(() => defHttp.get({ url }, { isTransformResponse: false, successMessageMode: 'none' }), groupIdKey).then((res) => {
  177. if (res.success) {
  178. initDictOptionData(res.result.dictOptions);
  179. cgRpConfigId.value = res.result.cgRpConfigId;
  180. title.value = res.result.cgRpConfigName;
  181. const currColumns = res.result.columns;
  182. for (let a = 0; a < currColumns.length; a++) {
  183. if (currColumns[a].customRender) {
  184. const dictCode = currColumns[a].customRender;
  185. currColumns[a].customRender = ({ text }) => {
  186. return filterMultiDictText(unref(dictOptions)[dictCode], text + '');
  187. };
  188. }
  189. // 排序字段受控
  190. if (unref(iSorter) && currColumns[a].dataIndex === unref(iSorter).column) {
  191. currColumns[a].sortOrder = unref(iSorter).order === 'asc' ? 'ascend' : 'descend';
  192. }
  193. }
  194. if (currColumns[0].key !== 'rowIndex') {
  195. currColumns.unshift({
  196. title: '序号',
  197. dataIndex: 'rowIndex',
  198. key: 'rowIndex',
  199. width: 60,
  200. align: 'center',
  201. customRender: function ({ text }) {
  202. return parseInt(text) + 1;
  203. },
  204. });
  205. }
  206. columns.value = [...currColumns];
  207. initQueryInfo(null);
  208. }
  209. });
  210. }
  211. /**
  212. * 加载列和数据[列表专用]
  213. */
  214. function loadColumnsAndData() {
  215. // 第一次加载 置空isTotal 在这里调用确保 该方法只是进入页面后 加载一次 其余查询不走该方法
  216. pagination.isTotal = '';
  217. const url = `${configUrl.getColumnsAndData}${props.id}`;
  218. //缓存key
  219. const groupIdKey = props.groupId ? `${props.groupId}${url}` : '';
  220. httpGroupRequest(() => defHttp.get({ url }, { isTransformResponse: false, successMessageMode: 'none' }), groupIdKey).then((res) => {
  221. if (res.success) {
  222. initDictOptionData(res.result.dictOptions);
  223. cgRpConfigId.value = props.id;
  224. const { columns: metaColumnList, cgreportHeadName, fieldHrefSlots, isGroupTitle } = res.result;
  225. title.value = cgreportHeadName;
  226. // href 跳转
  227. const fieldHrefSlotKeysMap = {};
  228. fieldHrefSlots.forEach((item) => (fieldHrefSlotKeysMap[item.slotName] = item));
  229. let currColumns = handleColumnHrefAndDict(metaColumnList, fieldHrefSlotKeysMap);
  230. // popup需要序号, 普通列表不需要
  231. if (clickThenCheckFlag === true) {
  232. currColumns.unshift({
  233. title: '序号',
  234. dataIndex: 'rowIndex',
  235. key: 'rowIndex',
  236. width: 60,
  237. align: 'center',
  238. customRender: function ({ text }) {
  239. return parseInt(text) + 1;
  240. },
  241. });
  242. }
  243. // 合并表头
  244. if (isGroupTitle === true) {
  245. currColumns = handleGroupTitle(currColumns);
  246. }
  247. columns.value = [...currColumns];
  248. initQueryInfo(res.result.data);
  249. } else {
  250. //update-begin-author:taoyan date:20220401 for: VUEN-583【vue3】JeecgBootException: sql黑名单校验不通过,请联系管理员!,前台无提示
  251. createMessage.warning(res.message);
  252. //update-end-author:taoyan date:20220401 for: VUEN-583【vue3】JeecgBootException: sql黑名单校验不通过,请联系管理员!,前台无提示
  253. }
  254. });
  255. }
  256. /**
  257. * 处理求和的列 合计逻辑 [待优化 3.0]
  258. */
  259. function handleSumColumn(metaColumnList: OnlineColumn[], dataTotal: number): void {
  260. // 获取需要合计列的dataIndex
  261. const sumColumnList = getNeedSumColumns(metaColumnList);
  262. // 判断是否为第一次获取数据,如果是的话,则需要重新设置pageSize
  263. if (pagination.isTotal == '') {
  264. if (sumColumnList.length > 0) {
  265. pagination.isTotal = true;
  266. // 有合计字段时,每次最多查询原pageSize-1条记录,另外需要第一次时将查询的10条中删除最后一条
  267. // 删除最后一条数据 如果第一次得到的数据长度等于pageSize的话,则删除最后一条
  268. if (dataSource.value.length == pagination.pageSize) {
  269. const remove_data = dataSource.value.pop();
  270. }
  271. pagination.realPageSize = pagination.pageSize - 1;
  272. } else {
  273. pagination.isTotal = false;
  274. }
  275. }
  276. // 需要添加合计字段
  277. if (pagination.isTotal) {
  278. const totalRow = {};
  279. sumColumnList.forEach((dataIndex) => {
  280. let count = 0;
  281. dataSource.value.forEach((row) => {
  282. // 统计去除null及空数据
  283. if (row[dataIndex] != null && row[dataIndex] != '') {
  284. count += parseFloat(row[dataIndex]);
  285. }
  286. });
  287. totalRow[dataIndex] = isNaN(count) ? '包含非数字内容' : count.toFixed(2);
  288. // 长整形时合计不显示.00后缀
  289. const v = metaColumnList.find((v) => v.dataIndex == dataIndex);
  290. if (v && v.fieldType == 'Long') {
  291. totalRow[dataIndex] = parseInt(totalRow[dataIndex]);
  292. }
  293. });
  294. dataSource.value.push(totalRow);
  295. pagination.realTotal = dataTotal;
  296. pagination.total = Number(dataTotal) + Number(Math.floor(dataTotal / pagination.realPageSize));
  297. }
  298. }
  299. /**
  300. * 获取需要求和的列 dataIndex
  301. * @param columns
  302. */
  303. function getNeedSumColumns(columns: OnlineColumn[]): string[] {
  304. const arr: string[] = [];
  305. for (const column of columns) {
  306. if (column.isTotal === '1') {
  307. arr.push(column.dataIndex!);
  308. }
  309. // 【VUEN-1569】【online报表】合计无效
  310. if (column.children && column.children.length > 0) {
  311. const subArray = getNeedSumColumns(column.children);
  312. if (subArray.length > 0) {
  313. arr.push(...subArray);
  314. }
  315. }
  316. }
  317. return arr;
  318. }
  319. /**
  320. * 处理列的href和字典翻译
  321. */
  322. function handleColumnHrefAndDict(columns: OnlineColumn[], fieldHrefSlotKeysMap: {}): OnlineColumn[] {
  323. for (const column of columns) {
  324. let { customRender, hrefSlotName, fieldType } = column;
  325. // online 报表中类型配置为日期(yyyy-MM-dd ),但是实际展示为日期时间格式(yyyy-MM-dd HH:mm:ss) issues/3042
  326. if (fieldType == 'Date') {
  327. column.customRender = ({ text }) => {
  328. if (!text) {
  329. return '';
  330. }
  331. if (text.length > 10) {
  332. return text.substring(0, 10);
  333. }
  334. return text;
  335. };
  336. } else {
  337. if (!hrefSlotName && column.scopedSlots && column.scopedSlots.customRender) {
  338. //【Online报表】字典和href互斥 这里通过fieldHrefSlotKeysMap 先找到是href的列
  339. if (fieldHrefSlotKeysMap.hasOwnProperty(column.scopedSlots.customRender)) {
  340. hrefSlotName = column.scopedSlots.customRender;
  341. }
  342. }
  343. // 如果 customRender 有值则代表使用了字典
  344. // 如果 hrefSlotName 有值则代表使用了href跳转
  345. // 两者可以兼容。兼容的具体思路为:先获取到字典替换的值,再添加href链接跳转
  346. if (customRender || hrefSlotName) {
  347. const dictCode = customRender as string;
  348. const replaceFlag = '_replace_text_';
  349. column.customRender = ({ text, record }) => {
  350. let value = text;
  351. // 如果 dictCode 有值,就进行字典转换
  352. if (dictCode) {
  353. if (dictCode.startsWith(replaceFlag)) {
  354. const textFieldName = dictCode.replace(replaceFlag, '');
  355. value = record[textFieldName];
  356. } else {
  357. value = filterMultiDictText(unref(dictOptions)[dictCode], text + '');
  358. }
  359. }
  360. // 扩展参数设置列的内容长度
  361. if (column.showLength) {
  362. if (value && value.length > column.showLength) {
  363. value = value.substr(0, column.showLength) + '...';
  364. }
  365. }
  366. // 如果 hrefSlotName 有值,就生成一个 a 标签,包裹住字典替换后(或原生)的值
  367. if (hrefSlotName) {
  368. const field = fieldHrefSlotKeysMap[hrefSlotName];
  369. if (field) {
  370. return h(
  371. 'a',
  372. {
  373. onClick: () => handleClickFieldHref(field, record),
  374. },
  375. value
  376. );
  377. }
  378. }
  379. return value;
  380. };
  381. }
  382. }
  383. }
  384. return columns;
  385. }
  386. /**
  387. * 处理合并表头
  388. * @param columns
  389. */
  390. function handleGroupTitle(columns: OnlineColumn[]): OnlineColumn[] {
  391. const newColumns: OnlineColumn[] = [];
  392. for (const column of columns) {
  393. //排序字段受控 ---- 此逻辑为新增逻辑 待
  394. if (unref(iSorter) && column.dataIndex === unref(iSorter).column) {
  395. column.sortOrder = unref(iSorter).order === 'asc' ? 'ascend' : 'descend';
  396. }
  397. //判断字段是否需要合并表头
  398. if (column.groupTitle) {
  399. const clIndex = newColumns.findIndex((im) => im.title === column.groupTitle);
  400. if (clIndex !== -1) {
  401. //表头已存在直接push children
  402. newColumns[clIndex].children!.push(column);
  403. } else {
  404. //表头不存在组装表头信息
  405. const clGroup: OnlineColumn = {},
  406. child: OnlineColumn[] = [];
  407. child.push(column);
  408. clGroup.title = column.groupTitle;
  409. clGroup.align = 'center';
  410. clGroup.children = child;
  411. newColumns.push(clGroup);
  412. }
  413. } else {
  414. newColumns.push(column);
  415. }
  416. }
  417. return newColumns;
  418. }
  419. // 获取路由器对象 href跳转用到
  420. const router = useRouter();
  421. /**
  422. * href 点击事件
  423. * @param field
  424. * @param record
  425. */
  426. function handleClickFieldHref(field, record) {
  427. let href = field.href;
  428. const urlPattern = /(ht|f)tp(s?)\:\/\/[0-9a-zA-Z]([-.\w]*[0-9a-zA-Z])*(:(0-9)*)*(\/?)([a-zA-Z0-9\-\.\?\,\'\/\\\+&amp;%\$#_]*)?/;
  429. const compPattern = /\.vue(\?.*)?$/;
  430. const jsPattern = /{{([^}]+)}}/g; // {{ xxx }}
  431. if (typeof href === 'string') {
  432. href = href.trim().replace(/\${([^}]+)?}/g, (s1, s2) => record[s2]);
  433. // 执行 {{...}} JS增强语句
  434. if (jsPattern.test(href)) {
  435. href = href.replace(jsPattern, function (text, s0) {
  436. try {
  437. // update-begin--author:liaozhiyang---date:20230904---for:【QQYUN-6390】eval替换成new Function,解决build警告
  438. return _eval(s0);
  439. // update-end--author:liaozhiyang---date:20230904---for:【QQYUN-6390】eval替换成new Function,解决build警告
  440. } catch (e) {
  441. console.error(e);
  442. return text;
  443. }
  444. });
  445. }
  446. if (urlPattern.test(href)) {
  447. window.open(href, '_blank');
  448. } else if (compPattern.test(href)) {
  449. // 处理弹框
  450. openHrefCompModal(href);
  451. } else {
  452. router.push(href);
  453. }
  454. }
  455. }
  456. /**
  457. * 导出
  458. */
  459. function handleExport() {
  460. const { handleExportXls } = useMethods();
  461. const url = `${configUrl.export}${cgRpConfigId.value}`;
  462. const params = getQueryParams(); //查询条件
  463. // 【VUEN-1568】如果选中了某些行,就只导出选中的行
  464. const keys = unref(checkedKeys);
  465. if (keys.length > 0) {
  466. params['force_id'] = keys
  467. .map((i) => selectRows.value.find((item) => combineRowKey(item) === i)?.id)
  468. .filter((i) => i != null && i !== '')
  469. .join(',');
  470. }
  471. handleExportXls(title.value, url, params);
  472. }
  473. /**
  474. * 合计逻辑 [待优化 3.0]
  475. * 分页 大小改变事件
  476. * @param _current
  477. * @param size
  478. */
  479. function onSizeChange(_current, size) {
  480. pagination.isTotal = '';
  481. pagination.pageSize = size;
  482. if (pagination.isTotal) {
  483. pagination.realPageSize = size - 1;
  484. } else {
  485. pagination.realPageSize = size;
  486. }
  487. pagination.current = 1;
  488. }
  489. /**
  490. * 合计逻辑 [待优化 3.0]
  491. * 显示总条数
  492. * @param total
  493. */
  494. function onShowTotal(total) {
  495. // 重新根据是否有合计计算每页显示的数据
  496. const start = (pagination.current - 1) * pagination.realPageSize + 1;
  497. const end = start + (pagination.isTotal ? dataSource.value.length - 1 : dataSource.value.length) - 1;
  498. const realTotal = pagination.isTotal ? pagination.realTotal : total;
  499. return start + '-' + end + ' 共' + realTotal + '条';
  500. }
  501. /**
  502. * 弹出框显示隐藏触发事件
  503. */
  504. async function visibleChange($event) {
  505. visible.value = $event;
  506. $event && loadColumnsInfo();
  507. }
  508. /**
  509. * 初始化查询条件
  510. * @param data 数据结果集
  511. */
  512. function initQueryInfo(data) {
  513. const url = `${configUrl.getQueryInfo}${unref(cgRpConfigId)}`;
  514. //缓存key
  515. const groupIdKey = props.groupId ? `${props.groupId}${url}` : '';
  516. httpGroupRequest(() => defHttp.get({ url }, { isTransformResponse: false, successMessageMode: 'none' }), groupIdKey).then((res) => {
  517. // console.log("获取查询条件", res);
  518. if (res.success) {
  519. dynamicParamHandler(res.result);
  520. queryInfo.value = res.result;
  521. console.log('queryInfo==>', queryInfo.value);
  522. //查询条件加载后再请求数据
  523. if (data) {
  524. setDataSource(data);
  525. //传递路由参数和动态参数,不生效,
  526. loadData(1);
  527. } else {
  528. //没有传递data时查询数据
  529. loadData(1);
  530. }
  531. } else {
  532. createMessage.warning(res.message);
  533. }
  534. });
  535. }
  536. /**
  537. * 加载表格数据
  538. * @param arg
  539. */
  540. function loadData(arg?) {
  541. if (arg == 1) {
  542. pagination.current = 1;
  543. }
  544. const params = getQueryParams(); //查询条件
  545. params['onlRepUrlParamStr'] = getUrlParamString();
  546. console.log('params', params);
  547. loading.value = true;
  548. const url = `${configUrl.getData}${unref(cgRpConfigId)}`;
  549. //缓存key
  550. const groupIdKey = props.groupId ? `${props.groupId}${url}${JSON.stringify(params)}` : '';
  551. httpGroupRequest(() => defHttp.get({ url, params }, { isTransformResponse: false, successMessageMode: 'none' }), groupIdKey).then((res) => {
  552. loading.value = false;
  553. const data = res.result;
  554. console.log('表格信息:', data);
  555. setDataSource(data);
  556. });
  557. }
  558. /**
  559. * 获取地址栏的参数
  560. */
  561. function getUrlParamString() {
  562. const query = route.query;
  563. const arr: any[] = [];
  564. if (query && Object.keys(query).length > 0) {
  565. Object.keys(query).map((k) => {
  566. arr.push(`${k}=${query[k]}`);
  567. });
  568. }
  569. return arr.join('&');
  570. }
  571. /**
  572. * 设置dataSource
  573. */
  574. function setDataSource(data) {
  575. if (data) {
  576. pagination.total = Number(data.total);
  577. const currentPage = pagination?.current ?? 1;
  578. for (let a = 0; a < data.records.length; a++) {
  579. if (!data.records[a].rowIndex) {
  580. data.records[a].rowIndex = a + (currentPage - 1) * 10;
  581. }
  582. }
  583. dataSource.value = data.records;
  584. //update-begin-author:taoyan date:2023-2-11 for:issues/356 在线报表分页有问题
  585. //update-begin-author:liusq date:2023-4-04 for:issues/426 修复356时候引入的回归错误 JPopupOnlReportModal.vue 中未修改
  586. tableRef?.value &&
  587. tableRef?.value?.setPagination({
  588. total: Number(data.total),
  589. });
  590. //update-end-author:liusq date:2023-4-04 for:issues/426 修复356时候引入的回归错误 JPopupOnlReportModal.vue 中未修改
  591. //update-end-author:taoyan date:2023-2-11 for:issues/356 在线报表分页有问题
  592. } else {
  593. pagination.total = 0;
  594. dataSource.value = [];
  595. }
  596. // 合计逻辑 [待优化 3.0]
  597. handleSumColumn(columns.value, pagination.total);
  598. }
  599. /**
  600. * 获取查询参数
  601. */
  602. function getQueryParams() {
  603. const paramTarget = {};
  604. if (unref(dynamicParam)) {
  605. //处理自定义参数
  606. Object.keys(unref(dynamicParam)).map((key) => {
  607. paramTarget['self_' + key] = unref(dynamicParam)[key];
  608. });
  609. }
  610. const param = Object.assign(paramTarget, unref(queryParam), unref(iSorter));
  611. param.pageNo = pagination.current;
  612. // 合计逻辑 [待优化 3.0]
  613. // 实际查询时不使用table组件的pageSize,而使用自定义的realPageSize,realPageSize会在第一次获取到数据后变化
  614. param.pageSize = pagination.realPageSize;
  615. return filterObj(param);
  616. }
  617. /**
  618. * 处理动态参数
  619. */
  620. function dynamicParamHandler(arr?) {
  621. if (arr && arr.length > 0) {
  622. //第一次加载查询条件前 初始化queryParam为空对象
  623. const queryTemp = {};
  624. for (const item of arr) {
  625. if (item.mode === 'single') {
  626. queryTemp[item.field] = '';
  627. }
  628. }
  629. queryParam.value = { ...queryTemp };
  630. }
  631. // 合并路由参数
  632. if (props.routeQuery) {
  633. queryParam.value = Object.assign(queryParam.value, props.routeQuery);
  634. }
  635. const dynamicTemp = {};
  636. if (props.param) {
  637. Object.keys(props.param).map((key) => {
  638. let str = props.param[key];
  639. if (key in queryParam.value) {
  640. if (str && str.startsWith("'") && str.endsWith("'")) {
  641. str = str.substring(1, str.length - 1);
  642. }
  643. //如果查询条件包含参数 设置值
  644. unref(queryParam)[key] = str;
  645. }
  646. dynamicTemp[key] = props.param[key];
  647. });
  648. }
  649. dynamicParam.value = { ...dynamicTemp };
  650. }
  651. /**
  652. * 分页
  653. * @param page
  654. * @param filters
  655. * @param sorter
  656. */
  657. function handleChangeInTable(page, filters, sorter) {
  658. console.log(page, filters, sorter);
  659. //分页、排序、筛选变化时触发
  660. if (Object.keys(sorter).length > 0) {
  661. iSorter.value = {
  662. column: sorter.field,
  663. order: 'ascend' === sorter.order ? 'asc' : 'desc',
  664. };
  665. // 排序字段受控
  666. unref(columns).forEach((col) => {
  667. if (col['dataIndex'] === sorter.field) {
  668. col['sortOrder'] = sorter.order;
  669. }
  670. });
  671. }
  672. pagination.current = page.current;
  673. pagination.pageSize = page.pageSize;
  674. loadData();
  675. }
  676. /**
  677. * 行点击事件
  678. * @param record
  679. */
  680. function clickThenCheck(record) {
  681. if (clickThenCheckFlag === true) {
  682. const rowKey = combineRowKey(record);
  683. if (!unref(checkedKeys) || unref(checkedKeys).length == 0) {
  684. const arr1: any[] = [],
  685. arr2: any[] = [];
  686. arr1.push(record);
  687. arr2.push(rowKey);
  688. checkedKeys.value = arr2;
  689. //selectRows.value = arr1;
  690. } else {
  691. if (unref(checkedKeys).indexOf(rowKey) < 0) {
  692. //不存在就选中
  693. checkedKeys.value.push(rowKey);
  694. //selectRows.value.push(record);
  695. } else {
  696. //已选中就取消
  697. const rowKey_index = unref(checkedKeys).indexOf(rowKey);
  698. checkedKeys.value.splice(rowKey_index, 1);
  699. //selectRows.value.splice(rowKey_index, 1);
  700. }
  701. }
  702. // update-begin--author:liaozhiyang---date:20230914---for:【issues/5357】点击行选中
  703. tableRef.value.setSelectedRowKeys([...checkedKeys.value]);
  704. // update-end--author:liaozhiyang---date:20230914---for:【issues/5357】点击行选中
  705. }
  706. }
  707. //防止字典中有垃圾数据
  708. function initDictOptionData(arr) {
  709. const obj = {};
  710. Object.keys(arr).map((k) => {
  711. obj[k] = arr[k].filter((item) => {
  712. return item != null;
  713. });
  714. });
  715. dictOptions.value = obj;
  716. }
  717. /**
  718. * 过滤对象中为空的属性
  719. * @param obj
  720. * @returns {*}
  721. */
  722. function filterObj(obj) {
  723. if (!(typeof obj == 'object')) {
  724. return;
  725. }
  726. for (const key in obj) {
  727. if (obj.hasOwnProperty(key) && (obj[key] == null || obj[key] == undefined || obj[key] === '')) {
  728. delete obj[key];
  729. }
  730. }
  731. return obj;
  732. }
  733. // 样式
  734. const dialogStyle = {
  735. top: 0,
  736. left: 0,
  737. height: '100%',
  738. margin: 0,
  739. padding: 0,
  740. };
  741. // 弹窗属性配置
  742. const hrefComponent = ref({
  743. model: {
  744. title: '',
  745. okText: '关闭',
  746. width: '100%',
  747. visible: false,
  748. destroyOnClose: true,
  749. style: dialogStyle,
  750. // dialogStyle: dialogStyle,
  751. bodyStyle: {
  752. padding: '8px',
  753. height: 'calc(100vh - 108px)',
  754. overflow: 'auto',
  755. overflowX: 'hidden',
  756. },
  757. // 隐藏掉取消按钮
  758. cancelButtonProps: { style: { display: 'none' } },
  759. },
  760. on: {
  761. ok: () => (hrefComponent.value.model.visible = false),
  762. cancel: () => (hrefComponent.value.model.visible = false),
  763. },
  764. is: <any>null,
  765. params: {},
  766. });
  767. // 超链点击事件--> 打开一个modal窗口
  768. function openHrefCompModal(href) {
  769. // 解析 href 参数
  770. const index = href.indexOf('?');
  771. let path = href;
  772. if (index !== -1) {
  773. path = href.substring(0, index);
  774. const paramString = href.substring(index + 1, href.length);
  775. const paramArray = paramString.split('&');
  776. const params = {};
  777. paramArray.forEach((paramObject) => {
  778. const paramItem = paramObject.split('=');
  779. params[paramItem[0]] = paramItem[1];
  780. });
  781. hrefComponent.value.params = params;
  782. } else {
  783. hrefComponent.value.params = {};
  784. }
  785. hrefComponent.value.model.visible = true;
  786. hrefComponent.value.model.title = '操作';
  787. hrefComponent.value.is = markRaw(defineAsyncComponent(() => importViewsFile(path)));
  788. }
  789. //update-begin-author:taoyan date:2022-5-31 for: VUEN-1155 popup 选择数据时,会选择多条重复数据
  790. /**
  791. * emit事件 获取选中的行数据
  792. */
  793. function getOkSelectRows(): any[] {
  794. const arr = unref(selectRows);
  795. const selectedRowKeys = checkedKeys.value;
  796. console.log('arr', arr);
  797. if (!selectedRowKeys || selectedRowKeys.length <= 0) {
  798. return [];
  799. }
  800. if (!arr || arr.length <= 0) {
  801. return [];
  802. }
  803. const rows: any = [];
  804. for (const key of selectedRowKeys) {
  805. for (let i = 0; i < arr.length; i++) {
  806. const combineKey = combineRowKey(arr[i]);
  807. if (key === combineKey) {
  808. rows.push(toRaw(arr[i]));
  809. break;
  810. }
  811. }
  812. }
  813. return rows;
  814. }
  815. //update-end-author:taoyan date:2022-5-31 for: VUEN-1155 popup 选择数据时,会选择多条重复数据
  816. return [
  817. {
  818. visibleChange,
  819. loadColumnsInfo,
  820. loadColumnsAndData,
  821. dynamicParamHandler,
  822. loadData,
  823. handleChangeInTable,
  824. combineRowKey,
  825. clickThenCheck,
  826. filterUnuseSelect,
  827. handleExport,
  828. getOkSelectRows,
  829. },
  830. {
  831. hrefComponent,
  832. visible,
  833. rowSelection,
  834. checkedKeys,
  835. selectRows,
  836. pagination,
  837. dataSource,
  838. columns,
  839. indexColumnProps,
  840. loading,
  841. title,
  842. iSorter,
  843. queryInfo,
  844. queryParam,
  845. dictOptions,
  846. },
  847. ];
  848. }