|
@@ -0,0 +1,370 @@
|
|
|
|
|
+<template>
|
|
|
|
|
+ <div class="app-container">
|
|
|
|
|
+ <div class="page-header">
|
|
|
|
|
+ <h2><i class="el-icon-setting"></i> 权重配置管理</h2>
|
|
|
|
|
+ <p class="page-desc">自定义成本、交付、账期三个维度的评估权重</p>
|
|
|
|
|
+ </div>
|
|
|
|
|
+
|
|
|
|
|
+ <el-card class="box-card">
|
|
|
|
|
+ <div slot="header" class="clearfix">
|
|
|
|
|
+ <span><i class="el-icon-edit-outline"></i> 权重配置</span>
|
|
|
|
|
+ </div>
|
|
|
|
|
+
|
|
|
|
|
+ <el-form
|
|
|
|
|
+ :model="weights"
|
|
|
|
|
+ :rules="rules"
|
|
|
|
|
+ ref="weightsForm"
|
|
|
|
|
+ label-width="120px"
|
|
|
|
|
+ >
|
|
|
|
|
+ <el-form-item label="成本权重" prop="成本">
|
|
|
|
|
+ <el-slider
|
|
|
|
|
+ v-model="weights.成本"
|
|
|
|
|
+ :step="0.01"
|
|
|
|
|
+ :min="0"
|
|
|
|
|
+ :max="1"
|
|
|
|
|
+ show-input
|
|
|
|
|
+ @change="onWeightChange"
|
|
|
|
|
+ />
|
|
|
|
|
+ </el-form-item>
|
|
|
|
|
+
|
|
|
|
|
+ <el-form-item label="交付权重" prop="交付">
|
|
|
|
|
+ <el-slider
|
|
|
|
|
+ v-model="weights.交付"
|
|
|
|
|
+ :step="0.01"
|
|
|
|
|
+ :min="0"
|
|
|
|
|
+ :max="1"
|
|
|
|
|
+ show-input
|
|
|
|
|
+ @change="onWeightChange"
|
|
|
|
|
+ />
|
|
|
|
|
+ </el-form-item>
|
|
|
|
|
+
|
|
|
|
|
+ <el-form-item label="账期权重" prop="账期">
|
|
|
|
|
+ <el-slider
|
|
|
|
|
+ v-model="weights.账期"
|
|
|
|
|
+ :step="0.01"
|
|
|
|
|
+ :min="0"
|
|
|
|
|
+ :max="1"
|
|
|
|
|
+ show-input
|
|
|
|
|
+ @change="onWeightChange"
|
|
|
|
|
+ />
|
|
|
|
|
+ </el-form-item>
|
|
|
|
|
+
|
|
|
|
|
+ <el-form-item>
|
|
|
|
|
+ <div class="weight-summary">
|
|
|
|
|
+ <p>权重总和: {{ totalWeight.toFixed(2) }}</p>
|
|
|
|
|
+ <p v-if="Math.abs(totalWeight - 1) > 0.001" class="warning">
|
|
|
|
|
+ 警告: 权重总和应为1
|
|
|
|
|
+ </p>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </el-form-item>
|
|
|
|
|
+
|
|
|
|
|
+ <el-form-item>
|
|
|
|
|
+ <el-button
|
|
|
|
|
+ type="primary"
|
|
|
|
|
+ :disabled="Math.abs(totalWeight - 1) > 0.001"
|
|
|
|
|
+ @click="updateWeights"
|
|
|
|
|
+ >
|
|
|
|
|
+ 保存权重
|
|
|
|
|
+ </el-button>
|
|
|
|
|
+ <el-button @click="resetWeights">重置</el-button>
|
|
|
|
|
+ </el-form-item>
|
|
|
|
|
+ </el-form>
|
|
|
|
|
+
|
|
|
|
|
+ <div
|
|
|
|
|
+ v-if="message"
|
|
|
|
|
+ class="el-alert"
|
|
|
|
|
+ :class="'el-alert--' + (isError ? 'error' : 'success')"
|
|
|
|
|
+ >
|
|
|
|
|
+ <div class="el-alert__content">
|
|
|
|
|
+ <span class="el-alert__description">{{ message }}</span>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </el-card>
|
|
|
|
|
+
|
|
|
|
|
+ <!-- 当前权重展示 -->
|
|
|
|
|
+ <el-card class="box-card">
|
|
|
|
|
+ <div slot="header" class="clearfix">
|
|
|
|
|
+ <span><i class="el-icon-data-line"></i> 当前评估维度权重配置</span>
|
|
|
|
|
+ </div>
|
|
|
|
|
+
|
|
|
|
|
+ <div class="weight-display">
|
|
|
|
|
+ <div class="weight-info">
|
|
|
|
|
+ 当前配置:成本 {{ (weights.成本 * 100).toFixed(0) }}% | 交付
|
|
|
|
|
+ {{ (weights.交付 * 100).toFixed(0) }}% | 账期
|
|
|
|
|
+ {{ (weights.账期 * 100).toFixed(0) }}%
|
|
|
|
|
+ </div>
|
|
|
|
|
+
|
|
|
|
|
+ <el-row :gutter="20">
|
|
|
|
|
+ <el-col :span="8">
|
|
|
|
|
+ <div class="info-box">
|
|
|
|
|
+ <div class="info-label">💰 成本维度</div>
|
|
|
|
|
+ <div class="info-value" style="color: #5b6cff">
|
|
|
|
|
+ {{ (weights.成本 * 100).toFixed(0) }}%
|
|
|
|
|
+ </div>
|
|
|
|
|
+ <div class="info-detail">
|
|
|
|
|
+ 评分规则:价格排名<br />
|
|
|
|
|
+ 第1名: 100分<br />
|
|
|
|
|
+ 第2名: 90分<br />
|
|
|
|
|
+ 第3名: 80分
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </el-col>
|
|
|
|
|
+
|
|
|
|
|
+ <el-col :span="8">
|
|
|
|
|
+ <div class="info-box">
|
|
|
|
|
+ <div class="info-label">🚚 交付维度</div>
|
|
|
|
|
+ <div class="info-value" style="color: #52c41a">
|
|
|
|
|
+ {{ (weights.交付 * 100).toFixed(0) }}%
|
|
|
|
|
+ </div>
|
|
|
|
|
+ <div class="info-detail">
|
|
|
|
|
+ D1-准时率: 50%<br />
|
|
|
|
|
+ D2-平均偏差: 30%<br />
|
|
|
|
|
+ D3-最长延迟: 10%<br />
|
|
|
|
|
+ D4-数量满足率: 10%
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </el-col>
|
|
|
|
|
+
|
|
|
|
|
+ <el-col :span="8">
|
|
|
|
|
+ <div class="info-box">
|
|
|
|
|
+ <div class="info-label">💳 账期维度</div>
|
|
|
|
|
+ <div class="info-value" style="color: #ff9800">
|
|
|
|
|
+ {{ (weights.账期 * 100).toFixed(0) }}%
|
|
|
|
|
+ </div>
|
|
|
|
|
+ <div class="info-detail">
|
|
|
|
|
+ ≥90天: 100分<br />
|
|
|
|
|
+ ≥60天: 90分<br />
|
|
|
|
|
+ ≥45天: 80分<br />
|
|
|
|
|
+ ≥30天: 60分
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </el-col>
|
|
|
|
|
+ </el-row>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </el-card>
|
|
|
|
|
+ </div>
|
|
|
|
|
+</template>
|
|
|
|
|
+
|
|
|
|
|
+<script>
|
|
|
|
|
+import request from "@/utils/request";
|
|
|
|
|
+
|
|
|
|
|
+export default {
|
|
|
|
|
+ name: "SupplyWeightsConfig",
|
|
|
|
|
+ data() {
|
|
|
|
|
+ return {
|
|
|
|
|
+ weights: {
|
|
|
|
|
+ 成本: 0.4,
|
|
|
|
|
+ 交付: 0.4,
|
|
|
|
|
+ 账期: 0.2,
|
|
|
|
|
+ },
|
|
|
|
|
+ loading: false,
|
|
|
|
|
+ message: "",
|
|
|
|
|
+ isError: false,
|
|
|
|
|
+ rules: {
|
|
|
|
|
+ 成本: [
|
|
|
|
|
+ { required: true, message: "请输入成本权重", trigger: "blur" },
|
|
|
|
|
+ {
|
|
|
|
|
+ type: "number",
|
|
|
|
|
+ min: 0,
|
|
|
|
|
+ max: 1,
|
|
|
|
|
+ message: "权重应在0到1之间",
|
|
|
|
|
+ trigger: "blur",
|
|
|
|
|
+ },
|
|
|
|
|
+ ],
|
|
|
|
|
+ 交付: [
|
|
|
|
|
+ { required: true, message: "请输入交付权重", trigger: "blur" },
|
|
|
|
|
+ {
|
|
|
|
|
+ type: "number",
|
|
|
|
|
+ min: 0,
|
|
|
|
|
+ max: 1,
|
|
|
|
|
+ message: "权重应在0到1之间",
|
|
|
|
|
+ trigger: "blur",
|
|
|
|
|
+ },
|
|
|
|
|
+ ],
|
|
|
|
|
+ 账期: [
|
|
|
|
|
+ { required: true, message: "请输入账期权重", trigger: "blur" },
|
|
|
|
|
+ {
|
|
|
|
|
+ type: "number",
|
|
|
|
|
+ min: 0,
|
|
|
|
|
+ max: 1,
|
|
|
|
|
+ message: "权重应在0到1之间",
|
|
|
|
|
+ trigger: "blur",
|
|
|
|
|
+ },
|
|
|
|
|
+ ],
|
|
|
|
|
+ },
|
|
|
|
|
+ };
|
|
|
|
|
+ },
|
|
|
|
|
+ computed: {
|
|
|
|
|
+ // 计算权重总和
|
|
|
|
|
+ totalWeight() {
|
|
|
|
|
+ return this.weights.成本 + this.weights.交付 + this.weights.账期;
|
|
|
|
|
+ },
|
|
|
|
|
+ },
|
|
|
|
|
+ created() {
|
|
|
|
|
+ this.fetchWeights();
|
|
|
|
|
+ },
|
|
|
|
|
+ methods: {
|
|
|
|
|
+ // 获取当前权重配置
|
|
|
|
|
+ async fetchWeights() {
|
|
|
|
|
+ this.loading = true;
|
|
|
|
|
+ try {
|
|
|
|
|
+ const response = await request({
|
|
|
|
|
+ url: "/system/supplier/weights",
|
|
|
|
|
+ method: "get",
|
|
|
|
|
+ });
|
|
|
|
|
+ this.weights = response.data || {
|
|
|
|
|
+ 成本: 0.4,
|
|
|
|
|
+ 交付: 0.4,
|
|
|
|
|
+ 账期: 0.2,
|
|
|
|
|
+ };
|
|
|
|
|
+ this.$modal.msgSuccess("权重配置加载成功");
|
|
|
|
|
+ } catch (err) {
|
|
|
|
|
+ console.error("获取权重配置失败:", err);
|
|
|
|
|
+ this.message = "获取权重配置失败";
|
|
|
|
|
+ this.isError = true;
|
|
|
|
|
+ this.$modal.msgError(this.message);
|
|
|
|
|
+ } finally {
|
|
|
|
|
+ this.loading = false;
|
|
|
|
|
+ }
|
|
|
|
|
+ },
|
|
|
|
|
+
|
|
|
|
|
+ // 更新权重配置
|
|
|
|
|
+ async updateWeights() {
|
|
|
|
|
+ if (Math.abs(this.totalWeight - 1) > 0.001) {
|
|
|
|
|
+ this.message = "权重总和必须为1";
|
|
|
|
|
+ this.isError = true;
|
|
|
|
|
+ this.$modal.msgError(this.message);
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ try {
|
|
|
|
|
+ const response = await request({
|
|
|
|
|
+ url: "/system/supplier/weights",
|
|
|
|
|
+ method: "put",
|
|
|
|
|
+ data: this.weights,
|
|
|
|
|
+ });
|
|
|
|
|
+ this.message = response.msg || "权重更新成功";
|
|
|
|
|
+ this.isError = false;
|
|
|
|
|
+ this.$modal.msgSuccess(this.message);
|
|
|
|
|
+ } catch (err) {
|
|
|
|
|
+ console.error("更新权重配置失败:", err);
|
|
|
|
|
+ this.message = err.message || "更新权重配置失败";
|
|
|
|
|
+ this.isError = true;
|
|
|
|
|
+ this.$modal.msgError(this.message);
|
|
|
|
|
+ }
|
|
|
|
|
+ },
|
|
|
|
|
+
|
|
|
|
|
+ // 重置权重
|
|
|
|
|
+ resetWeights() {
|
|
|
|
|
+ this.weights = {
|
|
|
|
|
+ 成本: 0.4,
|
|
|
|
|
+ 交付: 0.4,
|
|
|
|
|
+ 账期: 0.2,
|
|
|
|
|
+ };
|
|
|
|
|
+ this.$modal.msgInfo("权重已重置为默认值");
|
|
|
|
|
+ },
|
|
|
|
|
+
|
|
|
|
|
+ // 权重变更事件
|
|
|
|
|
+ onWeightChange() {
|
|
|
|
|
+ this.message = "";
|
|
|
|
|
+ this.isError = false;
|
|
|
|
|
+ },
|
|
|
|
|
+ },
|
|
|
|
|
+};
|
|
|
|
|
+</script>
|
|
|
|
|
+
|
|
|
|
|
+<style lang="scss" scoped>
|
|
|
|
|
+.app-container {
|
|
|
|
|
+ padding: 20px;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.page-header {
|
|
|
|
|
+ margin-bottom: 20px;
|
|
|
|
|
+
|
|
|
|
|
+ h2 {
|
|
|
|
|
+ font-size: 24px;
|
|
|
|
|
+ font-weight: 600;
|
|
|
|
|
+ color: #303133;
|
|
|
|
|
+ margin-bottom: 8px;
|
|
|
|
|
+
|
|
|
|
|
+ i {
|
|
|
|
|
+ margin-right: 8px;
|
|
|
|
|
+ color: #409eff;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ .page-desc {
|
|
|
|
|
+ color: #909399;
|
|
|
|
|
+ font-size: 14px;
|
|
|
|
|
+ margin: 0;
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.box-card {
|
|
|
|
|
+ margin-bottom: 20px;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.weight-summary {
|
|
|
|
|
+ margin: 20px 0;
|
|
|
|
|
+ padding: 15px;
|
|
|
|
|
+ background: #f8f9fa;
|
|
|
|
|
+ border-radius: 4px;
|
|
|
|
|
+ border-left: 4px solid #409eff;
|
|
|
|
|
+
|
|
|
|
|
+ p {
|
|
|
|
|
+ margin: 0 0 5px 0;
|
|
|
|
|
+ font-size: 14px;
|
|
|
|
|
+ color: #606266;
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.warning {
|
|
|
|
|
+ color: #e6a23c;
|
|
|
|
|
+ font-weight: 600;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.weight-display {
|
|
|
|
|
+ .weight-info {
|
|
|
|
|
+ margin-bottom: 20px;
|
|
|
|
|
+ color: #666;
|
|
|
|
|
+ font-size: 14px;
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.info-box {
|
|
|
|
|
+ background: #f8f9fa;
|
|
|
|
|
+ padding: 20px;
|
|
|
|
|
+ border-radius: 4px;
|
|
|
|
|
+ border: 1px solid #ebeef5;
|
|
|
|
|
+ transition: all 0.3s;
|
|
|
|
|
+
|
|
|
|
|
+ &:hover {
|
|
|
|
|
+ transform: translateY(-2px);
|
|
|
|
|
+ box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ .info-label {
|
|
|
|
|
+ font-size: 12px;
|
|
|
|
|
+ color: #909399;
|
|
|
|
|
+ margin-bottom: 10px;
|
|
|
|
|
+ font-weight: 600;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ .info-value {
|
|
|
|
|
+ font-size: 24px;
|
|
|
|
|
+ font-weight: 700;
|
|
|
|
|
+ margin-bottom: 12px;
|
|
|
|
|
+ color: #303133;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ .info-detail {
|
|
|
|
|
+ font-size: 13px;
|
|
|
|
|
+ color: #909399;
|
|
|
|
|
+ line-height: 1.8;
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+::v-deep .el-card__header {
|
|
|
|
|
+ font-weight: bold;
|
|
|
|
|
+}
|
|
|
|
|
+</style>
|