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/infoFormDia.vue | 719 ++++++++++++++++++++++-------------------------------------
1 files changed, 274 insertions(+), 445 deletions(-)
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>
--
Gitblit v1.9.3