瀏覽代碼

feat: 考核模板、考核管理

ystl_myq 1 月之前
父節點
當前提交
2db54b8718

+ 16 - 0
src/api/assessment.ts

@@ -30,6 +30,16 @@ export const getAssessmentObjectDetails = params => {
     }
   );
 };
+// 修改考核信息详情(考核指标)
+export const postUpdateAssessmentQuotaDetails = data => {
+  return http.request<addDeptList>(
+    "post",
+    "/assessment/updateAssessmentQuotaDetails",
+    {
+      data
+    }
+  );
+};
 // 考核详情
 export const getAssessmentDetails = params => {
   return http.request<addDept>("get", "/assessment/getAssessmentDetails", {
@@ -48,6 +58,12 @@ export const delAssessmentObject = data => {
     data
   });
 };
+// 考核指标批量删除考核指标相关信息
+export const delBatchDelScoreInfoVO = data => {
+  return http.request<addDept>("post", "/assessment/batchDelScoreInfoVO", {
+    data
+  });
+};
 // 考核信息详情(考核指标)
 export const getAssessmentQuotaDetails = params => {
   return http.request<addDeptList>(

+ 733 - 0
src/components/formula/manyFormula.vue

@@ -0,0 +1,733 @@
+<script setup lang="ts">
+import { ref, reactive, watch, onMounted, nextTick } from "vue";
+import { ElMessageBox, ElMessage } from "element-plus";
+// import { calculator } from "./evaluate";
+import {
+  getIndexInfo,
+  postUpdate,
+  calculateScoreByConditionMoCondition
+} from "@/api/templateInfo";
+import { conditionVerify } from "@/api/formula";
+import jishuanqi from "@/views/evaluate/children/change/components/jishuanqi.vue";
+import {
+  postListTreeWithUser,
+  postListTree,
+  postListTreeWithUserApi,
+  treeDept
+} from "@/api/department";
+import type { DrawerProps, FormItemProps, FormProps } from "element-plus";
+const $props = defineProps({
+  formulaJSON: {
+    type: Object
+  }
+});
+onMounted(() => {
+  if ($props.formulaJSON) {
+    nextTick(() => {
+      Object.assign(addmanyChange, JSON.parse($props.formulaJSON));
+      console.log("多公式", addmanyChange);
+    });
+    // let a = JSON.parse($props.formulaJSON);
+  }
+});
+const $emit = defineEmits(["handUpdataClick"]);
+const keywords = [
+  "目标值",
+  "完成值",
+  "挑战值",
+  "门槛值",
+  "增幅",
+  "降幅",
+  "上期完成值",
+  "上上期完成值"
+];
+const addmanyChange = reactive({
+  outerConditionValue: "",
+  outerConditionValueExpress: "",
+  innerConditionExpression: [
+    {
+      startValue: null,
+      endValue: null,
+      select: null,
+      comparisonStart: null,
+      comparisonEnd: null,
+      innerScore: null,
+      innerScoreExpress: null,
+      scoreRuleMoreInnerVO: [
+        // 内部公式类型
+        // {
+        //   innerConditionValue: null,
+        //   scoreRules: [
+        //     {
+        //       score: null,
+        //       startValue: null,
+        //       select: "",
+        //       endValue: null,
+        //       comparisonStart: null,
+        //       comparisonEnd: null
+        //     }
+        //   ]
+        // }
+      ]
+    }
+  ]
+});
+const jishuanqiRef = ref();
+const countNoConditionFormula = item => {
+  addmanyChange.outerConditionValue = item;
+  changeAddMay();
+};
+const countNoConditionFormula1 = (item, index) => {
+  addmanyChange.innerConditionExpression[index].endValue = item;
+  changeAddMay();
+};
+const countNoConditionFormula2 = (item, index) => {
+  // innerConditionValue
+  addmanyChange.innerConditionExpression[
+    index
+  ].scoreRuleMoreInnerVO[0].innerConditionValue = item;
+  changeAddMay();
+};
+const countNoConditionFormula3 = (item, index, indexList) => {
+  addmanyChange.innerConditionExpression[
+    index
+  ].scoreRuleMoreInnerVO[0].scoreRules[indexList].endValue = item;
+  changeAddMay();
+};
+const countNoConditionFormula4 = (item, index, indexList) => {
+  addmanyChange.innerConditionExpression[
+    index
+  ].scoreRuleMoreInnerVO[0].scoreRules[indexList].score = item;
+  changeAddMay();
+};
+const countNoConditionFormulaInnerScore = (item, index, indexList) => {
+  addmanyChange.innerConditionExpression[index].innerScore = item;
+  changeAddMay();
+};
+const changeAddMay = () => {
+  let addmanyChangeOldVal = JSON.parse(JSON.stringify(addmanyChange));
+  addmanyChange.innerConditionExpression.forEach((item, index, arr) => {
+    if (index + 1 <= arr.length) {
+      if (item.endValue) {
+        if (addmanyChangeOldVal.innerConditionExpression.length > 1) {
+          addmanyChangeOldVal.innerConditionExpression[index + 1].startValue =
+            item?.endValue;
+          addmanyChangeOldVal.innerConditionExpression[index + 1].startExpress =
+            item?.endExpress;
+          addmanyChangeOldVal.innerConditionExpression[
+            index + 1
+          ].comparisonStart = item?.comparisonEnd == "≥" ? ">" : "≥";
+        }
+      }
+      if (item.scoreRuleMoreInnerVO.length > 0) {
+        if (item.scoreRuleMoreInnerVO[0].scoreRules.length > 0) {
+          item.scoreRuleMoreInnerVO[0].scoreRules.map((it, id, arrChild) => {
+            if (id + 1 <= arrChild.length) {
+              if (it.endValue) {
+                // if (
+                //   addmanyChangeOldVal.innerConditionExpression[index + 1]
+                //     .scoreRuleMoreInnerVO.length > 0
+                // ) {
+                addmanyChangeOldVal.innerConditionExpression[
+                  index
+                ].scoreRuleMoreInnerVO[0].scoreRules[id + 1].startValue =
+                  it?.endValue;
+                addmanyChangeOldVal.innerConditionExpression[
+                  index
+                ].scoreRuleMoreInnerVO[0].scoreRules[id + 1].startExpress =
+                  it?.startExpress;
+                addmanyChangeOldVal.innerConditionExpression[
+                  index
+                ].scoreRuleMoreInnerVO[0].scoreRules[id + 1].comparisonStart =
+                  it?.comparisonEnd == "≥" ? ">" : "≥";
+                // }
+              }
+            }
+          });
+        }
+      }
+    }
+  });
+  Object.assign(addmanyChange, addmanyChangeOldVal);
+  $emit("handUpdataClick", addmanyChange);
+};
+const deleteItem = index => {
+  addmanyChange.innerConditionExpression.splice(index, 1);
+  changeAddMay();
+};
+const dataleListItemAll = (item, index) => {
+  item.scoreRuleMoreInnerVO = [];
+  changeAddMay();
+};
+const dataleListItem = (index, indexList) => {
+  addmanyChange.innerConditionExpression[
+    index
+  ].scoreRuleMoreInnerVO[0].scoreRules.splice(indexList, 1);
+  changeAddMay();
+};
+const addItemDataList = (
+  index: number,
+  itemList: any,
+  indexList: number,
+  item
+) => {
+  addmanyChange.innerConditionExpression[
+    index
+  ].scoreRuleMoreInnerVO[0].scoreRules.push({
+    select: null,
+    score: null,
+    scoreExpress: null,
+    startValue: itemList.endValue,
+    endValue: null,
+    comparisonStart: itemList.comparisonEnd,
+    comparisonEnd: null
+  });
+  addmanyChange.innerConditionExpression[index].innerScore = "";
+  changeAddMay();
+};
+// 添加子条件
+const addItemFormulaList = (item, index) => {
+  addmanyChange.innerConditionExpression[index].scoreRuleMoreInnerVO = [
+    {
+      innerConditionValue: null,
+      innerConditionValueExpress: null,
+      scoreRules: [
+        {
+          score: null,
+          scoreExpress: null,
+          startValue: null,
+          startExpress: null,
+          endValue: null,
+          endExpress: null,
+          select: null,
+          comparisonStart: null,
+          comparisonEnd: null
+        }
+      ]
+    }
+  ];
+  addmanyChange.innerConditionExpression[index].innerScore = "";
+  changeAddMay();
+};
+const addNewItemOldValue = item => {
+  addmanyChange.innerConditionExpression.push({
+    startValue: item.endValue,
+    select: null,
+    endValue: null,
+    comparisonStart: item.comparisonEnd == ">" ? "≥" : ">",
+    comparisonEnd: null,
+    scoreRuleMoreInnerVO: []
+  });
+  changeAddMay();
+};
+const addNewItem = () => {
+  addmanyChange.innerConditionExpression.push({
+    startValue: null,
+    endValue: null,
+    select: null,
+    comparisonStart: null,
+    comparisonEnd: null,
+    scoreRuleMoreInnerVO: []
+  });
+  changeAddMay();
+};
+function extractKeywordsAndPush(keywordsList, inputString) {
+  keywords.forEach(keyword => {
+    if (
+      inputString?.includes(keyword) && // 检查字符串是否包含关键字
+      !formulaForm.value.some(item => item.name === keyword) // 确保没有重复
+    ) {
+      // 如果包含且未重复,构造对象并push到formulaForm.value
+      formulaForm.value.push({
+        name: keyword,
+        value: null // 根据需求赋值
+      });
+    }
+  });
+
+  return formulaForm;
+}
+// 公式验证
+const grade = ref();
+const formulaForm = ref([]);
+const dialogFormVisibleFormula = ref(false);
+const manyConditions = () => {
+  grade.value = null;
+  dialogFormVisibleFormula.value = true;
+  formulaForm.value = [];
+  // 提取 addmanyChange 对象中的条件值
+  let oldValue = addmanyChange;
+  if (oldValue.outerConditionValue) {
+    extractKeywordsAndPush(keywords, oldValue.outerConditionValue);
+  }
+  if (oldValue.innerConditionExpression.length > 0) {
+    oldValue.innerConditionExpression.map(itemExp => {
+      if (itemExp.startValue) {
+        extractKeywordsAndPush(keywords, itemExp.startValue);
+      }
+      if (itemExp.endValue) {
+        extractKeywordsAndPush(keywords, itemExp.endValue);
+      }
+      if (itemExp.innerScore) {
+        extractKeywordsAndPush(keywords, itemExp.innerScore);
+      }
+      if (itemExp?.scoreRuleMoreInnerVO[0]?.innerConditionValue) {
+        extractKeywordsAndPush(
+          keywords,
+          itemExp.scoreRuleMoreInnerVO[0].innerConditionValue
+        );
+      }
+      if (itemExp?.scoreRuleMoreInnerVO.length > 0) {
+        if (itemExp?.scoreRuleMoreInnerVO[0]?.scoreRules.length > 0) {
+          itemExp?.scoreRuleMoreInnerVO[0]?.scoreRules.map(itSc => {
+            if (itSc.score) {
+              extractKeywordsAndPush(keywords, itSc.score);
+            }
+            if (itSc.startValue) {
+              extractKeywordsAndPush(keywords, itSc.startValue);
+            }
+            if (itSc.endValue) {
+              extractKeywordsAndPush(keywords, itSc.endValue);
+            }
+          });
+        }
+      }
+    });
+  }
+};
+function calculateScore(inputString) {
+  // 将 formulaForm.value 转换为一个键值对映射,方便替换
+  const valueMap = formulaForm.value.reduce((map, item) => {
+    map[item.name] = item.value !== null ? item.value : 0; // 用 0 替代 null
+    return map;
+  }, {});
+
+  // 替换字符串中的关键字为对应的 value 值
+  let formula = inputString;
+  for (const [key, value] of Object.entries(valueMap)) {
+    if (formula.includes(key)) {
+      // 使用正则替换所有匹配的关键字
+      const regex = new RegExp(key, "g");
+      formula = formula.replace(regex, value);
+    }
+  }
+
+  try {
+    // 使用 eval 计算公式
+    const result = eval(formula);
+    return result;
+  } catch (error) {
+    console.error("公式计算出错:", error);
+    return null;
+  }
+}
+// 取消计算
+const quxiaoCmputed = () => {
+  formulaForm.value = [];
+  dialogFormVisibleFormula.value = false;
+};
+const countComputed = async () => {
+  try {
+    let oldValue = JSON.parse(JSON.stringify(addmanyChange));
+    // Object.assign(oldValue, addmanyChange);
+    const formulaPar = JSON.stringify(oldValue);
+    const res = await conditionVerify({
+      formulaType: 1,
+      formula: formulaPar
+    });
+    if (res.code == 200) {
+      if (oldValue.outerConditionValue) {
+        oldValue.outerConditionValue = calculateScore(
+          oldValue.outerConditionValue
+        );
+      }
+      if (oldValue.innerConditionExpression.length > 0) {
+        oldValue.innerConditionExpression.map(itEx => {
+          if (itEx.startValue) {
+            itEx.startValue = calculateScore(itEx.startValue);
+          }
+          if (itEx.endValue) {
+            itEx.endValue = calculateScore(itEx.endValue);
+          }
+          if (itEx.innerScore) {
+            itEx.innerScore = calculateScore(itEx.innerScore);
+          }
+          if (itEx?.scoreRuleMoreInnerVO[0]?.innerConditionValue) {
+            itEx.scoreRuleMoreInnerVO[0].innerConditionValue = calculateScore(
+              itEx.scoreRuleMoreInnerVO[0].innerConditionValue
+            );
+          }
+          if (itEx?.scoreRuleMoreInnerVO[0]?.scoreRules.length > 0) {
+            itEx.scoreRuleMoreInnerVO[0].scoreRules.map(itRule => {
+              if (itRule.score) {
+                itRule.score = calculateScore(itRule.score);
+              }
+              if (itRule.startValue) {
+                itRule.startValue = calculateScore(itRule.startValue);
+              }
+              if (itRule.endValue) {
+                itRule.endValue = calculateScore(itRule.endValue);
+              }
+            });
+          }
+        });
+      }
+      // let newValue = reverseReplace(formListNum, oldValue);
+      const { code, msg, data } =
+        await calculateScoreByConditionMoCondition(oldValue);
+      if (code == 200) {
+        grade.value = data;
+      }
+    } else {
+      ElMessageBox.confirm(
+        "如果不修改将无法计算得分",
+        "公式计算错误,修改后确认",
+        {
+          type: "warning"
+        }
+      ).then(() => {
+        dialogFormVisibleFormula.value = false;
+      });
+    }
+  } catch (err) {
+    console.log(err);
+  }
+};
+</script>
+
+<template>
+  <div class="w-full">
+    <div class="flex items-center">
+      <el-text>条件值 = </el-text>
+      <jishuanqi
+        v-if="addmanyChange.outerConditionValue"
+        ref="jishuanqiRef"
+        :outerConditionValue="addmanyChange.outerConditionValue"
+        @handClick="countNoConditionFormula"
+      />
+    </div>
+    <div class="w-full mt-2">
+      <div
+        v-for="(item, index) in addmanyChange.innerConditionExpression"
+        :key="index"
+      >
+        <div class="mt-3">
+          <div class="flex">
+            <el-text class="w-[15px]" type="primary">
+              {{ index + 1 }}
+            </el-text>
+            <div class="w-[40px] ml-4">
+              {{ item.startValue }}
+            </div>
+            <div class="mr-2">
+              {{ item.comparisonStart }}
+            </div>
+            <div class="mr-2">条件值</div>
+            <el-select
+              v-model="item.comparisonEnd"
+              style="width: 60px"
+              placeholder=""
+              :disabled="
+                index + 1 == addmanyChange.innerConditionExpression.length &&
+                index >= 1
+                  ? true
+                  : false
+              "
+            >
+              <el-option label=">" value=">" />
+              <el-option label="≥" value="≥" />
+            </el-select>
+            <el-select
+              v-model="item.select"
+              class="ml-2"
+              style="width: 80px"
+              placeholder=""
+              :disabled="
+                index + 1 == addmanyChange.innerConditionExpression.length &&
+                index >= 1
+                  ? true
+                  : false
+              "
+            >
+              <el-option label="数值" value="数值" />
+              <el-option label="公式" value="公式" />
+            </el-select>
+            <el-input
+              v-if="
+                index + 1 == addmanyChange.innerConditionExpression.length &&
+                index >= 1
+              "
+              disabled
+              class="ml-2 mr-5"
+              style="width: 80px"
+            />
+            <div v-else>
+              <jishuanqi
+                v-if="item.select == '公式'"
+                ref="jishuanqiRef"
+                :index="index"
+                :outerConditionValue="item.endValue"
+                class="ml-2 mr-5"
+                style="width: 80px"
+                @handClick="countNoConditionFormula1"
+              />
+              <el-input
+                v-else
+                v-model="item.endValue"
+                class="ml-2 mr-5"
+                style="width: 80px"
+              />
+            </div>
+            <el-text v-if="item.scoreRuleMoreInnerVO.length == 0"
+              >得分 =
+            </el-text>
+            <div>
+              <jishuanqi
+                v-if="item.scoreRuleMoreInnerVO.length == 0"
+                ref="jishuanqiRef"
+                :index="index"
+                :outerConditionValue="item.innerScore"
+                class="ml-2 mr-6"
+                style="width: 100px"
+                @handClick="countNoConditionFormulaInnerScore"
+              />
+            </div>
+            <el-text type="danger" @click="deleteItem(index)">
+              <el-icon>
+                <Delete />
+              </el-icon>
+            </el-text>
+          </div>
+          <div
+            v-for="(itemVO, indexOV) in item.scoreRuleMoreInnerVO"
+            :key="indexOV"
+          >
+            <div class="flex mt-2 ml-20">
+              <div class="mr-2">条件值{{ index + 1 }} =</div>
+              <jishuanqi
+                ref="jishuanqiRef"
+                :index="index"
+                :outerConditionValue="itemVO.innerConditionValue"
+                class="ml-2 mr-6"
+                style="width: 208px"
+                @handClick="countNoConditionFormula2"
+              />
+              <!-- <el-input v-model="itemVO.innerConditionValue" class="ml-2 mr-6" style="width: 208px" /> -->
+              <el-text type="danger" @click="dataleListItemAll(item, index)">
+                <el-icon>
+                  <Delete />
+                </el-icon>
+              </el-text>
+            </div>
+            <div
+              v-for="(itemList, indexList) in itemVO.scoreRules"
+              :key="indexList"
+              class="ml-3"
+            >
+              <div class="flex mt-2 ml-16 items-center">
+                <div class="text_border">{{ indexList + 1 }}</div>
+                <!-- manyChange.dataList[index].dataList -->
+                <div class="w-[40px] ml-2">
+                  {{ itemList.startValue }}
+                </div>
+                <div class="mr-2">
+                  {{ itemList.comparisonStart }}
+                </div>
+                <div class="mr-2">条件值{{ index + 1 }}</div>
+                <el-select
+                  v-model="itemList.comparisonEnd"
+                  style="width: 60px"
+                  placeholder=""
+                  :disabled="
+                    indexList + 1 == itemVO.scoreRules.length ? true : false
+                  "
+                >
+                  <el-option label=">" value=">" />
+                  <el-option label="≥" value="≥" />
+                </el-select>
+                <el-select
+                  v-model="itemList.select"
+                  class="ml-2"
+                  style="width: 80px"
+                  placeholder=""
+                  :disabled="
+                    indexList + 1 == itemVO.scoreRules.length ? true : false
+                  "
+                >
+                  <el-option label="数值" value="数值" />
+                  <el-option label="公式" value="公式" />
+                </el-select>
+                <el-input
+                  v-if="indexList + 1 == itemVO.scoreRules.length"
+                  disabled
+                  class="ml-2"
+                  style="width: 80px"
+                />
+                <div v-else>
+                  <jishuanqi
+                    v-if="itemList.select == '公式'"
+                    ref="jishuanqiRef"
+                    :index="index"
+                    :indexList="indexList"
+                    :outerConditionValue="itemList.endValue"
+                    class="ml-2"
+                    style="width: 80px"
+                    @handClick="countNoConditionFormula3"
+                  />
+                  <el-input
+                    v-else
+                    v-model="itemList.endValue"
+                    class="ml-2"
+                    style="width: 80px"
+                  />
+                </div>
+                <div
+                  class="w-[150px] ml-2 mr-2 flex justify-between items-center"
+                >
+                  <div>得分</div>
+                  <div>=</div>
+                  <!-- <el-input v-if="
+                                  indexList + 1 == itemVO.scoreRules.length &&
+                                  index >= 1
+                                " disabled class="ml-2" style="width: 80px" /> -->
+                  <jishuanqi
+                    ref="jishuanqiRef"
+                    :index="index"
+                    :indexList="indexList"
+                    :outerConditionValue="itemList.score"
+                    class="ml-2"
+                    style="width: 80px"
+                    @handClick="countNoConditionFormula4"
+                  />
+                  <!-- <el-input
+                                  v-model="itemList.score"
+                                  class="ml-2"
+                                  style="width: 80px"
+                                /> -->
+                </div>
+                <el-text
+                  type="danger"
+                  @click="dataleListItem(index, indexList)"
+                >
+                  <el-icon>
+                    <Delete />
+                  </el-icon>
+                </el-text>
+              </div>
+              <div
+                v-if="indexList + 1 == itemVO.scoreRules.length"
+                class="ml-16 mt-2 text-xs cursor-pointer"
+              >
+                <el-text
+                  type="primary"
+                  @click="addItemDataList(index, itemList, indexList, item)"
+                >
+                  <el-icon>
+                    <Plus />
+                  </el-icon>
+                  添加子条件
+                </el-text>
+              </div>
+            </div>
+          </div>
+        </div>
+        <div
+          v-if="item?.scoreRuleMoreInnerVO?.length == 0"
+          class="ml-20 mt-2 text-xs cursor-pointer"
+        >
+          <el-text type="primary" @click="addItemFormulaList(item, index)">
+            <el-icon>
+              <Plus />
+            </el-icon>
+            添加子条件
+          </el-text>
+        </div>
+        <div
+          v-if="
+            addmanyChange.innerConditionExpression.length >= 1 &&
+            index + 1 == addmanyChange.innerConditionExpression.length
+          "
+          class="mt-5 text-xs cursor-pointer"
+        >
+          <el-text type="primary" @click="addNewItemOldValue(item)">
+            <el-icon>
+              <Plus />
+            </el-icon>
+            添加条件
+          </el-text>
+        </div>
+      </div>
+      <div
+        v-if="addmanyChange.innerConditionExpression.length < 1"
+        class="mt-5 text-xs cursor-pointer"
+      >
+        <el-text type="primary" @click="addNewItem">
+          <el-icon>
+            <Plus />
+          </el-icon>
+          添加条件
+        </el-text>
+      </div>
+      <div class="float-right mr-8">
+        <el-button type="primary" @click="manyConditions">公式验证</el-button>
+      </div>
+    </div>
+    <!-- 公式验证 -->
+    <el-dialog
+      v-model="dialogFormVisibleFormula"
+      title="完成值"
+      width="500"
+      :before-close="quxiaoCmputed"
+    >
+      <el-form :model="formulaForm">
+        <div v-for="(itemF, indexF) in formulaForm" :key="indexF">
+          <el-form-item :label="itemF.name">
+            <el-input v-model="itemF.value" autocomplete="off" />
+          </el-form-item>
+        </div>
+        <el-form-item label="得分">
+          <el-input v-model="grade" class="ml-3" autocomplete="off" disabled />
+        </el-form-item>
+      </el-form>
+      <template #footer>
+        <div class="dialog-footer">
+          <el-button @click="quxiaoCmputed">取消</el-button>
+          <el-button type="primary" @click="countComputed"> 计算 </el-button>
+        </div>
+      </template>
+    </el-dialog>
+  </div>
+</template>
+
+<style lang="scss" scoped>
+.compute {
+  // border: 1px solid #f3f3f3;
+  background-color: #f3f3f3;
+  border-radius: 5px;
+}
+
+.text-color {
+  color: #f3f3f3;
+}
+
+.areYouOK {
+  background-color: #409eff;
+}
+
+.bgBack {
+  background-color: #f3f3f3;
+}
+
+.text_border {
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  width: 14px;
+  height: 14px;
+  // margin-top: 5px;
+  margin-right: 5px;
+  font-size: 12px;
+  border: 1px solid gray;
+  border-radius: 50%;
+}
+</style>

+ 161 - 0
src/views/evaluate/children/change/components/editMould.vue

@@ -7,6 +7,7 @@ import {
   getDimensionRemove,
   postUpdateDept
 } from "@/api/dimension";
+import { postUpdate } from "@/api/templateInfo";
 import type { DrawerProps, FormItemProps, FormProps } from "element-plus";
 // const itemLabelPosition = ref<FormItemProps["labelPosition"]>("");
 const drawer = ref(false);
@@ -37,9 +38,12 @@ const formLabelAlign = reactive({
   showFinalValue: 0,
   showChallengeValue: 0,
   showStartValue: 0,
+  showRemark: 0,
   remark: "",
   tpId: ""
 });
+// 存储指标变量,修改指标最高值时使用
+const changeIndexList = ref([]);
 const newAddItem = ref();
 const handleClose = (done: () => void) => {
   done();
@@ -53,6 +57,7 @@ function confirmClick() {
     if (valid) {
       if (dalongTitle.value == "编辑") {
         postUpdateDeptApi();
+        postUpdateApi();
       } else {
         postAddDimensionApi();
       }
@@ -60,7 +65,9 @@ function confirmClick() {
   });
 }
 const titleName = ref("");
+const indexList = ref([]);
 const open = (row: any, title: string, order: number) => {
+  console.log("编辑", row, title);
   dalongTitle.value = title;
   if (title == "新建") {
     titleName.value = "新建考核维度";
@@ -77,6 +84,7 @@ const open = (row: any, title: string, order: number) => {
       showFinalValue: 0,
       showChallengeValue: 0,
       showStartValue: 0,
+      showRemark: 0,
       remark: "",
       order: order
     });
@@ -87,6 +95,31 @@ const open = (row: any, title: string, order: number) => {
       ...row,
       order
     });
+    formLabelAlign.tableData.map(item => {
+      item["indNameIndex"] = item.indName;
+    });
+    changeIndexList.value = formLabelAlign.tableData;
+    indexList.value = formLabelAlign.tableData.reduce((acc, current) => {
+      // 找到当前项的 indLimitScore 是否已经存在于结果数组中
+      let found = acc.find(
+        group => group[0].indLimitScore === current.indLimitScore
+      );
+      if (found) {
+        // 如果找到了,添加当前项到对应的数组中
+        found.push(current);
+      } else {
+        // 如果没有找到,创建一个新的数组并将当前项加入
+        acc.push([current]);
+      }
+
+      return acc;
+    }, []);
+    // indexList.value.map(item => {
+    //   item.map(it => {
+    //     it["indNameIndex"] = "";
+    //   });
+    // });
+    watchTableData();
   }
   drawer.value = true;
 };
@@ -138,6 +171,12 @@ const showStartValueValue = computed({
     formLabelAlign.showStartValue = value ? 1 : 0;
   }
 });
+const remarkValueValue = computed({
+  get: () => formLabelAlign.showRemark === 1,
+  set: value => {
+    formLabelAlign.showRemark = value ? 1 : 0;
+  }
+});
 // 分割————————————————————————————————————————————
 // 新建维度
 const postAddDimensionApi = async () => {
@@ -174,9 +213,70 @@ const postUpdateDeptApi = async () => {
     });
   }
 };
