Pārlūkot izejas kodu

完成供应链模块开发:新增overall页面,更新cost、delivery、payment、weights页面

wangyuhao 4 mēneši atpakaļ
vecāks
revīzija
cb9ddb02ba

+ 12 - 5
src/views/supply/cost/index.vue

@@ -107,16 +107,23 @@ export default {
       try {
         // 使用项目标准的request方式调用API
         const response = await request({
-          url: `/system/supplier/cost/${code}`,
+          url: `http://localhost:5000/api/product/${code}/details`,
           method: "get",
         });
 
-        if (response.code === 200) {
-          this.costDetails = response.data.cost_details || [];
+        // Flask API通常直接返回数据,没有code字段
+        if (response && response.cost_details !== undefined) {
+          this.costDetails = response.cost_details || [];
           this.$modal.msgSuccess("成本分析完成");
         } else {
-          this.error = response.msg || "获取成本数据失败";
-          this.$modal.msgError(this.error);
+          // 尝试其他可能的数据结构
+          if (response && Array.isArray(response)) {
+            this.costDetails = response || [];
+            this.$modal.msgSuccess("成本分析完成");
+          } else {
+            this.error = "获取成本数据失败,API响应格式不匹配";
+            this.$modal.msgError(this.error);
+          }
         }
       } catch (err) {
         console.error("获取成本数据失败:", err);

+ 12 - 5
src/views/supply/delivery/index.vue

@@ -119,16 +119,23 @@ export default {
       try {
         // 使用项目标准的request方式调用API
         const response = await request({
-          url: `/system/supplier/delivery/${code}`,
+          url: `http://localhost:5000/api/product/${code}/details`,
           method: "get",
         });
 
-        if (response.code === 200) {
-          this.deliveryDetails = response.data.delivery_details || [];
+        // Flask API通常直接返回数据,没有code字段
+        if (response && response.delivery_details !== undefined) {
+          this.deliveryDetails = response.delivery_details || [];
           this.$modal.msgSuccess("交付分析完成");
         } else {
-          this.error = response.msg || "获取交付数据失败";
-          this.$modal.msgError(this.error);
+          // 尝试其他可能的数据结构
+          if (response && Array.isArray(response)) {
+            this.deliveryDetails = response || [];
+            this.$modal.msgSuccess("交付分析完成");
+          } else {
+            this.error = "获取交付数据失败,API响应格式不匹配";
+            this.$modal.msgError(this.error);
+          }
         }
       } catch (err) {
         console.error("获取交付数据失败:", err);

+ 804 - 0
src/views/supply/overall/index.vue

@@ -0,0 +1,804 @@
+<template>
+  <div class="home">
+    <div class="page-header">
+      <div class="page-title">供应商能力综合评分面板</div>
+      <div class="page-subtitle">
+        实时监控供应商表现,智能分析综合能力,辅助决策优化供应链
+      </div>
+    </div>
+
+    <!-- Stats Grid -->
+    <div class="stats-grid">
+      <div class="stat-card">
+        <div class="stat-header">
+          <div class="stat-label">供应商总数</div>
+          <div class="stat-badge badge-time">实时</div>
+        </div>
+        <div class="stat-value">156</div>
+        <div class="stat-trend trend-up">
+          <span>↑ 6.2%</span>
+          <span style="color: #999">较上月</span>
+        </div>
+      </div>
+
+      <div class="stat-card">
+        <div class="stat-header">
+          <div class="stat-label">平均综合得分</div>
+          <div class="stat-badge badge-time">实时</div>
+        </div>
+        <div class="stat-value">82.5</div>
+        <div class="stat-trend trend-up">
+          <span>↑ 3.8%</span>
+          <span style="color: #999">较上月</span>
+        </div>
+      </div>
+
+      <div class="stat-card">
+        <div class="stat-header">
+          <div class="stat-label">预警供应商</div>
+          <div class="stat-badge badge-warning">预警</div>
+        </div>
+        <div class="stat-value">8</div>
+        <div class="stat-trend trend-down">
+          <span>↓ 2</span>
+          <span style="color: #999">低于60分</span>
+        </div>
+      </div>
+
+      <div class="stat-card">
+        <div class="stat-header">
+          <div class="stat-label">优秀供应商</div>
+          <div class="stat-badge badge-time">实时</div>
+        </div>
+        <div class="stat-value">45</div>
+        <div class="stat-trend trend-up">
+          <span>↑ 5</span>
+          <span style="color: #999">≥85分</span>
+        </div>
+      </div>
+    </div>
+
+    <!-- Search and Chart Section -->
+    <div class="content-card">
+      <div class="card-title">🔍 单个产品查询供应商评分</div>
+      <div class="search-box">
+        <div class="input-wrapper">
+          <input
+            v-model="inputProductCode"
+            type="text"
+            class="search-input"
+            placeholder="输入产品编码(如:20220606J0100MR4)"
+          />
+        </div>
+        <button @click="triggerEvaluation" class="search-btn">预测分析</button>
+      </div>
+
+      <div class="chart-container">
+        <div style="font-size: 14px; color: #666; margin-bottom: 15px">
+          产品供应商三维度评分趋势对比
+        </div>
+        <div class="chart-placeholder">
+          <svg
+            class="chart-lines"
+            viewBox="0 0 800 300"
+            preserveAspectRatio="none"
+          >
+            <polyline
+              points="50,250 150,180 250,120 350,80 450,90 550,110 650,140 750,200"
+              fill="none"
+              stroke="rgba(255,255,255,0.6)"
+              stroke-width="3"
+            />
+            <polyline
+              points="50,270 150,220 250,160 350,100 450,95 550,120 650,160 750,220"
+              fill="none"
+              stroke="rgba(255,255,255,0.4)"
+              stroke-width="2"
+              stroke-dasharray="5,5"
+            />
+            <polyline
+              points="50,280 150,240 250,200 350,140 450,130 550,150 650,180 750,240"
+              fill="none"
+              stroke="rgba(255,255,255,0.4)"
+              stroke-width="2"
+              stroke-dasharray="5,5"
+            />
+          </svg>
+          <div style="position: relative; z-index: 1">
+            <div style="font-size: 14px; opacity: 0.8; margin-bottom: 5px">
+              选择产品查看供应商评分趋势
+            </div>
+            <div style="font-size: 12px; opacity: 0.6">
+              蓝线:成本得分 | 红线:交付得分 | 绿线:账期得分
+            </div>
+          </div>
+        </div>
+      </div>
+
+      <div class="info-grid">
+        <div class="info-box">
+          <div class="info-label">评估结果</div>
+          <div class="info-value" style="color: #52c41a">已加载</div>
+          <div class="info-detail">
+            供应商数量: 5家<br />
+            评估完成时间: 2025-10-29 14:30<br />
+            <span style="color: #1890ff">最佳供应商: 华信电子</span>
+          </div>
+        </div>
+
+        <div class="info-box">
+          <div class="info-label">数据周期</div>
+          <div class="info-value">180天</div>
+          <div class="info-detail">
+            评估订单总数: 238笔<br />
+            时间范围: 2025-05-01 至 2025-10-28
+          </div>
+        </div>
+
+        <div class="info-box">
+          <div class="info-label">维度评分范围</div>
+          <div class="info-value">80-95分</div>
+          <div class="info-detail">
+            成本: 80-95分<br />
+            交付: 85-94分<br />
+            账期: 80-90分
+          </div>
+        </div>
+
+        <div class="info-box">
+          <div class="info-label">综合评级分布</div>
+          <div class="info-value">优秀: 5家</div>
+          <div class="info-detail">
+            A级(&ge;85分): 3家<br />
+            B级(70-85分): 2家<br />
+            C级(&lt;70分): 0家
+          </div>
+        </div>
+      </div>
+    </div>
+
+    <!-- Weights Configuration Summary -->
+    <div class="content-card">
+      <div class="card-title">📊 评估维度权重配置</div>
+      <div style="margin-bottom: 20px; color: #666; font-size: 14px">
+        当前配置:成本 40% | 交付 40% | 账期 20%
+      </div>
+      <div
+        style="display: grid; grid-template-columns: repeat(3, 1fr); gap: 20px"
+      >
+        <div class="info-box">
+          <div class="info-label">💰 成本维度</div>
+          <div class="info-value" style="color: #5b6cff">40%</div>
+          <div class="info-detail">
+            评分规则:价格排名<br />
+            第1名: 100分<br />
+            第2名: 90分<br />
+            第3名: 80分
+          </div>
+        </div>
+        <div class="info-box">
+          <div class="info-label">🚚 交付维度</div>
+          <div class="info-value" style="color: #52c41a">40%</div>
+          <div class="info-detail">
+            D1-准时率: 50%<br />
+            D2-平均偏差: 30%<br />
+            D3-最长延迟: 10%<br />
+            D4-数量满足率: 10%
+          </div>
+        </div>
+        <div class="info-box">
+          <div class="info-label">💳 账期维度</div>
+          <div class="info-value" style="color: #ff9800">20%</div>
+          <div class="info-detail">
+            ≥90天: 100分<br />
+            ≥60天: 90分<br />
+            ≥45天: 80分<br />
+            ≥30天: 60分
+          </div>
+        </div>
+      </div>
+    </div>
+
+    <!-- Data Statistics -->
+    <div class="content-card">
+      <div class="card-title">📋 评估数据统计</div>
+      <table class="supplier-table">
+        <thead>
+          <tr>
+            <th>维度</th>
+            <th>数据来源</th>
+            <th>评估指标</th>
+            <th>数据记录数</th>
+            <th>数据完整度</th>
+            <th>状态</th>
+          </tr>
+        </thead>
+        <tbody>
+          <tr>
+            <td><strong>💰 成本维度</strong></td>
+            <td>采购订单统计.xlsx</td>
+            <td>供应商报价排名</td>
+            <td>2,845条</td>
+            <td>
+              <div class="progress-bar">
+                <div class="progress-fill" style="width: 98.5%"></div>
+              </div>
+              <span style="font-size: 12px; color: #666">98.5%</span>
+            </td>
+            <td><span style="color: #52c41a">● 正常</span></td>
+          </tr>
+          <tr>
+            <td><strong>🚚 交付维度</strong></td>
+            <td>采购数据_双键合并结果.xlsx</td>
+            <td>准时率、偏差、延迟、满足率</td>
+            <td>5,126条</td>
+            <td>
+              <div class="progress-bar">
+                <div class="progress-fill" style="width: 99.2%"></div>
+              </div>
+              <span style="font-size: 12px; color: #666">99.2%</span>
+            </td>
+            <td><span style="color: #52c41a">● 正常</span></td>
+          </tr>
+          <tr>
+            <td><strong>💳 账期维度</strong></td>
+            <td>供应商账期.xlsx</td>
+            <td>结算期限天数</td>
+            <td>156条</td>
+            <td>
+              <div class="progress-bar">
+                <div class="progress-fill" style="width: 100%"></div>
+              </div>
+              <span style="font-size: 12px; color: #666">100%</span>
+            </td>
+            <td><span style="color: #52c41a">● 正常</span></td>
+          </tr>
+        </tbody>
+      </table>
+    </div>
+
+    <!-- Top 5 Suppliers -->
+    <div class="content-card">
+      <div class="card-title">
+        🏆 Top 5 供应商综合排名
+        <span
+          style="
+            font-size: 12px;
+            color: #999;
+            font-weight: normal;
+            margin-left: 10px;
+          "
+        >
+          基于产品代码: {{ displayedProductCode || "20220606J0100MR4" }}
+        </span>
+      </div>
+
+      <div v-if="loading" class="loading">加载中...</div>
+      <div v-else-if="error" class="error">{{ error }}</div>
+      <div v-else>
+        <table class="supplier-table">
+          <thead>
+            <tr>
+              <th>综合排名</th>
+              <th>供应商名称</th>
+              <th>供应商代码</th>
+              <th>综合得分</th>
+              <th>维度得分</th>
+              <th>参考价</th>
+              <th>成本排名</th>
+            </tr>
+          </thead>
+          <tbody>
+            <tr
+              v-for="(supplier, index) in evaluationData"
+              :key="supplier.供应商代码"
+            >
+              <td>
+                <span :class="['rank-badge', getRankClass(index + 1)]">{{
+                  index + 1
+                }}</span>
+              </td>
+              <td>
+                <strong>{{ supplier.供应商名称 }}</strong>
+              </td>
+              <td>{{ supplier.供应商代码 || "N/A" }}</td>
+              <td>
+                <strong style="font-size: 18px; color: #52c41a">{{
+                  parseFloat(supplier.综合得分).toFixed(2)
+                }}</strong>
+                <div class="progress-bar">
+                  <div
+                    class="progress-fill"
+                    :style="{ width: `${supplier.综合得分}%` }"
+                  ></div>
+                </div>
+              </td>
+              <td>
+                <div class="dimension-scores">
+                  <span class="dim-score"
+                    >成本:{{ parseFloat(supplier.成本分数).toFixed(0) }}</span
+                  >
+                  <span class="dim-score"
+                    >交付:{{ parseFloat(supplier.交付分数).toFixed(0) }}</span
+                  >
+                  <span class="dim-score"
+                    >账期:{{ parseFloat(supplier.账期分数).toFixed(0) }}</span
+                  >
+                </div>
+              </td>
+              <td>¥{{ parseFloat(supplier.参考价).toFixed(2) }}</td>
+              <td>第{{ supplier.成本排名 }}名</td>
+            </tr>
+          </tbody>
+        </table>
+      </div>
+    </div>
+  </div>
+</template>
+
+<script>
+import { getToken } from "@/utils/auth";
+import request from "@/utils/request";
+
+export default {
+  name: "SupplyOverallEvaluation",
+  data() {
+    return {
+      inputProductCode: "",
+      displayedProductCode: "",
+      evaluationData: [],
+      loading: false,
+      error: "",
+    };
+  },
+  created() {
+    // 如果有传入的 productCode,则自动触发评估
+    if (this.$route.query.productCode) {
+      this.inputProductCode = this.$route.query.productCode;
+      this.fetchEvaluationData(this.inputProductCode);
+    }
+  },
+  methods: {
+    // 监听路由传入的 productCode
+    triggerEvaluation() {
+      if (this.inputProductCode) {
+        this.fetchEvaluationData(this.inputProductCode);
+      }
+    },
+
+    async fetchEvaluationData(code) {
+      this.loading = true;
+      this.error = "";
+      this.displayedProductCode = code;
+      try {
+        const response = await request({
+          url: "http://localhost:5000/api/evaluate",
+          method: "post",
+          data: {
+            product_code: code,
+          },
+        });
+        // Flask API可能直接返回数据,而不是包装在特定字段中
+        if (Array.isArray(response)) {
+          this.evaluationData = response;
+        } else if (response && response.data) {
+          this.evaluationData = response.data;
+        } else {
+          this.evaluationData = response || [];
+        }
+        this.$modal.msgSuccess("评估完成");
+      } catch (err) {
+        console.error("获取评估数据失败:", err);
+        this.error = err.message || "获取评估数据失败";
+        this.$modal.msgError(this.error);
+      } finally {
+        this.loading = false;
+      }
+    },
+
+    // 获取排名样式类
+    getRankClass(rank) {
+      if (rank === 1) return "rank-1";
+      if (rank === 2) return "rank-2";
+      if (rank === 3) return "rank-3";
+      return "rank-other";
+    },
+  },
+};
+</script>
+
+<style scoped>
+.page-header {
+  margin-bottom: 40px;
+  padding-bottom: 20px;
+  border-bottom: 2px solid rgba(102, 126, 234, 0.1);
+}
+
+.page-title {
+  font-size: 32px;
+  font-weight: 700;
+  margin-bottom: 12px;
+  background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
+  -webkit-background-clip: text;
+  -webkit-text-fill-color: transparent;
+  background-clip: text;
+}
+
+.page-subtitle {
+  color: #666;
+  font-size: 15px;
+  font-weight: 400;
+}
+
+.stats-grid {
+  display: grid;
+  grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
+  gap: 24px;
+  margin-bottom: 40px;
+}
+
+.stat-card {
+  background: white;
+  padding: 28px;
+  border-radius: 16px;
+  box-shadow: 0 4px 20px rgba(0, 0, 0, 0.08);
+  transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
+  border: 1px solid rgba(102, 126, 234, 0.1);
+  position: relative;
+  overflow: hidden;
+}
+
+.stat-card::before {
+  content: "";
+  position: absolute;
+  top: 0;
+  left: 0;
+  right: 0;
+  height: 4px;
+  background: linear-gradient(90deg, #667eea 0%, #764ba2 100%);
+}
+
+.stat-card:hover {
+  transform: translateY(-4px);
+  box-shadow: 0 8px 30px rgba(102, 126, 234, 0.15);
+}
+
+.stat-header {
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+  margin-bottom: 20px;
+}
+
+.stat-label {
+  color: #666;
+  font-size: 14px;
+  font-weight: 500;
+}
+
+.stat-badge {
+  padding: 4px 10px;
+  border-radius: 12px;
+  font-size: 11px;
+  font-weight: 600;
+  text-transform: uppercase;
+  letter-spacing: 0.5px;
+}
+
+.badge-time {
+  background: linear-gradient(135deg, #e6f0ff 0%, #d6e5ff 100%);
+  color: #667eea;
+}
+
+.badge-warning {
+  background: linear-gradient(135deg, #fff7e6 0%, #ffe6cc 100%);
+  color: #ff9800;
+}
+
+.stat-value {
+  font-size: 36px;
+  font-weight: 700;
+  margin-bottom: 12px;
+  color: #2c3e50;
+  line-height: 1.2;
+}
+
+.stat-trend {
+  font-size: 13px;
+  display: flex;
+  align-items: center;
+  gap: 6px;
+  font-weight: 500;
+}
+
+.trend-up {
+  color: #52c41a;
+}
+
+.trend-down {
+  color: #ff4d4f;
+}
+
+.content-card {
+  background: white;
+  padding: 32px;
+  border-radius: 16px;
+  box-shadow: 0 4px 20px rgba(0, 0, 0, 0.08);
+  margin-bottom: 24px;
+  border: 1px solid rgba(102, 126, 234, 0.1);
+  transition: all 0.3s;
+}
+
+.content-card:hover {
+  box-shadow: 0 8px 30px rgba(0, 0, 0, 0.12);
+}
+
+.card-title {
+  font-size: 18px;
+  font-weight: 700;
+  margin-bottom: 24px;
+  display: flex;
+  align-items: center;
+  gap: 10px;
+  color: #2c3e50;
+}
+
+.search-box {
+  display: flex;
+  gap: 16px;
+  margin-bottom: 32px;
+}
+
+.input-wrapper {
+  flex: 1;
+  position: relative;
+}
+
+.search-input {
+  width: 100%;
+  padding: 16px 20px;
+  border: 2px solid #e8ecf1;
+  border-radius: 12px;
+  font-size: 15px;
+  outline: none;
+  transition: all 0.3s;
+  background: #fafbfc;
+  font-weight: 500;
+}
+
+.search-input:focus {
+  border-color: #667eea;
+  background: white;
+  box-shadow: 0 0 0 4px rgba(102, 126, 234, 0.1);
+}
+
+.search-btn {
+  padding: 16px 40px;
+  background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
+  color: white;
+  border: none;
+  border-radius: 12px;
+  font-size: 15px;
+  font-weight: 600;
+  cursor: pointer;
+  transition: all 0.3s;
+  box-shadow: 0 4px 15px rgba(102, 126, 234, 0.4);
+  white-space: nowrap;
+}
+
+.search-btn:hover {
+  transform: translateY(-2px);
+  box-shadow: 0 6px 20px rgba(102, 126, 234, 0.5);
+}
+
+.search-btn:active {
+  transform: translateY(0);
+}
+
+.chart-container {
+  margin-bottom: 32px;
+}
+
+.chart-placeholder {
+  width: 100%;
+  height: 320px;
+  background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
+  border-radius: 16px;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  color: white;
+  font-size: 16px;
+  position: relative;
+  overflow: hidden;
+  box-shadow: 0 8px 30px rgba(102, 126, 234, 0.3);
+}
+
+.chart-lines {
+  position: absolute;
+  width: 100%;
+  height: 100%;
+  opacity: 0.2;
+}
+
+.info-grid {
+  display: grid;
+  grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
+  gap: 20px;
+}
+
+.info-box {
+  background: linear-gradient(135deg, #f8f9fa 0%, #f0f2f5 100%);
+  padding: 24px;
+  border-radius: 12px;
+  border: 1px solid #e8ecf1;
+  transition: all 0.3s;
+}
+
+.info-box:hover {
+  transform: translateY(-2px);
+  box-shadow: 0 4px 15px rgba(0, 0, 0, 0.08);
+}
+
+.info-label {
+  font-size: 12px;
+  color: #999;
+  margin-bottom: 10px;
+  font-weight: 600;
+  text-transform: uppercase;
+  letter-spacing: 0.5px;
+}
+
+.info-value {
+  font-size: 28px;
+  font-weight: 700;
+  margin-bottom: 12px;
+  color: #2c3e50;
+}
+
+.info-detail {
+  font-size: 13px;
+  color: #666;
+  line-height: 1.8;
+}
+
+.supplier-table {
+  width: 100%;
+  border-collapse: separate;
+  border-spacing: 0;
+  margin-top: 24px;
+  border-radius: 12px;
+  overflow: hidden;
+  box-shadow: 0 2px 10px rgba(0, 0, 0, 0.05);
+}
+
+.supplier-table th {
+  background: linear-gradient(135deg, #f8f9fa 0%, #f0f2f5 100%);
+  padding: 16px;
+  text-align: left;
+  font-size: 13px;
+  color: #666;
+  font-weight: 700;
+  text-transform: uppercase;
+  letter-spacing: 0.5px;
+  border-bottom: 2px solid #e8ecf1;
+}
+
+.supplier-table td {
+  padding: 18px 16px;
+  border-bottom: 1px solid #f0f0f0;
+  font-size: 14px;
+  background: white;
+}
+
+.supplier-table tr:last-child td {
+  border-bottom: none;
+}
+
+.supplier-table tr:hover td {
+  background: #f8f9ff;
+}
+
+.rank-badge {
+  display: inline-flex;
+  align-items: center;
+  justify-content: center;
+  width: 32px;
+  height: 32px;
+  border-radius: 50%;
+  font-weight: 700;
+  font-size: 14px;
+  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
+}
+
+.rank-1 {
+  background: linear-gradient(135deg, #ffd700 0%, #ffed4e 100%);
+  color: #8b6914;
+}
+.rank-2 {
+  background: linear-gradient(135deg, #c0c0c0 0%, #e8e8e8 100%);
+  color: #666;
+}
+.rank-3 {
+  background: linear-gradient(135deg, #cd7f32 0%, #e6a052 100%);
+  color: white;
+}
+.rank-other {
+  background: #f0f0f0;
+  color: #666;
+}
+
+.progress-bar {
+  width: 100%;
+  height: 8px;
+  background: #f0f0f0;
+  border-radius: 10px;
+  overflow: hidden;
+  margin-top: 8px;
+}
+
+.progress-fill {
+  height: 100%;
+  background: linear-gradient(90deg, #52c41a 0%, #95de64 100%);
+  border-radius: 10px;
+  transition: width 0.5s cubic-bezier(0.4, 0, 0.2, 1);
+  box-shadow: 0 2px 8px rgba(82, 196, 26, 0.3);
+}
+
+.dimension-scores {
+  display: flex;
+  gap: 8px;
+  font-size: 12px;
+  flex-wrap: wrap;
+}
+
+.dim-score {
+  padding: 6px 12px;
+  background: linear-gradient(135deg, #f0f2ff 0%, #e8ecff 100%);
+  border-radius: 8px;
+  font-weight: 600;
+  color: #667eea;
+  border: 1px solid rgba(102, 126, 234, 0.2);
+}
+
+.loading,
+.error {
+  font-size: 16px;
+  margin: 3rem 0;
+  text-align: center;
+  padding: 40px;
+  background: white;
+  border-radius: 12px;
+  box-shadow: 0 4px 20px rgba(0, 0, 0, 0.08);
+}
+
+.loading {
+  color: #667eea;
+}
+
+.error {
+  color: #ff4d4f;
+  background: #fff5f5;
+  border: 1px solid #ffccc7;
+}
+
+@media (max-width: 1200px) {
+  .stats-grid {
+    grid-template-columns: repeat(2, 1fr);
+  }
+}
+
+@media (max-width: 768px) {
+  .stats-grid {
+    grid-template-columns: 1fr;
+  }
+
+  .search-box {
+    flex-direction: column;
+  }
+
+  .search-btn {
+    width: 100%;
+  }
+}
+</style>

+ 12 - 5
src/views/supply/payment/index.vue

@@ -99,16 +99,23 @@ export default {
       try {
         // 使用项目标准的request方式调用API
         const response = await request({
-          url: `/system/supplier/payment/${code}`,
+          url: `http://localhost:5000/api/product/${code}/details`,
           method: "get",
         });
 
-        if (response.code === 200) {
-          this.paymentDetails = response.data.payment_details || [];
+        // Flask API通常直接返回数据,没有code字段
+        if (response && response.payment_details !== undefined) {
+          this.paymentDetails = response.payment_details || [];
           this.$modal.msgSuccess("账期分析完成");
         } else {
-          this.error = response.msg || "获取账期数据失败";
-          this.$modal.msgError(this.error);
+          // 尝试其他可能的数据结构
+          if (response && Array.isArray(response)) {
+            this.paymentDetails = response || [];
+            this.$modal.msgSuccess("账期分析完成");
+          } else {
+            this.error = "获取账期数据失败,API响应格式不匹配";
+            this.$modal.msgError(this.error);
+          }
         }
       } catch (err) {
         console.error("获取账期数据失败:", err);

+ 37 - 8
src/views/supply/weights/index.vue

@@ -209,14 +209,36 @@ export default {
       this.loading = true;
       try {
         const response = await request({
-          url: "/system/supplier/weights",
+          url: "http://localhost:5000/api/config/weights",
           method: "get",
         });
-        this.weights = response.data || {
-          成本: 0.4,
-          交付: 0.4,
-          账期: 0.2,
-        };
+        // Flask API可能直接返回权重对象,而不是封装在data字段中
+        if (
+          response &&
+          typeof response === "object" &&
+          !Array.isArray(response)
+        ) {
+          this.weights = {
+            成本:
+              response.成本 || response.成本权重 || response.cost_weight || 0.4,
+            交付:
+              response.交付 ||
+              response.交付权重 ||
+              response.delivery_weight ||
+              0.4,
+            账期:
+              response.账期 ||
+              response.账期权重 ||
+              response.payment_weight ||
+              0.2,
+          };
+        } else {
+          this.weights = {
+            成本: 0.4,
+            交付: 0.4,
+            账期: 0.2,
+          };
+        }
         this.$modal.msgSuccess("权重配置加载成功");
       } catch (err) {
         console.error("获取权重配置失败:", err);
@@ -239,11 +261,18 @@ export default {
 
       try {
         const response = await request({
-          url: "/system/supplier/weights",
+          url: "http://localhost:5000/api/config/weights",
           method: "put",
           data: this.weights,
         });
-        this.message = response.msg || "权重更新成功";
+        // Flask API可能直接返回成功消息,而不是封装在msg字段中
+        if (response && response.message) {
+          this.message = response.message;
+        } else if (response && response.msg) {
+          this.message = response.msg;
+        } else {
+          this.message = "权重更新成功";
+        }
         this.isError = false;
         this.$modal.msgSuccess(this.message);
       } catch (err) {