newAdd.vue 18 KB

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