hcong
2024-09-27 5aa63351c15fde21178f0c962570df65eba38560
评估
已修改6个文件
已添加4个文件
1039 ■■■■■ 文件已修改
src/api/fysp/evaluateApi.js 46 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components.d.ts 10 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/constants/menu.js 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main.js 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/router/index.js 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/utils/fileUtils.js 65 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/fysp/config/EvalutationRule.vue 339 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/fysp/config/components/evalution/CompEvalutionRuleUpd.vue 172 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/fysp/config/components/evalution/CompEvalutionSubRuleUpd.vue 138 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/fysp/evaluation/EvalutationEdit.vue 256 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/fysp/evaluateApi.js
@@ -62,5 +62,49 @@
          window.URL.revokeObjectURL(url);
        }
      });
  }
  },
  /**
   * ä¿®æ”¹æœ€å°é¡¹å¾—分
   */
  updateScore({itemList, subTaskId}) {
    const param = `?subTaskId=${subTaskId}`
    return $fysp.post(`/itemevaluation/update${param}`, itemList).then((res) => res.data);
  },
  /**
   * èŽ·å¾—æ‰€æœ‰è§„åˆ™çˆ¶èŠ‚ç‚¹
   */
  getAllParentRules() {
    return $fysp.get("evaluationrule").then((res) => res.data);
  },
  /** æ ¹æ®çˆ¶èŠ‚ç‚¹id获取子规则 */
  getSubRules(id) {
    const param = `?id=${id}`
    return $fysp.get(`/evaluationsubrule/byRule${param}`).then((res) => res.data);
  },
  /**
   * æ›´æ–°çˆ¶èŠ‚ç‚¹è§„åˆ™
   */
  updateParentRule(data) {
    return $fysp.post("evaluationrule", data).then((res) => res.data);
  },
  /**
   * åˆ é™¤çˆ¶èŠ‚ç‚¹è§„åˆ™
   */
  deleteParentRuleById(id) {
    return $fysp.delete(`evaluationrule/${id}`).then((res) => res.data);
  },
  /**
   * æ›´æ–°å­èŠ‚ç‚¹è§„åˆ™
   */
  updateSubRule(data) {
    return $fysp.post("evaluationsubrule", data).then((res) => res.data);
  },
  /**
   * åˆ é™¤å­èŠ‚ç‚¹è§„åˆ™
   */
  deleteSubRuleById(id) {
    return $fysp.delete(`evaluationsubrule/${id}`).then((res) => res.data);
  },
};
src/components.d.ts
@@ -18,7 +18,6 @@
    ElBreadcrumb: typeof import('element-plus/es')['ElBreadcrumb']
    ElBreadcrumbItem: typeof import('element-plus/es')['ElBreadcrumbItem']
    ElButton: typeof import('element-plus/es')['ElButton']
    ElButtonGroup: typeof import('element-plus/es')['ElButtonGroup']
    ElCard: typeof import('element-plus/es')['ElCard']
    ElCascader: typeof import('element-plus/es')['ElCascader']
    ElCheckbox: typeof import('element-plus/es')['ElCheckbox']
@@ -31,9 +30,6 @@
    ElDialog: typeof import('element-plus/es')['ElDialog']
    ElDivider: typeof import('element-plus/es')['ElDivider']
    ElDrawer: typeof import('element-plus/es')['ElDrawer']
    ElDropdown: typeof import('element-plus/es')['ElDropdown']
    ElDropdownItem: typeof import('element-plus/es')['ElDropdownItem']
    ElDropdownMenu: typeof import('element-plus/es')['ElDropdownMenu']
    ElEmpty: typeof import('element-plus/es')['ElEmpty']
    ElForm: typeof import('element-plus/es')['ElForm']
    ElFormItem: typeof import('element-plus/es')['ElFormItem']
@@ -47,8 +43,8 @@
    ElMenuItem: typeof import('element-plus/es')['ElMenuItem']
    ElMenuItemGroup: typeof import('element-plus/es')['ElMenuItemGroup']
    ElOption: typeof import('element-plus/es')['ElOption']
    ElPageHeader: typeof import('element-plus/es')['ElPageHeader']
    ElPagination: typeof import('element-plus/es')['ElPagination']
    ElPopconfirm: typeof import('element-plus/es')['ElPopconfirm']
    ElPopover: typeof import('element-plus/es')['ElPopover']
    ElRadioButton: typeof import('element-plus/es')['ElRadioButton']
    ElRadioGroup: typeof import('element-plus/es')['ElRadioGroup']
