queryForm.vue 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484
  1. <template>
  2. <div class="form-filter">
  3. <el-form label-position="left" :model="queryForm" class='form-content'>
  4. <template v-for="(option, index) in option.queryFormFields" :key="index">
  5. <!-- input -->
  6. <el-form-item :label="option.label" class='form-input r-24 border position-box'
  7. v-if="option.inputType == 'input'" @mouseenter="option.isShowDelIcon = true"
  8. @mouseleave="option.isShowDelIcon = false">
  9. <el-input class="input-deep input-w" v-model="queryForm.data[option.key]" :placeholder="`请输入${option.label}`"
  10. clearable>
  11. </el-input>
  12. <template v-if='!option.defaultFlag'>
  13. <view class='icon-del' @click='del(option)' v-show='option.isShowDelIcon'>
  14. <el-icon>
  15. <CircleCloseFilled color='#ccc' :size='30' />
  16. </el-icon>
  17. </view>
  18. </template>
  19. </el-form-item>
  20. <!-- select -->
  21. <el-form-item :label="option.label" class='form-select-single form-date-cascader r-24 border position-box'
  22. v-if="option.inputType == 'select-single'" @mouseenter="option.isShowDelIcon = true"
  23. @mouseleave="option.isShowDelIcon = false">
  24. <el-select class='min-w ' v-if="option.label == '保险公司'" v-model="queryForm.data[option.key]" placeholder=""
  25. @change='singleChange($event, option, false)'>
  26. <el-option v-for="item in option.listOption" :key="item.value" :label="item.label" :value="item.value">
  27. </el-option>
  28. </el-select>
  29. <el-cascader v-if="option.label == '合作保险公司'" v-model="queryForm.data[option.key]" :options="option.listOption"
  30. :props="tableProps"></el-cascader>
  31. <template v-if='!option.defaultFlag'>
  32. <view class='icon-del' @click='del(option)' v-show='option.isShowDelIcon'>
  33. <el-icon>
  34. <CircleCloseFilled color='#ccc' :size='30' />
  35. </el-icon>
  36. </view>
  37. </template>
  38. </el-form-item>
  39. <!-- 日期 -->
  40. <el-form-item :label="option.label" class='form-date-picker r-24 border position-box'
  41. v-if="option.inputType == 'date-picker'" @mouseenter="option.isShowDelIcon = true"
  42. @mouseleave="option.isShowDelIcon = false">
  43. <el-date-picker v-model="queryForm.data[option.key]" type="daterange" unlink-panels start-placeholder="开始日期"
  44. end-placeholder="结束日期" :shortcuts="shortcuts" value-format="YYYY-MM-DD">
  45. <template #range-separator>
  46. <view>⇀</view>
  47. </template>
  48. </el-date-picker>
  49. <template v-if='!option.defaultFlag'>
  50. <view class='icon-del' @click='del(option)' v-show='option.isShowDelIcon'>
  51. <el-icon>
  52. <CircleCloseFilled color='#ccc' :size='30' />
  53. </el-icon>
  54. </view>
  55. </template>
  56. </el-form-item>
  57. <!-- 年份 -->
  58. <el-form-item :label="option.label" class='form-date-picker r-24 border position-box'
  59. v-if="option.inputType == 'date-year'" @mouseenter="option.isShowDelIcon = true"
  60. @mouseleave="option.isShowDelIcon = false">
  61. <el-date-picker v-model="queryForm.data[option.key]" type="year" placeholder="选择年份" value-format="YYYY">
  62. <template #range-separator>
  63. <view>⇀</view>
  64. </template>
  65. </el-date-picker>
  66. <template v-if='!option.defaultFlag'>
  67. <view class='icon-del' @click='del(option)' v-show='option.isShowDelIcon'>
  68. <el-icon>
  69. <CircleCloseFilled color='#ccc' :size='30' />
  70. </el-icon>
  71. </view>
  72. </template>
  73. </el-form-item>
  74. <!-- tree selectValue: [], //选中的Key存储的值 listOption原始数据 -->
  75. <el-form-item :label="option.label" class='form-date-tree r-24 border position-box'
  76. v-if="option.inputType == 'date-tree'" @mouseenter="option.isShowDelIcon = true"
  77. @mouseleave="option.isShowDelIcon = false">
  78. <el-tree-select v-model="queryForm.data[option.key]" :data="option.listOption" :render-after-expand="false"
  79. :props="defaultProps" node-key="id" show-checkbox multiple
  80. @check="(data, checked) => handleCheckChange(data, checked, option, queryForm.data[option.key])">
  81. <template #tag>
  82. <view v-show='option.selectValue'>{{ option.selectValue }}</view>
  83. </template>
  84. </el-tree-select>
  85. <template v-if='!option.defaultFlag'>
  86. <view class='icon-del' @click='del(option)' v-show='option.isShowDelIcon'>
  87. <el-icon>
  88. <CircleCloseFilled color='#ccc' :size='30' />
  89. </el-icon>
  90. </view>
  91. </template>
  92. </el-form-item>
  93. <!-- 级联选择 -->
  94. <el-form-item :label="option.label" class='form-date-cascader r-24 border position-box'
  95. v-if="option.inputType == 'date-cascader'" @mouseenter="option.isShowDelIcon = true"
  96. @mouseleave="option.isShowDelIcon = false">
  97. <el-cascader v-model="queryForm.data[option.key]" :options="option.listOption" clearable
  98. :props="optionProps" />
  99. <template v-if='!option.defaultFlag'>
  100. <view class='icon-del' @click='del(option)' v-show='option.isShowDelIcon'>
  101. <el-icon>
  102. <CircleCloseFilled color='#ccc' :size='30' />
  103. </el-icon>
  104. </view>
  105. </template>
  106. </el-form-item>
  107. </template>
  108. <el-button type="primary" @click='initQuery'>查询</el-button>
  109. </el-form>
  110. </div>
  111. </template>
  112. <script setup lang="ts">
  113. import { useRouter } from "vue-router";
  114. import { timestampFormat } from "@/utils/dayjs";
  115. import api from "@/api";
  116. const emit = defineEmits(["query", "delSelect"]);
  117. const props = defineProps({
  118. option: {
  119. type: Object,
  120. default: () => {
  121. return {
  122. labelWidth: {}, // label宽度,
  123. };
  124. },
  125. },
  126. });
  127. const defaultProps = {
  128. children: "children",
  129. label: "name",
  130. };
  131. const optionProps = {
  132. value: "areaCode",
  133. label: "areaCname",
  134. children: "child",
  135. };
  136. let companyoption = ref([])
  137. const tableProps = ref({
  138. value: "id",
  139. label: "name",
  140. children: "children",
  141. checkStrictly: true,
  142. });
  143. const showDelete = ref(false);
  144. let queryForm = reactive({ data: {} });
  145. const shortcuts = [
  146. {
  147. text: "今日",
  148. value: () => {
  149. const end = new Date();
  150. const start = new Date();
  151. start.setTime(start.getTime());
  152. return [start, end];
  153. },
  154. },
  155. {
  156. text: "最近7天",
  157. value: () => {
  158. const end = new Date();
  159. const start = new Date();
  160. start.setTime(start.getTime() - 3600 * 1000 * 24 * 7);
  161. return [start, end];
  162. },
  163. },
  164. {
  165. text: "本月",
  166. value: () => {
  167. const year = new Date().getFullYear();
  168. const month = new Date().getMonth() + 1;
  169. const date = new Date(year, month, 0).getDate();
  170. const end = new Date(year, month - 1, date);
  171. const start = new Date(year, new Date().getMonth(), 1);
  172. return [start, end];
  173. },
  174. },
  175. {
  176. text: "本年",
  177. value: () => {
  178. const end = new Date(new Date().getFullYear(), 11, 31);
  179. const start = new Date(new Date().getFullYear(), 0, 1);
  180. return [start, end];
  181. },
  182. },
  183. ];
  184. //获取默认值
  185. const propsOption = props.option;
  186. const isEmptyValue = (value) => {
  187. return (
  188. value == null ||
  189. value == undefined ||
  190. (Array.isArray(value) && value.length === 0)
  191. );
  192. };
  193. const initDefaultSaveForm = () => {
  194. const defaultSaveForm = {};
  195. const { queryFormFields = [] } = propsOption;
  196. const currentTimestamp = Date.now();
  197. const formatTime = (timestamp, format = "") => {
  198. return timestampFormat(timestamp, format);
  199. };
  200. // 处理不同输入类型
  201. const typeHandlers = {
  202. "date-picker": (item, baseValue) => {
  203. if (isEmptyValue(baseValue)) {
  204. const defaultTime = formatTime(currentTimestamp);
  205. return [defaultTime, defaultTime];
  206. }
  207. return baseValue;
  208. },
  209. "date-year": () => {
  210. return [formatTime(currentTimestamp, "YYYY")];
  211. },
  212. "select-multiple": (item, baseValue) => {
  213. const base = item.listOption ? baseValue : "0";
  214. const resultValue =
  215. base == "0" ? ["0"] : Array.isArray(base) ? base : [base];
  216. if (base != "0" && base != 0) {
  217. moreChange(resultValue, item, item.listOption);
  218. }
  219. return resultValue;
  220. },
  221. "select-single": (item, baseValue) => {
  222. const value = item.listOption || item.defaultValue ? baseValue : "";
  223. if (item.isFirst) {
  224. singleChange(baseValue, item, true);
  225. }
  226. return value;
  227. },
  228. "date-tree": (item, baseValue) => {
  229. return item.selectValue ? baseValue : [];
  230. },
  231. default: (_, baseValue) => baseValue,
  232. };
  233. queryFormFields.forEach((item) => {
  234. if (!item?.key) return;
  235. const { key, inputType } = item;
  236. const baseValue = queryForm.data[key] ?? item.defaultValue;
  237. const handler = typeHandlers[inputType] || typeHandlers.default;
  238. defaultSaveForm[key] = handler(item, baseValue);
  239. });
  240. // 更新表单数据并返回
  241. queryForm.data = { ...defaultSaveForm };
  242. // 处理单选框返回值格式
  243. const processedForm = { ...defaultSaveForm };
  244. queryFormFields
  245. .filter((item) => item.inputType == "select-single")
  246. .forEach((item) => {
  247. const { key } = item;
  248. const value = processedForm[key] ?? item.defaultValue;
  249. processedForm[key] =
  250. item.key === "companyId"
  251. ? value
  252. : Array.isArray(value)
  253. ? value
  254. : [value];
  255. });
  256. return processedForm;
  257. };
  258. //多选中发生变化
  259. const moreChange = (selectedValues: CheckboxValueType, item, foodList) => {
  260. const foodLabels = getMultiLabels(selectedValues, foodList, "value");
  261. item.selectValue = foodLabels.join(",");
  262. };
  263. //tree change
  264. const handleCheckChange = (data, row, option, ids) => {
  265. const foodLabels = getMultiLabels(ids, row.checkedNodes, "id");
  266. option.selectValue = foodLabels.join(",");
  267. };
  268. //数据过滤
  269. const getMultiLabels = (selectedValues, foodList, key) => {
  270. return selectedValues.map((targetValue) => {
  271. const matchedItem = foodList.find((item) => item[key] === targetValue);
  272. return matchedItem ? matchedItem.label || matchedItem.name : "";
  273. });
  274. };
  275. //单选查联动数据
  276. const singleChange = async (val, option, isDefault) => {
  277. if (option.isFirst) {
  278. //查询合作的保险公司数据
  279. const info=option.listOption.find((a)=>a.value==val)//获取选中的保险公司名称
  280. const { data } = await api.agreementApi.findTree({name:info.label});
  281. propsOption.queryFormFields.forEach((e) => {
  282. if (e.key == "partnerCompanyIds") {
  283. e.listOption = data;
  284. queryForm.data.partnerCompanyIds =
  285. option.defaultValue && isDefault ? option.defaultValue : "0";
  286. }
  287. });
  288. }
  289. };
  290. //查询
  291. const querySelect = () => {
  292. const from = { ...queryForm.data };
  293. const { queryFormFields } = propsOption;
  294. const typeHandlers = {
  295. "select-single": (item, value) => {
  296. // 特殊处理companyId,其他单选转换为数组格式
  297. return item.key === "companyId"
  298. ? value
  299. : Array.isArray(value)
  300. ? value
  301. : [value];
  302. },
  303. "date-tree": (item, value) => {
  304. // 日期树选择器:无默认值时转换为空数组
  305. return item.selectValue ? value : [];
  306. },
  307. "select-multiple": (item, value) => {
  308. // 多选框:无默认值时转换为空数组
  309. return item.defaultValue ? value : [];
  310. },
  311. "date-picker": (item, value) => {
  312. // 日期选择器:无值时转换为空数组
  313. return value ? value : [];
  314. },
  315. "date-year": (item, value) => {
  316. // 年份选择器:确保始终返回数组格式
  317. if (!value) return [];
  318. return Array.isArray(value) ? value : [value];
  319. },
  320. };
  321. queryFormFields.forEach((item) => {
  322. const { inputType, key } = item;
  323. const handler = typeHandlers[inputType];
  324. if (handler) {
  325. from[key] = handler(item, from[key]);
  326. }
  327. });
  328. return from;
  329. };
  330. const initQuery = () => {
  331. const from = querySelect();
  332. emit("query", from);
  333. };
  334. //删除
  335. const del = (option) => {
  336. const { inputType, key, id } = option;
  337. const isInputOrCompanyId = inputType === "input" || key === "companyId";
  338. if (isInputOrCompanyId) {
  339. queryForm.data[key] = "";
  340. } else {
  341. option.selectValue = "";
  342. queryForm.data[key] = [];
  343. }
  344. emit("delSelect", id);
  345. };
  346. // 暴露给父组件的方法
  347. defineExpose({
  348. initDefaultSaveForm,
  349. querySelect,
  350. });
  351. </script>
  352. <style scoped lang="scss">
  353. .form-content {
  354. display: flex;
  355. flex-wrap: wrap;
  356. .r-24 {
  357. margin-right: 24px;
  358. }
  359. .border {
  360. border-radius: 2px 2px 2px 2px;
  361. border: 1px solid #e5e5e5;
  362. }
  363. :deep(.el-form-item__label) {
  364. padding-left: 12px;
  365. }
  366. .min-w {
  367. min-width: 200px;
  368. }
  369. .input-w {
  370. width: 200px;
  371. }
  372. .position-box {
  373. position: relative;
  374. .icon-del {
  375. position: absolute;
  376. right: -8px;
  377. top: -14px;
  378. }
  379. :deep(.el-icon) {
  380. font-size: 20px;
  381. }
  382. }
  383. .text-color {
  384. color: #a3a8b3;
  385. }
  386. }
  387. // input
  388. .form-input {
  389. .input-deep {
  390. :deep(.el-input__wrapper) {
  391. box-shadow: 0 0 0 0px var(--el-input-border-color, var(--el-border-color)) inset;
  392. cursor: default;
  393. .el-input__inner {
  394. cursor: default !important;
  395. }
  396. }
  397. }
  398. }
  399. //select
  400. .form-select-single,
  401. .form-select-multiple {
  402. :deep(.el-select__wrapper) {
  403. border: none;
  404. /* 去除边框 */
  405. box-shadow: none;
  406. }
  407. }
  408. //picker
  409. .form-date-picker {
  410. :deep(.el-date-editor.el-input__wrapper) {
  411. border: none;
  412. /* 去除边框 */
  413. box-shadow: none;
  414. padding-left: 0;
  415. padding-right: 0;
  416. width: 240px;
  417. }
  418. :deep(.el-input__wrapper) {
  419. border: none;
  420. /* 去除边框 */
  421. box-shadow: none;
  422. }
  423. :deep(.el-date-editor .el-range__icon) {
  424. display: none;
  425. }
  426. }
  427. //tree
  428. .form-date-tree {
  429. :deep(.el-select__wrapper) {
  430. box-shadow: none;
  431. min-width: 240px;
  432. }
  433. }
  434. //el-cascader
  435. .form-date-cascader {
  436. :deep(.el-cascader .el-input__wrapper) {
  437. box-shadow: 0 0 0 0px var(--el-input-border-color, var(--el-border-color)) inset;
  438. }
  439. }
  440. </style>