newAdd.vue 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704
  1. <script setup lang="ts">
  2. defineOptions({
  3. name: "evaluateNewAdd"
  4. });
  5. import { ref, reactive, onMounted } from "vue";
  6. import one from "@/assets/svg/2.svg";
  7. import two from "@/assets/svg/1.svg";
  8. import one1 from "@/assets/svg/2-2.svg";
  9. import two2 from "@/assets/svg/1-1.svg";
  10. import { useRouter, useRoute } from "vue-router";
  11. import { Edit } from "@element-plus/icons-vue";
  12. import { ElMessageBox, ElMessage } from "element-plus";
  13. import { postAddRelationList, postUpdateDept } from "@/api/dimension";
  14. import { useAppStoreHook } from "@/store/modules/app";
  15. import { addQuota } from "@/api/indexDefine";
  16. import { postUpdateTemplateIn, deleteIndicator } from "@/api/templateInfo";
  17. import {
  18. postAddDimension,
  19. getDimensionRemove,
  20. getQuotaByDimensionId
  21. } from "@/api/dimension";
  22. import editMould from "./editMould.vue";
  23. import {
  24. VueDraggable,
  25. useDraggable,
  26. type DraggableEvent,
  27. type UseDraggableReturn
  28. } from "vue-draggable-plus";
  29. import { delQuota, postAddDisposableQuota } from "@/api/indexDefine";
  30. import settingIndexDrawer from "./settingIndexDrawer.vue";
  31. import {
  32. postAddTemplate,
  33. getInfo,
  34. getListBy,
  35. postUpdate
  36. } from "@/api/templateInfo";
  37. import importIndex from "./importIndex.vue";
  38. const router = useRouter();
  39. const route = useRoute();
  40. const formRef = ref();
  41. const active = ref(0);
  42. const editDrawer = ref();
  43. const editDrawerShow = ref(false);
  44. const titleShow = ref(false);
  45. // 序号
  46. const order = ref();
  47. // 指标设置
  48. const settingIndexDrawerRef = ref();
  49. const settingIndexDrawerShow = ref(false);
  50. // 导入指标
  51. const importIndexRef = ref();
  52. const importIndexShow = ref(false);
  53. const handleSelect = index => {
  54. // console.log(index);
  55. active.value = index;
  56. };
  57. const tepName = ref();
  58. const tepNameForm = reactive({
  59. tpName: "",
  60. id: ""
  61. });
  62. onMounted(() => {
  63. if (route.query.tpName && route.query.id) {
  64. tepNameForm.tpName = route.query.tpName;
  65. tepNameForm.id = route.query.id;
  66. }
  67. });
  68. const tableData = ref([]);
  69. // 新建模板
  70. const postAddTemplateApi = async () => {
  71. const res = await postAddTemplate({ ...tepNameForm });
  72. Object.assign(tepNameForm, {
  73. tpName: "",
  74. id: ""
  75. });
  76. if (res.code === 200) {
  77. ElMessage({
  78. message: "创建成功",
  79. type: "success"
  80. });
  81. tepNameForm.tpName = res.data.tpName;
  82. tepNameForm.id = res.data.id;
  83. titleShow.value = true;
  84. } else {
  85. ElMessage.error(res.msg);
  86. }
  87. };
  88. // 考核维度卡片
  89. const eaxmCard = ref([]);
  90. // 获取维度
  91. const getListByApi = async (id?: number | string) => {
  92. eaxmCard.value = [];
  93. const obj = {
  94. tpId: tepNameForm.id,
  95. id
  96. };
  97. const { code, data, msg } = await getListBy(obj);
  98. if (code === 200) {
  99. titleShow.value = true;
  100. eaxmCard.value = data;
  101. eaxmCard.value.forEach(item => {
  102. initializeTableData(item);
  103. });
  104. } else {
  105. ElMessage.error(msg);
  106. }
  107. };
  108. const getAddListByApi = async id => {
  109. const obj = {
  110. tpId: id
  111. };
  112. const { code, data, msg } = await getListBy(obj);
  113. if (code === 200) {
  114. eaxmCard.value = data;
  115. eaxmCard.value.forEach(item => {
  116. initializeTableData(item);
  117. });
  118. } else {
  119. ElMessage.error(msg);
  120. }
  121. };
  122. // 获取指标信息
  123. const paramsIndex = reactive({
  124. id: "",
  125. tpId: "",
  126. dimId: ""
  127. });
  128. const getQuotaByDimensionIdApi = async id => {
  129. paramsIndex.dimId = id;
  130. const { code, data, msg } = await getQuotaByDimensionId(paramsIndex);
  131. if (code === 200) {
  132. return data;
  133. } else {
  134. ElMessage.error(msg);
  135. return [];
  136. }
  137. };
  138. const initializeTableData = async item => {
  139. item.tableData = await getQuotaByDimensionIdApi(item.id);
  140. };
  141. const amountTo = itemList => {
  142. let num = 0;
  143. if (itemList) {
  144. itemList.forEach(item => {
  145. num = num + item.weight;
  146. });
  147. return num;
  148. }
  149. };
  150. const addDimension = reactive({
  151. list: [
  152. {
  153. id: "",
  154. dimName: "",
  155. dimWeight: "",
  156. mode: ""
  157. }
  158. ],
  159. dimName: "",
  160. dimWeight: "",
  161. mode: "",
  162. showIndicRemark: "",
  163. showScoreRule: "",
  164. showDatasource: "",
  165. showTargetValue: "",
  166. showFinalValue: "",
  167. showChallengeValue: "",
  168. showStartValue: "",
  169. remark: ""
  170. });
  171. // 创建考核维度
  172. const createAdd = () => {
  173. order.value = eaxmCard.value.length + 1;
  174. editDrawer.value.open(tepNameForm, "新建", order.value);
  175. };
  176. const backChange = () => {
  177. useAppStoreHook().toggleSideBar(true, "打开");
  178. router.back();
  179. };
  180. // 更新模板
  181. const postUpdateTemplateInApi = async () => {
  182. const { code, msg } = await postUpdateTemplateIn({
  183. tpName: tepNameForm.tpName,
  184. id: tepNameForm.id
  185. });
  186. if (code == 200) {
  187. titleShow.value = true;
  188. } else {
  189. ElMessage.error(msg);
  190. }
  191. };
  192. // 保存
  193. const save = () => {
  194. if (titleShow.value) {
  195. router.back();
  196. useAppStoreHook().toggleSideBar(true, "打开");
  197. } else {
  198. formRef.value.validate(valid => {
  199. if (valid) {
  200. if (tepNameForm.id) {
  201. getAddListByApi(tepNameForm.id);
  202. postUpdateTemplateInApi();
  203. if (router.query) {
  204. }
  205. } else {
  206. postAddTemplateApi();
  207. }
  208. }
  209. });
  210. }
  211. };
  212. const deleteRow = row => {
  213. console.log(row);
  214. ElMessageBox.confirm(
  215. "指标删除后不可恢复,请谨慎操作!",
  216. "确定删除该指标吗?",
  217. {
  218. confirmButtonText: "确认",
  219. cancelButtonText: "取消",
  220. type: "warning"
  221. }
  222. )
  223. .then(async () => {
  224. const { code, msg } = await deleteIndicator(row.id);
  225. if (code === 200) {
  226. ElMessage({
  227. type: "success",
  228. message: "删除成功"
  229. });
  230. // initializeTableData(row.dimId);
  231. getListByApi();
  232. } else {
  233. ElMessage.error(msg);
  234. }
  235. })
  236. .catch(() => {
  237. ElMessage({
  238. type: "info",
  239. message: "用户取消"
  240. });
  241. });
  242. };
  243. // 编辑
  244. const editPen = (item, order) => {
  245. editDrawer.value.open(item, "编辑", order);
  246. };
  247. // 删除考核维度
  248. const deletePen = item => {
  249. ElMessageBox.confirm(
  250. "该维度删除后不可恢复,请谨慎操作!",
  251. "确定删除考核维度",
  252. {
  253. confirmButtonText: "确认",
  254. cancelButtonText: "取消",
  255. type: "warning"
  256. }
  257. )
  258. .then(async () => {
  259. // eaxmCard.value.splice(index, 1);
  260. const { code, msg } = await getDimensionRemove(item.id);
  261. if (code === 200) {
  262. getListByApi();
  263. ElMessage({
  264. type: "success",
  265. message: "删除成功"
  266. });
  267. } else {
  268. ElMessage.error(msg);
  269. }
  270. })
  271. .catch(() => {
  272. ElMessage({
  273. type: "info",
  274. message: "用户取消"
  275. });
  276. });
  277. };
  278. const settingIndex = row => {
  279. settingIndexDrawerRef.value.open(row);
  280. };
  281. const importIndexDialog = row => {
  282. importIndexRef.value.open(row);
  283. };
  284. const importIndexOne = async row => {
  285. let formula = JSON.stringify({
  286. noConditionFormula: ""
  287. });
  288. const { code, data, msg } = await postAddDisposableQuota({ name: "" });
  289. if (code == 200) {
  290. const res = await postAddRelationList([
  291. {
  292. dimId: row.id,
  293. indId: data.id,
  294. tpId: row.tpId,
  295. formula,
  296. scoreStandard: 0
  297. }
  298. ]);
  299. if (res.code === 200) {
  300. initializeTableData(row);
  301. ElMessage({
  302. type: "success",
  303. message: "添加成功"
  304. });
  305. } else {
  306. ElMessage.error(res.msg);
  307. }
  308. } else {
  309. ElMessage.error(msg);
  310. }
  311. };
  312. // 拖拽
  313. const elDraggable = ref();
  314. const elDraggableTableData = ref();
  315. // 更新
  316. const postUpdateDeptApi = async (id, dimName, order) => {
  317. await postUpdateDept({
  318. id,
  319. dimName,
  320. order,
  321. tpId: tepNameForm.id
  322. });
  323. };
  324. const onEnd = (e: DraggableEvent) => {
  325. eaxmCard.value.map((item, index) => {
  326. postUpdateDeptApi(item.id, item.dimName, index + 1);
  327. });
  328. };
  329. const onStart = (e: DraggableEvent) => {};
  330. const onUpdate = (e: DraggableEvent) => {};
  331. // const { start } = useDraggable(elDraggableTableData, eaxmCard.tableData, {
  332. // animation: 150,
  333. // ghostClass: "ghost",
  334. // onStart() {
  335. // // console.log("start");
  336. // },
  337. // onUpdate(item, index) {
  338. // console.log("update", item);
  339. // console.log("index", index);
  340. // }
  341. // });
  342. // const onEndTbl = (item: any, id: any) => {
  343. // console.log(item, id);
  344. // item.map((item, index) => {
  345. // postUpdateApi(id, item.id, index + 1);
  346. // });
  347. // };
  348. // 指标更新
  349. // const postUpdateApi = async (dimId, indId, order) => {
  350. // await postUpdate({
  351. // tpId: tepNameForm.id,
  352. // dimId,
  353. // indId,
  354. // order
  355. // });
  356. // };
  357. const postUpdateApi = async () => {
  358. console.log();
  359. // indexOf.indName = indexOf.name
  360. const { code, msg } = await postUpdate(indexOf);
  361. if (code == 200) {
  362. getListByApi();
  363. ElMessage.success("编辑成功");
  364. } else {
  365. ElMessage.error(msg);
  366. }
  367. };
  368. const indexOf = reactive({
  369. id: "",
  370. tpId: "",
  371. dimId: "",
  372. indId: "",
  373. valueInput: 0,
  374. designatedPersonnel: "",
  375. scoreStandard: 0,
  376. remark: "",
  377. createUser: "",
  378. createTime: 0,
  379. updateUser: "",
  380. updateTime: 0,
  381. isDelete: 0,
  382. scoreRule: "",
  383. targetValue: 0,
  384. finalValue: 0,
  385. challengeValue: 0,
  386. startValue: 0,
  387. datasoure: "",
  388. weight: 0,
  389. scoreValue: 0,
  390. formula: "",
  391. formulaType: 0,
  392. order: 0,
  393. indName: ""
  394. });
  395. const editConfig = ref<any>({
  396. trigger: "click",
  397. mode: "cell"
  398. });
  399. const tableVxeRef = ref();
  400. const editClosedEvent = ({ row, column }) => {
  401. console.log("row", row);
  402. const $table = tableVxeRef.value;
  403. if ($table) {
  404. Object.assign(indexOf, row);
  405. postUpdateApi();
  406. }
  407. };
  408. </script>
  409. <template>
  410. <div class="w-[100%]">
  411. <!-- 导入指标 -->
  412. <importIndex
  413. ref="importIndexRef"
  414. v-model="importIndexShow"
  415. @handClickInit="getListByApi"
  416. />
  417. <!-- 指标设置 -->
  418. <settingIndexDrawer
  419. ref="settingIndexDrawerRef"
  420. v-model:drawerValue="settingIndexDrawerShow"
  421. />
  422. <!-- 新增、编辑模块 -->
  423. <editMould
  424. ref="editDrawer"
  425. v-model:drawerValue="editDrawerShow"
  426. @handClick="getAddListByApi"
  427. />
  428. <div class="w-[100%] flex justify-evenly">
  429. <div class="left-box">
  430. <el-text class="cursor-pointer" @click="backChange"
  431. ><el-icon> <ArrowLeft /> </el-icon>返回</el-text
  432. >
  433. </div>
  434. <div class="center-box">
  435. <div
  436. style="max-width: 220px"
  437. class="m-auto flex justify-between items-center"
  438. >
  439. <div
  440. :class="{ 'step-success': !titleShow, 'step-error': titleShow }"
  441. class="w-[100px] flex justify-center items-center"
  442. @click="titleShow = false"
  443. >
  444. <one v-if="titleShow" />
  445. <two2 v-else />基础信息
  446. </div>
  447. <div
  448. :class="{ 'step-success': titleShow, 'step-error': !titleShow }"
  449. class="w-[100px] flex justify-center items-center"
  450. @click="titleShow = true"
  451. >
  452. <two v-if="titleShow" />
  453. <one1 v-else />考核指标
  454. </div>
  455. </div>
  456. </div>
  457. <div class="right-box">
  458. <el-button type="primary" class="mr-2" @click="save()">保存</el-button>
  459. </div>
  460. </div>
  461. <div class="mt-2">
  462. <div v-if="!titleShow" class="w-[40%] m-auto mt-10">
  463. <el-form
  464. ref="formRef"
  465. :model="tepNameForm"
  466. label-width="auto"
  467. style="max-width: 600px"
  468. >
  469. <el-form-item
  470. prop="tpName"
  471. label="模板名称"
  472. :rules="[
  473. {
  474. required: true,
  475. message: '请输入模板名称',
  476. trigger: 'blur'
  477. }
  478. ]"
  479. >
  480. <el-input
  481. v-model="tepNameForm.tpName"
  482. placeholder="最多输入100字"
  483. />
  484. </el-form-item>
  485. </el-form>
  486. </div>
  487. <div v-else class="w-[90%] m-auto mt-4">
  488. <div class="relative h-10">
  489. <el-button class="float-right" type="primary" plain @click="createAdd"
  490. >创建考核维度</el-button
  491. >
  492. </div>
  493. <VueDraggable
  494. ref="elDraggable"
  495. v-model="eaxmCard"
  496. :animation="150"
  497. ghostClass="ghost"
  498. class="flex flex-col gap-2 p-4 w-300px h-300px m-auto bg-gray-500/5 rounded"
  499. @start="onStart"
  500. @update="onUpdate"
  501. @end="onEnd"
  502. >
  503. <el-card v-for="(item, index) in eaxmCard" :key="index" class="mb-3">
  504. <template #header>
  505. <div class="card-header">
  506. <span>{{ item.dimName }}{{ item.dimWeight }}%)</span>
  507. <div class="float-right mr-7">
  508. <el-icon class="mr-3" @click="editPen(item, index + 1)">
  509. <EditPen />
  510. </el-icon>
  511. <el-icon @click="deletePen(item)">
  512. <Delete class="text-red-500" />
  513. </el-icon>
  514. </div>
  515. </div>
  516. </template>
  517. <!-- <el-table :data="item.tableData" style="width: 100%" max-height="250">
  518. <el-table-column ref="elDraggableTableData" fixed prop="name" label="指标名称">
  519. <template #default="{ row }">
  520. <div>{{ row.name }}</div>
  521. </template>
  522. </el-table-column>
  523. <el-table-column v-if="item.showIndicRemark" prop="remark" label="指标说明" width="120" />
  524. <el-table-column v-if="item.showScoreRule" prop="scoreRule" label="评价标准" width="300" />
  525. <el-table-column v-if="item.showDatasource" prop="stshowDatasourceate" label="数据来源" width="120" />
  526. <el-table-column v-if="item.mode" prop="weight" label="权重" width="120" />
  527. <el-table-column v-if="item.showTargetValue" prop="targetValue" label="目标值" width="120" />
  528. <el-table-column v-if="item.showFinalValue" prop="finalValue" label="完成值" width="120" />
  529. <el-table-column v-if="item.showChallengeValue" prop="challengeValue" label="挑战值" width="120" />
  530. <el-table-column v-if="item.showStartValue" prop="startValue" label="门槛值" width="120" />
  531. <el-table-column fixed="right" label="操作">
  532. <template #default="{ row }">
  533. <el-icon class="mr-3" @click="settingIndex(row)">
  534. <Setting />
  535. </el-icon>
  536. <el-icon @click="deleteRow(row)">
  537. <Delete class="text-red-500" />
  538. </el-icon>
  539. </template>
  540. </el-table-column>
  541. </el-table> -->
  542. <vxe-table
  543. ref="tableVxeRef"
  544. border
  545. show-overflow
  546. :edit-config="editConfig"
  547. :data="item.tableData"
  548. max-height="250"
  549. @edit-closed="editClosedEvent"
  550. >
  551. <vxe-column
  552. field="indName"
  553. fixed
  554. title="指标名称"
  555. :edit-render="{ name: 'input' }"
  556. />
  557. <vxe-column
  558. v-if="item.showIndicRemark"
  559. field="remark"
  560. title="指标说明"
  561. :edit-render="{ name: 'input' }"
  562. />
  563. <vxe-column
  564. v-if="item.showScoreRule"
  565. field="scoreRule"
  566. title="评价标准"
  567. :edit-render="{ name: 'input' }"
  568. width="300"
  569. />
  570. <vxe-column
  571. v-if="item.showDatasource"
  572. field="stshowDatasourceate"
  573. title="数据来源"
  574. />
  575. <vxe-column
  576. v-if="item.mode"
  577. field="weight"
  578. title="权重"
  579. :edit-render="{ name: 'input' }"
  580. />
  581. <vxe-column
  582. field="scoreValue"
  583. title="分值"
  584. :edit-render="{ name: 'input' }"
  585. />
  586. <vxe-column
  587. v-if="item.showTargetValue"
  588. field="targetValue"
  589. title="目标值"
  590. :edit-render="{ name: 'input' }"
  591. />
  592. <!-- <vxe-column
  593. v-if="item.showFinalValue"
  594. field="finalValue"
  595. title="完成值"
  596. :edit-render="{ name: 'input' }"
  597. /> -->
  598. <vxe-column
  599. v-if="item.showChallengeValue"
  600. field="challengeValue"
  601. title="挑战值"
  602. :edit-render="{ name: 'input' }"
  603. />
  604. <vxe-column
  605. v-if="item.showStartValue"
  606. field="startValue"
  607. title="门槛值"
  608. :edit-render="{ name: 'input' }"
  609. />
  610. <vxe-column field="age" fixed="right" title="操作">
  611. <template #default="{ row }">
  612. <el-icon class="mr-3" @click="settingIndex(row)">
  613. <Setting />
  614. </el-icon>
  615. <el-icon @click="deleteRow(row)">
  616. <Delete class="text-red-500" />
  617. </el-icon>
  618. </template>
  619. </vxe-column>
  620. </vxe-table>
  621. <template #footer>
  622. <el-button
  623. type="primary"
  624. link
  625. class="mr-4"
  626. @click="importIndexOne(item)"
  627. >
  628. 添加指标
  629. </el-button>
  630. <el-button type="primary" link @click="importIndexDialog(item)">
  631. 导入指标
  632. </el-button>
  633. <span class="float-right num"
  634. >指标权重合计:{{ amountTo(item.tableData) }}</span
  635. >
  636. </template>
  637. </el-card>
  638. </VueDraggable>
  639. </div>
  640. </div>
  641. </div>
  642. </template>
  643. <style lang="scss" scoped>
  644. .left-box {
  645. display: flex;
  646. flex: 0 0 5%;
  647. align-items: center;
  648. margin: auto;
  649. text-align: center;
  650. // justify-content: center;
  651. }
  652. .center-box {
  653. flex: 0 0 70%;
  654. }
  655. .right-box {
  656. display: flex;
  657. flex: 0 0 5%;
  658. align-items: center;
  659. justify-content: center;
  660. margin: auto;
  661. }
  662. .step-success {
  663. height: 24px;
  664. padding-bottom: 5px;
  665. font-size: 16px;
  666. // font-family: PingFangSC-SNaNpxibold;
  667. font-weight: 600;
  668. line-height: 24px;
  669. color: black;
  670. color: #000000e6;
  671. border-bottom: 2px solid #022bbd;
  672. }
  673. .step-error {
  674. height: 24px;
  675. padding-bottom: 5px;
  676. font-size: 16px;
  677. // font-family: PingFangSC-SNaNpxibold;
  678. font-weight: 600;
  679. line-height: 24px;
  680. color: #0006;
  681. letter-spacing: 0;
  682. }
  683. .num {
  684. font-size: 14px;
  685. // font-family: PingFangSC-Regular;
  686. font-weight: 400;
  687. line-height: 22px;
  688. color: #0009;
  689. letter-spacing: 0;
  690. }
  691. </style>