addExam.vue 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627
  1. <script setup lang="ts">
  2. import { ref, reactive, nextTick, watch } from "vue";
  3. import { ElMessageBox, ElMessage } from "element-plus";
  4. import { Calendar } from "@element-plus/icons-vue";
  5. import dayjs from "dayjs";
  6. import { postAddAssessment } from "@/api/assessment";
  7. import {
  8. postListTreeWithUser,
  9. postListTree,
  10. postListTreeWithUserApi,
  11. treeDept
  12. } from "@/api/department";
  13. import { encryption } from "@/utils/encrypt";
  14. // 人员,医疗组,负责人
  15. import {
  16. postUserList,
  17. postOrganizationUserPage,
  18. getLeaderList
  19. } from "@/api/userSetting";
  20. // 医疗组
  21. import { getTemplateInfoList } from "@/api/templateInfo";
  22. // 获取医疗组的数据
  23. import { postPageGroup } from "@/api/userGroup";
  24. import ElPicker from "@/components/ELPicker/index.vue";
  25. const $emit = defineEmits(["addHandClick"]);
  26. const dialogVisibleAdd = ref(false);
  27. const titleHeader = ref<any>("发起考核");
  28. // 季度 半年
  29. const ElPickerRef = ref();
  30. const form = reactive({
  31. name: "",
  32. cycle: "月度",
  33. cycleValue: "",
  34. assessmentType: null,
  35. listArr: [
  36. {
  37. assessmentObjectId: "",
  38. idList: [],
  39. assessmentObjectName: "",
  40. assessmentModelId: "",
  41. assessmentModelName: ""
  42. }
  43. ]
  44. });
  45. const rules = reactive({
  46. name: [{ required: true, message: "请输入考核名称", trigger: "blur" }],
  47. cycle: [{ required: true, message: "请选择考核周期", trigger: "change" }]
  48. });
  49. const formLeftRules = reactive({
  50. left: [{ required: true, message: "请选择考核指标", trigger: "blur" }],
  51. value: [{ required: true, message: "请选择被考核对象", trigger: "blur" }]
  52. });
  53. const formRightRules = reactive({
  54. left: [{ required: true, message: "请选择考核指标", trigger: "blur" }],
  55. right: [{ required: true, message: "请选择考核模板", trigger: "blur" }]
  56. });
  57. const formRef = ref();
  58. const handleClose = () => {
  59. formRef.value.clearValidate(); // 清除验证错误
  60. formRef.value.resetFields(); // 重置表单字段
  61. dialogVisibleAdd.value = !dialogVisibleAdd.value;
  62. ElMessage({
  63. message: "已关闭"
  64. });
  65. // ElMessageBox.confirm("确认关闭弹窗吗?")
  66. // .then(() => {})
  67. // .catch(() => {
  68. // // catch error
  69. // });
  70. };
  71. const arrList = ref([]); // 考核对象与模版设置
  72. const transformArrayFormat = data => {
  73. return data
  74. .map(item => {
  75. return item.idList.map((id, index) => {
  76. return {
  77. assessmentObjectId: item?.assessmentObjectId[index],
  78. assessmentObjectName: item?.assessmentObjectName[index],
  79. assessmentModelId: item?.assessmentModelId,
  80. assessmentModelName: item?.assessmentModelName
  81. };
  82. });
  83. })
  84. .flat();
  85. };
  86. // 添加部门保存
  87. const saveDepartment = () => {
  88. formRef.value.validate(async valid => {
  89. if (valid) {
  90. if (!form.cycleValue) {
  91. ElMessage.error("请选择考核周期的具体时间");
  92. return false;
  93. }
  94. console.log("考核周期", form.listArr);
  95. form.assessmentObjectList = transformArrayFormat(form.listArr);
  96. if (timeType.value == "月度") {
  97. form.cycleValue = dayjs(new Date(form.cycleValue)).format("YYYY-MM");
  98. }
  99. if (timeType.value == "年度") {
  100. form.cycleValue = dayjs(new Date(form.cycleValue)).format("YYYY");
  101. }
  102. if (timeType.value == "日期") {
  103. form.cycleValue = dayjs(new Date(form.cycleValue)).format("YYYY-MM-DD");
  104. }
  105. form.assessmentObjectList = form.assessmentObjectList.filter(
  106. item => item.assessmentObjectId && item.assessmentObjectName
  107. );
  108. delete form.listArr;
  109. const { code, msg } = await postAddAssessment(form);
  110. if (code === 200) {
  111. ElMessage({
  112. message: "添加成功",
  113. type: "success"
  114. });
  115. $emit("addHandClick");
  116. dialogVisibleAdd.value = false;
  117. } else {
  118. // ElMessage.error(msg);
  119. }
  120. }
  121. });
  122. };
  123. const open = (item: any, index: string) => {
  124. // postListTreeWithUserApi();
  125. assessmentTypeShow.value = true;
  126. Object.assign(form, {
  127. name: "",
  128. cycle: "月度",
  129. cycleValue: "",
  130. assessmentType: null,
  131. listArr: [
  132. {
  133. idList: [],
  134. assessmentObjectId: null,
  135. assessmentObjectName: null,
  136. assessmentModelId: null,
  137. assessmentModelName: null
  138. }
  139. ]
  140. });
  141. if (item) {
  142. titleHeader.value = index;
  143. }
  144. dialogVisibleAdd.value = true;
  145. };
  146. const addNew = () => {
  147. form.listArr.push({
  148. assessmentObjectId: "",
  149. idList: [],
  150. assessmentObjectName: "",
  151. assessmentModelId: "",
  152. assessmentModelName: ""
  153. });
  154. arrList.value.push([]);
  155. // form.assessmentObjectList.left.push({ value: "" });
  156. };
  157. const deleteItem = (index: any) => {
  158. form.listArr.splice(index, 1);
  159. // form.assessmentObjectList.right.splice(index, 1);
  160. };
  161. // 单选
  162. const timeType = ref<any>("月度");
  163. const quarterValue = ref(true);
  164. const format = ref<any>("YYYY-MM");
  165. const pickerType = ref<any>("month");
  166. const handleRegionChange = (value: any) => {
  167. timeType.value = value;
  168. console.log("timeType.value", timeType.value);
  169. switch (value) {
  170. case "年度":
  171. form.cycleValue = "";
  172. format.value = "YYYY";
  173. pickerType.value = "year";
  174. break;
  175. case "月度":
  176. form.cycleValue = "";
  177. format.value = "YYYY-MM";
  178. pickerType.value = "month";
  179. break;
  180. case "日期":
  181. form.cycleValue = "";
  182. format.value = "YYYY-MM-DD";
  183. pickerType.value = "";
  184. break;
  185. case "季度":
  186. form.cycleValue = "";
  187. quarterValue.value = true;
  188. break;
  189. case "半年":
  190. form.cycleValue = "";
  191. quarterValue.value = false;
  192. break;
  193. }
  194. };
  195. const yearTime = ref<any>(dayjs(new Date()).format("YYYY"));
  196. const decreaseYear = () => {
  197. yearTime.value = dayjs().year(yearTime.value).subtract(1, "year").year(); // 减一年
  198. };
  199. const increaseYear = () => {
  200. yearTime.value = dayjs().year(yearTime.value).add(1, "year").year(); // 加一年
  201. };
  202. const monthOne = item => {
  203. let start = "";
  204. let end = "";
  205. switch (item) {
  206. case "第一季度":
  207. start = `${yearTime.value}-01-01`;
  208. end = `${yearTime.value}-03-31`;
  209. break;
  210. case "第二季度":
  211. start = `${yearTime.value}-04-01`;
  212. end = `${yearTime.value}-06-30`;
  213. break;
  214. case "第三季度":
  215. start = `${yearTime.value}-07-01`;
  216. end = `${yearTime.value}-09-30`;
  217. break;
  218. case "第四季度":
  219. start = `${yearTime.value}-10-01`;
  220. end = `${yearTime.value}-12-31`;
  221. break;
  222. case "上半年":
  223. start = `${yearTime.value}-01-01`;
  224. end = `${yearTime.value}-06-30`;
  225. break;
  226. case "下半年":
  227. start = `${yearTime.value}-07-01`;
  228. end = `${yearTime.value}-12-31`;
  229. break;
  230. }
  231. form.cycleValue = `${yearTime.value}年${item}`;
  232. // return `从 ${start} 到 ${end}`; // 设置时间区间
  233. };
  234. // 部门人员与考核模板数据
  235. const treeDeptList = ref([]);
  236. const templateparams = reactive({
  237. page: 1,
  238. pageSize: 100
  239. });
  240. const resTmp = ref([]);
  241. // 医疗 -- 部门负责人
  242. const selectRefs = ref();
  243. const handChange = index => {
  244. const arr = treeDeptList.value.filter(item => {
  245. return form.listArr[index].idList.includes(item.groupCode);
  246. });
  247. form.listArr[index].assessmentObjectId = arr.map(item => item.groupCode);
  248. form.listArr[index].assessmentObjectName = arr.map(item => item.groupName);
  249. };
  250. const handChange1 = index => {
  251. const arr = treeDeptList.value.filter(item => {
  252. return form.listArr[index].idList.includes(item.userCode);
  253. });
  254. form.listArr[index].assessmentObjectId = arr.map(item => item.userCode);
  255. form.listArr[index].assessmentObjectName = arr.map(item => item.realName);
  256. };
  257. const assessmentTypeRef = ref();
  258. const handleRreeSelect = index => {
  259. const arr = assessmentTypeRef.value[index].getCheckedNodes().filter(item => {
  260. return item.children.length == 0;
  261. });
  262. if (form.assessmentType === 0) {
  263. // 更新选中的 idList
  264. // form.listArr[index].idList = filteredNodes;
  265. // let aa = [];
  266. // form.listArr[index].idList.map(item => {
  267. // if (item.substring(0, 4) == "user") {
  268. // aa.push(item);
  269. // }
  270. // });
  271. // console.log(11111, aa);
  272. // form.listArr[index].idList = aa;
  273. form.listArr[index].assessmentObjectId = arr.map(item => {
  274. if (item.value.substring(0, 4) == "user") {
  275. return item.value;
  276. }
  277. });
  278. form.listArr[index].assessmentObjectName = arr.map(item => {
  279. if (item.value.substring(0, 4) == "user") {
  280. return item.label;
  281. }
  282. });
  283. } else {
  284. form.listArr[index].assessmentObjectId = arr.map(item => {
  285. return item.value;
  286. });
  287. form.listArr[index].assessmentObjectName = arr.map(item => {
  288. return item.label;
  289. });
  290. }
  291. };
  292. const handleSelect = index => {
  293. form.listArr[index].assessmentModelName = form.listArr[index].am.tpName;
  294. form.listArr[index].assessmentModelId = form.listArr[index].am.id;
  295. };
  296. const aaaa = a => {
  297. console.log(a);
  298. };
  299. // 考核类型
  300. const dpetTree = ref();
  301. // 转换函数 --- 部门
  302. const convertDepartmentDataRecursive = data => {
  303. return data.map(department => {
  304. const { deptCode, deptName, childrenRes } = department;
  305. return {
  306. value: deptCode,
  307. label: deptName,
  308. children:
  309. childrenRes.length > 0
  310. ? childrenRes.map(child => convertDepartmentDataRecursive([child])[0])
  311. : []
  312. };
  313. });
  314. };
  315. // 转换函数 --- 人员
  316. const convertDepartmentDataRecursive_Person = data => {
  317. return data.map(department => {
  318. const { userNameNew, userCodeNew, children } = department;
  319. return {
  320. value: userCodeNew,
  321. label: userNameNew,
  322. children:
  323. children.length > 0
  324. ? children.map(
  325. child => convertDepartmentDataRecursive_Person([child])[0]
  326. )
  327. : []
  328. };
  329. });
  330. };
  331. const treeDeptListOkay = ref([]);
  332. const assessmentTypeShow = ref(true);
  333. const assessmentTypeApi = async value => {
  334. assessmentTypeShow.value = false;
  335. // 人员,医疗组,负责人
  336. const { data, code } = await getTemplateInfoList(templateparams);
  337. resTmp.value = data.records;
  338. switch (value) {
  339. case 0:
  340. postListTreeWithUserApi();
  341. break;
  342. case 1:
  343. const { data, code } = await postListTree();
  344. dpetTree.value = convertDepartmentDataRecursive(data);
  345. break;
  346. case 2:
  347. const yiliao = await postPageGroup({
  348. pageNumber: 1,
  349. pageSize: 1000
  350. });
  351. treeDeptList.value = yiliao.data.records;
  352. break;
  353. case 3:
  354. const fuzhere = await getLeaderList({
  355. type: "dept"
  356. });
  357. treeDeptList.value = fuzhere.data;
  358. }
  359. };
  360. const monthTime = ref("");
  361. defineExpose({
  362. open
  363. });
  364. const handChangeTree = value => {
  365. console.log(1122131, value);
  366. // if (Array.isArray(value)) {
  367. // value.forEach(item => {
  368. // if (item.substring(0, 4) != "user") {
  369. // return delete item;
  370. // }
  371. // });
  372. // }
  373. };
  374. const idList = ref([]);
  375. </script>
  376. <template>
  377. <div>
  378. <el-dialog v-model="dialogVisibleAdd" :title="titleHeader" width="500">
  379. <el-form
  380. ref="formRef"
  381. :model="form"
  382. label-width="auto"
  383. style="max-width: 600px"
  384. :rules="rules"
  385. label-position="top"
  386. >
  387. <el-form-item label="考核名称" prop="name">
  388. <el-input v-model="form.name" placeholder="请输入" />
  389. </el-form-item>
  390. <el-form-item label="考核周期" prop="cycle">
  391. <el-radio-group v-model="form.cycle" @change="handleRegionChange">
  392. <el-radio value="月度" size="large">月度</el-radio>
  393. <el-radio value="季度" size="large">季度</el-radio>
  394. <el-radio value="半年" size="large">半年</el-radio>
  395. <el-radio value="年度" size="large">年度</el-radio>
  396. <el-radio value="日期" size="large">日期</el-radio>
  397. </el-radio-group>
  398. <el-date-picker
  399. v-if="
  400. timeType === '月度' || timeType === '日期' || timeType === '年度'
  401. "
  402. v-model="form.cycleValue"
  403. :type="pickerType"
  404. :format="format"
  405. placeholder="请选择"
  406. @change="aaaa"
  407. />
  408. <el-dropdown
  409. v-else-if="timeType === '季度' || timeType === '半年'"
  410. trigger="click"
  411. >
  412. <span class="el-dropdown-link navbar-bg-hover select-none">
  413. <el-input
  414. v-model="form.cycleValue"
  415. style="width: 240px"
  416. placeholder="请选择"
  417. :prefix-icon="Calendar"
  418. />
  419. </span>
  420. <template #dropdown>
  421. <el-dropdown-menu class="setting" style="width: 300px">
  422. <div class="flex justify-between align-center text-base mt-4">
  423. <div
  424. class="cursor-pointer ml-4 text-xs pt-2"
  425. @click="decreaseYear"
  426. >
  427. <el-icon>
  428. <DArrowLeft />
  429. </el-icon>
  430. </div>
  431. <div>{{ yearTime }}</div>
  432. <div
  433. class="cursor-pointer mr-4 text-xs pt-2"
  434. @click="increaseYear"
  435. >
  436. <el-icon>
  437. <DArrowRight />
  438. </el-icon>
  439. </div>
  440. </div>
  441. <div
  442. v-if="quarterValue"
  443. class="flex justify-center align-center mt-5 mb-5"
  444. >
  445. <el-dropdown-item @click="monthOne('一季度')">
  446. 一季度
  447. </el-dropdown-item>
  448. <el-dropdown-item @click="monthOne('二季度')">
  449. 二季度
  450. </el-dropdown-item>
  451. <el-dropdown-item @click="monthOne('三季度')">
  452. 三季度
  453. </el-dropdown-item>
  454. <el-dropdown-item @click="monthOne('四季度')">
  455. 四季度
  456. </el-dropdown-item>
  457. </div>
  458. <div v-else class="flex justify-around align-center mt-5 mb-5">
  459. <el-dropdown-item @click="monthOne('上半年')">
  460. 上半年
  461. </el-dropdown-item>
  462. <el-dropdown-item @click="monthOne('下半年')">
  463. 下半年
  464. </el-dropdown-item>
  465. </div>
  466. </el-dropdown-menu>
  467. </template>
  468. </el-dropdown>
  469. </el-form-item>
  470. <el-form-item label="被考核类型">
  471. <el-select
  472. v-model="form.assessmentType"
  473. placeholder="请选择被考核类型"
  474. @change="assessmentTypeApi"
  475. >
  476. <el-option label="员工" :value="0" />
  477. <el-option label="部门" :value="1" />
  478. <el-option label="医疗组" :value="2" />
  479. <el-option label="部门负责人" :value="3" />
  480. </el-select>
  481. </el-form-item>
  482. <el-form-item
  483. label="被考核对象与模板设置"
  484. prop="form1"
  485. label-position="top"
  486. >
  487. <div class="w-full flex">
  488. <div class="w-1/3">
  489. <el-form
  490. label-position="top"
  491. :model="form.listArr"
  492. :rules="formLeftRules"
  493. >
  494. <el-form-item label="被考核对象" prop="left">
  495. <div
  496. v-for="(item, index) in form.listArr"
  497. :key="index"
  498. class="w-full mt-1"
  499. >
  500. <el-tree-select
  501. v-if="form.assessmentType === 0"
  502. ref="assessmentTypeRef"
  503. v-model="item.idList"
  504. multiple
  505. :data="convertDepartmentDataRecursive_Person(treeDept)"
  506. :render-after-expand="false"
  507. show-checkbox
  508. style="width: 180px"
  509. @change="handChangeTree"
  510. @check-change="handleRreeSelect(index)"
  511. />
  512. <el-tree-select
  513. v-if="form.assessmentType === 1"
  514. ref="assessmentTypeRef"
  515. v-model="item.idList"
  516. :data="dpetTree"
  517. show-checkbox
  518. multiple
  519. style="width: 180px"
  520. :render-after-expand="false"
  521. @check-change="handleRreeSelect(index)"
  522. />
  523. <el-select
  524. v-if="form.assessmentType == 2"
  525. ref="selectRefs"
  526. v-model="item.idList"
  527. multiple
  528. @change="handChange(index)"
  529. >
  530. <el-option
  531. v-for="(it, id) in treeDeptList"
  532. :key="id"
  533. :label="it.groupName"
  534. :value="it.groupCode"
  535. />
  536. </el-select>
  537. <el-select
  538. v-if="form.assessmentType == 3"
  539. ref="selectRefs"
  540. v-model="item.idList"
  541. multiple
  542. @change="handChange1(index)"
  543. >
  544. <el-option
  545. v-for="it in treeDeptList"
  546. :key="it.userCode"
  547. :label="it.realName"
  548. :value="it.userCode"
  549. />
  550. </el-select>
  551. <el-select v-if="assessmentTypeShow" multiple />
  552. </div>
  553. </el-form-item>
  554. </el-form>
  555. </div>
  556. <div class="w-1/2 ml-7">
  557. <el-form
  558. label-position="top"
  559. :model="form.listArr"
  560. :rules="formRightRules"
  561. >
  562. <el-form-item label="考核模板" prop="right">
  563. <div
  564. v-for="(item, index) in form.listArr"
  565. :key="index"
  566. class="w-full flex mt-1"
  567. >
  568. <el-select
  569. v-model="item.am"
  570. placeholder="请选择"
  571. filterable
  572. style="width: 180px"
  573. value-key="id"
  574. @change="handleSelect(index)"
  575. >
  576. <el-option
  577. v-for="itemTmp in resTmp"
  578. :key="itemTmp.id"
  579. :label="itemTmp.tpName"
  580. :value="itemTmp"
  581. style="width: 180px"
  582. />
  583. </el-select>
  584. <div
  585. v-if="index !== 0"
  586. class="ml-7 cursor-pointer w-1"
  587. @click="deleteItem(index)"
  588. >
  589. <el-text type="danger">
  590. <el-icon>
  591. <Delete />
  592. </el-icon>
  593. </el-text>
  594. </div>
  595. </div>
  596. </el-form-item>
  597. </el-form>
  598. </div>
  599. </div>
  600. </el-form-item>
  601. <el-form-item>
  602. <template #label>
  603. <div class="cursor-pointer w-14" @click="addNew">
  604. <el-text type="primary">
  605. <el-icon> <Plus /> </el-icon>添加
  606. </el-text>
  607. </div>
  608. </template>
  609. </el-form-item>
  610. </el-form>
  611. <template #footer>
  612. <div class="dialog-footer">
  613. <el-button @click="handleClose">取消</el-button>
  614. <el-button type="primary" @click="saveDepartment"> 确认 </el-button>
  615. </div>
  616. </template>
  617. </el-dialog>
  618. </div>
  619. </template>