+const handClose = (indName, ind, indId) => {
+  // console.log("item", ind, indId);
+  indexList.value[ind].splice(indId, 1);
+  if (indexList.value[ind].length == 0) {
+    indexList.value.splice(ind, 1);
+  }
+  let newIndName = indName;
+  newIndName.indLimitScore = null;
+  formLabelAlign.tableData.push(newIndName);
+};
+const delteIndex = (index, item) => {
+  indexList.value[index].map(it => {
+    it.indLimitScore = null;
+    formLabelAlign.tableData.push(it);
+  });
+  indexList.value.splice(index, 1);
+};
+const addIndex = () => {
+  indexList.value.push([
+    {
+      indNameIndex: "",
+      indLimitScore: null
+    }
+  ]);
+};
+const watchTableData = () => {
+  const idsToDelete = new Set();
+  // 通过 indexList 删除 tableData 中相同 id 的数据
+  // 迭代 indexList 中的每个 id
+  indexList.value.forEach(group => {
+    group.forEach(item => {
+      idsToDelete.add(item.id);
+    });
+  });
+  const filteredTableData = formLabelAlign.tableData.filter(
+    item => !idsToDelete.has(item.id)
+  );
+  formLabelAlign.tableData = filteredTableData;
+  console.log("tableDatatableData", filteredTableData);
+};
+const handChangeIndex = (ind, val) => {
+  changeIndexList.value.map(item => {
+    if (item.id == val) {
+      formLabelAlign.tableData;
+      indexList.value[ind].push(item);
+      watchTableData();
+    }
+  });
+};
+const postUpdateApi = async () => {
+  indexList.value.map(item => {
+    item.map(async (item1, index1, arr1) => {
+      if (item1.id) {
+        item1.indLimitScore = arr1[item.length - 1].indLimitScore;
+        const { code } = await postUpdate(item1);
+      }
+    });
+  });
+  console.log("indexList", indexList.value);
+};
 defineExpose({
   open
 });
