From ace1b66fe094e791216f6c46f4bd628e1c23b2dd Mon Sep 17 00:00:00 2001
From: liding <756868258@qq.com>
Date: 星期四, 08 十月 2026 17:09:01 +0800
Subject: [PATCH] 协同办公系统模块优化

---
 src/views/collaborativeApproval/approvalProcess/components/approvalDia.vue       |   22 +
 src/api/collaborativeApproval/approvalProcess.js                                 |   33 ++
 src/views/collaborativeApproval/approvalProcess/index5.vue                       |    4 
 src/views/collaborativeApproval/approvalProcess/index1.vue                       |    2 
 src/views/collaborativeApproval/approvalProcess/index.vue                        |   46 ++
 src/views/collaborativeApproval/approvalProcess/index3.vue                       |    4 
 src/views/collaborativeApproval/approvalProcess/components/infoFormDia.vue       |  719 +++++++++++++++++---------------------------
 src/views/collaborativeApproval/approvalProcess/components/flowDefinitionDia.vue |  100 ++++++
 8 files changed, 462 insertions(+), 468 deletions(-)

diff --git a/src/api/collaborativeApproval/approvalProcess.js b/src/api/collaborativeApproval/approvalProcess.js
index 415bed8..40a54df 100644
--- a/src/api/collaborativeApproval/approvalProcess.js
+++ b/src/api/collaborativeApproval/approvalProcess.js
@@ -60,4 +60,35 @@
         url: '/approveNode/details/' + query,
         method: 'get',
     })
-}
\ No newline at end of file
+}
+
+export function approveFlowDefinitionList(query) {
+    return request({
+        url: '/approveFlowDefinition/list',
+        method: 'get',
+        params: query,
+    })
+}
+
+export function approveFlowDefinitionGet(id) {
+    return request({
+        url: '/approveFlowDefinition/' + id,
+        method: 'get',
+    })
+}
+
+export function approveFlowDefinitionAdd(data) {
+    return request({ url: '/approveFlowDefinition', method: 'post', data })
+}
+
+export function approveFlowDefinitionUpdate(id, data) {
+    return request({ url: '/approveFlowDefinition/' + id, method: 'put', data })
+}
+
+export function approveFlowDefinitionEnabled(id, enabled) {
+    return request({ url: '/approveFlowDefinition/' + id + '/enabled', method: 'put', params: { enabled } })
+}
+
+export function approveFlowDefinitionDelete(id) {
+    return request({ url: '/approveFlowDefinition/' + id, method: 'delete' })
+}
diff --git a/src/views/collaborativeApproval/approvalProcess/components/approvalDia.vue b/src/views/collaborativeApproval/approvalProcess/components/approvalDia.vue
index c38ee89..99c5173 100644
--- a/src/views/collaborativeApproval/approvalProcess/components/approvalDia.vue
+++ b/src/views/collaborativeApproval/approvalProcess/components/approvalDia.vue
@@ -74,6 +74,13 @@
 				</el-row>
 			</el-form>
 
+      <el-descriptions v-if="[1, 3, 5].includes(Number(props.approveType))" :column="2" border style="margin-bottom: 18px">
+        <el-descriptions-item label="涓氬姟缂栧彿">{{ form.businessNo || '-' }}</el-descriptions-item>
+        <el-descriptions-item label="瀹℃壒鏍囬">{{ form.businessTitle || '-' }}</el-descriptions-item>
+        <el-descriptions-item label="閲戦">{{ form.amount == null ? '-' : `楼${form.amount}` }}</el-descriptions-item>
+        <el-descriptions-item label="鐢宠浜嬬敱">{{ form.approveReason || '-' }}</el-descriptions-item>
+      </el-descriptions>
+
       <!-- 鎶ヤ环瀹℃壒锛氬睍绀烘姤浠疯鎯咃紙澶嶇敤閿�鍞姤浠封�滄煡鐪嬭鎯呭璇濇鈥濆唴瀹圭粨鏋勶級 -->
       <div v-if="isQuotationApproval" style="margin: 10px 0 18px;">
         <el-divider content-position="left">鎶ヤ环璇︽儏</el-divider>
