From 53e0b9466d3fdd3e5caf7c42e476fffdb468bc2a Mon Sep 17 00:00:00 2001
From: yyb <995253665@qq.com>
Date: 星期五, 27 三月 2026 17:17:22 +0800
Subject: [PATCH] 1

---
 src/views/salesManagement/salesLedger/components/ProcessFlowConfigSelectDialog.vue |  255 +++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 255 insertions(+), 0 deletions(-)

diff --git a/src/views/salesManagement/salesLedger/components/ProcessFlowConfigSelectDialog.vue b/src/views/salesManagement/salesLedger/components/ProcessFlowConfigSelectDialog.vue
new file mode 100644
index 0000000..f3c33b5
--- /dev/null
+++ b/src/views/salesManagement/salesLedger/components/ProcessFlowConfigSelectDialog.vue
@@ -0,0 +1,255 @@
+<template>
+  <el-dialog
+    v-model="visible"
+    title="閫夋嫨宸ヨ壓璺嚎閰嶇疆"
+    width="1000px"
+    :close-on-click-modal="false"
+    @close="handleClose"
+  >
+    <el-row :gutter="20">
+      <el-col :span="24">
+        <div style="font-weight: 600; margin-bottom: 8px;">閰嶇疆</div>
+        <div style="font-size: 12px; margin-bottom: 8px;">
+          <span v-if="boundRouteName" style="color: #67c23a;">宸茬粦瀹氾細{{ boundRouteName }}</span>
+          <span v-else style="color: #e6a23c;">鏈粦瀹�</span>
+        </div>
+        <el-select
+          v-model="selectedRouteId"
+          filterable
+          clearable
+          placeholder="璇烽�夋嫨宸ヨ壓璺嚎"
+          style="width: 100%;"
+          @change="handleRouteChange"
+        >
+          <el-option
+            v-for="cfg in routeList"
+            :key="cfg.routeId"
+            :label="cfg.processRouteName"
+            :value="cfg.routeId"
+          />
+        </el-select>
+
+        <el-divider style="margin: 16px 0;" />
+
+        <div style="font-weight: 600; margin-bottom: 8px;">姝ラ棰勮</div>
+        <div style="font-size: 12px; color: #909399; margin-bottom: 10px;">
+          鏍规嵁鎵�閫夐厤缃睍绀烘祦绋嬪浘
+        </div>
+      </el-col>
+
+      <el-col :span="24">
+        <div class="process-diagram">
+          <div v-if="steps.length === 0" class="process-diagram-empty">鏆傛棤姝ラ</div>
+          <div
+            v-for="(step, idx) in steps"
+            :key="String(step.processId) + '_' + idx"
+            class="process-diagram-segment"
+          >
+            <div class="process-diagram-node">
+              <div class="process-diagram-index">{{ idx + 1 }}</div>
+              <div class="process-diagram-name">{{ step.processName }}</div>
+            </div>
+            <div v-if="idx < steps.length - 1" class="process-diagram-arrow">鈫�</div>
+          </div>
+        </div>
+        <div v-if="selectedRouteId === null" style="margin-top: 10px; font-size: 12px; color: #909399;">
+          璇峰厛閫夋嫨涓�鏉″凡缁存姢濂界殑宸ヨ壓璺嚎
+        </div>
+      </el-col>
+    </el-row>
+
+    <template #footer>
+      <div class="dialog-footer">
+        <el-button @click="handleClose">鍙栨秷</el-button>
+        <el-button type="primary" :loading="saving" @click="confirmSelect">
+          纭畾
+        </el-button>
+      </div>
+    </template>
+  </el-dialog>
+</template>
+
+<script setup>
+import { computed, getCurrentInstance, ref, watch } from "vue";
+import { salesProcessFlowConfigList, salesProcessFlowConfigItemList } from "@/api/salesManagement/salesProcessFlowConfig.js";
+
+const emit = defineEmits(["update:visible", "confirm"]);
+
+const props = defineProps({
+  visible: { type: Boolean, default: false },
+  // 鎵撳紑寮圭獥鏃剁殑鍥炴樉锛氳嫢涓氬姟宸茬粦瀹氬伐鑹鸿矾绾垮垯浼犲叆璇� routeId锛涘惁鍒欓粯璁ゅ睍绀哄垪琛ㄧ涓�鏉�
+  defaultRouteId: { type: [Number, String, null], default: null },
+  // 椤甸潰鎻愮ず锛氳鍗曞凡缁戝畾鐨勫伐鑹鸿矾绾垮悕绉�
+  boundRouteName: { type: String, default: "" },
+});
+
+const { proxy } = getCurrentInstance();
+
+const visible = computed({
+  get() {
+    return props.visible;
+  },
+  set(v) {
+    emit("update:visible", v);
+  },
+});
+
+const routeList = ref([]);
+const selectedRouteId = ref(null);
+const steps = ref([]);
+const saving = ref(false);
+
+const normalizeStepsFromApi = (list) => {
+  if (!Array.isArray(list)) return [];
+  return list.map((s, idx) => ({
+    stepId: s.stepId ?? s.id ?? null,
+    processId: s.processId ?? s.process_id ?? s.id ?? null,
+    processName: s.processName ?? s.process_name ?? s.name ?? "",
+    sortNo: s.sortNo ?? idx + 1,
+  }));
+};
+
+const normalizeRouteList = (list) => {
+  if (!Array.isArray(list)) return [];
+  return list.map((r) => ({
+    routeId: r.routeId ?? r.id ?? null,
+    processRouteName: r.processRouteName ?? r.routeName ?? r.name ?? "",
+    isDefault: Boolean(r.isDefault),
+  }));
+};
+
+const fetchRouteList = async () => {
+  // 閫夋嫨寮圭獥锛氬敖閲忎竴娆℃�ф媺鍏紝閬垮厤鍒嗛〉褰卞搷閫夋嫨浣撻獙
+  const res = await salesProcessFlowConfigList({ current: 1, size: 1000 });
+  const records = res?.records ?? res?.data?.records ?? res?.data ?? res ?? [];
+  routeList.value = normalizeRouteList(records).filter((r) => r.routeId !== null && r.routeId !== undefined && r.routeId !== "");
+};
+
+const fetchRouteSteps = async (routeId) => {
+  if (!routeId) {
+    steps.value = [];
+    return;
+  }
+  const res = await salesProcessFlowConfigItemList(routeId);
+  const raw = res?.data ?? res ?? [];
+  steps.value = normalizeStepsFromApi(raw);
+};
+
+watch(
+  () => props.visible,
+  async (v) => {
+    if (v) {
+      try {
+        await fetchRouteList();
+
+        // 鍥炴樉缁戝畾锛�
+        // 1. 鑻ヤ紶鍏� defaultRouteId锛屽垯浼樺厛浣跨敤瀹�
+        // 2. 鍚﹀垯浼樺厛閫変腑鏍囪涓洪粯璁�(isDefault=true)鐨勫伐鑹鸿矾绾�
+        // 3. 鑻ラ兘娌℃湁锛屽垯鍥為��涓虹涓�鏉�
+        const first = routeList.value?.[0] ?? null;
+        const defaultRoute =
+          routeList.value.find((r) => r.isDefault) ?? first;
+        const desired = props.defaultRouteId ?? (defaultRoute ? defaultRoute.routeId : null);
+        selectedRouteId.value = desired ?? null;
+        await fetchRouteSteps(selectedRouteId.value);
+      } catch {
+        proxy?.$modal?.msgError?.("鑾峰彇宸ヨ壓璺嚎閰嶇疆澶辫触");
+      }
+    }
+  }
+);
+
+const handleRouteChange = async () => {
+  await fetchRouteSteps(selectedRouteId.value);
+};
+
+const handleClose = () => {
+  emit("update:visible", false);
+  saving.value = false;
+};
+
+const confirmSelect = async () => {
+  if (saving.value) return;
+  if (selectedRouteId.value === null || selectedRouteId.value === undefined || selectedRouteId.value === "") {
+    proxy?.$modal?.msgWarning?.("璇烽�夋嫨宸ヨ壓璺嚎");
+    return;
+  }
+  saving.value = true;
+  try {
+    emit("confirm", selectedRouteId.value);
+  } catch (e) {
+    proxy?.$modal?.msgError?.("纭澶辫触锛岃绋嶅悗閲嶈瘯");
+  } finally {
+    saving.value = false;
+  }
+};
+</script>
+
+<style scoped>
+.process-diagram {
+  display: flex;
+  align-items: center;
+  gap: 0;
+  flex-wrap: nowrap;
+  overflow-x: auto;
+  padding: 10px 0;
+}
+
+.process-diagram-segment {
+  display: flex;
+  align-items: center;
+}
+
+.process-diagram-node {
+  width: 160px;
+  min-width: 160px;
+  height: 78px;
+  border: 1px solid #ebeef5;
+  border-radius: 10px;
+  background: #fff;
+  display: flex;
+  flex-direction: column;
+  justify-content: center;
+  padding: 10px 12px;
+  margin-right: 10px;
+  box-sizing: border-box;
+}
+
+.process-diagram-index {
+  font-size: 12px;
+  color: #909399;
+  margin-bottom: 4px;
+}
+
+.process-diagram-name {
+  font-size: 14px;
+  font-weight: 600;
+  color: #303133;
+  white-space: nowrap;
+  overflow: hidden;
+  text-overflow: ellipsis;
+}
+
+.process-diagram-arrow {
+  font-size: 18px;
+  color: #909399;
+  margin-right: 14px;
+  margin-left: -6px;
+}
+
+.process-diagram-empty {
+  width: 100%;
+  text-align: center;
+  padding: 40px 0;
+  color: #909399;
+  border: 1px dashed #ebeef5;
+  border-radius: 8px;
+}
+
+.dialog-footer {
+  display: flex;
+  justify-content: flex-end;
+  gap: 10px;
+}
+</style>
+

--
Gitblit v1.9.3