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