+const value = ref("");
 </script>
 
 <template>
@@ -228,6 +328,63 @@ defineExpose({
                 <el-radio :value="1" size="large">加和</el-radio>
               </el-radio-group>
             </el-form-item>
+            <el-form-item
+              v-if="dalongTitle == '编辑'"
+              label="指标最高分限制"
+              label-position="top"
+            >
+              <div>
+                <div v-for="(int, ind) in indexList" :key="ind" class="mt-2">
+                  <el-text
+                    class="mx-1"
+                    type="danger"
+                    @click="delteIndex(ind, int)"
+                    ><el-icon> <Delete /> </el-icon
+                  ></el-text>
+                  <el-text class="mx-1">不超过</el-text>
+                  <el-input
+                    v-model="int[int.length - 1].indLimitScore"
+                    size="small"
+                    style="width: 30px"
+                  />
+                  <el-text class="mx-1">分</el-text>
+                  <!-- <el-select v-model="int[int.length - 1].indNameIndex" placeholder="Select" style="width: 140px" -->
+                  <el-select
+                    v-model="int[int.length - 1].indNameIndex"
+                    placeholder="Select"
+                    style="width: 140px"
+                    filterable
+                    @change="handChangeIndex(ind, $event)"
+                  >
+                    <el-option
+                      v-for="item in formLabelAlign.tableData"
+                      :key="item.id"
+                      :label="item.indName"
+                      :value="item.id"
+                    />
+                  </el-select>
+                  <span v-for="(indName, indId) in int" :key="indId">
+                    <el-tag
+                      v-if="indName.indName"
+                      type="info"
+                      class="ml-2"
+                      closable
+                      @close="handClose(indName, ind, indId)"
+                    >
+                      {{ indName.indName }}
+                    </el-tag>
+                  </span>
+                </div>
+                <!-- <el-text size="large" type="primary">
+                  <el-icon>
+                    <Plus />
+                  </el-icon>
+                </el-text> -->
+                <el-tag type="primary" @click="addIndex">
+                  <el-icon> <Plus /> </el-icon>添加
+                </el-tag>
+              </div>
+            </el-form-item>
             <el-form-item label="指标显示字段设置" label-position="top">
               <template #default>
                 <div>
@@ -259,6 +416,10 @@ defineExpose({
                     <el-text type="info">门槛值</el-text>
                     <el-switch v-model="showStartValueValue" class="ml-2" />
                   </div>
+                  <div class="ml-3">
+                    <el-text type="info">备注</el-text>
+                    <el-switch v-model="remarkValueValue" class="ml-2" />
+                  </div>
                 </div>
               </template>
             </el-form-item>

+ 1 - 1
src/views/evaluate/children/change/components/jishuanqi.vue

@@ -198,7 +198,7 @@
 <script setup lang="ts">
 import { reactive, ref, onMounted } from "vue";
 const dropdown = ref();
-const $emit = defineEmits(["handClick", "clickIndex"]);
+const $emit = defineEmits(["handClick"]);
 const $props = defineProps({
   index: {
     type: Number

+ 29 - 2
src/views/evaluate/children/change/components/newAdd.vue

@@ -58,12 +58,15 @@ const handleSelect = index => {
 const tepName = ref();
 const tepNameForm = reactive({
   tpName: "",
-  id: ""
+  id: "",
+  isScoreConverse: 1
 });
 onMounted(() => {
   if (route.query.tpName && route.query.id) {
     tepNameForm.tpName = route.query.tpName;
     tepNameForm.id = route.query.id;
+    console.log("route.query", route.query);
+    tepNameForm.isScoreConverse = Number(route.query.isScoreConverse);
   }
 });
 const tableData = ref([]);
@@ -82,6 +85,7 @@ const postAddTemplateApi = async () => {
     });
     tepNameForm.tpName = res.data.tpName;
     tepNameForm.id = res.data.id;
+    tepNameForm.isScoreConverse = res.data.isScoreConverse;
     titleShow.value = true;
   } else {
     ElMessage.error(res.msg);
@@ -183,7 +187,8 @@ const backChange = () => {
 const postUpdateTemplateInApi = async () => {
   const { code, msg } = await postUpdateTemplateIn({
     tpName: tepNameForm.tpName,
-    id: tepNameForm.id
+    id: tepNameForm.id,
+    isScoreConverse: tepNameForm.isScoreConverse
   });
   if (code == 200) {
     titleShow.value = true;
@@ -486,6 +491,22 @@ const titleShowClick = () => {
               placeholder="最多输入100字"
             />
           </el-form-item>
+          <el-form-item
+            prop="isScoreConverse"
+            label="是否支持得分换算"
+            :rules="[
+              {
+                required: true,
+                message: '是否支持得分换算',
+                trigger: 'blur'
+              }
+            ]"
+          >
+            <el-radio-group v-model="tepNameForm.isScoreConverse">
+              <el-radio :value="1" size="large">是</el-radio>
+              <el-radio :value="0" size="large">否</el-radio>
+            </el-radio-group>
+          </el-form-item>
         </el-form>
       </div>
       <div v-else class="w-[90%] m-auto mt-4">
@@ -615,6 +636,12 @@ const titleShowClick = () => {
                 title="门槛值"
                 :edit-render="{ name: 'input' }"
               />
+              <vxe-column
+                v-if="item.showRRemark"
+                field="remark"
+                title="备注"
+                :edit-render="{ name: 'input' }"
+              />
               <vxe-column field="age" fixed="right" title="操作">
                 <template #default="{ row }">
                   <el-icon class="mr-3" @click="settingIndex(row)">

+ 7 - 0
src/views/evaluate/children/change/components/settingIndexDrawer.vue

@@ -68,6 +68,7 @@ const params = reactive({
   startValue: "",
   datasoure: "",
   weight: "",
+  valueScore: 0,
   scoreValue: "",
   formula: {
     noConditionFormula: ""
@@ -938,6 +939,12 @@ const formulaFocus = () => {
                 @check-change="handleRreeSelect()"
               />
             </el-form-item>
+            <el-form-item label="完成值计算方式" label-position="top">
+              <el-radio-group v-model="params.valueScore">
+                <el-radio :value="0" size="large">统计计算</el-radio>
+                <el-radio :value="1" size="large">累加计算</el-radio>
+              </el-radio-group>
+            </el-form-item>
             <el-form-item label="评分方式" label-position="top">
               <el-select v-model="params.scoreStandard" placeholder="请选择">
                 <el-option label="手动输入" :value="0" />

+ 349 - 0
src/views/evaluate/children/change/mould/editIndex.vue

@@ -0,0 +1,349 @@
+<script setup lang="ts">
+import { ref, reactive, onMounted } from "vue";
+import { ElMessage, ElMessageBox } from "element-plus";
+import type { DrawerProps, FormProps } from "element-plus";
+import { editListApi } from "@/api/indexData";
+import dayjs from "dayjs";
+// getIndexInfo,
+// postUpdate,
+import { postUpdateAssessmentQuotaDetails } from "@/api/assessment";
+import { conditionVerify } from "@/api/formula";
+import jishuanqi from "@/views/evaluate/children/change/components/jishuanqi.vue";
+import manyFormula from "@/components/formula/manyFormula.vue";
+const emit = defineEmits(["updateDialog"]);
+const formRef = ref();
+const drawer = ref(false);
+const disabledShow = ref<any>(true);
+const direction = ref<DrawerProps["direction"]>("rtl");
+// 表单
+const formulaOne = ref();
+const formLabelAlign = reactive({
+  relationId: "",
+  targetValue: 0,
+  finalValue: 0,
+  addValue: 0,
+  decValue: 0,
+  challengeValue: 0,
+  startValue: 0,
+  upperValue: 0,
+  agupperValue: 0,
+  dataSource: "",
+  score: 0,
+  assessmentObjectId: "",
+  assessmentModelId: "",
+  id: "",
+  dimId: "",
+  assessmentId: "",
+  formulaType: 0,
+  formula: ""
+});
+// 抽屉逻辑
+const open = row => {
+  console.log("编辑", row);
+  Object.assign(formLabelAlign, row);
+  // console.log(1111, JSON.parse(formLabelAlign.formula));
+  let dataJSon = JSON.parse(row.formula);
+  formulaOne.value = dataJSon.noConditionFormula;
+  // if (formLabelAlign.formulaType == 0) {
+  // } else {
+  //   formula
+  // }
+  drawer.value = true;
+};
+// 无条件
+const countNoConditionFormulaClick = (data: any) => {
+  formulaOne.value = data;
+};
+defineExpose({
+  open
+});
+const handleClose = (done: () => void) => {
+  if (disabledShow.value) {
+    disabledShow.value = true;
+    drawer.value = false;
+  } else {
+    ElMessageBox.confirm("配置项未保存,确认关闭", {
+      type: "warning"
+    }).then(() => {
+      formRef.value.clearValidate(); // 清除验证错误
+      formRef.value.resetFields(); // 重置表单字段
+      disabledShow.value = true;
+      drawer.value = false;
+    });
+  }
+};
+const cancelClick = () => {
+  formRef.value.validate(valid => {
+    if (valid) {
+      disabledShow.value = true;
+    }
+  });
+};
+// 公式验证
+const dialogFormVisibleFormula = ref(false);
+const formulaForm = ref([]);
+const grade = ref();
+const conditionVerifyApi = async () => {
+  grade.value = null;
+  formulaForm.value = [];
+  dialogFormVisibleFormula.value = true;
+  try {
+    formulaForm.value = [];
+    grade.value = "";
+    const keywords = [
+      "完成值",
+      "目标值",
+      "门槛值",
+      "挑战值",
+      "增幅",
+      "降幅",
+      "上期完成值",
+      "上上期完成值"
+    ];
+    let str = formulaOne.value;
+    // 创建一个正则表达式,匹配这些关键词
+    const regex = new RegExp(keywords.join("|"), "g");
+    // 提取字符串中的所有关键词
+    let matches = str.match(regex);
+    matches.forEach(matchItem => {
+      formulaForm.value.push({
+        name: matchItem,
+        value: ""
+      });
+    });
+    let result = str.replace(regex, match => {
+      return `${match}`;
+    });
+  } catch (err) {
+    //
+  }
+};
+// 取消计算
+const quxiaoCmputed = () => {
+  formulaForm.value = [];
+  dialogFormVisibleFormula.value = false;
+};
+const countComputed = async () => {
+  try {
+    if (formLabelAlign.formulaType == 0) {
+      const formula = JSON.stringify({
+        noConditionFormula: formulaOne.value
+      });
+      // const aa = JSON.stringify(formula);
+      // console.log("formula", aa);
+      const { code, msg } = await conditionVerify({
+        formulaType: formLabelAlign.formulaType,
+        formula
+      });
+      if (code == 200) {
+        const keywords = [
+          "完成值",
+          "目标值",
+          "门槛值",
+          "挑战值",
+          "增幅",
+          "降幅",
+          "上期完成值",
+          "上上期完成值"
+        ];
+        let str = formulaOne.value;
+        // 创建一个正则表达式,匹配这些关键词
+        const regex = new RegExp(keywords.join("|"), "g");
+        let result = str.replace(regex, match => {
+          // 在 formulaForm.value 中查找匹配的项
+          let matchedItem = formulaForm.value.find(item => item.name === match);
+
+          // 如果找到匹配项,返回其 value,否则返回原始匹配值
+          if (matchedItem) {
+            return matchedItem.value; // 替换为对应的值
+          }
+          return match; // 如果没有匹配项,返回原始匹配值
+        });
+        // calculator.calculate(result);
+        // grade.value = calculator.get();
+        grade.value = eval(result).toFixed(2);
+      } else {
+        ElMessageBox.confirm(
+          "如果不修改将无法计算得分",
+          "公式计算错误,修改后确认",
+          {
+            type: "warning"
+          }
+        ).then(() => {
+          dialogFormVisibleFormula.value = false;
+        });
+      }
+    }
+  } catch (err) {
+    console.log(err);
+  }
+};
+// 确认
+const confirmClick = () => {
+  postUpdateApi();
+};
+// 更新模板指标关联
+const postUpdateApi = async () => {
+  let params = {};
+  Object.assign(params, formLabelAlign);
+  params.formula = JSON.stringify({
+    noConditionFormula: formulaOne.value
+  });
+  // if (formLabelAlign.formulaType ==0) {
+  // }
+  // else if (formLabelAlign.formulaType == 1) {
+  // }
+  const { code, msg } = await postUpdateAssessmentQuotaDetails(params);
+  if (code === 200) {
+    ElMessage.success("修改成功");
+    drawer.value = false;
+  } else {
+    // ElMessage.error(msg);
+  }
+};
+</script>
+
+<template>
+  <div>
+    <el-drawer
+      v-model="drawer"
+      :direction="direction"
+      :before-close="handleClose"
+      size="700px"
+    >
+      <template #header>
+        <h4>公式设置</h4>
+      </template>
+      <template #default>
+        <div>
+          <el-form
+            ref="formRef"
+            label-position="top"
+            label-width="auto"
+            :model="formLabelAlign"
+          >
+            <el-form-item
+              label="考核对象"
+              label-position="top"
+              prop="sourceValue"
+            >
+              <el-input
+                v-model="formLabelAlign.assessmentObjectName"
+                disabled
+              />
+            </el-form-item>
+            <el-form-item
+              label="考核模板"
+              label-position="top"
+              prop="sourceValue"
+            >
+              <el-input v-model="formLabelAlign.assessmentModelName" disabled />
+            </el-form-item>
+            <el-form-item
+              label="指标名称"
+              label-position="top"
+              prop="sourceValue"
+            >
+              <el-input v-model="formLabelAlign.name" disabled />
+            </el-form-item>
+            <el-form-item
+              label="完成值录入人"
+              label-position="top"
+              prop="sourceValue"
+            >
+              <el-select v-model="formLabelAlign.valueInput" disabled>
+                <el-option label="被考核人" :value="0" />
+                <!-- <el-option label="上级" :value="1" /> -->
+                <el-option label="指定人员" :value="2" />
+                <el-option label="考核管理员" :value="3" />
+                <el-option label="指标自动采集" :value="4" />
+              </el-select>
+            </el-form-item>
+            <el-form-item
+              label="评分方式"
+              label-position="top"
+              prop="sourceValue"
+            >
+              <el-select v-model="formLabelAlign.scoreStandard" disabled>
+                <el-option label="手动输入" :value="0" />
+                <el-option label="公式自动计算" :value="1" />
+              </el-select>
+            </el-form-item>
+            <el-form-item
+              label="公式类型"
+              label-position="top"
+              prop="sourceValue"
+            >
+              <el-select v-model="formLabelAlign.formulaType">
+                <el-option label="无条件公式" :value="0" />
+                <el-option label="多条件公式" :value="1" />
+              </el-select>
+            </el-form-item>
+            <el-form-item
+              v-if="formLabelAlign.formulaType == 0"
+              label="设置"
+              label-position="top"
+              prop="sourceValue"
+            >
+              <div class="w-full flex item-center">
+                <div class="mr-4"><el-text>得分 =</el-text></div>
+                <jishuanqi
+                  :outerConditionValue="formulaOne"
+                  @handClick="countNoConditionFormulaClick"
+                />
+                <div class="ml-8">
+                  <el-button type="primary" @click="conditionVerifyApi">
+                    公式验证
+                  </el-button>
+                </div>
+              </div>
+            </el-form-item>
+            <el-form-item
+              v-else
+              label="设置"
+              label-position="top"
+              prop="sourceValue"
+            >
+              <div class="w-full flex item-center">
+                <manyFormula
+                  :formulaJSON="formulaOne"
+                  @handUpdataClick="countNoConditionFormulaClick"
+                />
+              </div>
+            </el-form-item>
+          </el-form>
+        </div>
+      </template>
+      <template #footer>
+        <div>
+          <el-button @click="cancelClick">取消</el-button>
+          <el-button type="primary" @click="confirmClick">确认</el-button>
+        </div>
+      </template>
+    </el-drawer>
+    <!-- 公式验证 -->
+    <el-dialog
+      v-model="dialogFormVisibleFormula"
+      title="完成值"
+      width="500"
+      :before-close="quxiaoCmputed"
+    >
+      <el-form :model="formulaForm">
+        <div v-for="(itemF, indexF) in formulaForm" :key="indexF">
+          <el-form-item :label="itemF.name">
+            <el-input v-model="itemF.value" autocomplete="off" />
+          </el-form-item>
+        </div>
+        <el-form-item label="得分">
+          <el-input v-model="grade" class="ml-3" autocomplete="off" disabled />
+        </el-form-item>
+      </el-form>
+      <template #footer>
+        <div class="dialog-footer">
+          <el-button @click="quxiaoCmputed">取消</el-button>
+          <el-button type="primary" @click="countComputed"> 计算 </el-button>
+        </div>
+      </template>
+    </el-dialog>
+  </div>
+</template>

+ 67 - 1
src/views/evaluate/children/change/mould/manageObject.vue

@@ -13,8 +13,10 @@ import {
   alterFinishValue,
   automaticCollection,
   setTableHeader,
+  delBatchDelScoreInfoVO,
   getAssessmentDetails
 } from "@/api/assessment";
+import editIndex from "./editIndex.vue";
 import { getTemplateInfoList } from "@/api/templateInfo";
 import { useRouter } from "vue-router";
 import { ElMessage, ElMessageBox } from "element-plus";
@@ -1111,10 +1113,65 @@ const hideColEvent = field => {
     $table.hideColumn(field);
   }
 };
+const editIndexShow = ref(null);
+const editIndexOpen = (row: Object) => {
+  editIndexShow.value.open({
+    ...row,
+    assessmentId: initParams.indexParams.assessmentId
+  });
+};
+const deleteParam = ref([]);
+// 批量删除指标
+const deleteMantList = () => {
+  if (deleteParam.value.length === 0) {
+    ElMessage.warning("请选择要删除的考核指标");
+  } else {
+    ElMessageBox.confirm(
+      "这些考核项删除后将不可恢复,请谨慎操作",
+      "确定删除这些考核项吗?",
+      {
+        confirmButtonText: "确定",
+        cancelButtonText: "取消",
+        type: "warning"
+      }
+    ).then(async () => {
+      deleteParam.value.map(item => {
+        item.assessmentId = initParams.indexParams.assessmentId;
+      });
+      const { code } = await delBatchDelScoreInfoVO(deleteParam.value);
+      if (code === 200) {
+        getAssessmentQuotaDetailsApi();
+        activeName.value = "second";
+        ElMessage({
+          type: "success",
+          message: "删除成功"
+        });
+      }
+    });
+  }
+};
+// 单选
+const selectChangeEvent = row => {
+  const $table = tableVxeRef.value;
+  deleteParam.value = [];
+  if ($table) {
+    deleteParam.value = row.records;
+  }
+};
+// 全选
+const selectAllChangeEvent = row => {
+  const $table = tableVxeRef.value;
+  deleteParam.value = [];
+  if ($table) {
+    deleteParam.value = row.records;
+  }
+};
 </script>
 
 <template>
   <div class="w-full">
+    <!-- 指标编辑 -->
+    <editIndex ref="editIndexShow" />
     <div class="w-full flex items-center justify-between">
       <div class="flex items-center justify-between mt-2">
         <div class="bg-icon">
@@ -1293,6 +1350,9 @@ const hideColEvent = field => {
             >
           </div> -->
           <div class="mr-10 flex items-center justify-between">
+            <el-button type="primary" plain @click="deleteMantList"
+              >批量删除</el-button
+            >
             <el-button type="primary" plain @click="automaticCollectionApi"
               >同步最新数据</el-button
             >
@@ -1312,6 +1372,8 @@ const hideColEvent = field => {
           :edit-rules="validRules"
           :data="initParams.Indexlist"
           @edit-closed="editClosedEvent"
+          @checkbox-change="selectChangeEvent"
+          @checkbox-all="selectAllChangeEvent"
           @selection-change="changeSelection"
           @edit-disabled="editDisabledEvent"
         >
@@ -1621,7 +1683,11 @@ const hideColEvent = field => {
                 </template>
               </el-dropdown>
             </template>
-            <template #default> - </template>
+            <template #default="{ row }">
+              <el-icon @click="editIndexOpen(row)">
+                <Edit />
+              </el-icon>
+            </template>
           </vxe-column>
         </vxe-table>
         <div class="flex justify-between item-center">