Просмотр исходного кода

Merge branch 'BVS' into allTestUrgent

qymljy 7 месяцев назад
Родитель
Сommit
46728a0dca

+ 7 - 0
.trae/rules/project_rules.md

@@ -0,0 +1,7 @@
+
+## UI库
+  - 所有页面都使用element-ui组件库
+
+## 前端库
+  - 所有页面都使用vue.js框架
+  - 所有页面都使用vue2

+ 16 - 9
src/components/newLayout/index.vue

@@ -89,11 +89,15 @@ export default {
   },
   methods: {
     onRender() {
-      this.$refs.menu.rander();
-      this.$refs.AsideTemp.dateNow = Date.now();
-      this.$refs.AsideTemp.systemList = JSON.parse(
-        sessionStorage.getItem("module_info")
-      );
+      if (this.$refs.menu && this.$refs.menu.rander) {
+        this.$refs.menu.rander();
+      }
+      if (this.$refs.AsideTemp) {
+        this.$refs.AsideTemp.dateNow = Date.now();
+        this.$refs.AsideTemp.systemList = JSON.parse(
+          sessionStorage.getItem("module_info")
+        );
+      }
       this.dateNow = false;
       this.$nextTick(() => {
         this.debouned();
@@ -108,6 +112,10 @@ export default {
         clearTimeout(this.timer);
       }
       this.timer = setTimeout(() => {
+        // 检查 $refs 是否存在
+        if (!this.$refs.menu || !this.$refs.menu.$refs.menuList) {
+          return;
+        }
         let size = this.$refs.menu.$refs.menuList.$el.clientHeight / 40 - 1;
         if (this.$refs.menu.$refs.menuList.$el.clientHeight === 80) {
           this.divTop =
@@ -176,7 +184,9 @@ export default {
         this.dialogVisible = true;
       }
     }
-    /*this.debouned()*/
+    this.$nextTick(() => {
+      this.debouned();
+    });
     /* console.log('长度')
     console.log(this.$refs.menu.$refs.menuList.$el.clientHeight,'高度')
     console.log(this.$refs.menu.$refs.menuList.$el.clientHeight % 60)
@@ -188,9 +198,6 @@ export default {
   },
   created() {
     window.addEventListener("resize", this.debouned);
-    this.$nextTick(() => {
-      this.debouned();
-    });
   },
 };
 </script>

+ 9 - 1
src/components/normal-basic-layout/index.vue

@@ -59,7 +59,7 @@
 
             <template v-slot:opreation="scope">
 
-              <drawerTemp class="inline-16" v-if="detailPath && checkRowStatus(scope.data.status)" :data="scope.data" :detailPath="detailPath" :idName="idName" @onSuccess="listData"></drawerTemp>
+              <drawerTemp class="inline-16" v-if="detailPath && checkRowStatus(scope.data.status)" :data="scope.data" :detailPath="getComputedDetailPath(scope.data)" :idName="idName" @onSuccess="listData"></drawerTemp>
               <slot :data="scope" name="tbOpreation"></slot>
               <!--systemappid != 163 排除报表应用-->
               <reportCenter class="inline-16"  size="mini" :data="reportCenterLsit.filter(item => item.type == 'printinfo')" v-if="reportCenterLsit.filter(item => item.type == 'printinfo').length > 0 && systemappid != 163" :status="scope.data.status">
@@ -152,6 +152,14 @@ export default {
     }
   },
   methods:{
+    getComputedDetailPath(data) {
+      // 如果detailPath是函数,则调用它并传入数据
+      if (typeof this.detailPath === 'function') {
+        return this.detailPath(data);
+      }
+      // 否则直接返回detailPath对象
+      return this.detailPath;
+    },
     clearSearch () {
       this.$store.state.searchValue = ''
       this.listData(this.param.content.pageNumber = 1)

BIN
src/optionSystem/.DS_Store


+ 651 - 0
src/optionSystem/calculationAndSelection/index.css

@@ -0,0 +1,651 @@
+/* stylelint-disable at-rule-empty-line-before,at-rule-name-space-after,at-rule-no-unknown */
+/* stylelint-disable no-duplicate-selectors */
+/* stylelint-disable */
+/* stylelint-disable declaration-bang-space-before,no-duplicate-selectors,string-no-newline */
+.ant-steps {
+    box-sizing: border-box;
+    margin: 0;
+    padding: 0;
+    color: rgba(0, 0, 0, 0.65);
+    font-size: 14px;
+    font-variant: tabular-nums;
+    line-height: 1.5;
+    list-style: none;
+    font-feature-settings: 'tnum';
+    display: flex;
+    width: 100%;
+    font-size: 0;
+  }
+  .ant-steps-item {
+    position: relative;
+    display: inline-block;
+    flex: 1;
+    overflow: hidden;
+    vertical-align: top;
+  }
+  .ant-steps-item-container {
+    outline: none;
+  }
+  .ant-steps-item:last-child {
+    flex: none;
+  }
+  .ant-steps-item:last-child > .ant-steps-item-container > .ant-steps-item-tail,
+  .ant-steps-item:last-child > .ant-steps-item-container > .ant-steps-item-content > .ant-steps-item-title::after {
+    display: none;
+  }
+  .ant-steps-item-icon,
+  .ant-steps-item-content {
+    display: inline-block;
+    vertical-align: top;
+  }
+  .ant-steps-item-icon {
+    width: 32px;
+    height: 32px;
+    margin-right: 8px;
+    font-size: 16px;
+    font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei', 'Helvetica Neue', Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol';
+    line-height: 32px;
+    text-align: center;
+    border: 1px solid rgba(0, 0, 0, 0.25);
+    border-radius: 32px;
+    transition: background-color 0.3s, border-color 0.3s;
+  }
+  .ant-steps-item-icon > .ant-steps-icon {
+    position: relative;
+    top: -1px;
+    color: #1890ff;
+    line-height: 1;
+  }
+  .ant-steps-item-tail {
+    position: absolute;
+    top: 12px;
+    left: 0;
+    width: 100%;
+    padding: 0 10px;
+  }
+  .ant-steps-item-tail::after {
+    display: inline-block;
+    width: 100%;
+    height: 1px;
+    background: #e8e8e8;
+    border-radius: 1px;
+    transition: background 0.3s;
+    content: '';
+  }
+  .ant-steps-item-title {
+    position: relative;
+    display: inline-block;
+    padding-right: 16px;
+    color: rgba(0, 0, 0, 0.65);
+    font-size: 16px;
+    line-height: 32px;
+  }
+  .ant-steps-item-title::after {
+    position: absolute;
+    top: 16px;
+    left: 100%;
+    display: block;
+    width: 9999px;
+    height: 1px;
+    background: #e8e8e8;
+    content: '';
+  }
+  .ant-steps-item-subtitle {
+    display: inline;
+    margin-left: 8px;
+    color: rgba(0, 0, 0, 0.45);
+    font-weight: normal;
+    font-size: 14px;
+  }
+  .ant-steps-item-description {
+    color: rgba(0, 0, 0, 0.45);
+    font-size: 14px;
+  }
+  .ant-steps-item-wait .ant-steps-item-icon {
+    background-color: #fff;
+    border-color: rgba(0, 0, 0, 0.25);
+  }
+  .ant-steps-item-wait .ant-steps-item-icon > .ant-steps-icon {
+    color: rgba(0, 0, 0, 0.25);
+  }
+  .ant-steps-item-wait .ant-steps-item-icon > .ant-steps-icon .ant-steps-icon-dot {
+    background: rgba(0, 0, 0, 0.25);
+  }
+  .ant-steps-item-wait > .ant-steps-item-container > .ant-steps-item-content > .ant-steps-item-title {
+    color: rgba(0, 0, 0, 0.45);
+  }
+  .ant-steps-item-wait > .ant-steps-item-container > .ant-steps-item-content > .ant-steps-item-title::after {
+    background-color: #e8e8e8;
+  }
+  .ant-steps-item-wait > .ant-steps-item-container > .ant-steps-item-content > .ant-steps-item-description {
+    color: rgba(0, 0, 0, 0.45);
+  }
+  .ant-steps-item-wait > .ant-steps-item-container > .ant-steps-item-tail::after {
+    background-color: #e8e8e8;
+  }
+  .ant-steps-item-process .ant-steps-item-icon {
+    background-color: #fff;
+    border-color: #1890ff;
+  }
+  .ant-steps-item-process .ant-steps-item-icon > .ant-steps-icon {
+    color: #1890ff;
+  }
+  .ant-steps-item-process .ant-steps-item-icon > .ant-steps-icon .ant-steps-icon-dot {
+    background: #1890ff;
+  }
+  .ant-steps-item-process > .ant-steps-item-container > .ant-steps-item-content > .ant-steps-item-title {
+    color: rgba(0, 0, 0, 0.85);
+  }
+  .ant-steps-item-process > .ant-steps-item-container > .ant-steps-item-content > .ant-steps-item-title::after {
+    background-color: #e8e8e8;
+  }
+  .ant-steps-item-process > .ant-steps-item-container > .ant-steps-item-content > .ant-steps-item-description {
+    color: rgba(0, 0, 0, 0.65);
+  }
+  .ant-steps-item-process > .ant-steps-item-container > .ant-steps-item-tail::after {
+    background-color: #e8e8e8;
+  }
+  .ant-steps-item-process .ant-steps-item-icon {
+    background: #1890ff;
+  }
+  .ant-steps-item-process .ant-steps-item-icon > .ant-steps-icon {
+    color: #fff;
+  }
+  .ant-steps-item-process .ant-steps-item-title {
+    font-weight: 500;
+  }
+  .ant-steps-item-finish .ant-steps-item-icon {
+    background-color: #fff;
+    border-color: #1890ff;
+  }
+  .ant-steps-item-finish .ant-steps-item-icon > .ant-steps-icon {
+    color: #1890ff;
+  }
+  .ant-steps-item-finish .ant-steps-item-icon > .ant-steps-icon .ant-steps-icon-dot {
+    background: #1890ff;
+  }
+  .ant-steps-item-finish > .ant-steps-item-container > .ant-steps-item-content > .ant-steps-item-title {
+    color: rgba(0, 0, 0, 0.65);
+  }
+  .ant-steps-item-finish > .ant-steps-item-container > .ant-steps-item-content > .ant-steps-item-title::after {
+    background-color: #1890ff;
+  }
+  .ant-steps-item-finish > .ant-steps-item-container > .ant-steps-item-content > .ant-steps-item-description {
+    color: rgba(0, 0, 0, 0.45);
+  }
+  .ant-steps-item-finish > .ant-steps-item-container > .ant-steps-item-tail::after {
+    background-color: #1890ff;
+  }
+  .ant-steps-item-error .ant-steps-item-icon {
+    background-color: #fff;
+    border-color: #f5222d;
+  }
+  .ant-steps-item-error .ant-steps-item-icon > .ant-steps-icon {
+    color: #f5222d;
+  }
+  .ant-steps-item-error .ant-steps-item-icon > .ant-steps-icon .ant-steps-icon-dot {
+    background: #f5222d;
+  }
+  .ant-steps-item-error > .ant-steps-item-container > .ant-steps-item-content > .ant-steps-item-title {
+    color: #f5222d;
+  }
+  .ant-steps-item-error > .ant-steps-item-container > .ant-steps-item-content > .ant-steps-item-title::after {
+    background-color: #e8e8e8;
+  }
+  .ant-steps-item-error > .ant-steps-item-container > .ant-steps-item-content > .ant-steps-item-description {
+    color: #f5222d;
+  }
+  .ant-steps-item-error > .ant-steps-item-container > .ant-steps-item-tail::after {
+    background-color: #e8e8e8;
+  }
+  .ant-steps-item.ant-steps-next-error .ant-steps-item-title::after {
+    background: #f5222d;
+  }
+  .ant-steps .ant-steps-item:not(.ant-steps-item-active) > .ant-steps-item-container[role='button'] {
+    cursor: pointer;
+  }
+  .ant-steps .ant-steps-item:not(.ant-steps-item-active) > .ant-steps-item-container[role='button'] .ant-steps-item-title,
+  .ant-steps .ant-steps-item:not(.ant-steps-item-active) > .ant-steps-item-container[role='button'] .ant-steps-item-description,
+  .ant-steps .ant-steps-item:not(.ant-steps-item-active) > .ant-steps-item-container[role='button'] .ant-steps-item-icon .ant-steps-icon {
+    transition: color 0.3s;
+  }
+  .ant-steps .ant-steps-item:not(.ant-steps-item-active) > .ant-steps-item-container[role='button']:hover .ant-steps-item-title,
+  .ant-steps .ant-steps-item:not(.ant-steps-item-active) > .ant-steps-item-container[role='button']:hover .ant-steps-item-subtitle,
+  .ant-steps .ant-steps-item:not(.ant-steps-item-active) > .ant-steps-item-container[role='button']:hover .ant-steps-item-description {
+    color: #1890ff;
+  }
+  .ant-steps .ant-steps-item:not(.ant-steps-item-active):not(.ant-steps-item-process) > .ant-steps-item-container[role='button']:hover .ant-steps-item-icon {
+    border-color: #1890ff;
+  }
+  .ant-steps .ant-steps-item:not(.ant-steps-item-active):not(.ant-steps-item-process) > .ant-steps-item-container[role='button']:hover .ant-steps-item-icon .ant-steps-icon {
+    color: #1890ff;
+  }
+  .ant-steps-horizontal:not(.ant-steps-label-vertical) .ant-steps-item {
+    margin-right: 16px;
+    white-space: nowrap;
+  }
+  .ant-steps-horizontal:not(.ant-steps-label-vertical) .ant-steps-item:last-child {
+    margin-right: 0;
+  }
+  .ant-steps-horizontal:not(.ant-steps-label-vertical) .ant-steps-item:last-child .ant-steps-item-title {
+    padding-right: 0;
+  }
+  .ant-steps-horizontal:not(.ant-steps-label-vertical) .ant-steps-item-tail {
+    display: none;
+  }
+  .ant-steps-horizontal:not(.ant-steps-label-vertical) .ant-steps-item-description {
+    max-width: 140px;
+    white-space: normal;
+  }
+  .ant-steps-item-custom .ant-steps-item-icon {
+    height: auto;
+    background: none;
+    border: 0;
+  }
+  .ant-steps-item-custom .ant-steps-item-icon > .ant-steps-icon {
+    top: 0;
+    left: 0.5px;
+    width: 32px;
+    height: 32px;
+    font-size: 24px;
+    line-height: 32px;
+  }
+  .ant-steps-item-custom.ant-steps-item-process .ant-steps-item-icon > .ant-steps-icon {
+    color: #1890ff;
+  }
+  .ant-steps:not(.ant-steps-vertical) .ant-steps-item-custom .ant-steps-item-icon {
+    width: auto;
+  }
+  .ant-steps-small.ant-steps-horizontal:not(.ant-steps-label-vertical) .ant-steps-item {
+    margin-right: 12px;
+  }
+  .ant-steps-small.ant-steps-horizontal:not(.ant-steps-label-vertical) .ant-steps-item:last-child {
+    margin-right: 0;
+  }
+  .ant-steps-small .ant-steps-item-icon {
+    width: 24px;
+    height: 24px;
+    font-size: 12px;
+    line-height: 24px;
+    text-align: center;
+    border-radius: 24px;
+  }
+  .ant-steps-small .ant-steps-item-title {
+    padding-right: 12px;
+    font-size: 14px;
+    line-height: 24px;
+  }
+  .ant-steps-small .ant-steps-item-title::after {
+    top: 12px;
+  }
+  .ant-steps-small .ant-steps-item-description {
+    color: rgba(0, 0, 0, 0.45);
+    font-size: 14px;
+  }
+  .ant-steps-small .ant-steps-item-tail {
+    top: 8px;
+  }
+  .ant-steps-small .ant-steps-item-custom .ant-steps-item-icon {
+    width: inherit;
+    height: inherit;
+    line-height: inherit;
+    background: none;
+    border: 0;
+    border-radius: 0;
+  }
+  .ant-steps-small .ant-steps-item-custom .ant-steps-item-icon > .ant-steps-icon {
+    font-size: 24px;
+    line-height: 24px;
+    transform: none;
+  }
+  .ant-steps-vertical {
+    display: block;
+  }
+  .ant-steps-vertical .ant-steps-item {
+    display: block;
+    overflow: visible;
+  }
+  .ant-steps-vertical .ant-steps-item-icon {
+    float: left;
+    margin-right: 16px;
+  }
+  .ant-steps-vertical .ant-steps-item-content {
+    display: block;
+    min-height: 48px;
+    overflow: hidden;
+  }
+  .ant-steps-vertical .ant-steps-item-title {
+    line-height: 32px;
+  }
+  .ant-steps-vertical .ant-steps-item-description {
+    padding-bottom: 12px;
+  }
+  .ant-steps-vertical > .ant-steps-item > .ant-steps-item-container > .ant-steps-item-tail {
+    position: absolute;
+    top: 0;
+    left: 16px;
+    width: 1px;
+    height: 100%;
+    padding: 38px 0 6px;
+  }
+  .ant-steps-vertical > .ant-steps-item > .ant-steps-item-container > .ant-steps-item-tail::after {
+    width: 1px;
+    height: 100%;
+  }
+  .ant-steps-vertical > .ant-steps-item:not(:last-child) > .ant-steps-item-container > .ant-steps-item-tail {
+    display: block;
+  }
+  .ant-steps-vertical > .ant-steps-item > .ant-steps-item-container > .ant-steps-item-content > .ant-steps-item-title::after {
+    display: none;
+  }
+  .ant-steps-vertical.ant-steps-small .ant-steps-item-container .ant-steps-item-tail {
+    position: absolute;
+    top: 0;
+    left: 12px;
+    padding: 30px 0 6px;
+  }
+  .ant-steps-vertical.ant-steps-small .ant-steps-item-container .ant-steps-item-title {
+    line-height: 24px;
+  }
+  @media (max-width: 480px) {
+    .ant-steps-horizontal.ant-steps-label-horizontal {
+      display: block;
+    }
+    .ant-steps-horizontal.ant-steps-label-horizontal .ant-steps-item {
+      display: block;
+      overflow: visible;
+    }
+    .ant-steps-horizontal.ant-steps-label-horizontal .ant-steps-item-icon {
+      float: left;
+      margin-right: 16px;
+    }
+    .ant-steps-horizontal.ant-steps-label-horizontal .ant-steps-item-content {
+      display: block;
+      min-height: 48px;
+      overflow: hidden;
+    }
+    .ant-steps-horizontal.ant-steps-label-horizontal .ant-steps-item-title {
+      line-height: 32px;
+    }
+    .ant-steps-horizontal.ant-steps-label-horizontal .ant-steps-item-description {
+      padding-bottom: 12px;
+    }
+    .ant-steps-horizontal.ant-steps-label-horizontal > .ant-steps-item > .ant-steps-item-container > .ant-steps-item-tail {
+      position: absolute;
+      top: 0;
+      left: 16px;
+      width: 1px;
+      height: 100%;
+      padding: 38px 0 6px;
+    }
+    .ant-steps-horizontal.ant-steps-label-horizontal > .ant-steps-item > .ant-steps-item-container > .ant-steps-item-tail::after {
+      width: 1px;
+      height: 100%;
+    }
+    .ant-steps-horizontal.ant-steps-label-horizontal > .ant-steps-item:not(:last-child) > .ant-steps-item-container > .ant-steps-item-tail {
+      display: block;
+    }
+    .ant-steps-horizontal.ant-steps-label-horizontal > .ant-steps-item > .ant-steps-item-container > .ant-steps-item-content > .ant-steps-item-title::after {
+      display: none;
+    }
+    .ant-steps-horizontal.ant-steps-label-horizontal.ant-steps-small .ant-steps-item-container .ant-steps-item-tail {
+      position: absolute;
+      top: 0;
+      left: 12px;
+      padding: 30px 0 6px;
+    }
+    .ant-steps-horizontal.ant-steps-label-horizontal.ant-steps-small .ant-steps-item-container .ant-steps-item-title {
+      line-height: 24px;
+    }
+  }
+  .ant-steps-label-vertical .ant-steps-item {
+    overflow: visible;
+  }
+  .ant-steps-label-vertical .ant-steps-item-tail {
+    margin-left: 58px;
+    padding: 3.5px 24px;
+  }
+  .ant-steps-label-vertical .ant-steps-item-content {
+    display: block;
+    width: 116px;
+    margin-top: 8px;
+    text-align: center;
+  }
+  .ant-steps-label-vertical .ant-steps-item-icon {
+    display: inline-block;
+    margin-left: 42px;
+  }
+  .ant-steps-label-vertical .ant-steps-item-title {
+    padding-right: 0;
+  }
+  .ant-steps-label-vertical .ant-steps-item-title::after {
+    display: none;
+  }
+  .ant-steps-label-vertical .ant-steps-item-subtitle {
+    display: block;
+    margin-bottom: 4px;
+    margin-left: 0;
+    line-height: 1.5;
+  }
+  .ant-steps-label-vertical.ant-steps-small:not(.ant-steps-dot) .ant-steps-item-icon {
+    margin-left: 46px;
+  }
+  .ant-steps-dot .ant-steps-item-title,
+  .ant-steps-dot.ant-steps-small .ant-steps-item-title {
+    line-height: 1.5;
+  }
+  .ant-steps-dot .ant-steps-item-tail,
+  .ant-steps-dot.ant-steps-small .ant-steps-item-tail {
+    top: 2px;
+    width: 100%;
+    margin: 0 0 0 70px;
+    padding: 0;
+  }
+  .ant-steps-dot .ant-steps-item-tail::after,
+  .ant-steps-dot.ant-steps-small .ant-steps-item-tail::after {
+    width: calc(100% - 20px);
+    height: 3px;
+    margin-left: 12px;
+  }
+  .ant-steps-dot .ant-steps-item:first-child .ant-steps-icon-dot,
+  .ant-steps-dot.ant-steps-small .ant-steps-item:first-child .ant-steps-icon-dot {
+    left: 2px;
+  }
+  .ant-steps-dot .ant-steps-item-icon,
+  .ant-steps-dot.ant-steps-small .ant-steps-item-icon {
+    width: 8px;
+    height: 8px;
+    margin-left: 67px;
+    padding-right: 0;
+    line-height: 8px;
+    background: transparent;
+    border: 0;
+  }
+  .ant-steps-dot .ant-steps-item-icon .ant-steps-icon-dot,
+  .ant-steps-dot.ant-steps-small .ant-steps-item-icon .ant-steps-icon-dot {
+    position: relative;
+    float: left;
+    width: 100%;
+    height: 100%;
+    border-radius: 100px;
+    transition: all 0.3s;
+    /* expand hover area */
+  }
+  .ant-steps-dot .ant-steps-item-icon .ant-steps-icon-dot::after,
+  .ant-steps-dot.ant-steps-small .ant-steps-item-icon .ant-steps-icon-dot::after {
+    position: absolute;
+    top: -12px;
+    left: -26px;
+    width: 60px;
+    height: 32px;
+    background: rgba(0, 0, 0, 0.001);
+    content: '';
+  }
+  .ant-steps-dot .ant-steps-item-content,
+  .ant-steps-dot.ant-steps-small .ant-steps-item-content {
+    width: 140px;
+  }
+  .ant-steps-dot .ant-steps-item-process .ant-steps-item-icon,
+  .ant-steps-dot.ant-steps-small .ant-steps-item-process .ant-steps-item-icon {
+    width: 10px;
+    height: 10px;
+    line-height: 10px;
+  }
+  .ant-steps-dot .ant-steps-item-process .ant-steps-item-icon .ant-steps-icon-dot,
+  .ant-steps-dot.ant-steps-small .ant-steps-item-process .ant-steps-item-icon .ant-steps-icon-dot {
+    top: -1px;
+  }
+  .ant-steps-vertical.ant-steps-dot .ant-steps-item-icon {
+    margin-top: 8px;
+    margin-left: 0;
+  }
+  .ant-steps-vertical.ant-steps-dot .ant-steps-item > .ant-steps-item-container > .ant-steps-item-tail {
+    top: 2px;
+    left: -9px;
+    margin: 0;
+    padding: 22px 0 4px;
+  }
+  .ant-steps-vertical.ant-steps-dot .ant-steps-item:first-child .ant-steps-icon-dot {
+    left: 0;
+  }
+  .ant-steps-vertical.ant-steps-dot .ant-steps-item-process .ant-steps-icon-dot {
+    left: -2px;
+  }
+  .ant-steps-navigation {
+    padding-top: 12px;
+  }
+  .ant-steps-navigation.ant-steps-small .ant-steps-item-container {
+    margin-left: -12px;
+  }
+  .ant-steps-navigation .ant-steps-item {
+    overflow: visible;
+    text-align: center;
+  }
+  .ant-steps-navigation .ant-steps-item-container {
+    display: inline-block;
+    height: 100%;
+    margin-left: -16px;
+    padding-bottom: 12px;
+    text-align: left;
+    transition: opacity 0.3s;
+  }
+  .ant-steps-navigation .ant-steps-item-container .ant-steps-item-content {
+    max-width: auto;
+  }
+  .ant-steps-navigation .ant-steps-item-container .ant-steps-item-title {
+    max-width: 100%;
+    padding-right: 0;
+    overflow: hidden;
+    white-space: nowrap;
+    text-overflow: ellipsis;
+  }
+  .ant-steps-navigation .ant-steps-item-container .ant-steps-item-title::after {
+    display: none;
+  }
+  .ant-steps-navigation .ant-steps-item:not(.ant-steps-item-active) .ant-steps-item-container[role='button'] {
+    cursor: pointer;
+  }
+  .ant-steps-navigation .ant-steps-item:not(.ant-steps-item-active) .ant-steps-item-container[role='button']:hover {
+    opacity: 0.85;
+  }
+  .ant-steps-navigation .ant-steps-item:last-child {
+    flex: 1;
+  }
+  .ant-steps-navigation .ant-steps-item:last-child::after {
+    display: none;
+  }
+  .ant-steps-navigation .ant-steps-item::after {
+    position: absolute;
+    top: 50%;
+    left: 100%;
+    display: inline-block;
+    width: 12px;
+    height: 12px;
+    margin-top: -14px;
+    margin-left: -2px;
+    border: 1px solid rgba(0, 0, 0, 0.25);
+    border-bottom: none;
+    border-left: none;
+    transform: rotate(45deg);
+    content: '';
+  }
+  .ant-steps-navigation .ant-steps-item::before {
+    position: absolute;
+    bottom: 0;
+    left: 50%;
+    display: inline-block;
+    width: 0;
+    height: 3px;
+    background-color: #1890ff;
+    transition: width 0.3s, left 0.3s;
+    transition-timing-function: ease-out;
+    content: '';
+  }
+  .ant-steps-navigation .ant-steps-item.ant-steps-item-active::before {
+    left: 0;
+    width: 100%;
+  }
+  @media (max-width: 480px) {
+    .ant-steps-navigation > .ant-steps-item {
+      margin-right: 0 !important;
+    }
+    .ant-steps-navigation > .ant-steps-item::before {
+      display: none;
+    }
+    .ant-steps-navigation > .ant-steps-item.ant-steps-item-active::before {
+      top: 0;
+      right: 0;
+      left: unset;
+      display: block;
+      width: 3px;
+      height: calc(100% - 24px);
+    }
+    .ant-steps-navigation > .ant-steps-item::after {
+      position: relative;
+      top: -2px;
+      left: 50%;
+      display: block;
+      width: 8px;
+      height: 8px;
+      margin-bottom: 8px;
+      text-align: center;
+      transform: rotate(135deg);
+    }
+    .ant-steps-navigation > .ant-steps-item > .ant-steps-item-container > .ant-steps-item-tail {
+      visibility: hidden;
+    }
+  }
+  .ant-steps-flex-not-supported.ant-steps-horizontal.ant-steps-label-horizontal .ant-steps-item {
+    margin-left: -16px;
+    padding-left: 16px;
+    background: #fff;
+  }
+  .ant-steps-flex-not-supported.ant-steps-horizontal.ant-steps-label-horizontal.ant-steps-small .ant-steps-item {
+    margin-left: -12px;
+    padding-left: 12px;
+  }
+  .ant-steps-flex-not-supported.ant-steps-dot .ant-steps-item:last-child {
+    overflow: hidden;
+  }
+  .ant-steps-flex-not-supported.ant-steps-dot .ant-steps-item:last-child .ant-steps-icon-dot::after {
+    right: -200px;
+    width: 200px;
+  }
+  .ant-steps-flex-not-supported.ant-steps-dot .ant-steps-item .ant-steps-icon-dot::before,
+  .ant-steps-flex-not-supported.ant-steps-dot .ant-steps-item .ant-steps-icon-dot::after {
+    position: absolute;
+    top: 0;
+    left: -10px;
+    width: 10px;
+    height: 8px;
+    background: #fff;
+    content: '';
+  }
+  .ant-steps-flex-not-supported.ant-steps-dot .ant-steps-item .ant-steps-icon-dot::after {
+    right: -10px;
+    left: auto;
+  }
+  .ant-steps-flex-not-supported.ant-steps-dot .ant-steps-item-wait .ant-steps-item-icon > .ant-steps-icon .ant-steps-icon-dot {
+    background: #ccc;
+  }
+  

+ 1839 - 0
src/optionSystem/calculationAndSelection/index.vue

@@ -0,0 +1,1839 @@
+<template>
+  <div class="calculation-selection">
+    <div class="step-content">
+      <div class="step-container">
+        <div class="my-steps">
+          <a-steps :current="activeStep" style="margin-bottom: 10px">
+            <a-step
+              :title="$t(item.title)"
+              v-for="(item, index) in stepItems"
+              :key="index"
+            >
+              <i
+                slot="icon"
+                class="iconfont"
+                style="font-size: 32px; color: #3874f6 !important"
+                v-if="activeStep > index"
+                >&#xe6fd;</i
+              >
+            </a-step>
+          </a-steps>
+        </div>
+      </div>
+      <!-- 步骤1: 基本信息 -->
+      <div v-if="activeStep === 0" class="step-panel">
+        <el-card class="step-card" shadow="never">
+          <el-form :model="basicInfo" :rules="basicRules" ref="basicForm" label-width="140px" size="small">
+            
+            <!-- 环境条件 -->
+            <el-divider content-position="left">{{$t('环境条件')}}</el-divider>
+            <el-row :gutter="20">
+              <el-col :span="5">
+                <el-form-item :label="$t('大气压') + ' (mH₂O)'" prop="pa">
+                  <el-input v-model="basicInfo.pa" placeholder="10.339"></el-input>
+                </el-form-item>
+              </el-col>
+              <el-col :span="5">
+                <el-form-item :label="$t('重力加速度') + ' (m/s²)'" prop="g">
+                  <el-input v-model="basicInfo.g" placeholder="9.81"></el-input>
+                </el-form-item>
+              </el-col>
+              <el-col :span="5">
+                <el-form-item :label="$t('饱和蒸气压') + ' (mH₂O)'" prop="pv">
+                  <el-input v-model="basicInfo.pv" placeholder="0.23"></el-input>
+                </el-form-item>
+              </el-col>
+              <el-col :span="5">
+                <el-form-item :label="$t('温度') + ' (℃)'" prop="t">
+                  <el-input v-model="basicInfo.t" placeholder="20"></el-input>
+                </el-form-item>
+              </el-col>
+            </el-row>
+
+            <!-- 阀门条件 -->
+            <el-divider content-position="left">{{$t('阀门条件')}}</el-divider>
+            <el-row :gutter="20">
+              <el-col :span="8">
+                <el-form-item :label="$t('公称通径')" prop="caliber">
+                  <el-select v-model="basicInfo.caliber" :placeholder="$t('请选择')" style="width: 100%">
+                    <el-option v-for="item in typeList" :label="item.remarks" :value="item.value" :key="item.value"></el-option>
+                  </el-select>
+                </el-form-item>
+              </el-col>
+              <el-col :span="8">
+                <el-form-item :label="$t('公称压力')" prop="pressure">
+                  <el-select v-model="basicInfo.pressure" :placeholder="$t('请选择')" style="width: 100%">
+                    <el-option v-for="item in pressureList" :label="item.remarks" :value="item.value" :key="item.value"></el-option>
+                  </el-select>
+                </el-form-item>
+              </el-col>
+              <el-col :span="8">
+                <el-form-item :label="$t('管道外径') + ' (mm)'" prop="od">
+                  <el-input v-model="basicInfo.od" :placeholder="$t('请输入')"></el-input>
+                </el-form-item>
+              </el-col>
+            </el-row>
+            <el-row :gutter="20">
+              <el-col :span="8">
+                <el-form-item :label="$t('壁厚') + ' (mm)'" prop="wt">
+                  <el-input v-model="basicInfo.wt" :placeholder="$t('请输入')"></el-input>
+                </el-form-item>
+              </el-col>
+              <el-col :span="8">
+                <el-form-item :label="$t('控制点名称')" prop="cname">
+                  <el-input v-model="basicInfo.cname" :placeholder="$t('请输入')"></el-input>
+                </el-form-item>
+              </el-col>
+              <el-col :span="8">
+                <el-form-item :label="$t('应用场景')" prop="purpose">
+                  <el-select v-model="basicInfo.purpose" :placeholder="$t('请选择')" style="width: 100%">
+                    <el-option :label="$t('通用')" value="通用"></el-option>
+                    <el-option :label="$t('水库引水')" value="水库引水"></el-option>
+                  </el-select>
+                </el-form-item>
+              </el-col>
+            </el-row>
+            <el-row :gutter="20">
+              <el-col :span="8">
+                <el-form-item :label="$t('介质')" prop="mediatype">
+                  <div style="display: flex; align-items: center; gap: 8px;">
+                    <el-select v-model="basicInfo.mediatype" @change="onMediumTypeChange" :placeholder="$t('请选择')" style="flex: 1;">
+                      <el-option :label="$t('水') +'/'+densityMap[$t('水')]" value="水"></el-option>
+                      <el-option :label="$t('蒸汽') +'/'+densityMap[$t('蒸汽')]" value="蒸汽"></el-option>
+                      <el-option :label="$t('油') +'/'+densityMap[$t('油')]" value="油"></el-option>
+                      <el-option :label="$t('气体') + '/'+densityMap[$t('气体')]" value="气体"></el-option>
+                    </el-select>
+                    <!-- <span style="color: #606266; font-size: 14px; white-space: nowrap;">{{basicInfo.p}}</span> -->
+                    <!-- <el-input v-model="basicInfo.p" :disabled="true" style="width: 80px;"></el-input> -->
+                  </div>
+                </el-form-item>
+              </el-col>
+              <el-col :span="8">
+                <el-form-item :label="$t('要求最大开度') + ' (%)'" prop="maxli">
+                  <el-input v-model="basicInfo.maxli" :placeholder="$t('请输入')"></el-input>
+                </el-form-item>
+              </el-col>
+              <el-col :span="8">
+                <el-form-item :label="$t('要求最小开度') + ' (%)'" prop="minli">
+                  <el-input v-model="basicInfo.minli" placeholder="10"></el-input>
+                </el-form-item>
+              </el-col>
+            </el-row>
+            <el-row :gutter="20">
+              
+              <el-col :span="8">
+                <el-form-item :label="$t('起点高程') + ' (m)'">
+                  <el-input v-model="basicInfo.z1" :placeholder="$t('请输入')"></el-input>
+                </el-form-item>
+              </el-col>
+              <el-col :span="8">
+                <el-form-item :label="$t('末点高程') + ' (m)'">
+                  <el-input v-model="basicInfo.z2" :placeholder="$t('请输入')"></el-input>
+                </el-form-item>
+              </el-col>
+              <el-col :span="8">
+                <el-form-item :label="$t('阀中心高程') + ' (m)'">
+                  <el-input v-model="basicInfo.zv" :placeholder="$t('请输入')"></el-input>
+                </el-form-item>
+              </el-col>
+            </el-row>
+          </el-form>
+        </el-card>
+      </div>
+
+      <!-- 步骤2: 工况条件 -->
+      <div v-if="activeStep === 1" class="step-panel">
+        <el-card class="step-card" shadow="never">
+          <el-form :model="workingCondition" :rules="workingRules" ref="workingForm" label-width="120px" size="small">
+            <!-- 条件要求 -->
+            <el-divider content-position="left">{{$t('工况要求')}}</el-divider>
+            
+            <!-- 最小流量 -->
+            <el-row :gutter="20" style="margin-bottom: 20px;">
+              <el-col :span="2" style="display: flex; align-items: center; justify-content: center; background-color: #f5f5f5; border: 1px solid #ddd; height: 40px;">
+                <span style="font-weight: bold;">{{$t('最小流量')}}</span>
+              </el-col>
+              <el-col :span="5">
+                <el-form-item :label="$t('流量') + ':'" prop="minCondition.flow" style="margin-bottom: 0;">
+                  <el-input v-model="workingCondition.minCondition.flow" @input="calculatePressureDrop('min')">
+                    
+                    <span style="color:blue" slot="suffix">
+                      m³/h
+                    </span>
+                  </el-input>
+                </el-form-item>
+              </el-col>
+              <el-col :span="5">
+                <el-form-item :label="$t('阀前压力') + ':'" prop="minCondition.beforePressure" style="margin-bottom: 0;">
+                  <el-input v-model="workingCondition.minCondition.beforePressure" @input="calculatePressureDrop('min')">
+                    <span style="color:blue" slot="suffix">kpa
+                    </span>
+                  </el-input>
+                </el-form-item>
+              </el-col>
+              <el-col :span="5">
+                <el-form-item :label="$t('阀后压力') + ':'" prop="minCondition.afterPressure" style="margin-bottom: 0;">
+                  <el-input v-model="workingCondition.minCondition.afterPressure" @input="calculatePressureDrop('min')">
+                    <span style="color:blue" slot="suffix">kpa
+                    </span>
+                  </el-input>
+                </el-form-item>
+              </el-col>
+              <el-col :span="5">
+                <el-form-item :label="$t('前后压差') + ':'" style="margin-bottom: 0;">
+                  <el-input v-model="workingCondition.minCondition.pressureDrop" :disabled="true">
+                    <span style="color:blue" slot="suffix">kpa
+                    </span>
+                  </el-input>
+                </el-form-item>
+              </el-col>
+            </el-row>
+            
+            <!-- 最大流量 -->
+            <el-row :gutter="20">
+              <el-col :span="2" style="display: flex; align-items: center; justify-content: center; background-color: #f5f5f5; border: 1px solid #ddd; height: 40px;">
+                <span style="font-weight: bold;">{{$t('最大流量')}}</span>
+              </el-col>
+              <el-col :span="5">
+                <el-form-item :label="$t('流量') + ':'" prop="maxCondition.flow" style="margin-bottom: 0;">
+                  <el-input v-model="workingCondition.maxCondition.flow" @input="calculatePressureDrop('max')">
+                    <span style="color:blue" slot="suffix">
+                      m³/h
+                    </span>
+                  </el-input>
+                </el-form-item>
+              </el-col>
+              <el-col :span="5">
+                <el-form-item :label="$t('阀前压力') + ':'" prop="maxCondition.beforePressure" style="margin-bottom: 0;">
+                  <el-input v-model="workingCondition.maxCondition.beforePressure" @input="calculatePressureDrop('max')">
+                    <span style="color:blue" slot="suffix">kpa
+                    </span>
+                  </el-input>
+                </el-form-item>
+              </el-col>
+              <el-col :span="5">
+                <el-form-item :label="$t('阀后压力') + ':'" prop="maxCondition.afterPressure" style="margin-bottom: 0;">
+                  <el-input v-model="workingCondition.maxCondition.afterPressure" @input="calculatePressureDrop('max')">
+                    <span style="color:blue" slot="suffix">kpa
+                    </span>
+                  </el-input>
+                </el-form-item>
+              </el-col>
+              <el-col :span="5">
+                <el-form-item :label="$t('前后压差') + ':'" style="margin-bottom: 0;">
+                  <el-input v-model="workingCondition.maxCondition.pressureDrop" :disabled="true">
+                    <span style="color:blue" slot="suffix">kpa
+                    </span>
+                  </el-input>
+                </el-form-item>
+              </el-col>
+            </el-row>
+            
+            <!-- 数据验证提示 -->
+            <el-alert
+              v-if="validationMessage"
+              :title="validationMessage"
+              :type="validationType"
+              style="margin-top: 20px;"
+              show-icon>
+            </el-alert>
+          </el-form>
+        </el-card>
+      </div>
+
+      <!-- 步骤3: 阀门选型 -->
+      <div v-if="activeStep === 2" class="step-panel">
+        <el-card class="step-card" shadow="never">
+          <h3 class="mt-10">
+            节流件配置
+          </h3>
+          <div class="mt-10">
+            <p style="display: inline-block; width: 100px;;font-size:14px">{{$t('节流件类型')}}: </p>
+            <el-select v-model="valveSelection.throttletype" :placeholder="$t('请选择节流件类型')" size="small">
+              <el-option v-for="item in throttletype" :key="item.value" :label="item.remarks" :value="item.value"></el-option>
+            </el-select>&nbsp;
+            <!-- <el-button type="primary" size="small" disabled>开始选型</el-button> -->
+          </div>
+          <div class="mt-10">
+            <p style="display: inline-block; width: 100px;font-size:14px">{{$t('节流件')}}: </p>
+            <el-select :disabled="!valveSelection.throttletype" v-model="valveSelection.throttleValue" :placeholder="$t('请选择节流件类型')" size="small" @visible-change="queryThrottle">
+              <el-option v-for="item in throttle" :key="item.value" :label="item.itemname" :value="item.itemid"></el-option>
+            </el-select>&nbsp;
+            <el-button type="primary" :disabled="!valveSelection.throttleValue" size="small" @click="beginSelection(() => {},'table')">{{$t('开始选型')}}</el-button>
+          </div>
+          <el-table :data="tableData" style="width: 100%" size="mini" border>
+            <el-table-column prop="workingCondition" :label="$t('工况')" align="center"></el-table-column>
+              <el-table-column prop="conditionName" :label="$t('条件名称')" align="center"></el-table-column>
+              <el-table-column prop="q" :label="$t('流量') + '(q)'" align="center"></el-table-column>
+              <el-table-column prop="p1" :label="$t('阀前压力') + '(p1)'" align="center"></el-table-column>
+              <el-table-column prop="p2" :label="$t('阀后压力') + '(p2)'" align="center"></el-table-column>
+            <el-table-column prop="p" :label="$t('前后压差') + '(p)'" align="center"></el-table-column>
+            <el-table-column prop="pv" :label="$t('饱和蒸汽压') + '(pV)'" align="center"></el-table-column>
+            <el-table-column prop="kv" :label="$t('流量系数') + '(kv)'" align="center"></el-table-column>
+            <el-table-column prop="li" :label="$t('开度') + '(li)'" align="center"></el-table-column>
+            <el-table-column prop="ldc" :label="$t('临界汽蚀系数') + 'σc(Idc)'" align="center"></el-table-column>
+            <el-table-column prop="dc" :label="$t('气蚀系数') + 'σ(dc)'" align="center"></el-table-column>
+            <el-table-column prop="fi" :label="$t('压力恢复系数') + 'FI(fi)'" align="center"></el-table-column>
+            <el-table-column prop="fr" :label="$t('流阻系数') + 'ζ(fr)'" align="center"></el-table-column>
+            <el-table-column prop="fkv" :label="$t('阻塞流修正系数') + 'Fkv(fkv)'" align="center"></el-table-column>
+            <el-table-column prop="v" :label="$t('流速') + 'V(v)'" align="center"></el-table-column>
+          </el-table>
+          <!-- 开度设置 -->
+          <el-divider content-position="left">{{$t('开度设置')}}</el-divider>
+          <div class="opening-settings">
+            <el-row :gutter="20">
+              <el-col :span="12">
+                <el-input 
+                  v-model="openingSettings.openingValues" 
+                  :placeholder="$t('请输入开度值,用逗号分隔,如:10,20,30,40,50')"
+                  @blur="parseOpeningValues"
+                  size="small">
+                </el-input>
+              </el-col>
+              <el-col :span="12">
+                <div class="opening-info">
+                  <el-button type="primary" @click="beginSelection(() => {},'chart')" :disabled="!openingSettings.parsedValues.length || !valveSelection.throttleValue" size="small">生成曲线图表</el-button>
+                </div>
+              </el-col>
+            </el-row>
+            
+            <!-- 开度值预览 -->
+            <div v-if="openingSettings.parsedValues.length" class="opening-preview">
+              <span class="preview-label">开度值预览:</span>
+              <el-tag v-for="(value, index) in openingSettings.parsedValues" :key="index" size="small" style="margin-right: 8px;">{{ value }}%</el-tag>
+            </div>
+          </div>
+          <el-row>
+            <el-col :span="18">
+              <!-- KV曲线图 -->
+              <div v-if="showKvChart" class="chart-container">
+                <el-divider content-position="left">{{$t('KV曲线图')}}</el-divider>
+                <div id="kvChart" style="width: 100%; height: 400px;"></div>
+              </div>
+              <!-- 流阻系数曲线图 -->
+              <div v-if="showZetaChart" class="chart-container">
+                <el-divider content-position="left">{{$t('流阻系数曲线图')}}</el-divider>
+                <div id="zetaCoefficientChart" style="width: 100%; height: 400px;"></div>
+              </div>
+              
+              <!-- 气蚀系数曲线图 -->
+              <div v-if="showCavitationChart" class="chart-container">
+                <el-divider content-position="left">{{$t('气蚀系数曲线图')}}</el-divider>
+                <div id="cavitationCoefficientChart" style="width: 100%; height: 400px;"></div>
+              </div>
+              <!-- 流量开度曲线图 -->
+              <div v-if="showFlowChart" class="chart-container">
+                <el-divider content-position="left">{{$t('流量开度曲线图')}}</el-divider>
+                <div id="flowOpeningChart" style="width: 100%; height: 400px;"></div>
+              </div>
+            </el-col>
+          </el-row>
+        </el-card>
+      </div>
+      <!-- 操作按钮 -->
+      <div class="button-group">
+        <el-button v-if="activeStep > 0" @click="prevStep">{{$t('上一步')}}</el-button>
+        <el-button v-if="activeStep < 2" type="primary" @click="nextStep">{{$t('下一步')}}</el-button>
+        <el-button v-if="activeStep === 2" type="primary" @click="saveSelection">{{$t('保存选型')}}</el-button>
+      </div>
+    </div>
+
+    
+  </div>
+</template>
+
+<script>
+import './index.css'
+
+export default {
+  name: 'CalculationAndSelection',
+  data() {
+    return {
+      activeStep: 0,
+      stepItems: [
+        { title: this.$t('基本信息') },
+        { title: this.$t('工况条件') },
+        { title: this.$t('阀门选型') }
+      ],
+      densityMap: {
+        [this.$t('水')]: '1000',
+        [this.$t('蒸汽')]: '0.6',
+        [this.$t('油')]: '850',
+        [this.$t('气体')]: '1.2'
+      },
+      issave: false,
+      typeList: [],
+      pressureList: [],
+      throttletype: [],
+      throttle:[],
+      tableData:[],
+      // 基本信息
+      basicInfo: {
+        // 环境条件
+        pa: '101.390',
+        pv: '2.329',
+        pc: '22120',
+        g: '9.81',
+        t: '20',
+        
+        // 阀门条件
+        caliber: '',
+        pressure: '',
+        od: '',
+        wt: '',
+        cname: '',
+        purpose: this.$t('通用'),
+        mediatype: this.$t('水'),
+        p: '1000',
+        maxli: '85',
+        minli: '10',
+        z1: '',
+        zv: '',
+        z2: ''
+      },
+      
+      // 工况条件
+      workingCondition: {
+        minCondition: {
+          flow: '',
+          beforePressure: '',
+          afterPressure: '',
+          pressureDrop: ''
+        },
+        maxCondition: {
+          flow: '',
+          beforePressure: '',
+          afterPressure: '',
+          pressureDrop: ''
+        }
+      },
+      
+      // 验证信息
+      validationMessage: '',
+      validationType: 'warning',
+      
+      // 阀门选型
+      valveSelection: {
+        throttletype: '',
+        throttleValue: '',
+      },
+      
+      // 开度设置
+      openingSettings: {
+        openingValues: '', // 用户输入的开度值字符串
+        parsedValues: [], // 解析后的开度值数组
+      },
+      
+      // 图表显示控制
+      showFlowChart: false,
+      showZetaChart: false,
+      showCavitationChart: false,
+      showKvChart: false,
+      
+      // 图表实例
+      flowChartInstance: null,
+      zetaChartInstance: null,
+      cavitationChartInstance: null,
+      kvChartInstance: null,
+      
+      // 计算结果
+      calculationResult: {
+        flowCoefficient: '',
+        opening: '',
+        noiseLevel: ''
+      },
+      
+      // 表单验证规则
+      basicRules: {
+        cname: [
+          { required: true, message: this.$t('请输入控制点名称'), trigger: 'blur' }
+        ],
+        purpose: [
+          { required: true, message: this.$t('请选择应用场景'), trigger: 'change' }
+        ],
+        mediatype: [
+          { required: true, message: this.$t('请选择介质'), trigger: 'change' }
+        ],
+        od: [
+          { required: true, message: this.$t('请输入管道外径'), trigger: 'blur' },
+          { pattern: /^\d+(\.\d+)?$/, message: this.$t('请输入有效的数值'), trigger: 'blur' }
+        ],
+        wt: [
+          { required: true, message: this.$t('请输入壁厚'), trigger: 'blur' },
+          { pattern: /^\d+(\.\d+)?$/, message: this.$t('请输入有效的数值'), trigger: 'blur' }
+        ],
+        z1: [
+          { required: true, message: this.$t('请输入起点高程'), trigger: 'blur' },
+          { pattern: /^-?\d+(\.\d+)?$/, message: this.$t('请输入有效的数值'), trigger: 'blur' }
+        ],
+        zv: [
+          { required: true, message: this.$t('请输入阀中心高程'), trigger: 'blur' },
+          { pattern: /^-?\d+(\.\d+)?$/, message: this.$t('请输入有效的数值'), trigger: 'blur' }
+        ],
+        z2: [
+          { required: true, message: this.$t('请输入末点高程'), trigger: 'blur' },
+          { pattern: /^-?\d+(\.\d+)?$/, message: this.$t('请输入有效的数值'), trigger: 'blur' }
+        ]
+      },
+      
+      workingRules: {
+        'minCondition.flow': [
+          { required: true, message: this.$t('请输入最小流量'), trigger: 'blur' },
+          { pattern: /^\d+(\.\d+)?$/, message: this.$t('请输入有效的数值'), trigger: 'blur' },
+          {
+            validator: (rule, value, callback) => {
+              if (value && this.workingCondition.maxCondition.flow) {
+                const minFlow = parseFloat(value)
+                const maxFlow = parseFloat(this.workingCondition.maxCondition.flow)
+                if (minFlow >= maxFlow) {
+                  callback(new Error(this.$t('最小流量不能大于或等于最大流量')))
+                } else {
+                  callback()
+                }
+              } else {
+                callback()
+              }
+            },
+            trigger: 'blur'
+          }
+        ],
+        'minCondition.beforePressure': [
+          { required: true, message: this.$t('请输入阀前压力'), trigger: 'blur' },
+          { pattern: /^\d+(\.\d+)?$/, message: this.$t('请输入有效的数值'), trigger: 'blur' }
+        ],
+        'minCondition.afterPressure': [
+          { required: true, message: this.$t('请输入阀后压力'), trigger: 'blur' },
+          { pattern: /^\d+(\.\d+)?$/, message: this.$t('请输入有效的数值'), trigger: 'blur' }
+        ],
+        'maxCondition.flow': [
+          { required: true, message: this.$t('请输入最大流量'), trigger: 'blur' },
+          { pattern: /^\d+(\.\d+)?$/, message: this.$t('请输入有效的数值'), trigger: 'blur' },
+          {
+            validator: (rule, value, callback) => {
+              if (value && this.workingCondition.minCondition.flow) {
+                const minFlow = parseFloat(this.workingCondition.minCondition.flow)
+                const maxFlow = parseFloat(value)
+                if (minFlow >= maxFlow) {
+                  callback(new Error(this.$t('最大流量必须大于最小流量')))
+                } else {
+                  callback()
+                }
+              } else {
+                callback()
+              }
+            },
+            trigger: 'blur'
+          }
+        ],
+        'maxCondition.beforePressure': [
+          { required: true, message: this.$t('请输入阀前压力'), trigger: 'blur' },
+          { pattern: /^\d+(\.\d+)?$/, message: this.$t('请输入有效的数值'), trigger: 'blur' }
+        ],
+        'maxCondition.afterPressure': [
+          { required: true, message: this.$t('请输入阀后压力'), trigger: 'blur' },
+          { pattern: /^\d+(\.\d+)?$/, message: this.$t('请输入有效的数值'), trigger: 'blur' }
+        ]
+      },
+      
+      conditionRules: {
+        workingPressure: [
+          { required: true, message: this.$t('请输入工作压力'), trigger: 'blur' },
+          { pattern: /^\d+(\.\d+)?$/, message: this.$t('请输入有效的数值'), trigger: 'blur' }
+        ],
+        workingTemperature: [
+          { required: true, message: this.$t('请输入工作温度'), trigger: 'blur' },
+          { pattern: /^-?\d+(\.\d+)?$/, message: this.$t('请输入有效的数值'), trigger: 'blur' }
+        ],
+        flowRate: [
+          { required: true, message: this.$t('请输入流量'), trigger: 'blur' },
+          { pattern: /^\d+(\.\d+)?$/, message: this.$t('请输入有效的数值'), trigger: 'blur' }
+        ]
+      },
+      
+      valveRules: {
+        valveType: [
+          { required: true, message: this.$t('请选择阀门类型'), trigger: 'change' }
+        ],
+        valveSize: [
+          { required: true, message: this.$t('请选择阀门口径'), trigger: 'change' }
+        ],
+        connectionType: [
+          { required: true, message: this.$t('请选择连接方式'), trigger: 'change' }
+        ],
+        material: [
+          { required: true, message: this.$t('请选择材质'), trigger: 'change' }
+        ]
+      }
+    }
+  },
+  
+  methods: {
+    // 下一步
+    nextStep() {
+      const formRefs = ['basicForm', 'workingForm', 'valveForm']
+      const currentForm = formRefs[this.activeStep]
+      
+      this.$refs[currentForm].validate((valid) => {
+        if (valid) {
+          this.activeStep++
+        } else {
+          this.$message.error(this.$t('请完善当前步骤的必填信息'))
+        }
+      })
+    },
+    
+    // 上一步
+    prevStep() {
+      this.activeStep--
+      // 清除当前步骤的表单验证状态
+      this.$nextTick(() => {
+        const formRefs = ['basicForm', 'workingForm', 'valveForm']
+        const currentForm = formRefs[this.activeStep]
+        if (this.$refs[currentForm]) {
+          this.$refs[currentForm].clearValidate()
+        }
+      })
+    },
+    
+    // 介质类型变化时自动设置密度
+    onMediumTypeChange(value) {
+      
+      this.basicInfo.p = this.densityMap[value] || '1000'
+    },
+    
+    // 计算前后压差
+    calculatePressureDrop(type) {
+      const condition = this.workingCondition[type + 'Condition']
+      
+      if (condition.beforePressure && condition.afterPressure) {
+        const beforePressure = parseFloat(condition.beforePressure)
+        const afterPressure = parseFloat(condition.afterPressure)
+        
+        if (!isNaN(beforePressure) && !isNaN(afterPressure)) {
+          condition.pressureDrop = (beforePressure - afterPressure).toFixed(2)
+          
+          // 验证数据合理性
+          this.validateWorkingCondition()
+        }
+      }
+      
+      // 触发流量字段的验证,确保流量比较验证能够实时生效
+      this.$nextTick(() => {
+        if (this.$refs.workingForm) {
+          this.$refs.workingForm.validateField('minCondition.flow')
+          this.$refs.workingForm.validateField('maxCondition.flow')
+        }
+      })
+    },
+    
+    // 验证工况条件数据
+    validateWorkingCondition() {
+      const minCondition = this.workingCondition.minCondition
+      const maxCondition = this.workingCondition.maxCondition
+      
+      this.validationMessage = ''
+      this.validationType = 'success'
+      
+      // 检查流量大小关系
+      if (minCondition.flow && maxCondition.flow) {
+        const minFlow = parseFloat(minCondition.flow)
+        const maxFlow = parseFloat(maxCondition.flow)
+        
+        if (minFlow >= maxFlow) {
+          this.validationMessage = this.$t('最大流量必须大于最小流量')
+          this.validationType = 'error'
+          return false
+        }
+      }
+      
+      // 检查阀前压力是否大于等于阀后压力
+      const conditions = [minCondition, maxCondition]
+      for (let condition of conditions) {
+        if (condition.beforePressure && condition.afterPressure) {
+          const beforePressure = parseFloat(condition.beforePressure)
+          const afterPressure = parseFloat(condition.afterPressure)
+          
+          if (beforePressure < afterPressure) {
+            this.validationMessage = this.$t('阀前压力必须大于等于阀后压力')
+            this.validationType = 'error'
+            return false
+          }
+        }
+      }
+      
+      // 如果所有验证都通过
+      if (minCondition.flow && maxCondition.flow && 
+          minCondition.beforePressure && minCondition.afterPressure &&
+          maxCondition.beforePressure && maxCondition.afterPressure) {
+        this.validationMessage = this.$t('工况条件数据验证通过')
+        this.validationType = 'success'
+      }
+      
+      return true
+    },
+    
+    // 保存选型
+    saveSelection() {
+      this.issave = true
+      this.beginSelection(()=>{
+        this.$message({
+          message: this.$t('选型方案保存成功!'),
+          type: 'success'
+        })
+        this.issave = false
+      },'save')
+    },
+    optionList() {
+      this.$store.dispatch("optiontypeselect", "caliber2").then((res) => {
+        this.typeList = res.data;
+        console.log(this.typeList, this.$t('公称通径'));
+      });
+       this.$store.dispatch("optiontypeselect", "pressure").then((res) => {
+        this.pressureList = res.data;
+        console.log(this.pressureList, this.$t('公称压力'));
+      });
+
+      this.$store.dispatch("optiontypeselect", "throttletype").then((res) => {
+        this.throttletype = res.data;
+        console.log(this.throttletype, this.$t('节流件类型'));
+      });
+    },
+
+    // 查询节流件
+    async queryThrottle() {
+      const res = await this.$api.requested(  {
+        "content": {
+        "isExport": 0,
+        "pageNumber": 1,
+        "pageSize": 100,
+        "where": {
+        "condition": "",
+        "throttletype": this.valveSelection.throttletype
+        }
+        },
+        "id": 2025091915552702,
+      })
+      if(res.data){
+        this.throttle = res.data
+      }
+    },
+    // 开始选型
+    async beginSelection(callback,type) {
+      
+      const res = await this.$api.requested({
+        "content": {
+          "itemid":this.valveSelection.throttleValue,
+          "issave":this.issave,//是否保存当前选型
+          "p_lis":this.openingSettings.parsedValues.length ? this.openingSettings.parsedValues : [10,20],//计算流量压差曲线值
+          "pa": parseFloat(this.basicInfo.pa), //大气压Pa
+          "pv": parseFloat(this.basicInfo.pv), //饱和蒸气压Pv
+          "pc": parseFloat(this.basicInfo.pc), //饱和蒸气压Pv
+          "g": parseFloat(this.basicInfo.g), //重力加速度
+          "t": parseFloat(this.basicInfo.t), //温度t(20℃)
+          "minli": parseFloat(this.basicInfo.minli), //要求最小开度(输入,默认值10%),后端默认除100
+          "maxli": parseFloat(this.basicInfo.maxli), //要求最大开度(输入,默认为85%),后端默认除100
+          "pressure": this.basicInfo.pressure, //公称压力(自定义选项)
+          "caliber": this.basicInfo.caliber, //公称通径(自定义选项)、
+          "od": parseFloat(this.basicInfo.od), //管道外径(mm)
+          "cname": this.basicInfo.cname, //控制点名称(必填,文本)
+          "wt": parseFloat(this.basicInfo.wt), //壁厚(mm)
+          "purpose": this.basicInfo.purpose, //用途(必填,自定义选项:通用、水库引水,默认通用)
+          "mediatype": this.basicInfo.mediatype, //介质类型(必填,自定义选项,默认为水)
+          "p": parseFloat(this.basicInfo.p), //液体密度ρ(根据介质类型自动带出)
+          "z1": parseFloat(this.basicInfo.z1), //起点高程(Z1)
+          "zv": parseFloat(this.basicInfo.zv), //阀中心高程(Zv)
+          "z2": parseFloat(this.basicInfo.z2), //末点高程(Z2),
+          "min": {
+            q: parseFloat(this.workingCondition.minCondition.flow),
+            q_unit: 'm³/h',
+            p1: parseFloat(this.workingCondition.minCondition.beforePressure),
+            p1_unit: 'kPa',
+            p2: parseFloat(this.workingCondition.minCondition.afterPressure),
+            p2_unit: 'kPa'
+          }, //最小流量
+          "max": {
+            q: parseFloat(this.workingCondition.maxCondition.flow),
+            q_unit: 'm³/h',
+            p1: parseFloat(this.workingCondition.maxCondition.beforePressure),
+            p1_unit: 'kPa',
+            p2: parseFloat(this.workingCondition.maxCondition.afterPressure),
+            p2_unit: 'kPa'
+          }, //最大流量
+        },
+        "id": 2025091909425802,
+      })
+      if(res.code == 1){
+        // 处理返回的图表数据
+        if(res.data.lines && type == 'chart') {
+          this.processChartData(res.data.lines)
+        }
+        if(callback && type == 'save'){
+          callback()
+        }
+        // 处理表格数据
+        const minData = {
+          ...res.data.min,
+          workingCondition: this.$t('通用'),
+          conditionName: this.$t('最小流量')
+        }
+        const maxData = {
+          ...res.data.max,
+          workingCondition: this.$t('通用'),
+          conditionName: this.$t('最大流量')
+        }
+        this.tableData = [minData, maxData]
+      } else {
+        // 如果没有返回数据,显示错误信息
+        this.$message.error(res.msg || this.$t('API调用失败,请检查网络连接或联系管理员'))
+      }
+    },
+    
+    // 解析开度值
+    parseOpeningValues() {
+      if (!this.openingSettings.openingValues.trim()) {
+        this.openingSettings.parsedValues = []
+        return
+      }
+      
+      const values = this.openingSettings.openingValues
+        .split(',')
+        .map(val => {
+          const num = parseFloat(val.trim())
+          return isNaN(num) ? null : num
+        })
+        .filter(val => val !== null && val >= 0 && val <= 100)
+        .sort((a, b) => a - b)
+      
+      // 去重
+      this.openingSettings.parsedValues = [...new Set(values)]
+      
+      if (this.openingSettings.parsedValues.length === 0) {
+        this.$message.warning(this.$t('请输入有效的开度值(0-100之间的数字)'))
+      }
+    },
+    
+    // 处理API返回的图表数据
+    processChartData(lineData) {
+      console.log('processChartData被调用,数据:', lineData)
+      
+      if (!lineData) {
+        this.$message.error(this.$t('未获取到图表数据'))
+        return
+      }
+      
+      // 显示所有图表
+      console.log('设置图表显示状态为true')
+      this.showFlowChart = true
+      this.showZetaChart = true
+      this.showCavitationChart = true
+      this.showKvChart = true
+      
+      console.log('图表显示状态:', {
+        showFlowChart: this.showFlowChart,
+        showZetaChart: this.showZetaChart,
+        showCavitationChart: this.showCavitationChart,
+        showKvChart: this.showKvChart
+      })
+      
+      // 等待DOM更新后初始化图表
+      this.$nextTick(() => {
+        // 从API数据中提取不同类型的曲线数据
+        const chartData = this.extractChartDataFromAPI(lineData)
+        
+        // 初始化四个图表
+        this.initFlowChart(chartData.flowData)
+        this.initZetaChart(chartData.zetaData)
+        this.initCavitationChart(chartData.cavitationData)
+        this.initKvChart(chartData.kvData)
+      })
+    },
+    
+    // 从API数据中提取图表数据
+    extractChartDataFromAPI(lineData) {
+      // 根据实际API数据结构解析数据
+      
+      // 提取流量压差数据
+      const flowData = []
+      const pressureDropData = []
+      
+      // 提取流阻系数数据
+      const zetaData = []
+      
+      // 提取气蚀系数数据
+      const cavitationData = []
+      
+      // 提取KV数据
+      const kvData = []
+      
+      // 解析dc气蚀系数曲线数据
+      if (lineData.dc && Array.isArray(lineData.dc)) {
+        lineData.dc.forEach(item => {
+          const opening = parseFloat(item.li) // 直接使用li原数据
+          const value = parseFloat(item.value)
+          if (!isNaN(opening) && !isNaN(value)) {
+            cavitationData.push([opening, value])
+          }
+        })
+      }
+      
+      // 解析flow流量压差开度曲线数据(嵌套对象结构)
+       if (lineData.flow && typeof lineData.flow === 'object') {
+         // 遍历不同压差条件(如"10", "20"等)
+         Object.keys(lineData.flow).forEach(pressureKey => {
+           const pressureData = lineData.flow[pressureKey]
+           if (Array.isArray(pressureData)) {
+             pressureData.forEach(item => {
+               const opening = parseFloat(item.li) // 直接使用li原数据
+               const value = parseFloat(item.value)
+               if (!isNaN(opening) && !isNaN(value)) {
+                 flowData.push([opening, value, pressureKey]) // 添加压差条件标识
+               }
+             })
+           }
+         })
+       }
+       
+       // 解析其他类型的曲线数据(如果存在)
+       if (lineData.pressureDrop && Array.isArray(lineData.pressureDrop)) {
+         lineData.pressureDrop.forEach(item => {
+           const opening = parseFloat(item.li) // 直接使用li原数据
+           const value = parseFloat(item.value)
+           if (!isNaN(opening) && !isNaN(value)) {
+             pressureDropData.push([opening, value])
+           }
+         })
+       }
+      
+      if (lineData.zeta && Array.isArray(lineData.zeta)) {
+         lineData.zeta.forEach(item => {
+           const opening = parseFloat(item.li) // 直接使用li原数据
+           const value = parseFloat(item.value)
+           if (!isNaN(opening) && !isNaN(value)) {
+             zetaData.push([opening, value])
+           }
+         })
+       }
+       
+       // 解析kv曲线数据
+       if (lineData.kv && Array.isArray(lineData.kv)) {
+         lineData.kv.forEach(item => {
+           const opening = parseFloat(item.li) // 直接使用li原数据
+           const value = parseFloat(item.value)
+           if (!isNaN(opening) && !isNaN(value)) {
+             kvData.push([opening, value])
+           }
+         })
+       }
+      
+      return {
+        flowData: {
+          flowData,
+          pressureDropData
+        },
+        zetaData: {
+          zetaData
+        },
+        cavitationData: {
+          cavitationData
+        },
+        kvData: {
+          kvData
+        }
+      }
+    },
+    
+    // 生成流量开度曲线
+    async generateFlowCurve() {
+      if (!this.openingSettings.parsedValues.length) {
+        this.$message.warning(this.$t('请先设置开度值'))
+        return
+      }
+      
+      if (!this.valveSelection.throttleValue) {
+        this.$message.warning(this.$t('请先选择节流件'))
+        return
+      }
+      
+      // 模拟生成曲线数据(实际应该调用API获取)
+      const chartData = this.generateMockChartData()
+      
+      this.showFlowChart = true
+      
+      // 等待DOM更新后初始化图表
+      this.$nextTick(() => {
+        this.initFlowChart(chartData)
+      })
+    },
+    
+    // 生成模拟图表数据
+    generateMockChartData() {
+      const openings = this.openingSettings.parsedValues
+      const flowData = []
+      const pressureDropData = []
+      
+      openings.forEach(opening => {
+        // 模拟流量数据(基于开度的二次函数关系)
+        const flow = Math.pow(opening / 100, 1.5) * 100 + Math.random() * 10
+        flowData.push([opening, parseFloat(flow.toFixed(2))])
+        
+        // 模拟压差数据
+        const pressureDrop = Math.pow(opening / 100, 2) * 50 + Math.random() * 5
+        pressureDropData.push([opening, parseFloat(pressureDrop.toFixed(2))])
+      })
+      
+      return {
+        openings,
+        flowData,
+        pressureDropData
+      }
+    },
+    
+    // 初始化流量开度图表
+    initFlowChart(data) {
+      console.log('initFlowChart被调用,数据:', data)
+      
+      // 销毁已存在的图表实例
+      if (this.flowChartInstance) {
+        this.flowChartInstance.destroy()
+      }
+      
+      const chartDom = document.getElementById('flowOpeningChart')
+      console.log('查找流量图表容器flowOpeningChart:', chartDom)
+      
+      if (!chartDom) {
+        this.$message.error(this.$t('图表容器未找到'))
+        console.error(this.$t('DOM容器flowOpeningChart未找到'))
+        return
+      }
+      
+      // 使用G2图表库
+      import('@antv/g2').then(({ Chart }) => {
+        // 清空容器
+        chartDom.innerHTML = ''
+        
+        // 创建图表实例
+        this.flowChartInstance = new Chart({
+          container: chartDom,
+          autoFit: true,
+          height: 400,
+          padding: [60, 80, 60, 80]
+        })
+        
+        // 准备数据 - 使用传入的真实数据或生成模拟数据
+        let chartData = []
+        
+        if (data && data.flowData && data.pressureDropData) {
+          // 使用真实数据 - 处理多条曲线
+          data.flowData.forEach(item => {
+            const pressureCondition = item[2] || this.$t('默认') // 获取压差条件
+            chartData.push({
+              opening: item[0],
+              value: item[1],
+              type: `流量-${pressureCondition}kPa`,
+              unit: 'm³/h'
+            })
+          })
+          data.pressureDropData.forEach(item => {
+            const pressureCondition = item[2] || this.$t('默认') // 获取压差条件
+            chartData.push({
+              opening: item[0],
+              value: item[1],
+              type: `压差-${pressureCondition}kPa`,
+              unit: 'kPa'
+            })
+          })
+        } else {
+          // 使用模拟数据作为后备
+          const mockData = this.generateMockChartData()
+          mockData.flowData.forEach(item => {
+            chartData.push({
+              opening: item[0],
+              value: item[1],
+              type: this.$t('流量'),
+              unit: 'm³/h'
+            })
+          })
+          mockData.pressureDropData.forEach(item => {
+            chartData.push({
+              opening: item[0],
+              value: item[1],
+              type: this.$t('压差'),
+              unit: 'kPa'
+            })
+          })
+        }
+        
+        // 设置数据
+        this.flowChartInstance.data(chartData)
+        
+        // 设置度量
+        this.flowChartInstance.scale({
+          opening: {
+            nice: true
+          },
+          value: {
+            nice: true
+          }
+        })
+        
+        // 设置坐标轴
+        this.flowChartInstance.axis('opening', {
+          title: {
+            text: this.$t('开度 (%)')
+          }
+        })
+        
+        this.flowChartInstance.axis('value', {
+          title: {
+            text: this.$t('数值')
+          }
+        })
+        
+        // 设置图例
+        this.flowChartInstance.legend({
+          position: 'top'
+        })
+        
+        // 设置提示信息
+        this.flowChartInstance.tooltip({
+          shared: true,
+          showCrosshairs: true,
+          crosshairs: {
+            type: 'xy'
+          }
+        })
+        
+        // 绘制线图
+        this.flowChartInstance
+          .line()
+          .position('opening*value')
+          .color('type', ['#409EFF', '#67C23A'])
+          .shape('smooth')
+          .tooltip('opening*value*type*unit', (opening, value, type, unit) => {
+            return {
+              name: type,
+              value: `${value} ${unit} (开度: ${opening}%)`
+            }
+          })
+        
+        this.flowChartInstance
+          .point()
+          .position('opening*value')
+          .color('type', ['#409EFF', '#67C23A'])
+          .size(4)
+          .shape('circle')
+          .style({
+            stroke: '#fff',
+            lineWidth: 1
+          })
+        
+        // 渲染图表
+        this.flowChartInstance.render()
+      }).catch(error => {
+        console.error(this.$t('图表库加载失败') + ':', error)
+        this.$message.error(this.$t('图表组件加载失败,请刷新页面重试'))
+      })
+    },
+    
+    // 初始化KV图表
+    initKvChart(chartData) {
+      // 销毁已存在的图表实例
+      if (this.kvChartInstance) {
+        this.kvChartInstance.destroy()
+      }
+      
+      const chartDom = document.getElementById('kvChart')
+      if (!chartDom) {
+        this.$message.error(this.$t('KV图表容器未找到'))
+        return
+      }
+      
+      // 使用G2图表库
+      import('@antv/g2').then(({ Chart }) => {
+        // 清空容器
+        chartDom.innerHTML = ''
+        
+        // 创建图表实例
+        this.kvChartInstance = new Chart({
+          container: chartDom,
+          autoFit: true,
+          height: 400,
+          padding: [60, 80, 60, 80]
+        })
+        
+        // 准备数据 - 使用传入的真实数据或生成模拟数据
+         let allData = []
+         
+         if (chartData && chartData.kvData) {
+           // 使用真实数据
+           chartData.kvData.forEach(item => {
+             allData.push({
+               opening: item[0],
+               value: item[1],
+               type: this.$t('KV系数')
+             })
+           })
+         } else {
+           // 使用模拟数据作为后备
+           const mockData = this.generateKvChartData()
+           mockData.kvData.forEach(item => {
+             allData.push({
+               opening: item[0],
+               value: item[1],
+               type: this.$t('KV系数')
+             })
+           })
+         }
+         
+         // 设置数据
+         this.kvChartInstance.data(allData)
+        
+        // 设置度量
+        this.kvChartInstance.scale({
+          opening: {
+            nice: true
+          },
+          value: {
+            nice: true
+          }
+        })
+        
+        // 设置坐标轴
+        this.kvChartInstance.axis('opening', {
+          title: {
+            text: this.$t('开度 (%)')
+          }
+        })
+        
+        this.kvChartInstance.axis('value', {
+          title: {
+            text: this.$t('KV系数')
+          }
+        })
+        
+        // 设置图例
+        this.kvChartInstance.legend({
+          position: 'top'
+        })
+        
+        // 设置提示信息
+        this.kvChartInstance.tooltip({
+          shared: true,
+          showCrosshairs: true,
+          crosshairs: {
+            type: 'xy'
+          }
+        })
+        
+        // 绘制线图
+        this.kvChartInstance
+          .line()
+          .position('opening*value')
+          .color('#409EFF')
+          .shape('smooth')
+          .tooltip('opening*value*type', (opening, value, type) => {
+            return {
+              name: type,
+              value: `${value} (开度: ${opening}%)`
+            }
+          })
+        
+        this.kvChartInstance
+          .point()
+          .position('opening*value')
+          .color('#409EFF')
+          .size(4)
+          .shape('circle')
+          .style({
+            stroke: '#fff',
+            lineWidth: 1
+          })
+        
+        // 渲染图表
+        this.kvChartInstance.render()
+      }).catch(error => {
+          console.error(this.$t('图表库加载失败') + ':', error)
+          this.$message.error(this.$t('图表组件加载失败,请刷新页面重试'))
+        })
+    },
+    
+    // 生成KV模拟数据
+    generateKvChartData() {
+      const openings = this.openingSettings.parsedValues
+      const kvData = []
+      
+      openings.forEach(opening => {
+        // 模拟KV系数数据(随开度变化的线性关系)
+        const kv = (opening / 100) * 50 + Math.random() * 5
+        kvData.push([opening, parseFloat(kv.toFixed(3))])
+      })
+      
+      return {
+        openings,
+        kvData
+      }
+    },
+    
+    // 生成流阻系数曲线
+    async generateZetaCurve() {
+      if (!this.openingSettings.parsedValues.length) {
+        this.$message.warning(this.$t('请先设置开度值'))
+        return
+      }
+      
+      if (!this.valveSelection.throttleValue) {
+        this.$message.warning(this.$t('请先选择节流件'))
+        return
+      }
+      
+      // 模拟生成流阻系数数据
+      const chartData = this.generateZetaChartData()
+      
+      this.showZetaChart = true
+      
+      // 等待DOM更新后初始化图表
+      this.$nextTick(() => {
+        this.initZetaChart(chartData)
+      })
+    },
+    
+    // 生成气蚀系数曲线
+    async generateCavitationCurve() {
+      if (!this.openingSettings.parsedValues.length) {
+        this.$message.warning(this.$t('请先设置开度值'))
+        return
+      }
+      
+      if (!this.valveSelection.throttleValue) {
+        this.$message.warning(this.$t('请先选择节流件'))
+        return
+      }
+      
+      // 模拟生成气蚀系数数据
+      const chartData = this.generateCavitationChartData()
+      
+      this.showCavitationChart = true
+      
+      // 等待DOM更新后初始化图表
+      this.$nextTick(() => {
+        this.initCavitationChart(chartData)
+      })
+    },
+    
+    // 生成流阻系数模拟数据
+    generateZetaChartData() {
+      const openings = this.openingSettings.parsedValues
+      const zetaData = []
+      
+      openings.forEach(opening => {
+        // 模拟流阻系数数据(随开度变化的非线性关系)
+        const zeta = Math.pow((100 - opening) / 100, 2) * 50 + Math.random() * 5
+        zetaData.push([opening, parseFloat(zeta.toFixed(3))])
+      })
+      
+      return {
+        openings,
+        zetaData
+      }
+    },
+    
+    // 生成气蚀系数模拟数据
+    generateCavitationChartData() {
+      const openings = this.openingSettings.parsedValues
+      const cavitationData = []
+      
+      openings.forEach(opening => {
+        // 模拟气蚀系数数据(开度越小气蚀系数越大)
+        const cavitation = Math.pow((100 - opening) / 100, 1.5) * 2 + 0.1 + Math.random() * 0.2
+        cavitationData.push([opening, parseFloat(cavitation.toFixed(3))])
+      })
+      
+      return {
+        openings,
+        cavitationData
+      }
+    },
+    
+    // 初始化流阻系数图表
+    initZetaChart(chartData) {
+      // 销毁已存在的图表实例
+      if (this.zetaChartInstance) {
+        this.zetaChartInstance.destroy()
+      }
+      
+      const chartDom = document.getElementById('zetaCoefficientChart')
+      if (!chartDom) {
+        this.$message.error(this.$t('流阻系数图表容器未找到'))
+        return
+      }
+      
+      // 使用G2图表库
+      import('@antv/g2').then(({ Chart }) => {
+        // 清空容器
+        chartDom.innerHTML = ''
+        
+        // 创建图表实例
+        this.zetaChartInstance = new Chart({
+          container: chartDom,
+          autoFit: true,
+          height: 400,
+          padding: [60, 80, 60, 80]
+        })
+        
+        // 准备数据 - 使用传入的真实数据或生成模拟数据
+         let allData = []
+         
+         if (chartData && chartData.zetaData) {
+           // 使用真实数据
+           chartData.zetaData.forEach(item => {
+             allData.push({
+               opening: item[0],
+               value: item[1],
+               type: this.$t('流阻系数ζ')
+             })
+           })
+         } else {
+           // 使用模拟数据作为后备
+           const mockData = this.generateZetaChartData()
+           mockData.zetaData.forEach(item => {
+             allData.push({
+               opening: item[0],
+               value: item[1],
+               type: this.$t('流阻系数ζ')
+             })
+           })
+         }
+        
+        // 设置数据
+         this.zetaChartInstance.data(allData)
+        
+        // 设置度量
+        this.zetaChartInstance.scale({
+          opening: {
+            nice: true
+          },
+          value: {
+            nice: true
+          }
+        })
+        
+        // 设置坐标轴
+        this.zetaChartInstance.axis('opening', {
+            title: {
+              text: this.$t('开度 (%)')
+            }
+          })
+        
+        this.zetaChartInstance.axis('value', {
+          title: {
+            text: this.$t('流阻系数ζ')
+          }
+        })
+        
+        // 设置图例
+        this.zetaChartInstance.legend({
+          position: 'top'
+        })
+        
+        // 设置提示信息
+        this.zetaChartInstance.tooltip({
+          shared: true,
+          showCrosshairs: true,
+          crosshairs: {
+            type: 'xy'
+          }
+        })
+        
+        // 绘制线图
+        this.zetaChartInstance
+          .line()
+          .position('opening*value')
+          .color('#E6A23C')
+          .shape('smooth')
+          .tooltip('opening*value*type', (opening, value, type) => {
+            return {
+              name: type,
+              value: `${value} (开度: ${opening}%)`
+            }
+          })
+        
+        this.zetaChartInstance
+          .point()
+          .position('opening*value')
+          .color('#E6A23C')
+          .size(4)
+          .shape('circle')
+          .style({
+            stroke: '#fff',
+            lineWidth: 1
+          })
+        
+        // 渲染图表
+        this.zetaChartInstance.render()
+      }).catch(error => {
+          console.error(this.$t('图表库加载失败') + ':', error)
+          this.$message.error(this.$t('图表组件加载失败,请刷新页面重试'))
+        })
+    },
+    
+    // 初始化气蚀系数图表
+    initCavitationChart(chartData) {
+      // 销毁已存在的图表实例
+      if (this.cavitationChartInstance) {
+        this.cavitationChartInstance.destroy()
+      }
+      
+      const chartDom = document.getElementById('cavitationCoefficientChart')
+      if (!chartDom) {
+        this.$message.error(this.$t('气蚀系数图表容器未找到'))
+        return
+      }
+      
+      // 使用G2图表库
+      import('@antv/g2').then(({ Chart }) => {
+        // 清空容器
+        chartDom.innerHTML = ''
+        
+        // 创建图表实例
+        this.cavitationChartInstance = new Chart({
+          container: chartDom,
+          autoFit: true,
+          height: 400,
+          padding: [60, 80, 60, 80]
+        })
+        
+        // 准备数据 - 使用传入的真实数据或生成模拟数据
+         let allData = []
+         
+         if (chartData && chartData.cavitationData) {
+           // 使用真实数据
+           chartData.cavitationData.forEach(item => {
+             allData.push({
+               opening: item[0],
+               value: item[1],
+               type: this.$t('气蚀系数σ')
+             })
+           })
+         } else {
+           // 使用模拟数据作为后备
+           const mockData = this.generateCavitationChartData()
+           mockData.cavitationData.forEach(item => {
+             allData.push({
+               opening: item[0],
+               value: item[1],
+               type: this.$t('气蚀系数σ')
+             })
+           })
+         }
+         
+         // 设置数据
+         this.cavitationChartInstance.data(allData)
+        
+        // 设置度量
+        this.cavitationChartInstance.scale({
+          opening: {
+            nice: true
+          },
+          value: {
+            nice: true
+          }
+        })
+        
+        // 设置坐标轴
+        this.cavitationChartInstance.axis('opening', {
+            title: {
+              text: this.$t('开度 (%)')
+            }
+          })
+        
+        this.cavitationChartInstance.axis('value', {
+          title: {
+            text: this.$t('气蚀系数σ')
+          }
+        })
+        
+        // 设置图例
+        this.cavitationChartInstance.legend({
+          position: 'top'
+        })
+        
+        // 设置提示信息
+        this.cavitationChartInstance.tooltip({
+          shared: true,
+          showCrosshairs: true,
+          crosshairs: {
+            type: 'xy'
+          }
+        })
+        
+        // 绘制线图
+        this.cavitationChartInstance
+          .line()
+          .position('opening*value')
+          .color('#F56C6C')
+          .shape('smooth')
+          .tooltip('opening*value*type', (opening, value, type) => {
+            return {
+              name: type,
+              value: `${value} (开度: ${opening}%)`
+            }
+          })
+        
+        this.cavitationChartInstance
+          .point()
+          .position('opening*value')
+          .color('#F56C6C')
+          .size(4)
+          .shape('circle')
+          .style({
+            stroke: '#fff',
+            lineWidth: 1
+          })
+        
+        // 渲染图表
+        this.cavitationChartInstance.render()
+      }).catch(error => {
+          console.error(this.$t('图表库加载失败') + ':', error)
+          this.$message.error(this.$t('图表组件加载失败,请刷新页面重试'))
+        })
+    },
+  },
+
+
+  mounted() {
+    this.optionList()
+  },
+  
+  beforeDestroy() {
+    // 销毁图表实例,避免内存泄漏
+    if (this.flowChartInstance) {
+      this.flowChartInstance.destroy()
+      this.flowChartInstance = null
+    }
+    if (this.zetaChartInstance) {
+      this.zetaChartInstance.destroy()
+      this.zetaChartInstance = null
+    }
+    if (this.cavitationChartInstance) {
+      this.cavitationChartInstance.destroy()
+      this.cavitationChartInstance = null
+    }
+    if (this.kvChartInstance) {
+      this.kvChartInstance.destroy()
+      this.kvChartInstance = null
+    }
+  },
+}
+</script>
+<style>
+  .step-content .ant-steps-item-process > .ant-steps-item-container > .ant-steps-item-content > .ant-steps-item-title {
+    color: #3874f6 !important;
+  }
+</style>
+<style scoped>
+.calculation-selection {
+  padding: 20px;
+  background-color: #fff;
+  min-height: calc(100vh - 40px);
+}
+
+.page-header {
+  margin-bottom: 30px;
+  text-align: center;
+}
+
+.page-header h2 {
+  color: #303133;
+  font-size: 24px;
+  font-weight: 500;
+  margin: 0;
+}
+
+.step-container {
+  padding: 30px;
+}
+
+.step-content {
+  margin-bottom: 30px;
+}
+
+.step-panel {
+  animation: fadeIn 0.3s ease-in-out;
+}
+
+@keyframes fadeIn {
+  from {
+    opacity: 0;
+    transform: translateY(20px);
+  }
+  to {
+    opacity: 1;
+    transform: translateY(0);
+  }
+}
+
+.step-card {
+  /* box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1); */
+  border-radius: 8px;
+}
+
+.card-header {
+  font-size: 18px;
+  font-weight: 500;
+  color: #303133;
+}
+
+.button-group {
+  text-align: center;
+  padding: 20px;
+}
+
+.button-group .el-button {
+  margin: 0 10px;
+  min-width: 100px;
+}
+
+.el-form-item {
+  margin-bottom: 22px;
+}
+
+.el-divider {
+  margin: 30px 0 20px 0;
+}
+
+
+
+
+
+/* 工况条件表格样式 */
+.condition-table {
+  border: 1px solid #ddd;
+  border-radius: 4px;
+  overflow: hidden;
+}
+
+.condition-row {
+  display: flex;
+  align-items: center;
+  min-height: 40px;
+}
+
+.condition-label {
+  background-color: #f5f5f5;
+  border-right: 1px solid #ddd;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  font-weight: bold;
+  height: 40px;
+}
+
+.condition-input {
+  padding: 0 10px;
+}
+
+.condition-input .el-form-item {
+  margin-bottom: 0;
+}
+
+.condition-input .el-form-item__label {
+  font-size: 12px;
+  color: #666;
+}
+
+/* 开度设置样式 */
+.opening-settings {
+  margin-top: 20px;
+}
+
+.input-tip {
+  font-size: 12px;
+  color: #909399;
+  margin-top: 5px;
+}
+
+.opening-info {
+  display: flex;
+  align-items: center;
+  height: 32px;
+}
+
+.info-text {
+  font-size: 14px;
+  color: #606266;
+}
+
+.opening-preview {
+  margin-top: 15px;
+  padding: 10px;
+  background-color: #f5f7fa;
+  border-radius: 4px;
+}
+
+/* 图表控制按钮样式 */
+.chart-controls {
+  margin: 20px 0;
+  text-align: center;
+}
+
+.chart-controls .el-button {
+  margin: 0 10px 10px 0;
+  min-width: 140px;
+}
+
+.chart-controls .el-button:last-child {
+  margin-right: 0;
+}
+
+.preview-label {
+  font-size: 14px;
+  color: #606266;
+  margin-right: 10px;
+}
+
+/* 图表容器样式 */
+.chart-container {
+  margin-top: 30px;
+}
+#kvChart,
+#flowOpeningChart,
+#zetaCoefficientChart,
+#cavitationCoefficientChart {
+  border: 1px solid #e4e7ed;
+  border-radius: 4px;
+  background-color: #fff;
+}
+
+.my-steps {
+  padding: 0px 68px;
+}
+
+/* 响应式设计 */
+@media (max-width: 768px) {
+  .calculation-selection {
+    padding: 10px;
+  }
+  
+  .step-container {
+    padding: 20px;
+  }
+  
+  .el-col {
+    margin-bottom: 10px;
+  }
+  
+  .condition-row {
+    flex-direction: column;
+  }
+  
+  .condition-label {
+    width: 100%;
+    border-right: none;
+    border-bottom: 1px solid #ddd;
+  }
+  
+  #flowOpeningChart {
+    height: 300px !important;
+  }
+}
+</style>

+ 830 - 0
src/optionSystem/optionOrder/detail/indexCalc.vue

@@ -0,0 +1,830 @@
+<template>
+  <div>
+    <basicDetails
+      ref="details"
+      :titleText="mainData.billno"
+      :oldFormPath="{ edit: 'optionSystem/optionOrder/detail/modules' }"
+      :editData="mainData"
+      :mainAreaData="mainAreaData"
+      turnPageId="2024071815534702"
+      idname="sa_lectotypecfgid"
+      ownertable="sa_lectotypecfg"
+      tags=""
+      :tabs="['产品配置']"
+      :statusCheck="[{ key: 'status', value: '审核' }]"
+      @pageChange="pageChange"
+      @onEditSuccess="
+        queryMainData($route.query.id);
+        $refs.Product.listData();
+      "
+    >
+      <div slot="slot0">
+        <el-descriptions title="环境条件" :column="4">
+            <el-descriptions-item label="大气压 (mH₂O)">{{mainData.calculate.pa}}</el-descriptions-item>
+            <el-descriptions-item label="重力加速度 (m/s²)">{{mainData.calculate.g}}</el-descriptions-item>
+            <el-descriptions-item label="饱和蒸气压 (mH₂O)">{{mainData.calculate.pv}}</el-descriptions-item>
+            <el-descriptions-item label="温度 (℃)">{{mainData.calculate.t}}</el-descriptions-item>
+        </el-descriptions>
+        <el-descriptions title="阀门条件" :column="4">
+            <el-descriptions-item label="公称通径">{{mainData.calculate.caliber}}</el-descriptions-item>
+            <el-descriptions-item label="公称压力">{{mainData.calculate.pressure}}</el-descriptions-item>
+            <el-descriptions-item label="管道外径 (mm)">{{mainData.calculate.od}}</el-descriptions-item>
+            <el-descriptions-item label="壁厚 (mm)">{{mainData.calculate.wt}}</el-descriptions-item>
+            <el-descriptions-item label="控制点名称">{{mainData.calculate.cname}}</el-descriptions-item>
+            <el-descriptions-item label="应用场景">{{mainData.calculate.purpose}}</el-descriptions-item>
+            <el-descriptions-item label="介质">{{mainData.calculate.mediatype}}</el-descriptions-item>
+            <el-descriptions-item label="密度">{{mainData.calculate.p}}</el-descriptions-item>
+            <el-descriptions-item label="起点高程">{{mainData.calculate.z1}}</el-descriptions-item>
+            <el-descriptions-item label="末点高程">{{mainData.calculate.z2}}</el-descriptions-item>
+            <el-descriptions-item label="阀中心高程">{{mainData.calculate.zv}}</el-descriptions-item>
+        </el-descriptions>
+        <h3 class="mt-10" style="color:#000">计算结果</h3>
+        <el-table :data="mainData.conditions" style="width: 100%" size="mini" border>
+          <el-table-column prop="workingCondition" label="工况" align="center"></el-table-column>
+          <el-table-column prop="conditionName" label="条件名称" align="center"></el-table-column>
+          <el-table-column prop="q" label="流量(q)" align="center"></el-table-column>
+          <el-table-column prop="p1" label="阀前压力(p1)" align="center"></el-table-column>
+          <el-table-column prop="p2" label="阀后压力(p2)" align="center"></el-table-column>
+          <el-table-column prop="p" label="前后压差(p)" align="center"></el-table-column>
+          <el-table-column prop="pv" label="饱和蒸汽压(pV)" align="center"></el-table-column>
+          <el-table-column prop="kv" label="KV(kv)" align="center"></el-table-column>
+          <el-table-column prop="li" label="开度(li)" align="center"></el-table-column>
+          <el-table-column prop="ldc" label="临界汽蚀系数σc(Idc)" align="center"></el-table-column>
+          <el-table-column prop="dc" label="气蚀系数σ(dc)" align="center"></el-table-column>
+          <el-table-column prop="fi" label="压力恢复系数FI(fi)" align="center"></el-table-column>
+          <el-table-column prop="fr" label="流阻系数ζ(fr)" align="center"></el-table-column>
+          <el-table-column prop="fkv" label="阻塞流修正系数Fkv(fkv)" align="center"></el-table-column>
+          <el-table-column prop="v" label="流速V(v)" align="center"></el-table-column>
+        </el-table>
+        
+        <!-- 图表区域 -->
+        <div v-if="showCharts" class="chart-section">
+          <el-row>
+            <el-col :span="18">
+              <!-- KV曲线图 -->
+              <div v-if="showKvChart" class="chart-container">
+                <el-divider content-position="left">KV曲线图</el-divider>
+                <div id="kvChart" style="width: 100%; height: 400px;"></div>
+              </div>
+              <!-- 流阻系数曲线图 -->
+              <div v-if="showZetaChart" class="chart-container">
+                <el-divider content-position="left">流阻系数曲线图</el-divider>
+                <div id="zetaCoefficientChart" style="width: 100%; height: 400px;"></div>
+              </div>
+              
+              <!-- 气蚀系数曲线图 -->
+              <div v-if="showCavitationChart" class="chart-container">
+                <el-divider content-position="left">气蚀系数曲线图</el-divider>
+                <div id="cavitationCoefficientChart" style="width: 100%; height: 400px;"></div>
+              </div>
+              <!-- 流量开度曲线图 -->
+              <div v-if="showFlowChart" class="chart-container">
+                <el-divider content-position="left">流量开度曲线图</el-divider>
+                <div id="flowOpeningChart" style="width: 100%; height: 400px;"></div>
+              </div>
+            </el-col>
+          </el-row>
+        </div>
+      </div>
+    </basicDetails>
+  </div>
+</template>
+
+  <script>
+import Table from "@/optionSystem/FProductManage/modules/table";
+import SetOrder from "./modules/setOrder.vue";
+export default {
+  name: "detail",
+  components: { Table, SetOrder },
+  provide() {
+    return {
+      resultArrs: () => this.$refs.Product.resultArr,
+    };
+  },
+  data() {
+    return {
+      mainData: {},
+      mainAreaData: {},
+      chartData: {},
+      // 图表显示控制
+      showCharts: false,
+      showFlowChart: false,
+      showZetaChart: false,
+      showCavitationChart: false,
+      showKvChart: false,
+      
+      // 图表实例
+      flowChartInstance: null,
+      zetaChartInstance: null,
+      cavitationChartInstance: null,
+      kvChartInstance: null
+    };
+  },
+  methods: {
+    async queryMainData(id) {
+      const res = await this.$api.requested({
+        id: 2025091909460102,
+        content: {
+          sa_lectotypecfgid: this.$route.query.id,
+        },
+      });
+      this.mainData = res.data;
+      const minData = {
+        ...res.data.conditions[0],
+        workingCondition: '通用',
+        conditionName: '最小流量'
+      }
+      const maxData = {
+        ...res.data.conditions[1],
+        workingCondition: '通用',
+        conditionName: '最大流量'
+      }
+      this.mainData.conditions = [minData, maxData]
+      this.chartData = res.data.curve
+      this.changeDataStructure();
+      
+      // 处理图表数据
+      if (this.chartData && Object.keys(this.chartData).length > 0) {
+        this.processChartData(this.chartData);
+      }
+     },
+     
+     // 初始化流量开度图表
+     initFlowChart(data) {
+       console.log('initFlowChart被调用,数据:', data)
+       
+       // 销毁已存在的图表实例
+       if (this.flowChartInstance) {
+         this.flowChartInstance.destroy()
+       }
+       
+       const chartDom = document.getElementById('flowOpeningChart')
+       console.log('查找流量图表容器flowOpeningChart:', chartDom)
+       
+       if (!chartDom) {
+         console.error('DOM容器flowOpeningChart未找到')
+         return
+       }
+       
+       // 使用G2图表库
+       import('@antv/g2').then(({ Chart }) => {
+         // 清空容器
+         chartDom.innerHTML = ''
+         
+         // 创建图表实例
+         this.flowChartInstance = new Chart({
+           container: chartDom,
+           autoFit: true,
+           height: 400,
+           padding: [60, 80, 60, 80]
+         })
+         
+         // 准备数据 - 使用传入的真实数据
+         let chartData = []
+         
+         if (data && data.flowData) {
+           // 使用真实数据 - 处理多条曲线
+           data.flowData.forEach(item => {
+             const pressureCondition = item[2] || '默认' // 获取压差条件
+             chartData.push({
+               opening: item[0],
+               value: item[1],
+               type: `流量-${pressureCondition}kPa`,
+               unit: 'm³/h'
+             })
+           })
+         }
+         
+         if (data && data.pressureDropData) {
+           data.pressureDropData.forEach(item => {
+             const pressureCondition = item[2] || '默认' // 获取压差条件
+             chartData.push({
+               opening: item[0],
+               value: item[1],
+               type: `压差-${pressureCondition}kPa`,
+               unit: 'kPa'
+             })
+           })
+         }
+         
+         // 设置数据
+         this.flowChartInstance.data(chartData)
+         
+         // 设置度量
+         this.flowChartInstance.scale({
+           opening: {
+             nice: true
+           },
+           value: {
+             nice: true
+           }
+         })
+         
+         // 设置坐标轴
+         this.flowChartInstance.axis('opening', {
+           title: {
+             text: '开度 (%)'
+           }
+         })
+         
+         this.flowChartInstance.axis('value', {
+           title: {
+             text: '数值'
+           }
+         })
+         
+         // 设置图例
+         this.flowChartInstance.legend({
+           position: 'top'
+         })
+         
+         // 设置提示信息
+         this.flowChartInstance.tooltip({
+           shared: true,
+           showCrosshairs: true,
+           crosshairs: {
+             type: 'xy'
+           }
+         })
+         
+         // 绘制线图
+         this.flowChartInstance
+           .line()
+           .position('opening*value')
+           .color('type', ['#409EFF', '#67C23A'])
+           .shape('smooth')
+           .tooltip('opening*value*type*unit', (opening, value, type, unit) => {
+             return {
+               name: type,
+               value: `${value} ${unit} (开度: ${opening}%)`
+             }
+           })
+         
+         this.flowChartInstance
+           .point()
+           .position('opening*value')
+           .color('type', ['#409EFF', '#67C23A'])
+           .size(4)
+           .shape('circle')
+           .style({
+             stroke: '#fff',
+             lineWidth: 1
+           })
+         
+         // 渲染图表
+         this.flowChartInstance.render()
+       }).catch(error => {
+         console.error('图表库加载失败:', error)
+       })
+     },
+     
+     // 初始化KV图表
+     initKvChart(chartData) {
+       // 销毁已存在的图表实例
+       if (this.kvChartInstance) {
+         this.kvChartInstance.destroy()
+       }
+       
+       const chartDom = document.getElementById('kvChart')
+       if (!chartDom) {
+         console.error('KV图表容器未找到')
+         return
+       }
+       
+       // 使用G2图表库
+       import('@antv/g2').then(({ Chart }) => {
+         // 清空容器
+         chartDom.innerHTML = ''
+         
+         // 创建图表实例
+         this.kvChartInstance = new Chart({
+           container: chartDom,
+           autoFit: true,
+           height: 400,
+           padding: [60, 80, 60, 80]
+         })
+         
+         // 准备数据 - 使用传入的真实数据
+          let allData = []
+          
+          if (chartData && chartData.kvData) {
+            // 使用真实数据
+            chartData.kvData.forEach(item => {
+              allData.push({
+                opening: item[0],
+                value: item[1],
+                type: 'Kv'
+              })
+            })
+          }
+          
+          // 设置数据
+          this.kvChartInstance.data(allData)
+         
+         // 设置度量
+         this.kvChartInstance.scale({
+           opening: {
+             nice: true
+           },
+           value: {
+             nice: true
+           }
+         })
+         
+         // 设置坐标轴
+         this.kvChartInstance.axis('opening', {
+           title: {
+             text: '开度 (%)'
+           }
+         })
+         
+         this.kvChartInstance.axis('value', {
+           title: {
+             text: 'KV系数'
+           }
+         })
+         
+         // 设置图例
+         this.kvChartInstance.legend({
+           position: 'top'
+         })
+         
+         // 设置提示信息
+         this.kvChartInstance.tooltip({
+           shared: true,
+           showCrosshairs: true,
+           crosshairs: {
+             type: 'xy'
+           }
+         })
+         
+         // 绘制线图
+         this.kvChartInstance
+           .line()
+           .position('opening*value')
+           .color('#409EFF')
+           .shape('smooth')
+           .tooltip('opening*value*type', (opening, value, type) => {
+             return {
+               name: type,
+               value: `${value} (开度: ${opening}%)`
+             }
+           })
+         
+         this.kvChartInstance
+           .point()
+           .position('opening*value')
+           .color('#409EFF')
+           .size(4)
+           .shape('circle')
+           .style({
+             stroke: '#fff',
+             lineWidth: 1
+           })
+         
+         // 渲染图表
+         this.kvChartInstance.render()
+       }).catch(error => {
+         console.error('图表库加载失败:', error)
+       })
+     },
+     
+     // 初始化流阻系数图表
+     initZetaChart(chartData) {
+       // 销毁已存在的图表实例
+       if (this.zetaChartInstance) {
+         this.zetaChartInstance.destroy()
+       }
+       
+       const chartDom = document.getElementById('zetaCoefficientChart')
+       if (!chartDom) {
+         console.error('流阻系数图表容器未找到')
+         return
+       }
+       
+       // 使用G2图表库
+       import('@antv/g2').then(({ Chart }) => {
+         // 清空容器
+         chartDom.innerHTML = ''
+         
+         // 创建图表实例
+         this.zetaChartInstance = new Chart({
+           container: chartDom,
+           autoFit: true,
+           height: 400,
+           padding: [60, 80, 60, 80]
+         })
+         
+         // 准备数据
+          let allData = []
+          
+          if (chartData && chartData.zetaData) {
+            chartData.zetaData.forEach(item => {
+              allData.push({
+                opening: item[0],
+                value: item[1],
+                type: '流阻系数'
+              })
+            })
+          }
+          
+          // 设置数据
+          this.zetaChartInstance.data(allData)
+         
+         // 设置度量
+         this.zetaChartInstance.scale({
+           opening: {
+             nice: true
+           },
+           value: {
+             nice: true
+           }
+         })
+         
+         // 设置坐标轴
+         this.zetaChartInstance.axis('opening', {
+           title: {
+             text: '开度 (%)'
+           }
+         })
+         
+         this.zetaChartInstance.axis('value', {
+           title: {
+             text: '流阻系数'
+           }
+         })
+         
+         // 设置图例
+         this.zetaChartInstance.legend({
+           position: 'top'
+         })
+         
+         // 设置提示信息
+         this.zetaChartInstance.tooltip({
+           shared: true,
+           showCrosshairs: true,
+           crosshairs: {
+             type: 'xy'
+           }
+         })
+         
+         // 绘制线图
+         this.zetaChartInstance
+           .line()
+           .position('opening*value')
+           .color('#E6A23C')
+           .shape('smooth')
+           .tooltip('opening*value*type', (opening, value, type) => {
+             return {
+               name: type,
+               value: `${value} (开度: ${opening}%)`
+             }
+           })
+         
+         this.zetaChartInstance
+           .point()
+           .position('opening*value')
+           .color('#E6A23C')
+           .size(4)
+           .shape('circle')
+           .style({
+             stroke: '#fff',
+             lineWidth: 1
+           })
+         
+         // 渲染图表
+         this.zetaChartInstance.render()
+       }).catch(error => {
+         console.error('图表库加载失败:', error)
+       })
+     },
+     
+     // 初始化气蚀系数图表
+     initCavitationChart(chartData) {
+       // 销毁已存在的图表实例
+       if (this.cavitationChartInstance) {
+         this.cavitationChartInstance.destroy()
+       }
+       
+       const chartDom = document.getElementById('cavitationCoefficientChart')
+       if (!chartDom) {
+         console.error('气蚀系数图表容器未找到')
+         return
+       }
+       
+       // 使用G2图表库
+       import('@antv/g2').then(({ Chart }) => {
+         // 清空容器
+         chartDom.innerHTML = ''
+         
+         // 创建图表实例
+         this.cavitationChartInstance = new Chart({
+           container: chartDom,
+           autoFit: true,
+           height: 400,
+           padding: [60, 80, 60, 80]
+         })
+         
+         // 准备数据
+          let allData = []
+          
+          if (chartData && chartData.cavitationData) {
+            chartData.cavitationData.forEach(item => {
+              allData.push({
+                opening: item[0],
+                value: item[1],
+                type: '气蚀系数'
+              })
+            })
+          }
+          
+          // 设置数据
+          this.cavitationChartInstance.data(allData)
+         
+         // 设置度量
+         this.cavitationChartInstance.scale({
+           opening: {
+             nice: true
+           },
+           value: {
+             nice: true
+           }
+         })
+         
+         // 设置坐标轴
+         this.cavitationChartInstance.axis('opening', {
+           title: {
+             text: '开度 (%)'
+           }
+         })
+         
+         this.cavitationChartInstance.axis('value', {
+           title: {
+             text: '气蚀系数'
+           }
+         })
+         
+         // 设置图例
+         this.cavitationChartInstance.legend({
+           position: 'top'
+         })
+         
+         // 设置提示信息
+         this.cavitationChartInstance.tooltip({
+           shared: true,
+           showCrosshairs: true,
+           crosshairs: {
+             type: 'xy'
+           }
+         })
+         
+         // 绘制线图
+         this.cavitationChartInstance
+           .line()
+           .position('opening*value')
+           .color('#F56C6C')
+           .shape('smooth')
+           .tooltip('opening*value*type', (opening, value, type) => {
+             return {
+               name: type,
+               value: `${value} (开度: ${opening}%)`
+             }
+           })
+         
+         this.cavitationChartInstance
+           .point()
+           .position('opening*value')
+           .color('#F56C6C')
+           .size(4)
+           .shape('circle')
+           .style({
+             stroke: '#fff',
+             lineWidth: 1
+           })
+         
+         // 渲染图表
+         this.cavitationChartInstance.render()
+       }).catch(error => {
+         console.error('图表库加载失败:', error)
+       })
+     },
+    changeDataStructure() {
+      let that = this;
+      this.mainAreaData = [
+        {
+          label: "状态",
+          value: this.mainData.status,
+          style: function () {
+            let statusColors = {
+              无需评审: "#67C23A",
+              待评审: "#3874f6",
+              评审中: "#e6a23c",
+              评审通过: "#67C23A",
+              评审拒绝: "#F56C6C",
+              "评审通过-暂无成品": "#67C23A",
+              "评审通过-已有成品": "#67C23A",
+            };
+            return { color: statusColors[that.mainData.status] };
+          },
+        },
+        {
+          label: "价格",
+          value: this.tool.formatAmount(this.mainData.price, 2),
+        },
+        {
+          label: "客户",
+          value: this.mainData.enterprisename,
+        },
+        {
+          label: "项目",
+          value: this.mainData.projectname,
+        },
+        {
+          label: "来源",
+          value: this.mainData.source,
+        },
+        {
+          label: "操作人",
+          value: this.mainData.createby,
+        },
+        {
+          label: "操作时间",
+          value: this.mainData.createdate,
+        },
+      ];
+      console.log(this.mainAreaData);
+    },
+    // 监听切换数据,上一页,下一页
+    pageChange(id, rowindex, tabIndex) {
+      this.flag = false;
+      this.queryMainData(id);
+    },
+    onSuccess() {
+      this.visible = false;
+      this.queryMainData(this.$route.query.id);
+      this.$emit("onSuccess");
+    },
+    
+    // 处理API返回的图表数据
+    processChartData(lineData) {
+      console.log('processChartData被调用,数据:', lineData)
+      
+      if (!lineData) {
+        console.log('未获取到图表数据')
+        return
+      }
+      
+      // 显示所有图表
+      console.log('设置图表显示状态为true')
+      this.showCharts = true
+      this.showFlowChart = true
+      this.showZetaChart = true
+      this.showCavitationChart = true
+      this.showKvChart = true
+      
+      console.log('图表显示状态:', {
+        showFlowChart: this.showFlowChart,
+        showZetaChart: this.showZetaChart,
+        showCavitationChart: this.showCavitationChart,
+        showKvChart: this.showKvChart
+      })
+      
+      // 等待DOM更新后初始化图表
+      this.$nextTick(() => {
+        // 从API数据中提取不同类型的曲线数据
+        const chartData = this.extractChartDataFromAPI(lineData)
+        
+        // 初始化四个图表
+        this.initFlowChart(chartData.flowData)
+        this.initZetaChart(chartData.zetaData)
+        this.initCavitationChart(chartData.cavitationData)
+        this.initKvChart(chartData.kvData)
+      })
+    },
+    
+    // 从API数据中提取图表数据
+    extractChartDataFromAPI(lineData) {
+      // 根据实际API数据结构解析数据
+      
+      // 提取流量压差数据
+      const flowData = []
+      const pressureDropData = []
+      
+      // 提取流阻系数数据
+      const zetaData = []
+      
+      // 提取气蚀系数数据
+      const cavitationData = []
+      
+      // 提取KV数据
+      const kvData = []
+      
+      // 解析dc气蚀系数曲线数据
+      if (lineData.dc && Array.isArray(lineData.dc)) {
+        lineData.dc.forEach(item => {
+          const opening = parseFloat(item.li) // 直接使用li原数据
+          const value = parseFloat(item.value)
+          if (!isNaN(opening) && !isNaN(value)) {
+            cavitationData.push([opening, value])
+          }
+        })
+      }
+      
+      // 解析flow流量压差开度曲线数据(嵌套对象结构)
+       if (lineData.flow && typeof lineData.flow === 'object') {
+         // 遍历不同压差条件(如"10", "20"等)
+         Object.keys(lineData.flow).forEach(pressureKey => {
+           const pressureData = lineData.flow[pressureKey]
+           if (Array.isArray(pressureData)) {
+             pressureData.forEach(item => {
+               const opening = parseFloat(item.li) // 直接使用li原数据
+               const value = parseFloat(item.value)
+               if (!isNaN(opening) && !isNaN(value)) {
+                 flowData.push([opening, value, pressureKey]) // 添加压差条件标识
+               }
+             })
+           }
+         })
+       }
+       
+       // 解析其他类型的曲线数据(如果存在)
+       if (lineData.pressureDrop && Array.isArray(lineData.pressureDrop)) {
+         lineData.pressureDrop.forEach(item => {
+           const opening = parseFloat(item.li) // 直接使用li原数据
+           const value = parseFloat(item.value)
+           if (!isNaN(opening) && !isNaN(value)) {
+             pressureDropData.push([opening, value])
+           }
+         })
+       }
+      
+      if (lineData.zeta && Array.isArray(lineData.zeta)) {
+         lineData.zeta.forEach(item => {
+           const opening = parseFloat(item.li) // 直接使用li原数据
+           const value = parseFloat(item.value)
+           if (!isNaN(opening) && !isNaN(value)) {
+             zetaData.push([opening, value])
+           }
+         })
+       }
+       
+       // 解析kv曲线数据
+       if (lineData.kv && Array.isArray(lineData.kv)) {
+         lineData.kv.forEach(item => {
+           const opening = parseFloat(item.li) // 直接使用li原数据
+           const value = parseFloat(item.value)
+           if (!isNaN(opening) && !isNaN(value)) {
+             kvData.push([opening, value])
+           }
+         })
+       }
+      
+      return {
+        flowData: {
+          flowData,
+          pressureDropData
+        },
+        zetaData: {
+          zetaData
+        },
+        cavitationData: {
+          cavitationData
+        },
+        kvData: {
+          kvData
+        }
+      }
+    },
+  },
+  created() {
+    this.queryMainData(this.$route.query.id);
+    this.tablecols = this.tool.tabelCol(
+      this.$route.name
+    ).productTable.tablecols;
+  },
+  mounted() {},
+  
+  beforeDestroy() {
+    // 销毁图表实例,避免内存泄漏
+    if (this.flowChartInstance) {
+      this.flowChartInstance.destroy()
+      this.flowChartInstance = null
+    }
+    if (this.kvChartInstance) {
+      this.kvChartInstance.destroy()
+      this.kvChartInstance = null
+    }
+    if (this.zetaChartInstance) {
+      this.zetaChartInstance.destroy()
+      this.zetaChartInstance = null
+    }
+    if (this.cavitationChartInstance) {
+      this.cavitationChartInstance.destroy()
+      this.cavitationChartInstance = null
+    }
+  }
+};
+</script>
+
+  <style scoped>
+</style>

+ 13 - 3
src/optionSystem/optionOrder/index.vue

@@ -5,9 +5,7 @@
     idName="sa_lectotypecfgid"
     ownertable="sa_lectotypecfg"
     :apiId="{ query: 2024071815534702, del: 2024071814493602 }"
-    :detailPath="{
-      path: '/optionOrderDetail',
-    }"
+    :detailPath="getDetailPath"
     :isExport="false"
   >
     <template #titleRight> </template>
@@ -93,6 +91,18 @@ export default {
     };
   },
   methods: {
+    getDetailPath(data) {
+      // 根据valvetype字段判断跳转路径
+      if (data && data.valvetype === '计算选型') {
+        return {
+          path: '/calcOptionOrderDetail'
+        };
+      }
+      // 默认跳转到普通详情页
+      return {
+        path: '/optionOrderDetail'
+      };
+    },
     selectStatusChange() {
       this.$refs["basicLayout"].param.content.where = this.selectParam;
       this.$refs["basicLayout"].param.content.pageNumber = 1;

+ 7 - 3
src/optionSystem/throttleManage/detail/index.vue

@@ -50,9 +50,13 @@
         <DetailInfo :more="true" :data="detailInfo"></DetailInfo>
       </div>
       <div slot="slot1">
-        <Attrite
-          :plm_item_throttleparamid="mainData.plm_item_throttleparamid"
-        ></Attrite>
+        <el-row>
+          <el-col :span="18">
+            <Attrite
+              :plm_item_throttleparamid="mainData.plm_item_throttleparamid"
+            ></Attrite>
+          </el-col>
+        </el-row>
       </div>
     </basicDetails>
   </div>

+ 6 - 4
src/optionSystem/throttleManage/detail/modules/attrite/index.vue

@@ -9,7 +9,7 @@
     <div class="line-box">
       <div class="item" v-show="source.dc.length">
         <div class="title">
-          {{ $t("Dc值") }}
+          {{ $t("σc值") }}
           <div v-if="tool.checkAuth($route.name, 'excel')" style="cursor: pointer; margin-left: 20px; margin-top: -3px">
             <el-button type="text" size="small" @click="excel('dc')">{{
               $t("导出")
@@ -144,7 +144,7 @@ export default {
           legend: {
             visible: false,
           },
-          smooth: false, // 关闭平滑曲线,显示折线
+          smooth: true, // 开启平滑曲线,显示曲线图
         });
 
         that.items[el].render();
@@ -185,15 +185,17 @@ export default {
 
 <style scoped>
 .attrite .item {
-  margin-top: 20px;
   position: relative;
+  border: 1px solid #dcdfe6;
+  padding: 20px;
+  margin: 10px 0;
+  border-radius:5px
 }
 
 .attrite .title {
   font-size: 16px;
   font-weight: bolder;
   color: #000000;
-  position: absolute;
   top: 0px;
   display: flex;
   z-index: 2;

+ 2 - 2
src/optionSystem/throttleManage/index.vue

@@ -24,7 +24,7 @@
       ></ImportFile>
     </template>
     <template #custom>
-      <div class="mt-10">
+      <!-- <div class="mt-10">
         <label class="search__label">{{ $t("创建时间") }}:</label>
         <el-date-picker
           style="margin-right: 24px !important"
@@ -39,7 +39,7 @@
           clearable
         >
         </el-date-picker>
-      </div>
+      </div> -->
       <div class="mt-10">
         <label class="search__label">{{ $t("阀门类型") }}:</label>
         <el-select

+ 11 - 1
src/optionSystem/throttleManage/modules/add.vue

@@ -83,6 +83,11 @@
                 </el-select>
               </el-form-item>
             </el-col>
+            <el-col :span="24">
+              <el-form-item :label="$t(`Kv100`)" :label-width="tool.onlyZh('100px')" prop="kv100">
+                <el-input  v-model="form.kv100" type="number" autocomplete="off" :placeholder="$t(`请输入Kv100`)"></el-input>
+              </el-form-item>
+            </el-col>
             <el-col :span="24">
               <el-form-item :label="$t(`R`)" :label-width="tool.onlyZh('100px')" prop="r">
                 <el-input  v-model="form.r" autocomplete="off" :placeholder="$t('请输入')"></el-input>
@@ -93,6 +98,7 @@
                 <el-input  v-model="form.marketprice" autocomplete="off" :placeholder="$t(`请输入牌价`)"></el-input>
               </el-form-item>
             </el-col>
+            
           </el-form>
         </el-row>
       </div>
@@ -129,6 +135,9 @@ export default {
         throttletype: [
           { required: true, message: this.$t('请选择节流件类型'), trigger: 'change' },
         ],
+        kv100: [
+          { required: true, message: this.$t('请输入Kv100'), trigger: 'blur' }
+        ],
       },
       form:{
         "itemid": 0,
@@ -142,7 +151,8 @@ export default {
         "material": "",
         "kvmode": "", //线性/等百
         "throttletype": "", //必选,自定义选项)
-        "r": ''
+        "r": '',
+        "kv100": ''
       },
       options:[],
     }

+ 11 - 1
src/optionSystem/throttleManage/modules/edit.vue

@@ -83,6 +83,11 @@
                 </el-select>
               </el-form-item>
             </el-col>
+            <el-col :span="24">
+              <el-form-item :label="$t(`Kv100`)" :label-width="tool.onlyZh('100px')" prop="kv100">
+                <el-input  v-model="form.kv100" type="number" autocomplete="off" :placeholder="$t(`请输入Kv100`)"></el-input>
+              </el-form-item>
+            </el-col>
             <el-col :span="24">
               <el-form-item :label="$t(`R`)" :label-width="tool.onlyZh('100px')" prop="r">
                 <el-input  v-model="form.r" autocomplete="off" :placeholder="$t(`请输入`)"></el-input>
@@ -93,6 +98,7 @@
                 <el-input  v-model="form.marketprice" autocomplete="off" :placeholder="$t(`请输入牌价`)"></el-input>
               </el-form-item>
             </el-col>
+            
           </el-form>
         </el-row>
       </div>
@@ -130,6 +136,9 @@ export default {
         throttletype: [
           { required: true, message: this.$t('请选择节流件类型'), trigger: 'change' },
         ],
+        kv100: [
+          { required: true, message: this.$t('请输入Kv100'), trigger: 'blur' }
+        ],
       },
       form:{
         "itemid": 0,
@@ -143,7 +152,8 @@ export default {
         "material": "",
         "kvmode": "", //线性/等百
         "throttletype": "", //必选,自定义选项)
-        "r": ''
+        "r": '',
+        "kv100": ''
       },
       options:[],
     }

+ 29 - 0
src/router/optionSystem.js

@@ -148,6 +148,26 @@ const OptionSystem = [
           component: () => import(/* webpackChunkName: "about" */ '@/optionSystem/optionOrder/detail/index.vue')
         },]
     },
+    {
+      path: '/optionOrder',
+      name: 'optionorder',
+      meta: {
+        title: '选型单列表',
+        ast_nav: true
+      },
+      component: () => import(/* webpackChunkName: "about" */ '@/optionSystem/optionOrder/index.vue'),
+      children: [
+        {
+          path: '/calcOptionOrderDetail',
+          name: 'optionorder',
+          meta: {
+            title: '选型单详情',
+            ast_nav: true,
+            keeproute: true
+          },
+          component: () => import(/* webpackChunkName: "about" */ '@/optionSystem/optionOrder/detail/indexCalc.vue')
+        },]
+    },
     {
       path: '/diefaOption',
       name: 'diefaOption',
@@ -166,6 +186,15 @@ const OptionSystem = [
       },
       component: () => import(/* webpackChunkName: "about" */ '@/optionSystem/priceRuleManage/index.vue'),
     },
+    {
+      path: '/calculationAndSelection',
+      name: 'calculationAndSelection',
+      meta: {
+        title: '计算选型',
+        ast_nav: true
+      },
+      component: () => import(/* webpackChunkName: "about" */ '@/optionSystem/calculationAndSelection/index.vue'),
+    }
 ]
 
 export default OptionSystem