useSuperQuery.ts 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524
  1. import { useModalInner } from '/@/components/Modal';
  2. import { randomString } from '/@/utils/common/compUtils';
  3. import { reactive, ref, toRaw, watch } from 'vue';
  4. import { useMessage } from '/@/hooks/web/useMessage';
  5. import { Modal } from 'ant-design-vue';
  6. import { createLocalStorage } from '/@/utils/cache';
  7. import { useRoute } from 'vue-router';
  8. /**
  9. * 表单类型转换成查询类型
  10. * 普通查询和高级查询组件区别 :高级查询不支持联动组件
  11. */
  12. const FORM_VIEW_TO_QUERY_VIEW = {
  13. password: 'text',
  14. file: 'text',
  15. image: 'text',
  16. textarea: 'text',
  17. umeditor: 'text',
  18. markdown: 'text',
  19. checkbox: 'list_multi',
  20. radio: 'list',
  21. };
  22. // 查询条件存储编码前缀
  23. const SAVE_CODE_PRE = 'JSuperQuerySaved_';
  24. /**
  25. * 查询项
  26. * */
  27. interface SuperQueryItem {
  28. field: string | undefined;
  29. rule: string | undefined;
  30. val: string | number;
  31. key: string;
  32. }
  33. /**
  34. * 查询项-第一个控件树model
  35. * */
  36. interface TreeModel {
  37. title: string;
  38. value: string;
  39. isLeaf?: boolean;
  40. disabled?: boolean;
  41. children?: TreeModel[];
  42. order?: number;
  43. }
  44. /**
  45. * 查询信息保存结构
  46. * */
  47. interface SaveModel {
  48. title: string;
  49. content: string;
  50. type: string;
  51. }
  52. export function useSuperQuery() {
  53. const { createMessage: $message } = useMessage();
  54. /** 表单ref*/
  55. const formRef = ref<any>();
  56. /** 数据*/
  57. const dynamicRowValues = reactive<{ values: SuperQueryItem[] }>({
  58. values: [],
  59. });
  60. /** and/or */
  61. const matchType = ref('and');
  62. // 弹框显示
  63. const [registerModal, { setModalProps }] = useModalInner(() => {
  64. setModalProps({ confirmLoading: false });
  65. });
  66. // 高级查询类型不支持联动组件,需要额外设置联动组件的view为text
  67. const view2QueryViewMap = Object.assign({}, { link_down: 'text' }, FORM_VIEW_TO_QUERY_VIEW);
  68. /**
  69. * 确认按钮事件
  70. */
  71. function handleSubmit() {
  72. console.log('handleSubmit', dynamicRowValues.values);
  73. }
  74. /**
  75. * 关闭按钮事件
  76. */
  77. function handleCancel() {
  78. //closeModal();
  79. }
  80. /**
  81. * val组件赋值
  82. */
  83. function setFormModel(key: string, value: any, item: any) {
  84. console.log('setFormModel', key, value);
  85. // formModel[key] = value;
  86. item['val'] = value;
  87. }
  88. // 字段-Properties
  89. const fieldProperties = ref<any>({});
  90. // 字段-左侧查询项-树控件数据
  91. const fieldTreeData = ref<any>([]);
  92. /**
  93. * 初始化数据-最开始的方法
  94. * 1.获取 表名@字段名-->配置 这样的一个map
  95. * 2.获取树形结构的数据 显示:文本; 存储:表名@字段名
  96. * 当树改变时,及时获取配置更新表单
  97. * @param json
  98. */
  99. function init(json) {
  100. let { allFields, treeData } = getAllFields(json);
  101. fieldProperties.value = allFields;
  102. fieldTreeData.value = treeData;
  103. }
  104. /**
  105. * 左侧查询项 添加一行
  106. * @param index
  107. */
  108. function addOne(index) {
  109. let item = {
  110. field: undefined,
  111. rule: 'eq',
  112. val: '',
  113. key: randomString(16),
  114. };
  115. if (index === false) {
  116. // 重置后需要调用
  117. dynamicRowValues.values = [];
  118. dynamicRowValues.values.push(item);
  119. } else if (index === true) {
  120. // 打开弹框是需要调用
  121. if (dynamicRowValues.values.length == 0) {
  122. dynamicRowValues.values.push(item);
  123. }
  124. } else {
  125. // 其余就是 正常的点击加号增加行
  126. dynamicRowValues.values.splice(++index, 0, item);
  127. }
  128. }
  129. /**
  130. * 左侧查询项 删除一行
  131. */
  132. function removeOne(item: SuperQueryItem) {
  133. let arr = toRaw(dynamicRowValues.values);
  134. let index = -1;
  135. for (let i = 0; i < arr.length; i++) {
  136. if (item.key == arr[i].key) {
  137. index = i;
  138. break;
  139. }
  140. }
  141. if (index != -1) {
  142. dynamicRowValues.values.splice(index, 1);
  143. }
  144. }
  145. // 默认的输入框
  146. const defaultInput = {
  147. field: 'val',
  148. label: '测试',
  149. component: 'Input',
  150. };
  151. /**
  152. * 左侧查询项 val组件 schema获取, 替代左侧字段树的change事件
  153. * @param item
  154. * @param index
  155. */
  156. function getSchema(item, index) {
  157. let map = fieldProperties.value;
  158. let prop = map[item.field];
  159. if (!prop) {
  160. return defaultInput;
  161. }
  162. if (view2QueryViewMap[prop.view]) {
  163. // 如果出现查询条件联动组件出来的场景,请跟踪此处
  164. prop.view = view2QueryViewMap[prop.view];
  165. }
  166. let temp;
  167. // temp.setFormRef(formRef)
  168. temp.noChange();
  169. // 查询条件中的 下拉框popContainer为parentNode
  170. temp.asSearchForm();
  171. temp.updateField(item.field + index);
  172. const setFieldValue = (values) => {
  173. item['val'] = values[item.field];
  174. };
  175. temp.setFunctionForFieldValue(setFieldValue);
  176. let schema = temp.getFormItemSchema();
  177. //schema['valueField'] = 'val'
  178. return schema;
  179. }
  180. /*-----------------------右侧保存信息相关-begin---------------------------*/
  181. /**
  182. * 右侧树 的 数据
  183. */
  184. const saveTreeData = ref<any>('');
  185. // 本地缓存
  186. const $ls = createLocalStorage();
  187. //需要保存的信息(一条)
  188. const saveInfo = reactive({
  189. visible: false,
  190. title: '',
  191. content: '',
  192. saveCode: '',
  193. });
  194. //按钮loading
  195. const loading = ref(false);
  196. // 当前页面路由
  197. const route = useRoute();
  198. // 监听路由信息,路由发生改变,则重新获取保存的查询信息-->currentPageSavedArray
  199. watch(
  200. () => route.fullPath,
  201. (val) => {
  202. console.log('fullpath', val);
  203. initSaveQueryInfoCode();
  204. }
  205. );
  206. // 当前页面存储的 查询信息
  207. const currentPageSavedArray = ref<SaveModel[]>([]);
  208. // 监听当前页面是否有新的数据保存了,然后更新右侧数据->saveTreeData
  209. watch(
  210. () => currentPageSavedArray.value,
  211. (val) => {
  212. let temp: any[] = [];
  213. if (val && val.length > 0) {
  214. val.map((item) => {
  215. let key = randomString(16);
  216. temp.push({
  217. title: item.title,
  218. slots: { icon: 'custom' },
  219. value: key,
  220. });
  221. });
  222. }
  223. saveTreeData.value = temp;
  224. },
  225. { immediate: true, deep: true }
  226. );
  227. // 重新获取保存的查询信息
  228. function initSaveQueryInfoCode() {
  229. let code = SAVE_CODE_PRE + route.fullPath;
  230. saveInfo.saveCode = code;
  231. let list = $ls.get(code);
  232. if (list && list instanceof Array) {
  233. currentPageSavedArray.value = list;
  234. }
  235. }
  236. // 执行一次 获取保存的查询信息
  237. initSaveQueryInfoCode();
  238. /**
  239. * 保存按钮事件
  240. */
  241. function handleSave() {
  242. // 获取实际数据转成字符串
  243. let fieldArray = getQueryInfo();
  244. if (!fieldArray) {
  245. $message.warning('空条件不能保存');
  246. return;
  247. }
  248. let content = JSON.stringify(fieldArray);
  249. openSaveInfoModal(content);
  250. }
  251. // 输入保存标题 弹框显示
  252. function openSaveInfoModal(content) {
  253. saveInfo.visible = true;
  254. saveInfo.title = '';
  255. saveInfo.content = content;
  256. }
  257. /**
  258. * 确认保存查询信息
  259. */
  260. function doSaveQueryInfo() {
  261. let { title, content, saveCode } = saveInfo;
  262. let index = getTitleIndex(title);
  263. if (index >= 0) {
  264. // 已存在是否覆盖
  265. Modal.confirm({
  266. title: '提示',
  267. content: `${title} 已存在,是否覆盖?`,
  268. okText: '确认',
  269. cancelText: '取消',
  270. onOk: () => {
  271. currentPageSavedArray.value.splice(index, 1, {
  272. content,
  273. title,
  274. type: matchType.value,
  275. });
  276. $ls.set(saveCode, currentPageSavedArray.value);
  277. saveInfo.visible = false;
  278. },
  279. });
  280. } else {
  281. currentPageSavedArray.value.push({
  282. content,
  283. title,
  284. type: matchType.value,
  285. });
  286. $ls.set(saveCode, currentPageSavedArray.value);
  287. saveInfo.visible = false;
  288. }
  289. }
  290. // 根据填入的 title找本地存储的信息,如果有需要询问是否覆盖
  291. function getTitleIndex(title) {
  292. let savedArray = currentPageSavedArray.value;
  293. let index = -1;
  294. for (let i = 0; i < savedArray.length; i++) {
  295. if (savedArray[i].title == title) {
  296. index = i;
  297. break;
  298. }
  299. }
  300. return index;
  301. }
  302. /**
  303. * 获取左侧所有查询条件,如果没有/或者条件无效则返回false
  304. */
  305. function getQueryInfo(isEmit = false) {
  306. let arr = dynamicRowValues.values;
  307. if (!arr || arr.length == 0) {
  308. return false;
  309. }
  310. let fieldArray: any = [];
  311. let fieldProps = fieldProperties.value;
  312. for (let item of arr) {
  313. if (item.field && (item.val || item.val === 0) && item.rule) {
  314. let tempVal: any = toRaw(item.val);
  315. if (tempVal instanceof Array) {
  316. tempVal = tempVal.join(',');
  317. }
  318. let fieldName = getRealFieldName(item);
  319. let obj = {
  320. field: fieldName,
  321. rule: item.rule,
  322. val: tempVal,
  323. };
  324. if (isEmit === true) {
  325. //如果当前数据用于emit事件,需要设置dbtype和type
  326. let prop = fieldProps[item.field];
  327. if (prop) {
  328. obj['type'] = prop.view;
  329. obj['dbType'] = prop.type;
  330. }
  331. }
  332. fieldArray.push(obj);
  333. }
  334. }
  335. if (fieldArray.length == 0) {
  336. return false;
  337. }
  338. return fieldArray;
  339. }
  340. //update-begin-author:taoyan date:2022-5-31 for: VUEN-1148 主子联动下,高级查询查子表数据,无效
  341. /**
  342. * 高级查询参数 字段名
  343. * 获取后台需要的 字段名格式:表名,字段名
  344. * @param item
  345. */
  346. function getRealFieldName(item) {
  347. let fieldName = item.field;
  348. if (fieldName.indexOf('@') > 0) {
  349. fieldName = fieldName.replace('@', ',');
  350. }
  351. return fieldName;
  352. }
  353. //update-end-author:taoyan date:2022-5-31 for: VUEN-1148 主子联动下,高级查询查子表数据,无效
  354. /**
  355. * 右侧数据 点击事件,重新将数据显示到左侧
  356. * @param key
  357. * @param node
  358. */
  359. function handleTreeSelect(key, { node }) {
  360. console.log(key, node);
  361. let title = node.dataRef.title;
  362. let arr = currentPageSavedArray.value.filter((item) => item.title == title);
  363. if (arr && arr.length > 0) {
  364. // 拿到数据渲染
  365. let { content, type } = arr[0];
  366. let data = JSON.parse(content);
  367. let rowsValues: SuperQueryItem[] = [];
  368. for (let item of data) {
  369. rowsValues.push(Object.assign({}, { key: randomString(16) }, item));
  370. }
  371. dynamicRowValues.values = rowsValues;
  372. matchType.value = type;
  373. }
  374. }
  375. /**
  376. * 右侧数据 删除事件
  377. */
  378. function handleRemoveSaveInfo(title) {
  379. console.log(title);
  380. let index = getTitleIndex(title);
  381. if (index >= 0) {
  382. currentPageSavedArray.value.splice(index, 1);
  383. $ls.set(saveInfo.saveCode, currentPageSavedArray.value);
  384. }
  385. }
  386. /*-----------------------右侧保存信息相关-end---------------------------*/
  387. // 获取所有字段配置信息
  388. function getAllFields(properties) {
  389. // 获取所有配置 查询字段 是否联合查询
  390. // const {properties, table, title } = json;
  391. let allFields = {};
  392. let order = 1;
  393. let treeData: TreeModel[] = [];
  394. /* let mainNode:TreeModel = {
  395. title,
  396. value: table,
  397. disabled: true,
  398. children: []
  399. };*/
  400. //treeData.push(mainNode)
  401. Object.keys(properties).map((field) => {
  402. let item = properties[field];
  403. if (item.view == 'table') {
  404. // 子表字段
  405. // 联合查询开启才需要子表字段作为查询条件
  406. let subProps = item['properties'] || item['fields'];
  407. let subTableOrder = order * 100;
  408. let subNode: TreeModel = {
  409. title: item.title,
  410. value: field,
  411. disabled: true,
  412. children: [],
  413. order: subTableOrder,
  414. };
  415. Object.keys(subProps).map((subField) => {
  416. let subItem = subProps[subField];
  417. // 保证排序统一
  418. subItem['order'] = subTableOrder + subItem['order'];
  419. let subFieldKey = field + '@' + subField;
  420. allFields[subFieldKey] = subItem;
  421. subNode.children!.push({
  422. title: subItem.title,
  423. value: subFieldKey,
  424. isLeaf: true,
  425. order: subItem['order'],
  426. });
  427. });
  428. orderField(subNode);
  429. treeData.push(subNode);
  430. order++;
  431. } else {
  432. // 主表字段
  433. //let fieldKey = table+'@'+field
  434. let fieldKey = field;
  435. allFields[fieldKey] = item;
  436. treeData.push({
  437. title: item.title,
  438. value: fieldKey,
  439. isLeaf: true,
  440. order: item.order,
  441. });
  442. }
  443. });
  444. orderField(treeData);
  445. return { allFields, treeData };
  446. }
  447. //根据字段的order重新排序
  448. function orderField(data) {
  449. let arr = data.children || data;
  450. arr.sort(function (a, b) {
  451. return a.order - b.order;
  452. });
  453. }
  454. function initDefaultValues(values) {
  455. const { params, matchType } = values;
  456. if (params) {
  457. let rowsValues: SuperQueryItem[] = [];
  458. for (let item of params) {
  459. rowsValues.push(Object.assign({}, { key: randomString(16) }, item));
  460. }
  461. dynamicRowValues.values = rowsValues;
  462. matchType.value = matchType;
  463. }
  464. }
  465. return {
  466. formRef,
  467. init,
  468. dynamicRowValues,
  469. matchType,
  470. registerModal,
  471. handleSubmit,
  472. handleCancel,
  473. handleSave,
  474. doSaveQueryInfo,
  475. saveInfo,
  476. saveTreeData,
  477. handleRemoveSaveInfo,
  478. handleTreeSelect,
  479. fieldTreeData,
  480. addOne,
  481. removeOne,
  482. setFormModel,
  483. getSchema,
  484. loading,
  485. getQueryInfo,
  486. initDefaultValues,
  487. };
  488. }