newAdd.vue 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731
  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. console.log(row, "获取的数据");
  289. const { code, data, msg } = await postAddDisposableQuota({ name: "" });
  290. if (code == 200) {
  291. const res = await postAddRelationList([
  292. {
  293. dimId: row.id,
  294. indId: data.id,
  295. tpId: row.tpId,
  296. formula,
  297. scoreStandard: 0,
  298. order: row.tableData.length + 1
  299. }
  300. ]);
  301. if (res.code === 200) {
  302. initializeTableData(row);
  303. ElMessage({
  304. type: "success",
  305. message: "添加成功"
  306. });
  307. } else {
  308. ElMessage.error(res.msg);
  309. }
  310. } else {
  311. ElMessage.error(msg);
  312. }
  313. };
  314. // 拖拽
  315. const elDraggable = ref();
  316. const elDraggableTableData = ref();
  317. // 更新
  318. const postUpdateDeptApi = async (id, dimName, order) => {
  319. await postUpdateDept({
  320. id,
  321. dimName,
  322. order,
  323. tpId: tepNameForm.id
  324. });
  325. };
  326. const onEnd = (e: DraggableEvent) => {
  327. eaxmCard.value.map((item, index) => {
  328. postUpdateDeptApi(item.id, item.dimName, index + 1);
  329. });
  330. };
  331. const onStart = (e: DraggableEvent) => {};
  332. const onUpdate = (e: DraggableEvent) => {};
  333. // const { start } = useDraggable(elDraggableTableData, eaxmCard.tableData, {
  334. // animation: 150,
  335. // ghostClass: "ghost",
  336. // onStart() {
  337. // // console.log("start");
  338. // },
  339. // onUpdate(item, index) {
  340. // console.log("update", item);
  341. // console.log("index", index);
  342. // }
  343. // });
  344. // const onEndTbl = (item: any, id: any) => {
  345. // console.log(item, id);
  346. // item.map((item, index) => {
  347. // postUpdateApi(id, item.id, index + 1);
  348. // });
  349. // };
  350. // 指标更新
  351. // const postUpdateApi = async (dimId, indId, order) => {
  352. // await postUpdate({
  353. // tpId: tepNameForm.id,
  354. // dimId,
  355. // indId,
  356. // order
  357. // });
  358. // };
  359. const postUpdateApi = async row => {
  360. console.log();
  361. // indexOf.indName = indexOf.name
  362. const { code, msg } = await postUpdate(row);
  363. if (code == 200) {
  364. getListByApi();
  365. ElMessage.success("编辑成功");
  366. } else {
  367. ElMessage.error(msg);
  368. }
  369. };
  370. const indexOf = reactive({
  371. id: "",
  372. tpId: "",
  373. dimId: "",
  374. indId: "",
  375. valueInput: 0,
  376. designatedPersonnel: "",
  377. scoreStandard: 0,
  378. remark: "",
  379. createUser: "",
  380. createTime: 0,
  381. updateUser: "",
  382. updateTime: 0,
  383. isDelete: 0,
  384. scoreRule: "",
  385. targetValue: 0,
  386. finalValue: 0,
  387. challengeValue: 0,
  388. startValue: 0,
  389. datasoure: "",
  390. weight: 0,
  391. scoreValue: 0,
  392. formula: "",
  393. formulaType: 0,
  394. order: 0,
  395. indName: ""
  396. });
  397. const editConfig = ref<any>({
  398. trigger: "click",
  399. mode: "cell"
  400. });
  401. const tableVxeRef = ref();
  402. const editClosedEvent = ({ row, column }) => {
  403. const $table = tableVxeRef.value;
  404. if ($table) {
  405. Object.assign(indexOf, row);
  406. console.log("indexOf", indexOf);
  407. postUpdateApi(row);
  408. }
  409. };
  410. // 列表行拖拽
  411. const columnConfig = reactive({
  412. useKey: true
  413. });
  414. const resultEvent = () => {
  415. const $table = tableRef.value;
  416. if ($table) {
  417. const { visibleData } = $table.getTableData();
  418. console.log(visibleData);
  419. }
  420. };
  421. const titleShowClick = () => {
  422. titleShow.value = true;
  423. if (route.query.id) {
  424. getListByApi();
  425. }
  426. };
  427. </script>
  428. <template>
  429. <div class="w-[100%]">
  430. <!-- 导入指标 -->
  431. <importIndex
  432. ref="importIndexRef"
  433. v-model="importIndexShow"
  434. @handClickInit="getListByApi"
  435. />
  436. <!-- 指标设置 -->
  437. <settingIndexDrawer
  438. ref="settingIndexDrawerRef"
  439. v-model:drawerValue="settingIndexDrawerShow"
  440. @refresh="getListByApi"
  441. />
  442. <!-- 新增、编辑模块 -->
  443. <editMould
  444. ref="editDrawer"
  445. v-model:drawerValue="editDrawerShow"
  446. @handClick="getAddListByApi"
  447. />
  448. <div class="w-[100%] flex justify-evenly">
  449. <div class="left-box">
  450. <el-text class="cursor-pointer" @click="backChange"
  451. ><el-icon> <ArrowLeft /> </el-icon>返回</el-text
  452. >
  453. </div>
  454. <div class="center-box">
  455. <div
  456. style="max-width: 220px"
  457. class="m-auto flex justify-between items-center"
  458. >
  459. <div
  460. :class="{ 'step-success': !titleShow, 'step-error': titleShow }"
  461. class="w-[100px] flex justify-center items-center"
  462. @click="titleShow = false"
  463. >
  464. <one v-if="titleShow" />
  465. <two2 v-else />基础信息
  466. </div>
  467. <div
  468. :class="{ 'step-success': titleShow, 'step-error': !titleShow }"
  469. class="w-[100px] flex justify-center items-center"
  470. @click="titleShowClick"
  471. >
  472. <two v-if="titleShow" />
  473. <one1 v-else />考核指标
  474. </div>
  475. </div>
  476. </div>
  477. <div class="right-box">
  478. <el-button type="primary" class="mr-2" @click="save()">保存</el-button>
  479. </div>
  480. </div>
  481. <div class="mt-2">
  482. <div v-if="!titleShow" class="w-[40%] m-auto mt-10">
  483. <el-form
  484. ref="formRef"
  485. :model="tepNameForm"
  486. label-width="auto"
  487. style="max-width: 600px"
  488. >
  489. <el-form-item
  490. prop="tpName"
  491. label="模板名称"
  492. :rules="[
  493. {
  494. required: true,
  495. message: '请输入模板名称',
  496. trigger: 'blur'
  497. }
  498. ]"
  499. >
  500. <el-input
  501. v-model="tepNameForm.tpName"
  502. placeholder="最多输入100字"
  503. />
  504. </el-form-item>
  505. </el-form>
  506. </div>
  507. <div v-else class="w-[90%] m-auto mt-4">
  508. <div class="relative h-10">
  509. <el-button class="float-right" type="primary" plain @click="createAdd"
  510. >创建考核维度</el-button
  511. >
  512. </div>
  513. <VueDraggable
  514. ref="elDraggable"
  515. v-model="eaxmCard"
  516. :animation="150"
  517. ghostClass="ghost"
  518. class="flex flex-col gap-2 p-4 w-300px h-300px m-auto bg-gray-500/5 rounded"
  519. @start="onStart"
  520. @update="onUpdate"
  521. @end="onEnd"
  522. >
  523. <el-card v-for="(item, index) in eaxmCard" :key="index" class="mb-3">
  524. <template #header>
  525. <div class="card-header">
  526. <span>{{ item.dimName }}({{ item.dimWeight }}%)</span>
  527. <div class="float-right mr-7">
  528. <el-icon class="mr-3" @click="editPen(item, index + 1)">
  529. <EditPen />
  530. </el-icon>
  531. <el-icon @click="deletePen(item)">
  532. <Delete class="text-red-500" />
  533. </el-icon>
  534. </div>
  535. </div>
  536. </template>
  537. <!-- <el-table :data="item.tableData" style="width: 100%" max-height="250">
  538. <el-table-column ref="elDraggableTableData" fixed prop="name" label="指标名称">
  539. <template #default="{ row }">
  540. <div>{{ row.name }}</div>
  541. </template>
  542. </el-table-column>
  543. <el-table-column v-if="item.showIndicRemark" prop="remark" label="指标说明" width="120" />
  544. <el-table-column v-if="item.showScoreRule" prop="scoreRule" label="评价标准" width="300" />
  545. <el-table-column v-if="item.showDatasource" prop="stshowDatasourceate" label="数据来源" width="120" />
  546. <el-table-column v-if="item.mode" prop="weight" label="权重" width="120" />
  547. <el-table-column v-if="item.showTargetValue" prop="targetValue" label="目标值" width="120" />
  548. <el-table-column v-if="item.showFinalValue" prop="finalValue" label="完成值" width="120" />
  549. <el-table-column v-if="item.showChallengeValue" prop="challengeValue" label="挑战值" width="120" />
  550. <el-table-column v-if="item.showStartValue" prop="startValue" label="门槛值" width="120" />
  551. <el-table-column fixed="right" label="操作">
  552. <template #default="{ row }">
  553. <el-icon class="mr-3" @click="settingIndex(row)">
  554. <Setting />
  555. </el-icon>
  556. <el-icon @click="deleteRow(row)">
  557. <Delete class="text-red-500" />
  558. </el-icon>
  559. </template>
  560. </el-table-column>
  561. </el-table> -->
  562. <vxe-table
  563. ref="tableVxeRef"
  564. border
  565. show-overflow
  566. :edit-config="editConfig"
  567. :data="item.tableData"
  568. max-height="250"
  569. :row-config="rowConfig"
  570. :column-config="columnConfig"
  571. @edit-closed="editClosedEvent"
  572. >
  573. <vxe-column
  574. field="indName"
  575. fixed
  576. drag-sort
  577. title="指标名称"
  578. :edit-render="{ name: 'input' }"
  579. />
  580. <vxe-column
  581. v-if="item.showIndicRemark"
  582. field="remark"
  583. title="指标说明"
  584. :edit-render="{ name: 'input' }"
  585. drag-sort
  586. />
  587. <vxe-column
  588. v-if="item.showScoreRule"
  589. field="scoreRule"
  590. title="评价标准"
  591. :edit-render="{ name: 'input' }"
  592. width="300"
  593. />
  594. <vxe-column
  595. v-if="item.showDatasource"
  596. field="stshowDatasourceate"
  597. title="数据来源"
  598. :edit-render="
  599. item.stshowDatasourceate === 'BI' ? null : { name: 'input' }
  600. "
  601. />
  602. <vxe-column
  603. v-if="item.mode == 0 || item.dimWeight != 0"
  604. field="weight"
  605. title="权重"
  606. :edit-render="{ name: 'input' }"
  607. />
  608. <vxe-column
  609. field="scoreValue"
  610. title="分值"
  611. :edit-render="{ name: 'input' }"
  612. />
  613. <vxe-column
  614. v-if="item.showTargetValue"
  615. field="targetValue"
  616. title="目标值"
  617. :edit-render="{ name: 'input' }"
  618. />
  619. <!-- <vxe-column
  620. v-if="item.showFinalValue"
  621. field="finalValue"
  622. title="完成值"
  623. :edit-render="{ name: 'input' }"
  624. /> -->
  625. <vxe-column
  626. v-if="item.showChallengeValue"
  627. field="challengeValue"
  628. title="挑战值"
  629. :edit-render="{ name: 'input' }"
  630. />
  631. <vxe-column
  632. v-if="item.showStartValue"
  633. field="startValue"
  634. title="门槛值"
  635. :edit-render="{ name: 'input' }"
  636. />
  637. <vxe-column field="age" fixed="right" title="操作">
  638. <template #default="{ row }">
  639. <el-icon class="mr-3" @click="settingIndex(row)">
  640. <Setting />
  641. </el-icon>
  642. <el-icon @click="deleteRow(row)">
  643. <Delete class="text-red-500" />
  644. </el-icon>
  645. </template>
  646. </vxe-column>
  647. </vxe-table>
  648. <template #footer>
  649. <el-button
  650. type="primary"
  651. link
  652. class="mr-4"
  653. @click="importIndexOne(item)"
  654. >
  655. 添加指标
  656. </el-button>
  657. <el-button type="primary" link @click="importIndexDialog(item)">
  658. 导入指标
  659. </el-button>
  660. <span class="float-right num"
  661. >指标权重合计:{{ amountTo(item.tableData) }}</span
  662. >
  663. </template>
  664. </el-card>
  665. </VueDraggable>
  666. </div>
  667. </div>
  668. </div>
  669. </template>
  670. <style lang="scss" scoped>
  671. .left-box {
  672. display: flex;
  673. flex: 0 0 5%;
  674. align-items: center;
  675. margin: auto;
  676. text-align: center;
  677. // justify-content: center;
  678. }
  679. .center-box {
  680. flex: 0 0 70%;
  681. }
  682. .right-box {
  683. display: flex;
  684. flex: 0 0 5%;
  685. align-items: center;
  686. justify-content: center;
  687. margin: auto;
  688. }
  689. .step-success {
  690. height: 24px;
  691. padding-bottom: 5px;
  692. font-size: 16px;
  693. // font-family: PingFangSC-SNaNpxibold;
  694. font-weight: 600;
  695. line-height: 24px;
  696. color: black;
  697. color: #000000e6;
  698. border-bottom: 2px solid #022bbd;
  699. }
  700. .step-error {
  701. height: 24px;
  702. padding-bottom: 5px;
  703. font-size: 16px;
  704. // font-family: PingFangSC-SNaNpxibold;
  705. font-weight: 600;
  706. line-height: 24px;
  707. color: #0006;
  708. letter-spacing: 0;
  709. }
  710. .num {
  711. font-size: 14px;
  712. // font-family: PingFangSC-Regular;
  713. font-weight: 400;
  714. line-height: 22px;
  715. color: #0009;
  716. letter-spacing: 0;
  717. }
  718. </style>