newAdd.vue 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705
  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. @refresh="getListByApi"
  422. />
  423. <!-- 新增、编辑模块 -->
  424. <editMould
  425. ref="editDrawer"
  426. v-model:drawerValue="editDrawerShow"
  427. @handClick="getAddListByApi"
  428. />
  429. <div class="w-[100%] flex justify-evenly">
  430. <div class="left-box">
  431. <el-text class="cursor-pointer" @click="backChange"
  432. ><el-icon> <ArrowLeft /> </el-icon>返回</el-text
  433. >
  434. </div>
  435. <div class="center-box">
  436. <div
  437. style="max-width: 220px"
  438. class="m-auto flex justify-between items-center"
  439. >
  440. <div
  441. :class="{ 'step-success': !titleShow, 'step-error': titleShow }"
  442. class="w-[100px] flex justify-center items-center"
  443. @click="titleShow = false"
  444. >
  445. <one v-if="titleShow" />
  446. <two2 v-else />基础信息
  447. </div>
  448. <div
  449. :class="{ 'step-success': titleShow, 'step-error': !titleShow }"
  450. class="w-[100px] flex justify-center items-center"
  451. @click="titleShow = true"
  452. >
  453. <two v-if="titleShow" />
  454. <one1 v-else />考核指标
  455. </div>
  456. </div>
  457. </div>
  458. <div class="right-box">
  459. <el-button type="primary" class="mr-2" @click="save()">保存</el-button>
  460. </div>
  461. </div>
  462. <div class="mt-2">
  463. <div v-if="!titleShow" class="w-[40%] m-auto mt-10">
  464. <el-form
  465. ref="formRef"
  466. :model="tepNameForm"
  467. label-width="auto"
  468. style="max-width: 600px"
  469. >
  470. <el-form-item
  471. prop="tpName"
  472. label="模板名称"
  473. :rules="[
  474. {
  475. required: true,
  476. message: '请输入模板名称',
  477. trigger: 'blur'
  478. }
  479. ]"
  480. >
  481. <el-input
  482. v-model="tepNameForm.tpName"
  483. placeholder="最多输入100字"
  484. />
  485. </el-form-item>
  486. </el-form>
  487. </div>
  488. <div v-else class="w-[90%] m-auto mt-4">
  489. <div class="relative h-10">
  490. <el-button class="float-right" type="primary" plain @click="createAdd"
  491. >创建考核维度</el-button
  492. >
  493. </div>
  494. <VueDraggable
  495. ref="elDraggable"
  496. v-model="eaxmCard"
  497. :animation="150"
  498. ghostClass="ghost"
  499. class="flex flex-col gap-2 p-4 w-300px h-300px m-auto bg-gray-500/5 rounded"
  500. @start="onStart"
  501. @update="onUpdate"
  502. @end="onEnd"
  503. >
  504. <el-card v-for="(item, index) in eaxmCard" :key="index" class="mb-3">
  505. <template #header>
  506. <div class="card-header">
  507. <span>{{ item.dimName }}({{ item.dimWeight }}%)</span>
  508. <div class="float-right mr-7">
  509. <el-icon class="mr-3" @click="editPen(item, index + 1)">
  510. <EditPen />
  511. </el-icon>
  512. <el-icon @click="deletePen(item)">
  513. <Delete class="text-red-500" />
  514. </el-icon>
  515. </div>
  516. </div>
  517. </template>
  518. <!-- <el-table :data="item.tableData" style="width: 100%" max-height="250">
  519. <el-table-column ref="elDraggableTableData" fixed prop="name" label="指标名称">
  520. <template #default="{ row }">
  521. <div>{{ row.name }}</div>
  522. </template>
  523. </el-table-column>
  524. <el-table-column v-if="item.showIndicRemark" prop="remark" label="指标说明" width="120" />
  525. <el-table-column v-if="item.showScoreRule" prop="scoreRule" label="评价标准" width="300" />
  526. <el-table-column v-if="item.showDatasource" prop="stshowDatasourceate" label="数据来源" width="120" />
  527. <el-table-column v-if="item.mode" prop="weight" label="权重" width="120" />
  528. <el-table-column v-if="item.showTargetValue" prop="targetValue" label="目标值" width="120" />
  529. <el-table-column v-if="item.showFinalValue" prop="finalValue" label="完成值" width="120" />
  530. <el-table-column v-if="item.showChallengeValue" prop="challengeValue" label="挑战值" width="120" />
  531. <el-table-column v-if="item.showStartValue" prop="startValue" label="门槛值" width="120" />
  532. <el-table-column fixed="right" label="操作">
  533. <template #default="{ row }">
  534. <el-icon class="mr-3" @click="settingIndex(row)">
  535. <Setting />
  536. </el-icon>
  537. <el-icon @click="deleteRow(row)">
  538. <Delete class="text-red-500" />
  539. </el-icon>
  540. </template>
  541. </el-table-column>
  542. </el-table> -->
  543. <vxe-table
  544. ref="tableVxeRef"
  545. border
  546. show-overflow
  547. :edit-config="editConfig"
  548. :data="item.tableData"
  549. max-height="250"
  550. @edit-closed="editClosedEvent"
  551. >
  552. <vxe-column
  553. field="indName"
  554. fixed
  555. title="指标名称"
  556. :edit-render="{ name: 'input' }"
  557. />
  558. <vxe-column
  559. v-if="item.showIndicRemark"
  560. field="remark"
  561. title="指标说明"
  562. :edit-render="{ name: 'input' }"
  563. />
  564. <vxe-column
  565. v-if="item.showScoreRule"
  566. field="scoreRule"
  567. title="评价标准"
  568. :edit-render="{ name: 'input' }"
  569. width="300"
  570. />
  571. <vxe-column
  572. v-if="item.showDatasource"
  573. field="stshowDatasourceate"
  574. title="数据来源"
  575. />
  576. <vxe-column
  577. v-if="item.mode"
  578. field="weight"
  579. title="权重"
  580. :edit-render="{ name: 'input' }"
  581. />
  582. <vxe-column
  583. field="scoreValue"
  584. title="分值"
  585. :edit-render="{ name: 'input' }"
  586. />
  587. <vxe-column
  588. v-if="item.showTargetValue"
  589. field="targetValue"
  590. title="目标值"
  591. :edit-render="{ name: 'input' }"
  592. />
  593. <!-- <vxe-column
  594. v-if="item.showFinalValue"
  595. field="finalValue"
  596. title="完成值"
  597. :edit-render="{ name: 'input' }"
  598. /> -->
  599. <vxe-column
  600. v-if="item.showChallengeValue"
  601. field="challengeValue"
  602. title="挑战值"
  603. :edit-render="{ name: 'input' }"
  604. />
  605. <vxe-column
  606. v-if="item.showStartValue"
  607. field="startValue"
  608. title="门槛值"
  609. :edit-render="{ name: 'input' }"
  610. />
  611. <vxe-column field="age" fixed="right" title="操作">
  612. <template #default="{ row }">
  613. <el-icon class="mr-3" @click="settingIndex(row)">
  614. <Setting />
  615. </el-icon>
  616. <el-icon @click="deleteRow(row)">
  617. <Delete class="text-red-500" />
  618. </el-icon>
  619. </template>
  620. </vxe-column>
  621. </vxe-table>
  622. <template #footer>
  623. <el-button
  624. type="primary"
  625. link
  626. class="mr-4"
  627. @click="importIndexOne(item)"
  628. >
  629. 添加指标
  630. </el-button>
  631. <el-button type="primary" link @click="importIndexDialog(item)">
  632. 导入指标
  633. </el-button>
  634. <span class="float-right num"
  635. >指标权重合计:{{ amountTo(item.tableData) }}</span
  636. >
  637. </template>
  638. </el-card>
  639. </VueDraggable>
  640. </div>
  641. </div>
  642. </div>
  643. </template>
  644. <style lang="scss" scoped>
  645. .left-box {
  646. display: flex;
  647. flex: 0 0 5%;
  648. align-items: center;
  649. margin: auto;
  650. text-align: center;
  651. // justify-content: center;
  652. }
  653. .center-box {
  654. flex: 0 0 70%;
  655. }
  656. .right-box {
  657. display: flex;
  658. flex: 0 0 5%;
  659. align-items: center;
  660. justify-content: center;
  661. margin: auto;
  662. }
  663. .step-success {
  664. height: 24px;
  665. padding-bottom: 5px;
  666. font-size: 16px;
  667. // font-family: PingFangSC-SNaNpxibold;
  668. font-weight: 600;
  669. line-height: 24px;
  670. color: black;
  671. color: #000000e6;
  672. border-bottom: 2px solid #022bbd;
  673. }
  674. .step-error {
  675. height: 24px;
  676. padding-bottom: 5px;
  677. font-size: 16px;
  678. // font-family: PingFangSC-SNaNpxibold;
  679. font-weight: 600;
  680. line-height: 24px;
  681. color: #0006;
  682. letter-spacing: 0;
  683. }
  684. .num {
  685. font-size: 14px;
  686. // font-family: PingFangSC-Regular;
  687. font-weight: 400;
  688. line-height: 22px;
  689. color: #0009;
  690. letter-spacing: 0;
  691. }
  692. </style>