@@ -62,14 +58,10 @@
    ElSwitch: typeof import('element-plus/es')['ElSwitch']
    ElTable: typeof import('element-plus/es')['ElTable']
    ElTableColumn: typeof import('element-plus/es')['ElTableColumn']
    ElTabPane: typeof import('element-plus/es')['ElTabPane']
    ElTabs: typeof import('element-plus/es')['ElTabs']
    ElTag: typeof import('element-plus/es')['ElTag']
    ElText: typeof import('element-plus/es')['ElText']
    ElTooltip: typeof import('element-plus/es')['ElTooltip']
    ElTransfer: typeof import('element-plus/es')['ElTransfer']
    ElTree: typeof import('element-plus/es')['ElTree']
    ElUpload: typeof import('element-plus/es')['ElUpload']
    Footer: typeof import('./components/core/Footer.vue')['default']
    FormCol: typeof import('./components/layout/FormCol.vue')['default']
    FYBgTaskCard: typeof import('./components/bg-task/FYBgTaskCard.vue')['default']
src/constants/menu.js
@@ -59,6 +59,12 @@
        icon: 'List',
        name: '设备匹配',
      },
      {
        //评估规则管理
        path: '/fysp/config/evalutationRule',
        icon: 'List',
        name: '评估规则',
      },
    ],
  },
  {
src/main.js
@@ -5,6 +5,7 @@
import { router } from './router';
import App from './App.vue';
import timeUtil from './utils/time-util';
import DeepCopy from './utils/DeepCopy';
// import 'element-plus/dist/index.css';
import './assets/main.css';
src/router/index.js
@@ -84,6 +84,12 @@
    component: () => import('@/views/fysp/config/DeviceMatch.vue')
  },
  {
    //评估规则管理
    name: 'fyspEvalutationRule',
    path: '/fysp/config/evalutationRule',
    component: () => import('@/views/fysp/config/EvalutationRule.vue')
  },
  {
    //评估数据源
    name: 'fyspEvalutationTask',
    path: '/fysp/evaluation/evalutationTask',
src/utils/fileUtils.js
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,65 @@
export default {
    getBase64(url, callback) {
        //通过构造函数来创建的 img å®žä¾‹ï¼Œåœ¨èµ‹äºˆ src å€¼åŽå°±ä¼šç«‹åˆ»ä¸‹è½½å›¾ç‰‡ï¼Œç›¸æ¯” createElement() åˆ›å»º <img> çœåŽ»äº† append(),也就避免了文档冗余和污染
        var Img = new Image(),
            dataURL = '';
        Img.setAttribute('crossOrigin', 'Anonymous'); // è§£å†³æŽ§åˆ¶å°è·¨åŸŸæŠ¥é”™çš„问题
        if (url.startsWith("blob")) {
            Img.src = url;
        }else {
            Img.src = url + '?v=' + Math.random(); // å¤„理缓存,fix缓存bug,有缓存,浏览器会报错;
        }
        // Img.src = /^data:image/.test(url) ? url : url + '?' + new Date().getTime() + '&v=' + Math.random(); // å¤„理缓存,fix缓存bug,有缓存,浏览器会报错;
        // Img.crossOrigin = "*"; // è§£å†³æŽ§åˆ¶å°è·¨åŸŸæŠ¥é”™çš„问题
        Img.onload = function () {
            //要先确保图片完整获取到,这是个异步事件
            var canvas = document.createElement('canvas'), //创建canvas元素
                width = Img.width, //确保canvas的尺寸和图片一样
                height = Img.height;
            canvas.width = width;
            canvas.height = height;
            canvas.setAttribute('crossOrigin', 'Anonymous'); // è§£å†³æŽ§åˆ¶å°è·¨åŸŸæŠ¥é”™çš„问题
            canvas.getContext('2d').drawImage(Img, 0, 0, width, height); //将图片绘制到canvas中
            dataURL = canvas.toDataURL('image/jpeg'); //转换图片为dataURL
            callback ? callback(dataURL) : null; //调用回调函数
        };
    },
    getImageFiles(urls, callback) {
        if (urls.length == 0) {
            callback([])
        }
        var files = [];
        urls.forEach((url) => {
            this.setInitImg(url, (file) => {
                files.push(file);
                if (files.length == urls.length) {
                    callback(files);
                }
            });
        });
    },
    setInitImg(url, callback) {
        let img = url;
        let _ = this;
        let imgRes;
        this.getBase64(img, (dataURL) => {
            imgRes = this.dataURLtoFile(dataURL, img);
            console.log(imgRes);
            callback(imgRes);
        });
    },
    dataURLtoFile(dataurl, filename) {
        //将base64转换为文件,dataurl为base64字符串,filename为文件名(必须带后缀名,如.jpg,.png)
        var arr = dataurl.split(','),
          mime = arr[0].match(/:(.*?);/)[1],
          bstr = atob(arr[1]),
          n = bstr.length,
          u8arr = new Uint8Array(n);
        while (n--) {
          u8arr[n] = bstr.charCodeAt(n);
        }
        return new File([u8arr], filename, { type: mime });
      }
}
src/views/fysp/config/EvalutationRule.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,339 @@
<template>
  <div>
    <FYTable @search="onSearch" :pagination="false" ref="tableRef" :expandChange="expandChange">
      <template #options>
        <!-- åŒºåŽ¿ -->
        <!-- <FYOptionLocation
          :allOption="false"
          :level="3"
          :checkStrictly="false"
          v-model:value="formSearch.locations"
        ></FYOptionLocation> -->
      </template>
      <template #table-column>
        <el-table-column align="center" type="expand">
          <template v-slot="scope">
            <el-table :data="scope.row.children" table-layout="fixed">
              <el-table-column
                prop="itemname"
                label="名称"
                width="200"
                :show-overflow-tooltip="true"
              ></el-table-column>
              <el-table-column prop="itemdescription" label="描述"></el-table-column>
              <el-table-column prop="maxscore" label="最高分"></el-table-column>
              <el-table-column prop="minscore" label="最低分"></el-table-column>
              <el-table-column prop="defaultvalue" label="默认值"></el-table-column>
              <el-table-column
                prop="ertype"
                label="评分规则类型"
                width="150"
                :formatter="formatSubRuleType"
              >
              </el-table-column>
              <el-table-column
                prop="extension1"
                label="评分类型"
                width="150"
                :formatter="formatScoreMode"
              ></el-table-column>
              <el-table-column
                prop="extension2"
                label="得分模式"
                width="150"
                :formatter="formatScoreMode"
              ></el-table-column>
              <el-table-column
                prop="extension3"
                label="选择模式"
                width="150"
                :formatter="formatScoreMode"
              ></el-table-column>
              <!-- <el-table-column
                prop="usedanalyse"
                label="是否分析"
                width="100"
                :formatter="formatBoolean"
              >
              </el-table-column> -->
              <el-table-column
                prop="remark"
                label="备注"
                :show-overflow-tooltip="true"
              ></el-table-column>
              <el-table-column v-slot="scope" prop="操作" label="操作" width="150">
                <el-button link type="primary" @click="editSubRule(scope.row, 1)">查看</el-button>
                <el-button link type="primary" @click="editSubRule(scope.row, 2)">修改</el-button>
                <el-popconfirm title="确认删除?" @confirm="deleteSubRule(scope.row)">
                  <template #reference>
                    <el-button link type="danger">删除</el-button>
                  </template>
                </el-popconfirm>
              </el-table-column>
            </el-table>
          </template>
        </el-table-column>
        <el-table-column
          prop="rulename"
          label="规则名称"
          width="350"
          :show-overflow-tooltip="true"
        ></el-table-column>
        <el-table-column
          prop="ruletype"
          label="规则类型"
          :formatter="formatRuleType"
        ></el-table-column>
        <el-table-column prop="tasktype" label="任务类型"></el-table-column>
        <el-table-column prop="scensetype" label="场景类型"></el-table-column>
        <el-table-column prop="provincename" label="省份名称"></el-table-column>
        <el-table-column prop="cityname" label="城市名称"></el-table-column>
        <el-table-column prop="districtname" label="区县名称"></el-table-column>
        <el-table-column
          prop="suitable"
          label="是否适用"
          :formatter="formatBoolean"
        ></el-table-column>
        <el-table-column prop="isuse" label="是否启用" :formatter="formatBoolean"></el-table-column>
        <el-table-column v-slot="scope" prop="操作" label="操作" width="160">
          <el-button link type="primary" @click="editRule(scope.row, 1)">查看</el-button>
          <el-button link type="primary" @click="editRule(scope.row, 2)">修改</el-button>
          <el-popconfirm title="确认删除?" @confirm="deleteRule(scope.row)">
            <template #reference>
              <el-button link type="danger">删除</el-button>
            </template>
          </el-popconfirm>
        </el-table-column>
      </template>
    </FYTable>
    <!-- çˆ¶èŠ‚ç‚¹çš„ä¿®æ”¹é¡µé¢ -->
    <el-dialog title="修改" width="80%" v-model="evalutionRuleVisible">
      <CompEvalutionRuleUpd
        v-if="evalutionRuleVisible"
        :before-close="beforeEvalutionRuleDialogClose"
        :evalutionRule="currEvalutionRule"
        :readonly="parentReadOnly"
        @updated="onEvalutionRuleUpdated"
      />
    </el-dialog>
    <!-- å­èŠ‚ç‚¹çš„ä¿®æ”¹é¡µé¢ -->
    <el-dialog title="修改" width="80%" v-model="evalutionSubRuleVisible">
      <CompEvalutionSubRuleUpd
        v-if="evalutionSubRuleVisible"
        :before-close="beforeEvalutionSubRuleDialogClose"
        :evalutionSubRule="currEvalutionSubRule"
        :readonly="subReadOnly"
        @updated="onEvalutionSubRuleUpdated"
      />
    </el-dialog>
  </div>
</template>
<script>
import evaluateApi from '@/api/fysp/evaluateApi';
import CompEvalutionRuleUpd from './components/evalution/CompEvalutionRuleUpd.vue';
import CompEvalutionSubRuleUpd from './components/evalution/CompEvalutionSubRuleUpd.vue';
import { ElMessage } from 'element-plus';
export default {
  watch: {
    expandKeyId: {
      handler(newObj, oldObj) {
        console.log('expandKeyId', this.expandKeyId);
      },
      deep: true
    }
  },
  components: {
    CompEvalutionRuleUpd,
    CompEvalutionSubRuleUpd
  },
  mounted() {},
  methods: {
    // è¯„分规则子节点修改页面相关
    deleteSubRule(row) {
      evaluateApi.deleteSubRuleById(row.guid).then((res) => {
        if (res == 1) {
          ElMessage({
            message: '删除成功',
            type: 'success'
          });
          this.refreshTableData();
        }
      });
    },
    editSubRule(row, type) {
      this.subReadOnly = (type == 1);
      this.currEvalutionSubRule = row;
      this.evalutionSubRuleVisible = true;
    },
    onEvalutionSubRuleUpdated(isOk) {
      this.beforeEvalutionSubRuleDialogClose();
      if (!isOk) {
        return;
      }
      this.refreshTableData();
    },
    beforeEvalutionSubRuleDialogClose() {
      this.evalutionSubRuleVisible = false;
    },
    // è¯„分规则父节点修改页面相关
    deleteRule(row) {
      evaluateApi.deleteParentRuleById(row.guid).then((res) => {
        if (res == 1) {
          ElMessage({
            message: '删除成功',
            type: 'success'
          });
          this.refreshTableData();
        }
      });
    },
    editRule(row, type) {
      this.parentReadOnly = (type == 1);
      this.currEvalutionRule = row;
      this.evalutionRuleVisible = true;
    },
    onEvalutionRuleUpdated(isOk) {
      this.beforeEvalutionRuleDialogClose();
      if (!isOk) {
        return;
      }
      this.refreshTableData();
    },
    beforeEvalutionRuleDialogClose() {
      this.evalutionRuleVisible = false;
    },
    // åˆ·æ–°åˆ—表数据
    refreshTableData() {
      setTimeout(() => {
        this.$refs.tableRef.onSearch();
      }, 1000);
    },
    onSearch(page, func) {
      evaluateApi.getAllParentRules().then((res) => {
        this.expandData = [];
        this.expandKeyId = [];
        res.forEach((element) => {
          element.hasChildren = true;
          // èŽ·å–å­èŠ‚ç‚¹åˆ—è¡¨
          evaluateApi.getSubRules(element.guid).then((res) => {
            element.children = res.data;
          });
        });
        func({ data: res });
      });
    },
    // åŠ è½½å­èŠ‚ç‚¹
    load(row) {
      var topId = row.guid;
      evaluateApi.getSubRules(topId).then((res) => {
        return res.data;
      });
    },
    // åˆ—表展示内容键值对的映射方法
    formatBoolean(row, column, cellValue) {
      if (cellValue == null || cellValue == undefined) {
        return '';
      }
      return cellValue ? '是' : '否';
    },
    formatRuleType(row, column, cellValue) {
      for (let index = 0; index < this.ruleTypes.length; index++) {
        const item = this.ruleTypes[index];
        if (item.value == cellValue) {
          return item.label;
        }
      }
      return '';
    },
    formatSubRuleType(row, column, cellValue) {
      for (let index = 0; index < this.subRuleTypes.length; index++) {
        const item = this.subRuleTypes[index];
        if (item.value == cellValue) {
          return item.label;
        }
      }
      return '';
    },
    // åˆ†æ•°æ¨¡å¼
    formatScoreMode(row, column, cellValue) {
      for (let index = 0; index < this.scoreTypes.length; index++) {
        const item = this.scoreTypes[index];
        if (item.value == cellValue) {
          return item.label;
        }
      }
      return '';
    },
    // åˆ·æ–°æ•°æ®æ—¶ä¿å­˜è¡Œçš„展开状态
    saveExpandedRowsStatus() {
      this.tableData.forEach((item) => {
        if (item.guid == this.expandKeyId) {
          this.$refs.table.toggleRowExpansion(item, true);
        }
      });
    },
    // æ‰©å±•每次只能打开一个
    expandChange(row, expandedRows) {
      this.expandData = expandedRows;
      if (expandedRows.length == 1) {
        if (!this.expandKeyId) {
          this.expandKeyId = row.guid;
        }
        this.load(row);
      } else if (expandedRows.length >= 2) {
        //已经展开一行
        this.expandKeyId = expandedRows[expandedRows.length - 1].guid; //获取最后一个点开的rowID
        //遍历表格数据,关闭其他的展开行
        this.tableData.map((item) => {
          if (item.guid != this.expandKeyId) {
            this.$refs.table.toggleRowExpansion(item, false);
          }
        });
      } else {
        //关闭
        this.expandKeyId = undefined;
        this.expandData = [];
      }
    }
  },
  data() {
    return {
      subReadOnly: false,
      parentReadOnly: false,
      // å½“前展开的行
      expandKeyId: [],
      expandData: [],
      // è¯„分规则子节点修改页面相关
      currEvalutionSubRule: {},
      evalutionSubRuleVisible: false,
      // è¯„分规则父节点修改页面相关
      currEvalutionRule: {},
      evalutionRuleVisible: false,
      tableData: [],
      ruleTypes: [
        { label: '规范性', value: '1' },
        { label: '评分', value: '2' }
      ],
      subRuleTypes: [
        { label: '规范考核项', value: 1 },
        { label: '评分大项', value: 2 },
        { label: '评分小项', value: 3 },
        { label: '最小评分项', value: 4 }
      ],
      scoreTypes: [
        { label: '基础分', value: 'basic_score' },
        { label: '附加分', value: 'addition_score' },
        { label: '减分模式', value: 'minus_mode' },
        { label: '加分模式', value: 'add_mode' },
        { label: '单选模式', value: 'single_mode' },
        { label: '多选模式', value: 'multi_mode' },
        { label: '空', value: 'null' }
      ],
      formSearch: {}
    };
  }
};
</script>
<style scoped></style>
src/views/fysp/config/components/evalution/CompEvalutionRuleUpd.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,172 @@
<template>
  <FYForm
    :form-info="formInfo"
    :rules="rules"
    :showButtons="!readonly"
    @submit="submit"
  >
    <template #form-item="{ fyFormInfo }">
      <el-form-item label="规则名称" prop="rulename">
        <el-input v-model="formInfo.rulename" :disabled="readonly"></el-input>
      </el-form-item>
      <!-- <FYOptionScene
        :allOption="false"
        :type="2"
        v-model:value="formInfo._scenetype"
      ></FYOptionScene> -->
      <el-form-item label="场景类型" prop="_scenetype">
        <el-select v-model="formInfo._scenetype" placeholder="场景类型" :disabled="readonly">
          <el-option v-for="s in sceneTypes" :key="s.value" :label="s.label" :value="s" />
        </el-select>
      </el-form-item>
      <!-- åŒºåŽ¿ -->
      <FYOptionLocation
        :allOption="false"
        :level="3"
        :initValue="false"
        :checkStrictly="true"
        v-model:value="formInfo._locations"
      ></FYOptionLocation>
      <el-form-item label="规则类型" prop="ruletype">
        <el-select v-model="formInfo.ruletype" placeholder="请选择" :disabled="readonly">
          <el-option
            v-for="item in ruleTypeOptions"
            :key="item.value"
            :label="item.label"
            :value="item.value"
          >
          </el-option>
        </el-select>
      </el-form-item>
      <el-form-item label="任务类型" prop="tasktype">
        <el-select v-model="formInfo.tasktype" placeholder="请选择" :disabled="readonly">
          <el-option
            v-for="item in tasktypeOptions"
            :key="item.value"
            :label="item.label"
            :value="item.value"
          >
          </el-option>
        </el-select>
      </el-form-item>
      <el-form-item label="是否适用" prop="suitable">
        <el-switch v-model="formInfo.suitable" :disabled="readonly"></el-switch>
      </el-form-item>
      <el-form-item label="是否启用" prop="isuse">
        <el-switch v-model="formInfo.isuse" :disabled="readonly"></el-switch>
      </el-form-item>
    </template>
  </FYForm>
</template>
<script>
import { enumScene } from '@/enum/scene';
import { ElMessage } from 'element-plus';
import evaluateApi from '@/api/fysp/evaluateApi';
import { useCloned } from '@vueuse/core';
export default {
  props: {
    readonly: {
      type: Boolean,
      default: false,
    },
    evalutionRule: {
      type: Object,
      default: {}
    }
  },
  created() {
    this.initFormInfo();
  },
  mounted() {},
  methods: {
    // update方法
    updateEvalutionRule() {
      return evaluateApi.updateParentRule(this.formInfo);
    },
    initFormInfo() {
      this.formInfo = useCloned(this.evalutionRule).cloned.value;
      this.parseSceneBaseInfo(this.formInfo);
    },
    parseSceneBaseInfo(param) {
      const s = param;
      s._scenetype = {
        label: s.scensetype,
        value: s.scensetypeid + ''
      };
      s._locations = {
        pCode: s.provincecode,
        pName: s.provincename,
        cCode: s.citycode,
        cName: s.cityname,
        dCode: s.districtcode,
        dName: s.districtname
      };
      console.log('param', param);
    },
    // åˆ é™¤æ— å…³å­—段
    deleteExtraField(data) {
      if (!(data instanceof Object)) {
        return;
      }
      for (let i = data.length - 1; i >= 0; i--) {
        if (key.startsWith('_')) {
          delete data[key];
        }
      }
    },
    submit(formObj, success, fail) {
      // æ•°æ®å‡†å¤‡
      this.formInfo.scensetypeid = this.formInfo._scenetype.value;
      this.formInfo.scensetype = this.formInfo._scenetype.label;
      // è¡Œæ”¿åŒºåˆ’信息填充
      const a = this.formInfo._locations;
      this.formInfo.provincecode = a.pCode;
      this.formInfo.provincename = a.pName;
      this.formInfo.citycode = a.cCode;
      this.formInfo.cityname = a.cName;
      this.formInfo.districtcode = a.dCode;
      this.formInfo.districtname = a.dName;
      this.deleteExtraField(this.formInfo);
      console.log('数据处理结束', this.formInfo);
      return new Promise((reslove, reject) => {
        setTimeout(() => {
          this.$emit('updated', true);
          this.updateEvalutionRule().then((res) => {
            if (res != 1) {
              fail();
              reslove();
            }
            success();
          });
          reslove();
        }, 1000);
      });
    }
  },
  data() {
    return {
      sceneTypes: enumScene(2, false),
      formInfo: {},
      ruleTypeOptions: [
        { label: '规范性', value: '1' },
        { label: '评分', value: '2' }
      ],
      tasktypeOptions: [
        { label: '巡查', value: 1 },
        { label: '无人机巡查', value: 2 },
        { label: '复核', value: 3 },
        { label: '执法支持', value: 4 },
        { label: '监测运维', value: 5 },
        { label: '治理运维', value: 6 },
        { label: '改造', value: 7 },
        { label: '治理', value: 8 },
        { label: '咨询', value: 9 },
        { label: '自动评分', value: 99 }
      ]
    };
  }
};
</script>
<style scoped></style>
src/views/fysp/config/components/evalution/CompEvalutionSubRuleUpd.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,138 @@
<template>
  <FYForm :form-info="formInfo" :rules="rules" :showButtons="!readonly" @submit="submit">
    <template #form-item="{ fyFormInfo }">
      <el-form-item label="名称" prop="itemname">
        <el-input v-model="formInfo.itemname" :disabled="readonly"></el-input>
      </el-form-item>
      <el-form-item label="描述" prop="itemdescription">
        <el-input
          type="textarea"
          v-model="formInfo.itemdescription"
          :disabled="readonly"
        ></el-input>
      </el-form-item>
      <el-form-item label="最高分" prop="maxscore">
        <el-input-number v-model="formInfo.maxscore" :disabled="readonly"></el-input-number>
      </el-form-item>
      <el-form-item label="最低分" prop="minscore">
        <el-input-number v-model="formInfo.minscore" :disabled="readonly"></el-input-number>
      </el-form-item>
      <el-form-item label="默认值" prop="defaultvalue">
        <el-input-number v-model="formInfo.defaultvalue" :disabled="readonly"></el-input-number>
      </el-form-item>
      <el-form-item label="评分规则类型" prop="ertype">
        <el-select v-model="formInfo.ertype" placeholder="请选择" :disabled="readonly">
          <el-option
            v-for="item in subRuleTypeOptions"
            :key="item.value"
            :label="item.label"
            :value="item.value"
            :disabled="item.disabled"
          >
          </el-option>
        </el-select>
      </el-form-item>
      <el-form-item label="评分类型" prop="extension1">
        <el-select v-model="formInfo.extension1" placeholder="请选择" :disabled="readonly">
          <el-option
            v-for="item in score1Types"
            :key="item.value"
            :label="item.label"
            :value="item.value"
          >
          </el-option>
        </el-select>
      </el-form-item>
      <el-form-item label="得分模式" prop="extension2">
        <el-select v-model="formInfo.extension2" placeholder="请选择" :disabled="readonly">
          <el-option
            v-for="item in score2Types"
            :key="item.value"
            :label="item.label"
            :value="item.value"
          >
          </el-option>
        </el-select>
      </el-form-item>
      <el-form-item label="选择模式" prop="extension3">
        <el-select v-model="formInfo.extension3" placeholder="请选择" :disabled="readonly">
          <el-option
            v-for="item in score3Types"
            :key="item.value"
            :label="item.label"
            :value="item.value"
          >
          </el-option>
        </el-select>
      </el-form-item>
      <el-form-item label="备注" prop="remark">
        <el-input type="textarea" v-model="formInfo.remark" :disabled="readonly"></el-input>
      </el-form-item>
    </template>
  </FYForm>
</template>
<script>
import { ElMessage } from 'element-plus';
import evaluateApi from '@/api/fysp/evaluateApi';
import { useCloned } from '@vueuse/core';
export default {
  props: {
    readonly: {
      type: Boolean,
      default: false
    },
    evalutionSubRule: {
      type: Object,
      default: {}
    }
  },
  mounted() {
    this.formInfo = useCloned(this.evalutionSubRule).cloned.value;
  },
  methods: {
    updateEvalutionSubRule() {
      return evaluateApi.updateSubRule(this.formInfo);
    },
    submit(formObj, success, fail) {
      return new Promise((reslove, reject) => {
        setTimeout(() => {
          this.$emit('updated', true);
          this.updateEvalutionSubRule().then((res) => {
            if (res != 1) {
              fail();
              reslove();
            }
            success();
          });
          reslove();
        }, 1000);
      });
    }
  },
  data() {
    return {
      rules: {},
      formInfo: {},
      subRuleTypeOptions: [
        { label: '规范考核项', value: 1, disabled: true },
        { label: '评分大项', value: 2 },
        { label: '评分小项', value: 3 },
        { label: '最小评分项', value: 4 }
      ],
      score1Types: [
        { label: '基础分', value: 'basic_score' },
        { label: '附加分', value: 'addition_score' }
      ],
      score2Types: [
        { label: '减分模式', value: 'minus_mode' },
        { label: '加分模式', value: 'add_mode' }
      ],
      score3Types: [
        { label: '单选模式', value: 'single_mode' },
        { label: '多选模式', value: 'multi_mode' }
      ]
    };
  }
};
</script>
<style scoped></style>
src/views/fysp/evaluation/EvalutationEdit.vue
@@ -1,14 +1,44 @@
<template>
  <FYPageHeader title="评估结果详情"></FYPageHeader>
  <el-row v-for="item in evaluation" :key="item.id">
  </el-row>
  <el-row v-for="item in evaluation" :key="item.id"> </el-row>
  <div class="btns">
    <el-button type="primary" @click="submit" :disabled="!isUpdated">提交</el-button>
  </div>
  <el-table
    class="table-style"
    :data="tableData"
    ref="tableRef"
    :span-method="objectSpanMethod"
    table-layout="fixed"
    :cell-style="cellClassName"
    border
    stripe
  >
    <el-table-column v-slot="scope" prop="one_title" label="一级指标" width="200">
      <!-- <el-checkbox v-model="scope.row.one_select" @change="checked => oneSelectChange(checked, scope.row)">{{ scope.row.one_title }}</el-checkbox> -->
    </el-table-column>
    <el-table-column prop="one_score" label="分值" width="55" />
    <el-table-column prop="one_maxScore" label="最大分值" width="90" />
    <el-table-column v-slot="scope" prop="two_title" label="二级指标" width="200">
      <!-- <el-checkbox v-model="scope.row.two_select" @change="checked => twoSelectChange(checked, scope.row)">{{ scope.row.two_title }}</el-checkbox> -->
    </el-table-column>
    <el-table-column prop="two_score" label="分值" width="55" />
    <el-table-column prop="two_maxScore" label="最大分值" width="90" />
    <el-table-column v-slot="scope" prop="three_title" label="具体问题">
      <el-checkbox
        v-model="scope.row.three_select"
        @change="(checked) => threeSelectChange(checked, scope.row)"
        >{{ scope.row.three_title }}</el-checkbox
      >
    </el-table-column>
    <el-table-column prop="three_score" label="单项扣分" width="90" />
  </el-table>
</template>
<script>
import evaluateApi from '@/api/fysp/evaluateApi';
import { useFetchData } from '@/composables/fetchData';
import { ElMessage } from 'element-plus';
export default {
  setup() {
    const { loading, fetchData } = useFetchData();
@@ -16,7 +46,10 @@
  },
  data() {
    return {
      evaluation: []
      tableData: [],
      evaluation: [],
      subTaskId: '',
      isUpdated: false
    };
  },
  created() {
@@ -30,18 +63,217 @@
    //   // æ­¤æ—¶ data å·²ç»è¢« observed äº†
    //   { immediate: true }
    // );
    this.getScore();
  },
  computed: {
    // å·²è¢«å‹¾é€‰çš„item
    checkedUpdatedList() {
      var list = [];
      for (let index = 0; index < this.tableData.length; index++) {
        const element = this.tableData[index];
        if (element.three_select) {
          list.push(element.three_id);
        }
      }
      return list;
    }
  },
  mounted() {
    this.getList();
  },
  methods: {
    // èŽ·å–è¯„åˆ†
    getScore() {
      this.fetchData(() => {
        return evaluateApi.fetchItemEvaluation(this.$route.params.subTaskId).then((res) => {
          this.evaluation = res;
    // æ¯ä¸€ä¸ªå•元格的class
    cellClassName({ row, column, rowIndex, columnIndex }) {
      if (column.property === 'one_score') {
        if (row.one_score < 0) {
          return { color: 'red' };
        }
      } else if (column.property === 'two_score') {
        if (row.two_score < 0) {
          return { color: 'red' };
        }
      } else if (column.property === 'three_score') {
        if (row.three_score < 0) {
          return { color: 'red' };
        }
      }
      return { color: 'black' };
    },
    /** æä»· */
    submit() {
      evaluateApi
        .updateScore({
          subTaskId: this.subTaskId,
          itemList: this.checkedUpdatedList
        })
        .then((res) => {
          if (res.success) {
            ElMessage({
              message: res.message,
              type: 'success'
        });
          }else {
            ElMessage({
              message: res.message,
              type: 'error'
            });
          }
        });
      setTimeout(() => {
        this.getList();
      }, 1000);
    },
    /** é€šè¿‡ç¬¬ä¸‰çº§çš„id获取上级以及顶级 */
    getSuperObjByThreeId(threeId, list, path = []) {
      for (let index = 0; index < list.length; index++) {
        const item = list[index];
        // å°†å½“前项添加到路径中
        const currentPath = path.concat(item);
        if (item.id === threeId) {
          // å¦‚果找到匹配的 id,返回路径数组
          return currentPath;
        }
        const subList = item.subList;
        if (subList) {
          // é€’归查找子列表
          const result = this.getSuperObjByThreeId(threeId, subList, currentPath);
          if (result) {
            return result; // å¦‚果找到匹配的 id,返回结果
          }
        }
      }
      return null; // å¦‚果没有找到匹配的 id,返回 null
    },
    /** é—®é¢˜é€‰æ‹©æ¡† */
    threeSelectChange(isSelect, row) {
      this.isUpdated = true;
    },
    /** åˆ—合并 */
    objectSpanMethod({ row, column, rowIndex, columnIndex }) {
      if (columnIndex === 0 || columnIndex === 1 || columnIndex === 2) {
        // å¯¹ ä¸€çº§æŒ‡æ ‡ åˆ—进行合并
        let rowSpan = 1;
        for (let i = rowIndex + 1; i < this.tableData.length; i++) {
          if (this.tableData[i].one_id === row.one_id) {
            rowSpan++;
          } else {
            break;
          }
        }
        if (rowIndex > 0) {
          if (this.tableData[rowIndex - 1].one_id === row.one_id) {
            return { rowspan: 0, colspan: 0 };
          }
        }
        return { rowspan: rowSpan, colspan: 1 };
      } else if (columnIndex === 3 || columnIndex === 4 || columnIndex === 5) {
        // å¯¹ äºŒçº§æŒ‡æ ‡ åˆ—进行合并,确保 ä¸€çº§æŒ‡æ ‡ ä¸€æ ·
        let rowSpan = 1;
        for (let i = rowIndex + 1; i < this.tableData.length; i++) {
          if (this.tableData[i].one_id === row.one_id && this.tableData[i].two_id === row.two_id) {
            rowSpan++;
          } else {
            break;
          }
        }
        if (rowIndex > 0) {
          if (
            this.tableData[rowIndex - 1].one_id === row.one_id &&
            this.tableData[rowIndex - 1].two_id === row.two_id
          ) {
            return { rowspan: 0, colspan: 0 };
          }
        }
        return { rowspan: rowSpan, colspan: 1 };
      }
    },
    /** å¯¹è±¡å±žæ€§æ‹·è´ */
    deepCopyWithPrefix(obj, target, prefix) {
      // ç¡®ä¿ target æ˜¯ä¸€ä¸ªå¯¹è±¡
      if (typeof target !== 'object' || target === null) {
        target = {};
      }
      // éåŽ†å¯¹è±¡çš„æ‰€æœ‰å±žæ€§
      for (const key in obj) {
        if (obj.hasOwnProperty(key)) {
          // ä¸ºå±žæ€§ååŠ ä¸Šå‰ç¼€
          const newKey = prefix + key;
          // å¦‚果属性值是对象,则递归复制
          if (typeof obj[key] === 'object' && obj[key] !== null) {
            this.deepCopyWithPrefix(obj[key], (target[newKey] = {}), prefix);
          } else {
            // å¦åˆ™ç›´æŽ¥å¤åˆ¶å±žæ€§
            target[newKey] = obj[key];
          }
        }
      }
      return target;
    },
    /** @param data åˆ—表数据 */
    genTableData(data) {
      var result = [];
      if (data) {
        for (let i = 0; i < data.length; i++) {
          const firstLevelItem = data[i];
          var secondLevel = firstLevelItem.subList;
          if (secondLevel) {
            for (let j = 0; j < secondLevel.length; j++) {
              const secondLevelItem = secondLevel[j];
              var thirdLevel = secondLevelItem.subList;
              if (thirdLevel) {
                for (let q = 0; q < thirdLevel.length; q++) {
                  const thirdLevelItem = thirdLevel[q];
                  var item = {};
                  this.deepCopyWithPrefix(firstLevelItem, item, 'one_');
                  this.deepCopyWithPrefix(secondLevelItem, item, 'two_');
                  this.deepCopyWithPrefix(thirdLevelItem, item, 'three_');
                  result.push(item);
                }
              }
            }
          }
        }
      }
      return result;
    },
    getList() {
      this.subTaskId = this.$route.params.subTaskId;
      evaluateApi.fetchItemEvaluation(this.subTaskId).then((res) => {
        this.isUpdated = false;
        this.tableData = this.genTableData(res.data.details);
      });
    },
    onSearch(page, func) {
      evaluateApi.fetchItemEvaluation(this.$route.params.subTaskId).then((res) => {
        if (typeof func === 'function') {
          // å¤„理数据
          var data = this.genTableData(res.data);
          func({ data: data });
        }
        this.tableData = this.genTableData(res.data);
      });
    }
  }
};
</script>
<style scoped></style>
<style scoped>
.table-style {
  width: 100%;
  padding-bottom: 30px;
}
.btns {
  padding-bottom: 10px;
  padding-right: 30px;
  display: flex;
  flex-direction: row-reverse;
}
/* æ”¹å˜è¡¨æ ¼å†…单元格边框颜色 */
.el-table {
  --el-table-border-color: #000000;
}
.red-cell {
  background-color: red;
}
</style>