@@ -298,10 +305,17 @@
 // 鎻愪氦瀹℃壒
 const submitForm = (status) => {
   const filteredActivities = activities.value.filter(activity => activity.isShen);
+  if (!filteredActivities.length) {
+    proxy.$modal.msgError("褰撳墠娌℃湁鍙鎵圭殑鑺傜偣");
+    return;
+  }
+  const opinion = filteredActivities[0].approveNodeReason?.trim();
+  if (!opinion || (status === 2 && opinion.length < 2)) {
+    proxy.$modal.msgError(status === 2 ? "椹冲洖鎰忚鑷冲皯杈撳叆2涓瓧绗�" : "璇疯緭鍏ュ鎵规剰瑙�");
+    return;
+  }
   filteredActivities[0].approveNodeStatus = status;
-  // 鍒ゆ柇鏄惁涓烘渶鍚庝竴姝�
-  const isLast = activities.value.findIndex(a => a.isShen) === activities.value.length-1;
-  updateApproveNode({ ...filteredActivities[0], isLast }).then(() => {
+  updateApproveNode(filteredActivities[0]).then(() => {
     proxy.$modal.msgSuccess("鎻愪氦鎴愬姛");
     closeDia();
   });
@@ -350,4 +364,4 @@
 	width: 200px;
 	height: 60px;
 }
-</style>
\ No newline at end of file
+</style>
diff --git a/src/views/collaborativeApproval/approvalProcess/components/flowDefinitionDia.vue b/src/views/collaborativeApproval/approvalProcess/components/flowDefinitionDia.vue
new file mode 100644
index 0000000..bb0a408
--- /dev/null
+++ b/src/views/collaborativeApproval/approvalProcess/components/flowDefinitionDia.vue
@@ -0,0 +1,100 @@
+<template>
+  <el-dialog v-model="visible" title="棰勮瀹℃壒娴佺▼" width="820px">
+    <div class="toolbar"><el-button type="primary" @click="editFlow()">鏂板娴佺▼</el-button></div>
+    <el-table :data="flowList" border>
+      <el-table-column prop="flowName" label="娴佺▼鍚嶇О" />
+      <el-table-column label="榛樿娴佺▼" width="100"><template #default="{ row }">{{ row.isDefault === 1 ? '鏄�' : '鍚�' }}</template></el-table-column>
+      <el-table-column label="鐘舵��" width="90"><template #default="{ row }"><el-tag :type="row.enabled === 1 ? 'success' : 'info'">{{ row.enabled === 1 ? '鍚敤' : '鍋滅敤' }}</el-tag></template></el-table-column>
+      <el-table-column label="鎿嶄綔" width="250">
+        <template #default="{ row }">
+          <el-button link type="primary" @click="editFlow(row)">缂栬緫</el-button>
+          <el-button link type="primary" @click="toggleEnabled(row)">{{ row.enabled === 1 ? '鍋滅敤' : '鍚敤' }}</el-button>
+          <el-button link type="danger" @click="removeFlow(row)">鍒犻櫎</el-button>
+        </template>
+      </el-table-column>
+    </el-table>
+
+    <el-dialog v-model="editorVisible" :title="editor.definition.id ? '缂栬緫娴佺▼' : '鏂板娴佺▼'" width="720px" append-to-body>
+      <el-form label-width="100px">
+        <el-form-item label="娴佺▼鍚嶇О"><el-input v-model="editor.definition.flowName" /></el-form-item>
+        <el-form-item label="璁句负榛樿"><el-switch v-model="editor.definition.isDefault" :active-value="1" :inactive-value="0" /></el-form-item>
+        <el-form-item label="鍚敤"><el-switch v-model="editor.definition.enabled" :active-value="1" :inactive-value="0" /></el-form-item>
+      </el-form>
+      <el-divider content-position="left">瀹℃壒鑺傜偣</el-divider>
+      <div v-for="(node, index) in editor.nodes" :key="node.key" class="node-row">
+        <span>{{ index + 1 }}</span>
+        <el-input v-model="node.nodeName" placeholder="鑺傜偣鍚嶇О" style="width: 150px" />
+        <el-select v-model="node.approverValue" filterable placeholder="瀹℃壒浜�" style="width: 150px">
+          <el-option v-for="user in users" :key="user.userId" :label="user.nickName" :value="String(user.userId)" />
+        </el-select>
+        <el-select v-model="node.conditionOperator" style="width: 130px">
+          <el-option label="濮嬬粓鎵ц" value="ALWAYS" /><el-option label="閲戦澶т簬" value="GT" /><el-option label="閲戦澶т簬绛変簬" value="GTE" />
+        </el-select>
+        <el-input-number v-if="node.conditionOperator !== 'ALWAYS'" v-model="node.conditionValue" :min="0" :precision="2" style="width: 120px" />
+        <el-button link type="danger" :disabled="editor.nodes.length === 1" @click="editor.nodes.splice(index, 1)">鍒犻櫎</el-button>
+      </div>
+      <el-button type="primary" plain @click="editor.nodes.push(createNode())">鏂板鑺傜偣</el-button>
+      <template #footer><el-button @click="editorVisible = false">鍙栨秷</el-button><el-button type="primary" :loading="saving" @click="saveFlow">淇濆瓨</el-button></template>
+    </el-dialog>
+  </el-dialog>
+</template>
+
+<script setup>
+import { getCurrentInstance, reactive, ref } from 'vue'
+import { approveFlowDefinitionAdd, approveFlowDefinitionDelete, approveFlowDefinitionEnabled, approveFlowDefinitionGet, approveFlowDefinitionList, approveFlowDefinitionUpdate } from '@/api/collaborativeApproval/approvalProcess'
+import { userListNoPageByTenantId } from '@/api/system/user'
+
+const { proxy } = getCurrentInstance()
+const visible = ref(false)
+const editorVisible = ref(false)
+const saving = ref(false)
+const approveType = ref(3)
+const flowList = ref([])
+const users = ref([])
+let key = 1
+const createNode = (data = {}) => ({ key: key++, nodeName: data.nodeName || '', approverType: 'USER', approverValue: data.approverValue ? String(data.approverValue) : '', conditionField: data.conditionField || null, conditionOperator: data.conditionOperator || 'ALWAYS', conditionValue: data.conditionValue == null ? null : Number(data.conditionValue) })
+const editor = reactive({ definition: {}, nodes: [] })
+
+const load = async () => {
+  const [flows, userRes] = await Promise.all([approveFlowDefinitionList({ approveType: approveType.value }), userListNoPageByTenantId()])
+  flowList.value = flows.data || []
+  users.value = userRes.data || []
+}
+const open = async type => { approveType.value = Number(type); visible.value = true; await load() }
+const editFlow = async row => {
+  if (row?.id) {
+    const res = await approveFlowDefinitionGet(row.id)
+    editor.definition = { ...res.data.definition }
+    editor.nodes = (res.data.nodes || []).map(createNode)
+  } else {
+    editor.definition = { id: null, flowName: '', approveType: approveType.value, enabled: 1, isDefault: 0 }
+    editor.nodes = [createNode()]
+  }
+  editorVisible.value = true
+}
+const saveFlow = async () => {
+  if (!editor.definition.flowName?.trim()) return proxy.$modal.msgError('璇疯緭鍏ユ祦绋嬪悕绉�')
+  if (editor.nodes.some(node => !node.nodeName?.trim() || !node.approverValue)) return proxy.$modal.msgError('璇峰畬鏁村~鍐欏鎵硅妭鐐�')
+  const payload = { definition: { ...editor.definition, approveType: approveType.value }, nodes: editor.nodes.map((node, index) => ({ ...node, id: null, nodeOrder: index + 1, conditionField: node.conditionOperator === 'ALWAYS' ? null : 'amount', conditionValue: node.conditionValue == null ? null : String(node.conditionValue) })) }
+  saving.value = true
+  try {
+    if (editor.definition.id) await approveFlowDefinitionUpdate(editor.definition.id, payload)
+    else await approveFlowDefinitionAdd(payload)
+    proxy.$modal.msgSuccess('淇濆瓨鎴愬姛')
+    editorVisible.value = false
+    await load()
+  } finally { saving.value = false }
+}
+const toggleEnabled = async row => { await approveFlowDefinitionEnabled(row.id, row.enabled === 1 ? 0 : 1); await load() }
+const removeFlow = async row => {
+  await proxy.$modal.confirm(`纭鍒犻櫎娴佺▼鈥�${row.flowName}鈥濆悧锛焋)
+  await approveFlowDefinitionDelete(row.id)
+  await load()
+}
+defineExpose({ open })
+</script>
+
+<style scoped>
+.toolbar { margin-bottom: 12px; text-align: right; }
+.node-row { display: flex; align-items: center; gap: 8px; margin-bottom: 10px; }
+</style>
diff --git a/src/views/collaborativeApproval/approvalProcess/components/infoFormDia.vue b/src/views/collaborativeApproval/approvalProcess/components/infoFormDia.vue
index 4c9fce3..0f26e65 100644
--- a/src/views/collaborativeApproval/approvalProcess/components/infoFormDia.vue
+++ b/src/views/collaborativeApproval/approvalProcess/components/infoFormDia.vue
@@ -1,466 +1,295 @@
 <template>
-  <div>
-    <el-dialog
-        v-model="dialogFormVisible"
-        :title="operationType === 'add' ? '鏂板瀹℃壒娴佺▼' : '缂栬緫瀹℃壒娴佺▼'"
-        width="50%"
-        @close="closeDia"
-    >
-      <el-form :model="form" label-width="140px" label-position="top" :rules="rules" ref="formRef">
-        <el-row>
-          <el-col :span="24">
-            <el-form-item label="娴佺▼缂栧彿锛�" prop="approveId">
-              <el-input v-model="form.approveId" placeholder="鑷姩缂栧彿" clearable disabled/>
-            </el-form-item>
-          </el-col>
-        </el-row>
-        <el-row>
-          <el-col :span="24">
-            <!-- 鐢宠閮ㄩ棬锛氭牎楠屼娇鐢ㄩ儴闂↖D锛屼究浜庝笅鎷夐�夋嫨鍚庣珛鍗抽�氳繃鏍¢獙 -->
-            <el-form-item label="鐢宠閮ㄩ棬锛�" prop="approveDeptId">
-<!--              <el-input v-model="form.approveDeptName" placeholder="璇疯緭鍏�" clearable/>-->
-							<el-select
-								v-model="form.approveDeptId"
-								placeholder="閫夋嫨閮ㄩ棬"
-                @change="handleDeptChange"
-							>
-								<el-option
-									v-for="user in productOptions"
-									:key="user.deptId"
-									:label="user.deptName"
-									:value="user.deptId"
-								/>
-							</el-select>
-            </el-form-item>
-          </el-col>
-        </el-row>
-        <el-row>
-          <el-col :span="24">
-            <el-form-item :label="props.approveType == 5 ? '閲囪喘璇存槑锛�' : '瀹℃壒浜嬬敱锛�'" prop="approveReason">
-              <el-input v-model="form.approveReason" placeholder="璇疯緭鍏�" clearable type="textarea" />
-            </el-form-item>
-          </el-col>
-        </el-row>
-        <!-- 璇峰亣鏃堕棿锛堜粎褰� approveType 涓� 2 鏃舵樉绀猴級 -->
-        <el-row :gutter="30" v-if="props.approveType == 2">
-          <el-col :span="12">
-            <el-form-item label="璇峰亣寮�濮嬫椂闂达細" prop="startDate">
-              <el-date-picker
-                  v-model="form.startDate"
-                  type="date"
-                  placeholder="璇烽�夋嫨寮�濮嬫棩鏈�"
-                  value-format="YYYY-MM-DD"
-                  format="YYYY-MM-DD"
-                  clearable
-                  style="width: 100%"
-              />
-            </el-form-item>
-          </el-col>
-          <el-col :span="12">
-            <el-form-item label="璇峰亣缁撴潫鏃堕棿锛�" prop="endDate">
-              <el-date-picker
-                  v-model="form.endDate"
-                  type="date"
-                  placeholder="璇烽�夋嫨缁撴潫鏃ユ湡"
-                  value-format="YYYY-MM-DD"
-                  format="YYYY-MM-DD"
-                  clearable
-                  style="width: 100%"
-              />
-            </el-form-item>
-          </el-col>
-        </el-row>
-        <!-- 鎶ラ攢閲戦锛堜粎褰� approveType 涓� 4 鏃舵樉绀猴級 -->
-        <el-row v-if="props.approveType == 4">
-          <el-col :span="24">
-            <el-form-item label="鎶ラ攢閲戦锛�" prop="price">
-              <el-input-number
-                  v-model="form.price"
-                  placeholder="璇疯緭鍏ユ姤閿�閲戦"
-                  :min="0"
-                  :precision="2"
-                  :step="0.01"
-                  style="width: 100%"
-                  clearable
-              />
-            </el-form-item>
-          </el-col>
-        </el-row>
-        <!-- 鍑哄樊鍦扮偣锛堜粎褰� approveType 涓� 3 鏃舵樉绀猴級 -->
-        <el-row v-if="props.approveType == 3">
-          <el-col :span="24">
-            <el-form-item label="澶囨敞锛�" prop="location">
-              <el-input
-                  v-model="form.location"
-                  placeholder="璇疯緭鍏ュ娉�"
-                  clearable
-              />
-            </el-form-item>
-          </el-col>
-        </el-row>
-        <!-- 瀹℃壒浜洪�夋嫨锛堝姩鎬佽妭鐐癸級 -->
-        <el-row>
-          <el-col :span="24">
-            <el-form-item>
-              <template #label>
-                <span>瀹℃壒浜洪�夋嫨锛�</span>
-                <el-button type="primary" @click="addApproverNode" style="margin-left: 8px;">鏂板鑺傜偣</el-button>
-              </template>
-              <div style="display: flex; align-items: flex-end; flex-wrap: wrap;">
-                <div
-                  v-for="(node, index) in approverNodes"
-                  :key="node.id"
-                  style="margin-right: 30px; text-align: center; margin-bottom: 10px;"
-                >
-                  <div>
-                    <span>瀹℃壒浜�</span>
-                    鈫�
-                  </div>
-                  <el-select
-                    v-model="node.userId"
-                    placeholder="閫夋嫨浜哄憳"
-                    style="width: 120px; margin-bottom: 8px;"
-                  >
-                    <el-option
-                      v-for="user in userList"
-                      :key="user.userId"
-                      :label="user.nickName"
-                      :value="user.userId"
-                    />
-                  </el-select>
-                  <div>
-                    <el-button
-                      type="danger"
-                      size="small"
-                      @click="removeApproverNode(index)"
-                      v-if="approverNodes.length > 1"
-                    >鍒犻櫎</el-button>
-                  </div>
-                </div>
-              </div>
-            </el-form-item>
-          </el-col>
-        </el-row>
-        <el-row :gutter="30">
-          <el-col :span="12">
-            <el-form-item label="鐢宠浜猴細" prop="approveUser">
-							<el-select
-								v-model="form.approveUser"
-								placeholder="閫夋嫨浜哄憳"
-                filterable
-                default-first-option
-                :reserve-keyword="false"
-							>
-								<el-option
-									v-for="user in userList"
-									:key="user.userId"
-									:label="user.nickName"
-									:value="user.userId"
-								/>
-							</el-select>
-            </el-form-item>
-          </el-col>
-          <el-col :span="12">
-            <el-form-item label="鐢宠鏃ユ湡锛�" prop="approveTime">
-              <el-date-picker
-                  v-model="form.approveTime"
-                  type="date"
-                  placeholder="璇烽�夋嫨鏃ユ湡"
-                  value-format="YYYY-MM-DD"
-                  format="YYYY-MM-DD"
-                  clearable
-                  style="width: 100%"
-              />
-            </el-form-item>
-          </el-col>
-        </el-row>
-        <el-row :gutter="30">
-          <el-col :span="24">
-            <el-form-item label="闄勪欢鏉愭枡锛�" prop="remark">
-              <el-upload v-model:file-list="fileList" :action="upload.url" multiple ref="fileUpload" auto-upload
-                         :headers="upload.headers" :before-upload="handleBeforeUpload" :on-error="handleUploadError"
-                         :on-success="handleUploadSuccess" :on-remove="handleRemove">
-                <el-button type="primary" v-if="operationType !== 'view'">涓婁紶</el-button>
-                <template #tip v-if="operationType !== 'view'">
-                  <div class="el-upload__tip">
-                    鏂囦欢鏍煎紡鏀寔
-                    doc锛宒ocx锛寈ls锛寈lsx锛宲pt锛宲ptx锛宲df锛宼xt锛寈ml锛宩pg锛宩peg锛宲ng锛実if锛宐mp锛宺ar锛寊ip锛�7z
-                  </div>
-                </template>
-              </el-upload>
-            </el-form-item>
-          </el-col>
-        </el-row>
-      </el-form>
-      <template #footer>
-        <div class="dialog-footer">
-          <el-button type="primary" @click="submitForm">纭</el-button>
-          <el-button @click="closeDia">鍙栨秷</el-button>
-        </div>
+  <el-dialog v-model="visible" :title="operationType === 'add' ? `鏂板${typeName}` : `缂栬緫${typeName}`" width="760px" @close="closeDialog">
+    <el-form ref="formRef" :model="form" :rules="rules" label-width="120px">
+      <el-form-item label="娴佺▼缂栧彿">
+        <el-input v-model="form.approveId" disabled placeholder="鎻愪氦鍚庤嚜鍔ㄧ敓鎴�" />
+      </el-form-item>
+
+      <el-form-item v-if="approveTypeNumber === 3" label="閿�鍞悎鍚�" prop="businessId">
+        <el-select v-model="form.businessId" filterable placeholder="璇烽�夋嫨閿�鍞悎鍚�" style="width: 100%" @change="handleContractChange">
+          <el-option v-for="item in contractOptions" :key="item.id" :value="item.id"
+                     :label="`${item.salesContractNo || '-'} / ${item.customerName || '-'} / 楼${item.contractAmount || 0}`" />
+        </el-select>
+      </el-form-item>
+
+      <el-form-item v-if="approveTypeNumber === 3 && selectedContract" label="鍚堝悓淇℃伅">
+        <el-descriptions :column="2" border style="width: 100%">
+          <el-descriptions-item label="瀹㈡埛">{{ selectedContract.customerName || '-' }}</el-descriptions-item>
+          <el-descriptions-item label="椤圭洰">{{ selectedContract.projectName || '-' }}</el-descriptions-item>
+          <el-descriptions-item label="涓氬姟鍛�">{{ selectedContract.salesman || '-' }}</el-descriptions-item>
+          <el-descriptions-item label="鍚堝悓閲戦">楼{{ selectedContract.contractAmount || 0 }}</el-descriptions-item>
+        </el-descriptions>
+      </el-form-item>
+
+      <el-form-item v-if="[1, 5].includes(approveTypeNumber)" label="瀹℃壒鏍囬" prop="businessTitle">
+        <el-input v-model="form.businessTitle" maxlength="200" show-word-limit />
+      </el-form-item>
+
+      <template v-if="approveTypeNumber === 1">
+        <el-form-item label="浜嬮」绫诲瀷" prop="category">
+          <el-select v-model="form.category" style="width: 100%">
+            <el-option label="涓存椂璐圭敤鎶ラ攢" value="涓存椂璐圭敤鎶ラ攢" />
+            <el-option label="閮ㄩ棬鍗忎綔" value="閮ㄩ棬鍗忎綔" />
+            <el-option label="鍏朵粬" value="鍏朵粬" />
+          </el-select>
+        </el-form-item>
+        <el-form-item label="娑夊強閲戦">
+          <el-input-number v-model="form.amount" :min="0" :precision="2" style="width: 100%" />
+        </el-form-item>
       </template>
-    </el-dialog>
-  </div>
+
+      <template v-if="approveTypeNumber === 5">
+        <el-row :gutter="16">
+          <el-col :span="12">
+            <el-form-item label="閲囪喘绫诲埆" prop="category"><el-input v-model="form.category" /></el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="绱ф�ョ▼搴�" prop="urgency">
+              <el-select v-model="form.urgency" style="width: 100%">
+                <el-option label="鏅��" value="鏅��" /><el-option label="绱ф��" value="绱ф��" /><el-option label="鐗规��" value="鐗规��" />
+              </el-select>
+            </el-form-item>
+          </el-col>
+        </el-row>
+        <el-form-item label="閲囪喘鍐呭" prop="purchaseContent"><el-input v-model="form.purchaseContent" type="textarea" /></el-form-item>
+        <el-row :gutter="16">
+          <el-col :span="8"><el-form-item label="鏁伴噺" prop="quantity"><el-input-number v-model="form.quantity" :min="0.01" :precision="2" style="width: 100%" /></el-form-item></el-col>
+          <el-col :span="8"><el-form-item label="鍗曚綅" prop="unit"><el-input v-model="form.unit" /></el-form-item></el-col>
+          <el-col :span="8"><el-form-item label="棰勭畻閲戦" prop="amount"><el-input-number v-model="form.amount" :min="0.01" :precision="2" style="width: 100%" /></el-form-item></el-col>
+        </el-row>
+        <el-form-item label="鏈熸湜鍒拌揣鏃ユ湡" prop="expectedDate">
+          <el-date-picker v-model="form.expectedDate" type="date" value-format="YYYY-MM-DD" style="width: 100%" />
+        </el-form-item>
+      </template>
+
+      <el-row v-if="approveTypeNumber === 2" :gutter="16">
+        <el-col :span="12"><el-form-item label="璇峰亣寮�濮嬫棩鏈�" prop="startDate"><el-date-picker v-model="form.startDate" type="date" value-format="YYYY-MM-DD" style="width: 100%" /></el-form-item></el-col>
+        <el-col :span="12"><el-form-item label="璇峰亣缁撴潫鏃ユ湡" prop="endDate"><el-date-picker v-model="form.endDate" type="date" value-format="YYYY-MM-DD" style="width: 100%" /></el-form-item></el-col>
+      </el-row>
+      <el-form-item v-if="approveTypeNumber === 4" label="鎶ラ攢閲戦" prop="amount">
+        <el-input-number v-model="form.amount" :min="0.01" :precision="2" style="width: 100%" />
+      </el-form-item>
+
+      <el-form-item label="鐢宠浜嬬敱" prop="approveReason">
+        <el-input v-model="form.approveReason" type="textarea" :rows="3" maxlength="1000" show-word-limit />
+      </el-form-item>
+
+      <el-form-item label="鐢宠閮ㄩ棬" prop="approveDeptId">
+        <el-select v-model="form.approveDeptId" style="width: 100%">
+          <el-option v-for="dept in departmentOptions" :key="dept.deptId" :label="dept.deptName" :value="dept.deptId" />
+        </el-select>
+      </el-form-item>
+
+      <el-form-item v-if="[3, 5].includes(approveTypeNumber) && flowOptions.length" label="棰勮瀹℃壒娴佺▼">
+        <el-select v-model="form.flowDefinitionId" clearable placeholder="璇烽�夋嫨棰勮娴佺▼锛涚暀绌哄彲鎵嬪姩璁剧疆鑺傜偣" style="width: 100%">
+          <el-option v-for="flow in flowOptions" :key="flow.id" :label="flow.flowName" :value="flow.id" />
+        </el-select>
+      </el-form-item>
+
+      <el-divider content-position="left">瀹℃壒鑺傜偣</el-divider>
+      <el-alert v-if="form.flowDefinitionId && operationType === 'add'" title="鎻愪氦鍚庡皢鎸夐璁炬祦绋嬬敓鎴愬鎵硅妭鐐�" type="info" :closable="false" style="margin-bottom: 12px" />
+      <div v-for="(node, index) in approverNodes" v-show="!form.flowDefinitionId || operationType === 'edit'" :key="node.key" class="node-row">
+        <span class="node-order">{{ index + 1 }}</span>
+        <el-input v-model="node.nodeName" placeholder="鑺傜偣鍚嶇О" style="width: 150px" />
+        <el-select v-model="node.userId" filterable placeholder="瀹℃壒浜�" style="width: 150px">
+          <el-option v-for="user in userList" :key="user.userId" :label="user.nickName" :value="user.userId" />
+        </el-select>
+        <el-select v-model="node.conditionOperator" style="width: 130px" @change="handleConditionChange(node)">
+          <el-option label="濮嬬粓鎵ц" value="ALWAYS" />
+          <el-option label="閲戦澶т簬" value="GT" />
+          <el-option label="閲戦澶т簬绛変簬" value="GTE" />
+          <el-option label="閲戦灏忎簬" value="LT" />
+          <el-option label="閲戦灏忎簬绛変簬" value="LTE" />
+        </el-select>
+        <el-input-number v-if="node.conditionOperator !== 'ALWAYS'" v-model="node.conditionValue" :min="0" :precision="2" style="width: 130px" />
+        <el-button type="danger" link :disabled="approverNodes.length === 1" @click="removeNode(index)">鍒犻櫎</el-button>
+        <el-button link :disabled="index === 0" @click="moveNode(index, -1)">涓婄Щ</el-button>
+        <el-button link :disabled="index === approverNodes.length - 1" @click="moveNode(index, 1)">涓嬬Щ</el-button>
+      </div>
+      <el-button v-if="!form.flowDefinitionId || operationType === 'edit'" type="primary" plain class="add-node" @click="addNode">鏂板瀹℃壒鑺傜偣</el-button>
+
+      <el-form-item label="鐢宠鏃ユ湡">
+        <el-date-picker v-model="form.approveTime" type="date" value-format="YYYY-MM-DD" style="width: 100%" />
+      </el-form-item>
+      <el-form-item label="闄勪欢鏉愭枡">
+        <el-upload v-model:file-list="fileList" :action="upload.url" :headers="upload.headers" multiple
+                   :before-upload="beforeUpload" :on-success="uploadSuccess" :on-error="uploadError" :on-remove="removeFile">
+          <el-button type="primary">涓婁紶鏂囦欢</el-button>
+        </el-upload>
+      </el-form-item>
+    </el-form>
+    <template #footer>
+      <el-button @click="closeDialog">鍙栨秷</el-button>
+      <el-button type="primary" :loading="submitting" @click="submit">鎻愪氦</el-button>
+    </template>
+  </el-dialog>
 </template>
 
 <script setup>
-import {ref, reactive, toRefs, getCurrentInstance} from "vue";
-import {
-  approveProcessAdd, approveProcessGetInfo,
-  approveProcessUpdate,
-  getDept
-} from "@/api/collaborativeApproval/approvalProcess.js";
-import {
-  delLedgerFile,
-} from "@/api/salesManagement/salesLedger.js";
-import {userListNoPageByTenantId} from "@/api/system/user.js";
-import { getToken } from "@/utils/auth";
-const { proxy } = getCurrentInstance()
+import { computed, getCurrentInstance, reactive, ref } from 'vue'
+import { approveFlowDefinitionList, approveProcessAdd, approveProcessDetails, approveProcessGetInfo, approveProcessUpdate, getDept } from '@/api/collaborativeApproval/approvalProcess'
+import { delLedgerFile, ledgerListNoPage } from '@/api/salesManagement/salesLedger'
+import { userListNoPageByTenantId } from '@/api/system/user'
+import { getToken } from '@/utils/auth'
+import { getCurrentDate } from '@/utils'
+import useUserStore from '@/store/modules/user'
+
+const props = defineProps({ approveType: { type: [Number, String], default: 1 } })
 const emit = defineEmits(['close'])
-import useUserStore from "@/store/modules/user";
-import { getCurrentDate } from "@/utils/index.js";
-import log from "@/views/monitor/job/log.vue";
-const userStore = useUserStore();
+const { proxy } = getCurrentInstance()
+const userStore = useUserStore()
+const approveTypeNumber = computed(() => Number(props.approveType))
+const typeName = computed(() => ({ 1: '鑷敱鍗忓悓瀹℃壒', 3: '閿�鍞鎵�', 5: '閲囪喘瀹℃壒' }[approveTypeNumber.value] || '瀹℃壒娴佺▼'))
 
-const dialogFormVisible = ref(false);
-const operationType = ref('')
-const fileList = ref([]);
-const upload = reactive({
-  // 涓婁紶鐨勫湴鍧�
-  url: import.meta.env.VITE_APP_BASE_API + "/file/upload",
-  // 璁剧疆涓婁紶鐨勮姹傚ご閮�
-  headers: { Authorization: "Bearer " + getToken() },
-});
-const data = reactive({
-  form: {
-    approveTime: "",
-    approveId: "",
-    approveUser: "",
-    approveDeptId: "",
-    approveDeptName: "",
-    approveReason: "",
-    checkResult: "",
-    tempFileIds: [],
-    approverList: [], // 鏂板瀛楁锛屽瓨鍌ㄦ墍鏈夎妭鐐圭殑瀹℃壒浜篿d
-    startDate: "", // 璇峰亣寮�濮嬫椂闂�
-    endDate: "", // 璇峰亣缁撴潫鏃堕棿
-    price: null, // 鎶ラ攢閲戦
-    location: "" // 鍑哄樊鍦扮偣
-  },
-  rules: {
-    approveTime: [{ required: false, message: "璇疯緭鍏�", trigger: "change" }],
-    approveId: [{ required: false, message: "璇疯緭鍏�", trigger: "blur" }],
-    approveUser: [{ required: false, message: "璇疯緭鍏�", trigger: "blur" }],
-    // 浣跨敤閮ㄩ棬ID鍋氬繀濉牎楠岋紝閬垮厤鍚嶇О鏈悓姝ュ鑷磋鎶�
-    approveDeptId: [{ required: true, message: "璇烽�夋嫨鐢宠閮ㄩ棬", trigger: "change" }],
-    approveReason: [{ required: true, message: "璇疯緭鍏�", trigger: "blur" }],
-    checkResult: [{ required: false, message: "璇疯緭鍏�", trigger: "blur" }],
-    startDate: [{ required: true, message: "璇烽�夋嫨璇峰亣寮�濮嬫椂闂�", trigger: "change" }],
-    endDate: [{ required: true, message: "璇烽�夋嫨璇峰亣缁撴潫鏃堕棿", trigger: "change" }],
-    price: [{ required: true, message: "璇疯緭鍏ユ姤閿�閲戦", trigger: "blur" }],
-    location: [{ required: true, message: "璇疯緭鍏ュ嚭宸湴鐐�", trigger: "blur" }],
-  },
-});
-const { form, rules } = toRefs(data);
-const productOptions = ref([]);
-const currentApproveStatus = ref(0)
-const props = defineProps({
-  approveType: {
-    type: [Number, String],
-    default: 0
-  }
-})
-
-// 瀹℃壒浜鸿妭鐐圭浉鍏�
-const approverNodes = ref([
-  { id: 1, userId: null }
-])
-let nextApproverId = 2
+const visible = ref(false)
+const submitting = ref(false)
+const operationType = ref('add')
+const formRef = ref()
 const userList = ref([])
-function addApproverNode() {
-  approverNodes.value.push({ id: nextApproverId++, userId: null })
+const departmentOptions = ref([])
+const contractOptions = ref([])
+const flowOptions = ref([])
+const selectedContract = ref(null)
+const fileList = ref([])
+let nodeKey = 1
+const approverNodes = ref([])
+const upload = reactive({ url: import.meta.env.VITE_APP_BASE_API + '/file/upload', headers: { Authorization: 'Bearer ' + getToken() } })
+const emptyForm = () => ({
+  id: null, approveId: '', approveUser: userStore.id, approveDeptId: userStore.currentDeptId,
+  approveTime: getCurrentDate(), approveReason: '', businessId: null, businessNo: '', businessTitle: '',
+  amount: null, businessData: '', flowDefinitionId: null, category: '', urgency: '鏅��', purchaseContent: '', quantity: null,
+  unit: '', expectedDate: '', startDate: '', endDate: '', tempFileIds: []
+})
+const form = ref(emptyForm())
+const rules = {
+  approveDeptId: [{ required: true, message: '璇烽�夋嫨鐢宠閮ㄩ棬', trigger: 'change' }],
+  approveReason: [{ required: true, message: '璇疯緭鍏ョ敵璇蜂簨鐢�', trigger: 'blur' }],
+  businessId: [{ required: true, message: '璇烽�夋嫨閿�鍞悎鍚�', trigger: 'change' }],
+  businessTitle: [{ required: true, message: '璇疯緭鍏ュ鎵规爣棰�', trigger: 'blur' }],
+  category: [{ required: true, message: '璇疯緭鍏ユ垨閫夋嫨绫诲埆', trigger: 'blur' }],
+  urgency: [{ required: true, message: '璇烽�夋嫨绱ф�ョ▼搴�', trigger: 'change' }],
+  purchaseContent: [{ required: true, message: '璇疯緭鍏ラ噰璐唴瀹�', trigger: 'blur' }],
+  quantity: [{ required: true, message: '璇疯緭鍏ユ暟閲�', trigger: 'blur' }],
+  unit: [{ required: true, message: '璇疯緭鍏ュ崟浣�', trigger: 'blur' }],
+  amount: [{ required: true, message: '璇疯緭鍏ラ绠楅噾棰�', trigger: 'blur' }],
+  expectedDate: [{ required: true, message: '璇烽�夋嫨鏈熸湜鍒拌揣鏃ユ湡', trigger: 'change' }],
+  startDate: [{ required: true, message: '璇烽�夋嫨璇峰亣寮�濮嬫棩鏈�', trigger: 'change' }],
+  endDate: [{ required: true, message: '璇烽�夋嫨璇峰亣缁撴潫鏃ユ湡', trigger: 'change' }]
 }
-function removeApproverNode(index) {
-  approverNodes.value.splice(index, 1)
+
+const createNode = (data = {}) => ({ key: nodeKey++, userId: data.userId || null, nodeName: data.nodeName || '瀹℃壒', conditionField: data.conditionField || null, conditionOperator: data.conditionOperator || 'ALWAYS', conditionValue: data.conditionValue == null ? null : Number(data.conditionValue) })
+const addNode = () => approverNodes.value.push(createNode())
+const removeNode = index => approverNodes.value.splice(index, 1)
+const moveNode = (index, offset) => {
+  const target = index + offset
+  if (target < 0 || target >= approverNodes.value.length) return
+  const item = approverNodes.value.splice(index, 1)[0]
+  approverNodes.value.splice(target, 0, item)
 }
-// 澶勭悊閮ㄩ棬閫夋嫨鍙樺寲
-const handleDeptChange = (deptId) => {
-  if (deptId) {
-    const selectedDept = productOptions.value.find(dept => dept.deptId === deptId);
-    if (selectedDept) {
-      form.value.approveDeptName = selectedDept.deptName;
-    }
+const handleConditionChange = node => {
+  node.conditionField = node.conditionOperator === 'ALWAYS' ? null : 'amount'
+  if (node.conditionOperator === 'ALWAYS') node.conditionValue = null
+}
+
+const loadOptions = async () => {
+  const tasks = [userListNoPageByTenantId(), getDept()]
+  if (approveTypeNumber.value === 3) tasks.push(ledgerListNoPage({}))
+  const flowPromise = [3, 5].includes(approveTypeNumber.value) ? approveFlowDefinitionList({ approveType: approveTypeNumber.value }) : Promise.resolve({ data: [] })
+  tasks.push(flowPromise)
+  const results = await Promise.all(tasks)
+  userList.value = results[0].data || []
+  departmentOptions.value = results[1].data || []
+  if (approveTypeNumber.value === 3) {
+    contractOptions.value = results[2]?.data || []
+    flowOptions.value = results[3]?.data || []
   } else {
-    form.value.approveDeptName = '';
+    contractOptions.value = []
+    flowOptions.value = results[2]?.data || []
   }
-};
-// 鎵撳紑寮规
-const openDialog = (type, row) => {
-  operationType.value = type;
-  dialogFormVisible.value = true;
-	userListNoPageByTenantId().then((res) => {
-    userList.value = res.data;
-  });
-  getProductOptions();
-	form.value = {}
-	approverNodes.value = [
-		{ id: 1, userId: null }
-	]
-  form.value.approveUser = userStore.id;
-  form.value.approveTime = getCurrentDate();
-  
-  // 鑾峰彇褰撳墠鐢ㄦ埛淇℃伅骞惰缃儴闂↖D
-  form.value.approveDeptId = userStore.currentDeptId
-  if (operationType.value === 'edit') {
-    fileList.value = row.commonFileList
-    form.value.tempFileIds = fileList.value.map(file => file.id)
-		currentApproveStatus.value = row.approveStatus
-    approveProcessGetInfo({id: row.approveId,approveReason: '1'}).then(res => {
-			form.value = {...res.data}
-      // 鍙嶆樉瀹℃壒浜�
-      if (res.data && res.data.approveUserIds) {
-        const userIds = res.data.approveUserIds.split(',')
-        approverNodes.value = userIds.map((userId, idx) => ({
-          id: idx + 1, 
-          userId: parseInt(userId.trim())
-        }))
-        nextApproverId = userIds.length + 1
-      } else {
-        approverNodes.value = [{ id: 1, userId: null }]
-        nextApproverId = 2
-      }
-    })
-  }
+  const defaultFlow = flowOptions.value.find(item => item.isDefault === 1 && item.enabled === 1)
+  if (defaultFlow && operationType.value === 'add') form.value.flowDefinitionId = defaultFlow.id
 }
-const getProductOptions = () => {
-  getDept().then((res) => {
-    productOptions.value = res.data;
-  });
-};
-function convertIdToValue(data) {
-  return data.map((item) => {
-    const { id, children, ...rest } = item;
-    const newItem = {
-      ...rest,
-      value: id, // 灏� id 鏀逛负 value
-    };
-    if (children && children.length > 0) {
-      newItem.children = convertIdToValue(children);
-    }
-    
-    return newItem;
-  });
-}
-// 鎻愪氦浜у搧琛ㄥ崟
-const submitForm = () => {
-  // 鏀堕泦鎵�鏈夎妭鐐圭殑瀹℃壒浜篿d
-  form.value.approveUserIds = approverNodes.value.map(node => node.userId).join(',')
-  form.value.approveType = props.approveType
-  // 瀹℃壒浜哄繀濉牎楠�
-  const hasEmptyApprover = approverNodes.value.some(node => !node.userId)
-  if (hasEmptyApprover) {
-    proxy.$modal.msgError("璇蜂负鎵�鏈夊鎵硅妭鐐归�夋嫨瀹℃壒浜猴紒")
-    return
-  }
-  // 褰� approveType 涓� 2 鏃讹紝鏍¢獙璇峰亣鏃堕棿
-  if (props.approveType == 2) {
-    if (!form.value.startDate) {
-      proxy.$modal.msgError("璇烽�夋嫨璇峰亣寮�濮嬫椂闂达紒")
-      return
-    }
-    if (!form.value.endDate) {
-      proxy.$modal.msgError("璇烽�夋嫨璇峰亣缁撴潫鏃堕棿锛�")
-      return
-    }
-    // 鏍¢獙缁撴潫鏃堕棿涓嶈兘鏃╀簬寮�濮嬫椂闂�
-    if (new Date(form.value.endDate) < new Date(form.value.startDate)) {
-      proxy.$modal.msgError("璇峰亣缁撴潫鏃堕棿涓嶈兘鏃╀簬寮�濮嬫椂闂达紒")
-      return
-    }
-  }
-  // 褰� approveType 涓� 3 鏃讹紝鏍¢獙鍑哄樊鍦扮偣
-  if (props.approveType == 3) {
-    if (!form.value.location || form.value.location.trim() === '') {
-      proxy.$modal.msgError("璇疯緭鍏ュ嚭宸湴鐐癸紒")
-      return
-    }
-  }
-  // 褰� approveType 涓� 4 鏃讹紝鏍¢獙鎶ラ攢閲戦
-  if (props.approveType == 4) {
-    if (!form.value.price || form.value.price <= 0) {
-      proxy.$modal.msgError("璇疯緭鍏ユ湁鏁堢殑鎶ラ攢閲戦锛�")
-      return
-    }
-  }
-  proxy.$refs.formRef.validate(valid => {
-    if (valid) {
-      if (operationType.value === "add" || currentApproveStatus.value == 3) {
-        approveProcessAdd(form.value).then(res => {
-          proxy.$modal.msgSuccess("鎻愪氦鎴愬姛");
-          closeDia();
-        })
-      } else {
-        approveProcessUpdate(form.value).then(res => {
-          proxy.$modal.msgSuccess("鎻愪氦鎴愬姛");
-          closeDia();
-        })
-      }
-    }
-  })
-}
-// 鍏抽棴寮规
-const closeDia = () => {
+
+const openDialog = async (type, row) => {
+  operationType.value = type
+  visible.value = true
+  form.value = emptyForm()
+  approverNodes.value = [createNode()]
   fileList.value = []
-  proxy.resetForm("formRef");
-  dialogFormVisible.value = false;
-  emit('close')
-};
-
-// 涓婁紶鍓嶆牎妫�
-function handleBeforeUpload(file) {
-  // 鏍℃鏂囦欢澶у皬
-  // if (file.size > 1024 * 1024 * 10) {
-  //   proxy.$modal.msgError("涓婁紶鏂囦欢澶у皬涓嶈兘瓒呰繃10MB!");
-  //   return false;
-  // }
-  proxy.$modal.loading("姝e湪涓婁紶鏂囦欢锛岃绋嶅��...");
-  return true;
-}
-// 涓婁紶澶辫触
-function handleUploadError(err) {
-  proxy.$modal.msgError("涓婁紶鏂囦欢澶辫触");
-  proxy.$modal.closeLoading();
-}
-// 涓婁紶鎴愬姛鍥炶皟
-function handleUploadSuccess(res, file, uploadFiles) {
-  proxy.$modal.closeLoading();
-  if (res.code === 200) {
-    // 纭繚 tempFileIds 瀛樺湪涓斾负鏁扮粍
-    if (!form.value.tempFileIds) {
-      form.value.tempFileIds = [];
+  selectedContract.value = null
+  await loadOptions()
+  if (type === 'edit' && row?.approveId) {
+    const [processRes, nodeRes] = await Promise.all([approveProcessGetInfo({ id: row.approveId }), approveProcessDetails(row.approveId)])
+    const process = processRes.data || {}
+    let business = {}
+    try { business = process.businessData ? JSON.parse(process.businessData) : {} } catch (_) { business = {} }
+    form.value = { ...emptyForm(), ...process, ...business, tempFileIds: [] }
+    fileList.value = process.commonFileList || []
+    approverNodes.value = (nodeRes.data || []).map(item => createNode({
+      userId: item.approveNodeUserId,
+      nodeName: item.approveNodeName,
+      conditionField: item.conditionField,
+      conditionOperator: item.conditionOperator,
+      conditionValue: item.conditionValue
+    }))
+    if (!approverNodes.value.length) approverNodes.value = [createNode()]
+    if (approveTypeNumber.value === 3) {
+      selectedContract.value = contractOptions.value.find(item => item.id === process.businessId) || business
     }
-    form.value.tempFileIds.push(res.data.tempId);
-    proxy.$modal.msgSuccess("涓婁紶鎴愬姛");
-  } else {
-    proxy.$modal.msgError(res.msg);
-    proxy.$refs.fileUpload.handleRemove(file);
-  }
-}
-// 绉婚櫎鏂囦欢
-function handleRemove(file) {
-  if (operationType.value === "edit") {
-    let ids = [];
-    ids.push(file.id);
-    delLedgerFile(ids).then((res) => {
-      proxy.$modal.msgSuccess("鍒犻櫎鎴愬姛");
-    });
   }
 }
 
-defineExpose({
-  openDialog,
-});
+const handleContractChange = id => {
+  selectedContract.value = contractOptions.value.find(item => item.id === id) || null
+  if (selectedContract.value) form.value.businessTitle = `閿�鍞悎鍚屽鎵�-${selectedContract.value.salesContractNo || ''}`
+}
+
+const buildBusinessData = () => {
+  if (approveTypeNumber.value === 5) return JSON.stringify({ category: form.value.category, urgency: form.value.urgency, purchaseContent: form.value.purchaseContent, quantity: form.value.quantity, unit: form.value.unit, expectedDate: form.value.expectedDate })
+  if (approveTypeNumber.value === 1) return JSON.stringify({ category: form.value.category })
+  if (approveTypeNumber.value === 2) return JSON.stringify({ startDate: form.value.startDate, endDate: form.value.endDate })
+  if (approveTypeNumber.value === 4) return JSON.stringify({ amount: form.value.amount })
+  return form.value.businessData || ''
+}
+
+const submit = async () => {
+  await formRef.value.validate()
+  if (approveTypeNumber.value === 2 && new Date(form.value.endDate) < new Date(form.value.startDate)) return proxy.$modal.msgError('璇峰亣缁撴潫鏃ユ湡涓嶈兘鏃╀簬寮�濮嬫棩鏈�')
+  const usePresetFlow = operationType.value === 'add' && !!form.value.flowDefinitionId
+  if (!usePresetFlow && approverNodes.value.some(item => !item.userId || !item.nodeName)) return proxy.$modal.msgError('璇峰畬鏁村~鍐欏鎵硅妭鐐�')
+  if (!usePresetFlow && approverNodes.value.some((item, index) => index > 0 && item.userId === approverNodes.value[index - 1].userId)) return proxy.$modal.msgError('鐩搁偦瀹℃壒鑺傜偣涓嶈兘閫夋嫨鍚屼竴瀹℃壒浜�')
+  if (!usePresetFlow && approverNodes.value.some(item => item.conditionOperator !== 'ALWAYS' && item.conditionValue == null)) return proxy.$modal.msgError('璇峰~鍐欒妭鐐规潯浠堕噾棰�')
+  const nodes = usePresetFlow ? [] : approverNodes.value.map(item => ({ userId: item.userId, nodeName: item.nodeName, conditionField: item.conditionOperator === 'ALWAYS' ? null : 'amount', conditionOperator: item.conditionOperator, conditionValue: item.conditionValue == null ? null : String(item.conditionValue) }))
+  const payload = { ...form.value, approveType: approveTypeNumber.value, approveUser: userStore.id, nodes, approveUserIds: nodes.map(item => item.userId).join(','), businessData: buildBusinessData() }
+  submitting.value = true
+  try {
+    if (operationType.value === 'add') await approveProcessAdd(payload)
+    else await approveProcessUpdate(payload)
+    proxy.$modal.msgSuccess('鎻愪氦鎴愬姛')
+    closeDialog()
+  } finally {
+    submitting.value = false
+  }
+}
+
+const beforeUpload = () => { proxy.$modal.loading('姝e湪涓婁紶鏂囦欢锛岃绋嶅��...'); return true }
+const uploadSuccess = (res, file) => {
+  proxy.$modal.closeLoading()
+  if (res.code === 200) form.value.tempFileIds.push(res.data.tempId)
+  else { proxy.$modal.msgError(res.msg); proxy.$refs.fileUpload?.handleRemove(file) }
+}
+const uploadError = () => { proxy.$modal.closeLoading(); proxy.$modal.msgError('涓婁紶澶辫触') }
+const removeFile = file => {
+  if (file.id) delLedgerFile([file.id])
+  if (file.response?.data?.tempId) form.value.tempFileIds = form.value.tempFileIds.filter(id => id !== file.response.data.tempId)
+}
+const closeDialog = () => { visible.value = false; emit('close') }
+
+defineExpose({ openDialog })
 </script>
 
 <style scoped>
-
-</style>
\ No newline at end of file
+.node-row { display: flex; align-items: center; gap: 8px; margin-bottom: 10px; flex-wrap: wrap; }
+.node-order { display: inline-flex; width: 26px; height: 26px; align-items: center; justify-content: center; border-radius: 50%; color: #fff; background: #409eff; }
+.add-node { margin: 0 0 20px 120px; }
+</style>
diff --git a/src/views/collaborativeApproval/approvalProcess/index.vue b/src/views/collaborativeApproval/approvalProcess/index.vue
index afc2529..3815b70 100644
--- a/src/views/collaborativeApproval/approvalProcess/index.vue
+++ b/src/views/collaborativeApproval/approvalProcess/index.vue
@@ -1,8 +1,8 @@
 <template>
   <div class="app-container">
     <!-- 鏍囩椤靛垏鎹笉鍚岀殑瀹℃壒绫诲瀷 -->
-    <el-tabs v-model="activeTab" @tab-change="handleTabChange" class="approval-tabs">
-      <el-tab-pane label="鍗忓悓瀹℃壒" name="1"></el-tab-pane>
+    <el-tabs v-if="!fixedApproveType" v-model="activeTab" @tab-change="handleTabChange" class="approval-tabs">
+      <el-tab-pane label="鑷敱鍗忓悓瀹℃壒" name="1"></el-tab-pane>
       <el-tab-pane label="璇峰亣绠$悊" name="2"></el-tab-pane>
       <el-tab-pane label="閿�鍞鎵�" name="3"></el-tab-pane>
       <el-tab-pane label="鎶ラ攢瀹℃壒" name="4"></el-tab-pane>
@@ -35,6 +35,7 @@
         >
       </div>
       <div>
+        <el-button v-if="[3, 5].includes(currentApproveType)" @click="openFlowDefinition">娴佺▼閰嶇疆</el-button>
         <el-button type="primary" @click="openForm('add')" v-if="currentApproveType !== 6">鏂板</el-button>
         <el-button @click="handleOut">瀵煎嚭</el-button>
         <el-button type="danger" plain @click="handleDelete">鍒犻櫎</el-button>
@@ -56,25 +57,30 @@
     <info-form-dia ref="infoFormDia" @close="handleQuery" :approveType="currentApproveType"></info-form-dia>
     <approval-dia ref="approvalDia" @close="handleQuery" :approveType="currentApproveType"></approval-dia>
     <FileList ref="fileListRef" />
+    <FlowDefinitionDia ref="flowDefinitionRef" />
   </div>
 </template>
 
 <script setup>
 import FileList from "./fileList.vue";
 import { Search } from "@element-plus/icons-vue";
-import {onMounted, ref, computed, reactive, toRefs, nextTick, getCurrentInstance} from "vue";
+import {onMounted, ref, computed, reactive, toRefs, nextTick, getCurrentInstance, watch} from "vue";
 import {ElMessageBox} from "element-plus";
 import { useRoute } from 'vue-router';
 import InfoFormDia from "@/views/collaborativeApproval/approvalProcess/components/infoFormDia.vue";
 import ApprovalDia from "@/views/collaborativeApproval/approvalProcess/components/approvalDia.vue";
 import {approveProcessDelete, approveProcessListPage} from "@/api/collaborativeApproval/approvalProcess.js";
 import useUserStore from "@/store/modules/user";
+import FlowDefinitionDia from "./components/flowDefinitionDia.vue";
 
 const userStore = useUserStore();
 const route = useRoute();
+const props = defineProps({
+  approveType: { type: [Number, String], default: null }
+})
+const fixedApproveType = computed(() => props.approveType !== null && props.approveType !== undefined)
 
-// 褰撳墠閫変腑鐨勬爣绛鹃〉锛岄粯璁や负鍏嚭绠$悊
-const activeTab = ref('1');
+const activeTab = ref(String(props.approveType || '1'));
 
 // 褰撳墠瀹℃壒绫诲瀷锛屾牴鎹�変腑鐨勬爣绛鹃〉璁$畻
 const currentApproveType = computed(() => {
@@ -104,6 +110,7 @@
   const isLeaveType = currentApproveType.value === 2; // 璇峰亣绠$悊
   const isReimburseType = currentApproveType.value === 4; // 鎶ラ攢绠$悊
   const isQuotationType = currentApproveType.value === 6; // 鎶ヤ环瀹℃壒
+  const isBusinessApproval = [1, 3, 5].includes(currentApproveType.value)
   
   // 鍩虹鍒楅厤缃�
   const baseColumns = [
@@ -150,10 +157,11 @@
       width: 220
     },
     {
-      label: isQuotationType ? "鎶ヤ环鍗曞彿" : "瀹℃壒浜嬬敱",
-      prop: "approveReason",
+      label: isBusinessApproval ? "涓氬姟缂栧彿" : (isQuotationType ? "鎶ヤ环鍗曞彿" : "瀹℃壒浜嬬敱"),
+      prop: isBusinessApproval ? "businessNo" : "approveReason",
       width: 200
     },
+    ...(isBusinessApproval ? [{ label: "瀹℃壒鏍囬", prop: "businessTitle", width: 220 }] : []),
     {
       label: "鐢宠浜�",
       prop: "approveUserName",
@@ -168,6 +176,9 @@
       prop: "price",
       width: 120
     });
+  }
+  if ([1, 3, 5].includes(currentApproveType.value)) {
+    baseColumns.push({ label: currentApproveType.value === 3 ? "鍚堝悓閲戦锛堝厓锛�" : "閲戦锛堝厓锛�", prop: "amount", width: 140 })
   }
   
   // 鏃ユ湡鍒楋紙鏍规嵁绫诲瀷鍔ㄦ�侀厤缃級
@@ -205,7 +216,7 @@
         clickFun: (row) => {
           openForm("edit", row);
         },
-        disabled: (row) => currentApproveType.value === 6 || row.approveStatus == 2 || row.approveStatus == 1 || row.approveStatus == 4
+        disabled: (row) => currentApproveType.value === 6 || ![0, 3].includes(row.approveStatus) || row.approveUser !== userStore.id
       },
       {
         name: "瀹℃牳",
@@ -244,6 +255,7 @@
 });
 const infoFormDia = ref()
 const approvalDia = ref()
+const flowDefinitionRef = ref()
 const { proxy } = getCurrentInstance()
 
 // 鏌ヨ鍒楄〃
@@ -287,12 +299,12 @@
   }
   const url = urlMap[type] || urlMap[0]
   const nameMap = {
-    0: "鍗忓悓瀹℃壒绠$悊琛�",
-    1: "鍏嚭绠$悊瀹℃壒琛�",
+    0: "鑷敱鍗忓悓瀹℃壒琛�",
+    1: "鑷敱鍗忓悓瀹℃壒琛�",
     2: "璇峰亣绠$悊瀹℃壒琛�",
-    3: "鍑哄樊绠$悊瀹℃壒琛�",
+    3: "閿�鍞悎鍚屽鎵硅〃",
     4: "鎶ラ攢绠$悊瀹℃壒琛�",
-    5: "閲囪喘鐢宠瀹℃壒琛�",
+    5: "閲囪喘璁″垝瀹℃壒琛�",
     6: "鎶ヤ环瀹℃壒琛�",
     7: "鍑哄簱瀹℃壒琛�",
   }
@@ -316,6 +328,7 @@
     approvalDia.value?.openDialog(type, row)
   })
 };
+const openFlowDefinition = () => flowDefinitionRef.value?.open(currentApproveType.value)
 
 // 鍒犻櫎
 const handleDelete = () => {
@@ -326,7 +339,7 @@
     proxy.$modal.msgWarning("璇烽�夋嫨鏁版嵁");
     return;
   }
-  ElMessageBox.confirm("閫変腑鐨勫唴瀹瑰皢琚垹闄わ紝鏄惁纭鍒犻櫎锛�", "瀵煎嚭", {
+  ElMessageBox.confirm("閫変腑鐨勫唴瀹瑰皢琚垹闄わ紝鏄惁纭鍒犻櫎锛�", "鍒犻櫎", {
     confirmButtonText: "纭",
     cancelButtonText: "鍙栨秷",
     type: "warning",
@@ -359,6 +372,13 @@
   // 鏌ヨ鍒楄〃
   getList();
 });
+
+watch(() => props.approveType, value => {
+  if (value !== null && value !== undefined) {
+    activeTab.value = String(value)
+    handleQuery()
+  }
+})
 </script>
 
 <style scoped>
diff --git a/src/views/collaborativeApproval/approvalProcess/index1.vue b/src/views/collaborativeApproval/approvalProcess/index1.vue
index c46c68a..4f9be7a 100644
--- a/src/views/collaborativeApproval/approvalProcess/index1.vue
+++ b/src/views/collaborativeApproval/approvalProcess/index1.vue
@@ -10,7 +10,7 @@
 
 // 瀹氫箟缁勪欢鍚嶇О
 defineOptions({
-  name: 'ApprovalProcessIndex1'
+  name: 'FreeCollaborationApproval'
 })
 </script>
 
diff --git a/src/views/collaborativeApproval/approvalProcess/index3.vue b/src/views/collaborativeApproval/approvalProcess/index3.vue
index 3afb6f5..02813ea 100644
--- a/src/views/collaborativeApproval/approvalProcess/index3.vue
+++ b/src/views/collaborativeApproval/approvalProcess/index3.vue
@@ -10,7 +10,7 @@
 
 // 瀹氫箟缁勪欢鍚嶇О
 defineOptions({
-  name: 'ApprovalProcessIndex1'
+  name: 'SalesApproval'
 })
 </script>
 
@@ -19,4 +19,4 @@
   width: 100%;
   height: 100%;
 }
-</style>
\ No newline at end of file
+</style>
diff --git a/src/views/collaborativeApproval/approvalProcess/index5.vue b/src/views/collaborativeApproval/approvalProcess/index5.vue
index 2e0f4f3..55c7b96 100644
--- a/src/views/collaborativeApproval/approvalProcess/index5.vue
+++ b/src/views/collaborativeApproval/approvalProcess/index5.vue
@@ -10,7 +10,7 @@
 
 // 瀹氫箟缁勪欢鍚嶇О
 defineOptions({
-  name: 'ApprovalProcessIndex1'
+  name: 'PurchaseApproval'
 })
 </script>
 
@@ -19,4 +19,4 @@
   width: 100%;
   height: 100%;
 }
-</style>
\ No newline at end of file
+</style>

--
Gitblit v1.9.3