QueryForm.vue 10.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310
  1. <template>
  2. <div>
  3. <el-form :model="queryForm" label-width="auto" :inline="true" ref="formRef">
  4. <div class="select-group">
  5. <el-form-item label="问题来源:" prop="queryParam.source">
  6. <el-select
  7. v-model="queryForm.queryParam.source"
  8. placeholder="全部"
  9. clearable
  10. @change="handleSelectChange"
  11. >
  12. <el-option
  13. v-for="item in sourceOptions"
  14. :key="item.value"
  15. :label="item.label"
  16. :value="item.value"
  17. />
  18. </el-select>
  19. </el-form-item>
  20. <el-form-item label="类型:" prop="queryParam.issueTypeList">
  21. <el-cascader
  22. v-model="issueTypeValue"
  23. :options="options"
  24. :props="issueMainTypeProp"
  25. clearable
  26. collapse-tags
  27. :show-all-levels="false"
  28. popper-class="special-cascader"
  29. :disabled="typeDisable"
  30. @change="handleIssueMainTypeChange"
  31. />
  32. </el-form-item>
  33. <el-form-item label="地点:" prop="queryParam.workspaceId">
  34. <el-cascader
  35. v-model="workLocation"
  36. :options="locationOptions"
  37. :props="locationProp"
  38. clearable
  39. collapse-tags
  40. :show-all-levels="false"
  41. popper-class="special-cascader"
  42. @change="handleCascaderChange"
  43. />
  44. </el-form-item>
  45. <el-form-item label="处理状态:" prop="queryParam.issueState">
  46. <el-select v-model="tempState" clearable @change="handleIssueStateChange">
  47. <el-option
  48. v-for="item in issueStateOptions"
  49. :key="item.value"
  50. :label="item.label"
  51. :value="item.value"
  52. />
  53. </el-select>
  54. </el-form-item>
  55. <el-form-item label="生效状态:" prop="queryParam.hide">
  56. <el-select v-model="queryForm.queryParam.hide" clearable>
  57. <el-option
  58. v-for="item in hideStateOptions"
  59. :key="item.value"
  60. :label="item.label"
  61. :value="item.value"
  62. />
  63. </el-select>
  64. </el-form-item>
  65. <el-form-item label="日期:">
  66. <el-date-picker
  67. v-model="dateRange"
  68. type="daterange"
  69. range-separator="~"
  70. start-placeholder="开始时间"
  71. end-placeholder="结束时间"
  72. clearable
  73. unlink-panels
  74. value-format="YYYY-MM-DD HH:mm:ss"
  75. :default-time="defaultTime"
  76. @change="handleDateChange"
  77. />
  78. </el-form-item>
  79. </div>
  80. <div class="btn-group">
  81. <el-form-item>
  82. <el-button class="search-btn" type="primary" @click="handleSearch">查询</el-button>
  83. <el-button class="reset-btn" @click="handleReset">重置</el-button>
  84. <el-button class="reset-btn" @click="handleExport" v-if="!isShowTab">导出</el-button>
  85. </el-form-item>
  86. </div>
  87. </el-form>
  88. </div>
  89. </template>
  90. <script setup lang="ts">
  91. import type { FormInstance } from 'element-plus';
  92. import { reactive, ref } from 'vue';
  93. import { sourceOptions, hideStateOptions, issueStateOptions } from './constant.question';
  94. import { TableQueryForm } from '@/api/datamanagement/alert-default';
  95. interface Props {
  96. isShowTab: boolean; // true展示数据,false默认数据
  97. aiOptions: Array<any>;
  98. manualOptions: Array<any>;
  99. locationOptions: Array<any>;
  100. }
  101. const props = defineProps<Props>();
  102. const emits = defineEmits(['onSearch', 'onReset', 'onExport']);
  103. const formRef = ref<FormInstance>();
  104. const queryForm = reactive<TableQueryForm>({
  105. pageNumber: 1,
  106. pageSize: 10,
  107. queryParam: {},
  108. });
  109. type MainOption = {
  110. value: number;
  111. label: string;
  112. children: {
  113. value: number;
  114. label: string;
  115. }[];
  116. };
  117. const options = ref<MainOption[]>([]);
  118. const typeDisable = ref(true);
  119. const issueTypeValue = ref([]); // 问题类型,级联选择器
  120. const issueMainTypeProp = { multiple: true, expandTrigger: 'hover' as const };
  121. const workShopIds = ref([]);
  122. const workLocation = ref([]); // 级联选择器,为二维数组(提取workspaceId)
  123. const locationProp = { multiple: true, expandTrigger: 'hover' as const }; // 级联选择器(打开多选)
  124. const tempState = ref(''); // 状态,字符串转number[]
  125. const dateRange = ref([]); // 时间段,拆分成startTime/endTime
  126. const defaultTime = ref<[Date, Date]>([
  127. new Date(2000, 1, 1, 0, 0, 0),
  128. new Date(2000, 2, 1, 23, 59, 59),
  129. ]);
  130. const handleSearch = () => {
  131. emits('onSearch', queryForm);
  132. };
  133. const handleReset = () => {
  134. workShopIds.value = [];
  135. issueTypeValue.value = [];
  136. typeDisable.value = true;
  137. workLocation.value = [];
  138. tempState.value = '';
  139. dateRange.value = [];
  140. Reflect.deleteProperty(queryForm.queryParam, 'startTime');
  141. Reflect.deleteProperty(queryForm.queryParam, 'endTime');
  142. Reflect.deleteProperty(queryForm.queryParam, 'issueMainTypeList');
  143. Reflect.deleteProperty(queryForm.queryParam, 'issueTypeList');
  144. formRef.value?.resetFields();
  145. emits('onReset', queryForm);
  146. };
  147. const handleExport = () => {
  148. emits('onExport', queryForm, workShopIds.value);
  149. };
  150. const handleSelectChange = () => {
  151. if (Number(queryForm.queryParam.source) === 1) {
  152. typeDisable.value = false;
  153. options.value = props.aiOptions;
  154. } else if (Number(queryForm.queryParam.source) === 2) {
  155. typeDisable.value = false;
  156. options.value = props.manualOptions;
  157. } else {
  158. typeDisable.value = true;
  159. options.value = [];
  160. queryForm.queryParam.issueMainTypeList = undefined;
  161. queryForm.queryParam.issueTypeList = undefined;
  162. }
  163. };
  164. const handleIssueMainTypeChange = () => {
  165. if (issueTypeValue.value.length !== 0) {
  166. const arrMain = [];
  167. const arrSub = [];
  168. issueTypeValue.value.forEach((item) => {
  169. arrMain.push(item[0]);
  170. arrSub.push(item[1]);
  171. });
  172. queryForm.queryParam.issueMainTypeList = [...new Set(arrMain)];
  173. queryForm.queryParam.issueTypeList = arrSub;
  174. } else {
  175. Reflect.deleteProperty(queryForm.queryParam, 'issueMainTypeList');
  176. Reflect.deleteProperty(queryForm.queryParam, 'issueTypeList');
  177. }
  178. };
  179. const handleCascaderChange = () => {
  180. if (workLocation.value.length !== 0) {
  181. const arr = [];
  182. workShopIds.value = [];
  183. workLocation.value.forEach((item) => {
  184. arr.push(item[1]);
  185. workShopIds.value.push(item[0]);
  186. });
  187. queryForm.queryParam.workspaceId = arr;
  188. workShopIds.value = [...new Set(workShopIds.value)];
  189. } else {
  190. Reflect.deleteProperty(queryForm.queryParam, 'workspaceId');
  191. }
  192. };
  193. const handleIssueStateChange = () => {
  194. if (tempState.value) queryForm.queryParam.issueState = JSON.parse(tempState.value);
  195. else Reflect.deleteProperty(queryForm.queryParam, 'issueState');
  196. };
  197. const handleDateChange = () => {
  198. if (dateRange.value != null) {
  199. queryForm.queryParam.startTime = dateRange.value[0];
  200. queryForm.queryParam.endTime = dateRange.value[1];
  201. } else {
  202. Reflect.deleteProperty(queryForm.queryParam, 'startTime');
  203. Reflect.deleteProperty(queryForm.queryParam, 'endTime');
  204. }
  205. };
  206. // TODO: cascader点击任意位置选中,DOM方式实现一级,CSS方式无法穿透
  207. // TODO: el-cascader组件需添加 @expand-change="handleLocationExpandChange"(当前暂时删除)
  208. // const curLocationLevel = ref(0);
  209. // const handleLocationExpandChange = (event) => {
  210. // curLocationLevel.value = event.length;
  211. // nextTick(() => {
  212. // setCascaderDomEvent();
  213. // });
  214. // };
  215. // const setCascaderDomEvent = () => {
  216. // const cascaderDom = document.querySelectorAll('.special-cascader .el-cascader-menu__list');
  217. // if (cascaderDom.length >= curLocationLevel.value - 1) {
  218. // const optionDom = cascaderDom[curLocationLevel.value] as Element;
  219. // optionDom.querySelectorAll('.el-cascader-node__label').forEach((label: Element) => {
  220. // const nextDom = label.nextElementSibling;
  221. // label.addEventListener('click', cascaderCheckEvent);
  222. // if (!nextDom) {
  223. // (label as HTMLElement).style.cursor = 'pointer';
  224. // }
  225. // });
  226. // }
  227. // if (curLocationLevel.value) {
  228. // const optionDom = cascaderDom[curLocationLevel.value - 1] as Element;
  229. // optionDom.querySelectorAll('.el-cascader-node__label').forEach((label: Element) => {
  230. // const nextDom = label.nextElementSibling;
  231. // label.addEventListener('click', cascaderCheckEvent);
  232. // if (!nextDom) {
  233. // (label as HTMLElement).style.cursor = 'pointer';
  234. // }
  235. // });
  236. // }
  237. // };
  238. // const cascaderCheckEvent = (event: MouseEvent) => {
  239. // // 查找对应的输入框
  240. // let brother = (event.target as HTMLElement).previousElementSibling; // 获取前一个兄弟元素
  241. // const input = brother?.querySelector('input[type="checkbox"], input[type="radio"]'); // 支持复选框和单选框
  242. // if (input) {
  243. // (input as HTMLInputElement).click(); // 模拟点击复选框
  244. // }
  245. // // 如果有子菜单,展开/收起子菜单
  246. // const childMenu = (event.target as HTMLElement).nextElementSibling;
  247. // if (childMenu && childMenu.classList.contains('el-cascader-menu__list')) {
  248. // // 这里可以根据需求添加展开/收起的逻辑
  249. // }
  250. // };
  251. </script>
  252. <style scoped lang="less">
  253. .el-form {
  254. display: flex;
  255. justify-content: space-between;
  256. }
  257. :deep(.el-form--inline .el-form-item) {
  258. margin-right: 10px;
  259. }
  260. :deep(.el-form-item__label) {
  261. padding-left: 10px;
  262. }
  263. .select-group {
  264. flex: 1;
  265. }
  266. .btn-group {
  267. .search-btn {
  268. width: 65px;
  269. height: 32px;
  270. background: #1890ff;
  271. border-radius: 2px;
  272. }
  273. .reset-btn {
  274. width: 65px;
  275. height: 32px;
  276. border-radius: 2px;
  277. border: 1px solid #1890ff;
  278. color: #1890ff;
  279. }
  280. }
  281. .el-select {
  282. --el-select-width: 215px;
  283. }
  284. </style>