From 6bea4a03b32c48d72cee59e46c90accdf07b8b35 Mon Sep 17 00:00:00 2001
From: gaoluyang <2820782392@qq.com>
Date: 星期四, 23 四月 2026 17:59:22 +0800
Subject: [PATCH] 阳光彩印 1.协同审批管理不再需要选择审批人 2.审批管理添加审批流联调 3.销售发货、采购台账、销售报价不再需要选择审批人
---
src/views/collaborativeApproval/approvalProcess/components/approvalDia.vue | 100 --
src/views/procurementManagement/procurementLedger/index.vue | 139 ---
src/api/collaborativeApproval/approvalManagement.js | 20
src/views/collaborativeApproval/approvalProcess/index.vue | 474 +++++++++++-
src/views/salesManagement/salesLedger/index2.vue | 65 -
src/views/collaborativeApproval/approvalProcess/fileList.vue | 6
src/views/salesManagement/salesLedger/index.vue | 65 -
src/views/salesManagement/salesQuotation/index.vue | 176 -----
src/views/collaborativeApproval/approvalProcess/components/infoFormDia.vue | 161 ----
src/views/collaborativeApproval/approvalManagement/index.vue | 881 +++++++++++++++++++++++++
10 files changed, 1,339 insertions(+), 748 deletions(-)
diff --git a/src/api/collaborativeApproval/approvalManagement.js b/src/api/collaborativeApproval/approvalManagement.js
new file mode 100644
index 0000000..c2ce4c7
--- /dev/null
+++ b/src/api/collaborativeApproval/approvalManagement.js
@@ -0,0 +1,20 @@
+// 瀹℃壒绠$悊閰嶇疆
+import request from "@/utils/request";
+
+// 鏌ヨ瀹℃壒娴佺▼閰嶇疆鑺傜偣鍒楄〃
+export function getApproveProcessConfigNodeList(type) {
+ return request({
+ url: '/approveProcessConfigNode/list',
+ method: 'get',
+ params: { type },
+ })
+}
+
+// 鏂板瀹℃壒娴佺▼閰嶇疆鑺傜偣
+export function addApproveProcessConfigNode(data) {
+ return request({
+ url: '/approveProcessConfigNode/add',
+ method: 'post',
+ data: data,
+ })
+}
diff --git a/src/views/collaborativeApproval/approvalManagement/index.vue b/src/views/collaborativeApproval/approvalManagement/index.vue
new file mode 100644
index 0000000..4638392
--- /dev/null
+++ b/src/views/collaborativeApproval/approvalManagement/index.vue
@@ -0,0 +1,881 @@
+<template>
+ <div class="app-container">
+ <!-- 椤甸潰鏍囬 -->
+ <div class="page-header">
+ <div class="header-title">
+ <el-icon class="title-icon"><Setting /></el-icon>
+ <span>瀹℃壒娴佺▼閰嶇疆</span>
+ </div>
+ <div class="header-desc">涓轰笉鍚屽鎵圭被鍨嬮厤缃鎵规祦绋嬪拰瀹℃壒浜�</div>
+ </div>
+
+ <!-- 瀹℃壒绫诲瀷鍒囨崲 - 绱у噾鏍囩寮� -->
+ <div class="type-tabs">
+ <div
+ v-for="type in approveTypes"
+ :key="type.value"
+ class="type-tab"
+ :class="{ active: activeTab === type.value }"
+ @click="activeTab = type.value; handleTabChange()"
+ >
+ <el-icon :size="14" :style="{ color: activeTab === type.value ? type.color : '#909399' }">
+ <component :is="type.icon" />
+ </el-icon>
+ <span class="tab-name">{{ type.label }}</span>
+ </div>
+ </div>
+
+ <!-- 涓昏鍐呭鍖哄煙 -->
+ <el-card class="config-card" shadow="hover" v-loading="loading">
+ <template #header>
+ <div class="card-header">
+ <div class="header-left">
+ <div class="type-icon" :style="{ backgroundColor: getTypeColor(currentApproveType) }">
+ <el-icon :size="20" color="#fff"><component :is="getTypeIcon(currentApproveType)" /></el-icon>
+ </div>
+ <div class="header-info">
+ <span class="type-name">{{ currentApproveTypeName }}</span>
+ <el-tag :type="approverList.length > 0 ? 'success' : 'warning'" size="small" effect="light">
+ {{ approverList.length > 0 ? `宸查厤缃� ${approverList.length} 涓鎵逛汉` : '鏈厤缃鎵逛汉' }}
+ </el-tag>
+ </div>
+ </div>
+ <div class="header-actions" v-if="approverList.length > 0">
+ <el-button @click="handleReset" size="default">
+ <el-icon><RefreshLeft /></el-icon>
+ 閲嶇疆
+ </el-button>
+ <el-button type="primary" @click="handleSave" :loading="saveLoading" size="default">
+ <el-icon><Check /></el-icon>
+ 淇濆瓨閰嶇疆
+ </el-button>
+ </div>
+ </div>
+ </template>
+
+ <!-- 瀹℃壒娴佺▼灞曠ず -->
+ <div class="flow-wrapper" v-if="approverList.length > 0">
+ <div class="flow-container">
+ <div
+ v-for="(item, index) in approverList"
+ :key="index"
+ class="flow-item"
+ >
+ <!-- 瀹℃壒鑺傜偣鍗$墖 -->
+ <div class="node-card" :class="{ 'empty': !item.approverId }">
+ <!-- 椤堕儴搴忓彿鍜岀骇鍒� -->
+ <div class="node-badge">{{ index + 1 }}</div>
+
+ <!-- 澶村儚鍖哄煙 -->
+ <div class="node-avatar-section">
+ <div
+ class="node-avatar"
+ :class="{ 'has-user': item.approverId }"
+ :style="item.approverId ? { backgroundColor: getAvatarColor(item.approverName) } : {}"
+ >
+ <span v-if="item.approverId">{{ item.approverName.charAt(0) }}</span>
+ <el-icon v-else :size="24"><User /></el-icon>
+ </div>
+ <div class="node-level">{{ getLevelText(index) }}</div>
+ </div>
+
+ <!-- 閫夋嫨鍖哄煙 -->
+ <div class="node-select-section">
+ <el-select
+ v-model="item.approverId"
+ placeholder="閫夋嫨瀹℃壒浜�"
+ filterable
+ size="default"
+ @change="(val) => handleApproverChange(val, item)"
+ >
+ <el-option
+ v-for="user in userList"
+ :key="user.userId"
+ :label="user.nickName"
+ :value="user.userId"
+ />
+ </el-select>
+ </div>
+
+ <!-- 鎿嶄綔鎸夐挳 -->
+ <div class="node-actions">
+ <el-button
+ type="primary"
+ circle
+ :disabled="index === 0"
+ @click="moveLeft(index)"
+ size="small"
+ class="action-btn"
+ title="鍓嶇Щ"
+ >
+ <el-icon><ArrowLeft /></el-icon>
+ </el-button>
+ <el-button
+ type="primary"
+ circle
+ :disabled="index === approverList.length - 1"
+ @click="moveRight(index)"
+ size="small"
+ class="action-btn"
+ title="鍚庣Щ"
+ >
+ <el-icon><ArrowRight /></el-icon>
+ </el-button>
+ <el-button
+ type="danger"
+ circle
+ @click="handleDelete(index)"
+ size="small"
+ class="action-btn"
+ >
+ <el-icon><Delete /></el-icon>
+ </el-button>
+ </div>
+ </div>
+
+ <!-- 杩炴帴绠ご -->
+ <div class="arrow-connector" v-if="index < approverList.length - 1">
+ <div class="arrow-line"></div>
+ <el-icon class="arrow-icon"><ArrowRight /></el-icon>
+ </div>
+ </div>
+
+ <!-- 鏂板鑺傜偣鎸夐挳 - 鏀惧湪娴佺▼鏈�鍚� -->
+ <div class="add-node-item">
+ <div class="arrow-connector" v-if="approverList.length > 0">
+ <div class="arrow-line"></div>
+ <el-icon class="arrow-icon"><ArrowRight /></el-icon>
+ </div>
+ <div class="add-node-card" @click="handleAdd">
+ <div class="add-icon-wrapper">
+ <el-icon :size="28"><Plus /></el-icon>
+ </div>
+ <span class="add-text">鏂板瀹℃壒浜�</span>
+ </div>
+ </div>
+ </div>
+ </div>
+
+ <!-- 绌虹姸鎬� -->
+ <div class="empty-state" v-else>
+ <div class="empty-content">
+ <div class="empty-icon-wrapper">
+ <el-icon :size="48" color="#c0c4cc"><User /></el-icon>
+ </div>
+ <div class="empty-text">鏆傛棤瀹℃壒浜洪厤缃�</div>
+ <div class="empty-subtext">鐐瑰嚮涓嬫柟鎸夐挳娣诲姞绗竴涓鎵逛汉</div>
+ <el-button type="primary" size="large" @click="handleAdd" class="empty-add-btn">
+ <el-icon><Plus /></el-icon>
+ 鏂板瀹℃壒浜�
+ </el-button>
+ </div>
+ </div>
+ </el-card>
+
+ <!-- 搴曢儴鎻愮ず -->
+ <div class="bottom-tips">
+ <el-icon><InfoFilled /></el-icon>
+ <span>鎻愮ず锛氭瘡涓祦绋嬭嚦灏戦厤缃竴涓鎵逛汉锛屽鎵规寜椤哄簭娴佽浆锛屽彲閫氳繃绠ご璋冩暣椤哄簭</span>
+ </div>
+ </div>
+</template>
+
+<script setup>
+import { ref, computed, onMounted } from 'vue';
+import { ElMessage, ElMessageBox } from 'element-plus';
+import {
+ Plus, ArrowLeft, Delete, Check, RefreshLeft, Setting,
+ Suitcase, Calendar, Location, Money, ShoppingCart, DocumentChecked,
+ Van, ArrowRight, User, InfoFilled
+} from '@element-plus/icons-vue';
+import { getApproveProcessConfigNodeList, addApproveProcessConfigNode } from '@/api/collaborativeApproval/approvalManagement';
+import { userListNoPage } from '@/api/system/user';
+
+// 褰撳墠閫変腑鐨勬爣绛鹃〉
+const activeTab = ref('1');
+
+// 瀹℃壒绫诲瀷閰嶇疆鏁扮粍
+const approveTypes = [
+ { value: '1', label: '鍏嚭绠$悊', icon: 'Suitcase', color: '#409EFF' },
+ { value: '2', label: '璇峰亣绠$悊', icon: 'Calendar', color: '#67C23A' },
+ { value: '3', label: '鍑哄樊绠$悊', icon: 'Location', color: '#E6A23C' },
+ { value: '4', label: '鎶ラ攢绠$悊', icon: 'Money', color: '#F56C6C' },
+ { value: '5', label: '閲囪喘瀹℃壒', icon: 'ShoppingCart', color: '#909399' },
+ { value: '6', label: '鎶ヤ环瀹℃壒', icon: 'DocumentChecked', color: '#9B59B6' },
+ { value: '7', label: '鍙戣揣瀹℃壒', icon: 'Van', color: '#1ABC9C' },
+];
+
+// 瀹℃壒绫诲瀷鍚嶇О鏄犲皠
+const approveTypeNameMap = {
+ 1: '鍏嚭绠$悊',
+ 2: '璇峰亣绠$悊',
+ 3: '鍑哄樊绠$悊',
+ 4: '鎶ラ攢绠$悊',
+ 5: '閲囪喘瀹℃壒',
+ 6: '鎶ヤ环瀹℃壒',
+ 7: '鍙戣揣瀹℃壒',
+};
+
+// 瀹℃壒绫诲瀷鍥炬爣鏄犲皠
+const typeIconMap = {
+ 1: 'Suitcase',
+ 2: 'Calendar',
+ 3: 'Location',
+ 4: 'Money',
+ 5: 'ShoppingCart',
+ 6: 'DocumentChecked',
+ 7: 'Van',
+};
+
+// 瀹℃壒绫诲瀷棰滆壊鏄犲皠
+const typeColorMap = {
+ 1: '#409EFF',
+ 2: '#67C23A',
+ 3: '#E6A23C',
+ 4: '#F56C6C',
+ 5: '#909399',
+ 6: '#9B59B6',
+ 7: '#1ABC9C',
+};
+
+// 澶村儚棰滆壊姹�
+const avatarColors = ['#409EFF', '#67C23A', '#E6A23C', '#F56C6C', '#9B59B6', '#1ABC9C', '#FF6B6B', '#4ECDC4'];
+
+// 褰撳墠瀹℃壒绫诲瀷鍚嶇О
+const currentApproveTypeName = computed(() => {
+ return approveTypeNameMap[activeTab.value] || '鏈煡绫诲瀷';
+});
+
+// 褰撳墠瀹℃壒绫诲瀷
+const currentApproveType = computed(() => {
+ return Number(activeTab.value);
+});
+
+// 鑾峰彇绫诲瀷鍥炬爣
+const getTypeIcon = (type) => typeIconMap[type] || 'Setting';
+
+// 鑾峰彇绫诲瀷棰滆壊
+const getTypeColor = (type) => typeColorMap[type] || '#409EFF';
+
+// 鑾峰彇澶村儚棰滆壊
+const getAvatarColor = (name) => {
+ if (!name) return '#C0C4CC';
+ let hash = 0;
+ for (let i = 0; i < name.length; i++) {
+ hash = name.charCodeAt(i) + ((hash << 5) - hash);
+ }
+ return avatarColors[Math.abs(hash) % avatarColors.length];
+};
+
+// 鑾峰彇绾у埆鏂囨湰
+const getLevelText = (index) => {
+ const texts = ['绗竴绾�', '绗簩绾�', '绗笁绾�', '绗洓绾�', '绗簲绾�', '绗叚绾�', '绗竷绾�', '绗叓绾�'];
+ return texts[index] || `绗�${index + 1}绾;
+};
+
+// 瀹℃壒浜哄垪琛紙鐪熷疄鎺ュ彛锛�
+const userList = ref([]);
+
+// 瀹℃壒浜哄垪琛�
+const approverList = ref([]);
+
+// 鍘熷鏁版嵁锛岀敤浜庨噸缃�
+const originalList = ref([]);
+
+// 鍔犺浇鐘舵��
+const loading = ref(false);
+const saveLoading = ref(false);
+
+// 鏍囩椤靛垏鎹㈠鐞�
+const handleTabChange = () => {
+ loadData();
+};
+
+// 鍔犺浇瀹℃壒閰嶇疆鏁版嵁锛堟ā鎷燂級
+const loadData = async () => {
+ loading.value = true;
+ try {
+ const res = await getApproveProcessConfigNodeList(currentApproveType.value);
+ const source = Array.isArray(res?.data)
+ ? res.data
+ : Array.isArray(res?.rows)
+ ? res.rows
+ : Array.isArray(res?.data?.records)
+ ? res.data.records
+ : [];
+ const data = source.map((item, index) => ({
+ ...item,
+ sortOrder: item.nodeOrder ?? item.sortOrder ?? index + 1,
+ }));
+ approverList.value = data.sort((a, b) => (a.sortOrder || 0) - (b.sortOrder || 0));
+ originalList.value = JSON.parse(JSON.stringify(approverList.value));
+ } catch (error) {
+ approverList.value = [];
+ originalList.value = [];
+ ElMessage.error('鍔犺浇瀹℃壒閰嶇疆澶辫触');
+ } finally {
+ loading.value = false;
+ }
+};
+
+const loadUserList = async () => {
+ try {
+ const res = await userListNoPage();
+ userList.value = Array.isArray(res?.data) ? res.data : [];
+ } catch (error) {
+ userList.value = [];
+ ElMessage.error('鍔犺浇浜哄憳鍒楄〃澶辫触');
+ }
+};
+
+// 瀹℃壒浜洪�夋嫨鍙樺寲
+const handleApproverChange = (userId, row) => {
+ const user = userList.value.find((u) => u.userId === userId);
+ if (user) {
+ row.approverName = user.nickName;
+ }
+};
+
+// 鏂板瀹℃壒浜�
+const handleAdd = () => {
+ const newOrder = approverList.value.length + 1;
+ approverList.value.push({
+ id: null,
+ approveType: currentApproveType.value,
+ approverId: null,
+ approverName: '',
+ sortOrder: newOrder,
+ });
+};
+
+// 鍒犻櫎瀹℃壒浜�
+const handleDelete = (index) => {
+ ElMessageBox.confirm('纭畾鍒犻櫎璇ュ鎵逛汉鍚楋紵', '鎻愮ず', {
+ confirmButtonText: '纭畾',
+ cancelButtonText: '鍙栨秷',
+ type: 'warning',
+ })
+ .then(() => {
+ approverList.value.splice(index, 1);
+ approverList.value.forEach((item, idx) => {
+ item.sortOrder = idx + 1;
+ });
+ ElMessage.success('鍒犻櫎鎴愬姛');
+ })
+ .catch(() => {});
+};
+
+// 鍓嶇Щ
+const moveLeft = (index) => {
+ if (index === 0) return;
+ const temp = approverList.value[index];
+ approverList.value[index] = approverList.value[index - 1];
+ approverList.value[index - 1] = temp;
+ approverList.value[index].sortOrder = index + 1;
+ approverList.value[index - 1].sortOrder = index;
+};
+
+// 鍚庣Щ
+const moveRight = (index) => {
+ if (index === approverList.value.length - 1) return;
+ const temp = approverList.value[index];
+ approverList.value[index] = approverList.value[index + 1];
+ approverList.value[index + 1] = temp;
+ approverList.value[index].sortOrder = index + 1;
+ approverList.value[index + 1].sortOrder = index + 2;
+};
+
+// 淇濆瓨閰嶇疆
+const handleSave = async () => {
+ if (approverList.value.length === 0) {
+ ElMessage.warning('璇疯嚦灏戦厤缃竴涓鎵逛汉');
+ return;
+ }
+
+ const hasEmptyApprover = approverList.value.some((item) => !item.approverId);
+ if (hasEmptyApprover) {
+ ElMessage.warning('璇烽�夋嫨鎵�鏈夊鎵逛汉');
+ return;
+ }
+
+ const approverIds = approverList.value.map((item) => item.approverId);
+ const uniqueIds = [...new Set(approverIds)];
+ if (uniqueIds.length !== approverIds.length) {
+ ElMessage.warning('瀹℃壒浜轰笉鑳介噸澶�');
+ return;
+ }
+
+ saveLoading.value = true;
+ try {
+ const payload = approverList.value.map((item, index) => ({
+ approveType: currentApproveType.value,
+ nodeOrder: index + 1,
+ approverId: item.approverId,
+ approverName: item.approverName,
+ }));
+ await addApproveProcessConfigNode(payload);
+ ElMessage.success('淇濆瓨鎴愬姛');
+ await loadData();
+ } catch (error) {
+ ElMessage.error('淇濆瓨澶辫触');
+ } finally {
+ saveLoading.value = false;
+ }
+};
+
+// 閲嶇疆
+const handleReset = () => {
+ if (originalList.value.length === 0) {
+ approverList.value = [];
+ return;
+ }
+ ElMessageBox.confirm('纭畾瑕侀噸缃綋鍓嶉厤缃悧锛熸湭淇濆瓨鐨勬洿鏀瑰皢涓㈠け銆�', '鎻愮ず', {
+ confirmButtonText: '纭畾',
+ cancelButtonText: '鍙栨秷',
+ type: 'warning',
+ })
+ .then(() => {
+ approverList.value = JSON.parse(JSON.stringify(originalList.value));
+ ElMessage.success('宸查噸缃�');
+ })
+ .catch(() => {});
+};
+
+onMounted(async () => {
+ await loadUserList();
+ await loadData();
+});
+</script>
+
+<style scoped>
+.page-header {
+ margin-bottom: 20px;
+}
+
+.header-title {
+ display: flex;
+ align-items: center;
+ gap: 10px;
+ font-size: 20px;
+ font-weight: 600;
+ color: var(--el-text-color-primary, #303133);
+ margin-bottom: 6px;
+}
+
+.title-icon {
+ font-size: 24px;
+ color: var(--el-color-primary, #409EFF);
+}
+
+.header-desc {
+ font-size: 13px;
+ color: var(--el-text-color-secondary, #909399);
+ margin-left: 34px;
+}
+
+/* 瀹℃壒绫诲瀷鍒囨崲 - 绱у噾鏍囩寮� */
+.type-tabs {
+ display: flex;
+ gap: 4px;
+ margin-bottom: 16px;
+ padding: 4px;
+ background: var(--el-fill-color-light, #f5f7fa);
+ border-radius: 8px;
+ overflow-x: auto;
+}
+
+.type-tab {
+ display: flex;
+ align-items: center;
+ gap: 6px;
+ padding: 8px 14px;
+ border-radius: 6px;
+ cursor: pointer;
+ transition: all 0.2s ease;
+ white-space: nowrap;
+ font-size: 13px;
+ color: var(--el-text-color-regular, #606266);
+}
+
+.type-tab:hover {
+ background: var(--el-color-primary-light-9, rgba(64, 158, 255, 0.1));
+ color: var(--el-color-primary, #409EFF);
+}
+
+.type-tab.active {
+ background: var(--el-bg-color, #fff);
+ color: var(--el-color-primary, #409EFF);
+ font-weight: 600;
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
+}
+
+.tab-name {
+ font-size: 13px;
+}
+
+.tab-count {
+ min-width: 16px;
+ height: 16px;
+ padding: 0 5px;
+ background: var(--el-color-success, #67C23A);
+ color: #fff;
+ border-radius: 8px;
+ font-size: 11px;
+ font-weight: 600;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+}
+
+.config-card {
+ margin-bottom: 16px;
+ border-radius: 12px;
+}
+
+:deep(.el-card__header) {
+ padding: 16px 20px;
+ border-bottom: 1px solid var(--el-border-color-light, #ebeef5);
+}
+
+.card-header {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+}
+
+.header-left {
+ display: flex;
+ align-items: center;
+ gap: 14px;
+}
+
+.type-icon {
+ width: 44px;
+ height: 44px;
+ border-radius: 10px;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
+}
+
+.header-info {
+ display: flex;
+ flex-direction: column;
+ gap: 6px;
+}
+
+.type-name {
+ font-size: 16px;
+ font-weight: 600;
+ color: var(--el-text-color-primary, #303133);
+}
+
+.header-actions {
+ display: flex;
+ gap: 10px;
+}
+
+.flow-wrapper {
+ overflow-x: auto;
+ padding: 8px 4px;
+}
+
+.flow-container {
+ display: flex;
+ align-items: center;
+ gap: 0;
+ min-width: min-content;
+}
+
+.flow-item {
+ display: flex;
+ align-items: center;
+}
+
+.node-card {
+ width: 200px;
+ background: var(--el-bg-color, #fff);
+ border: 2px solid var(--el-border-color, #e4e7ed);
+ border-radius: 12px;
+ padding: 16px;
+ position: relative;
+ transition: all 0.3s ease;
+ flex-shrink: 0;
+}
+
+.node-card:hover {
+ border-color: var(--el-color-primary, #409EFF);
+ box-shadow: 0 4px 16px rgba(64, 158, 255, 0.15);
+ transform: translateY(-2px);
+}
+
+.node-card.empty {
+ border-style: dashed;
+ border-color: var(--el-border-color, #c0c4cc);
+ background: var(--el-fill-color-light, #fafbfc);
+}
+
+.node-card.empty:hover {
+ border-color: var(--el-color-primary, #409EFF);
+ background: var(--el-fill-color-light, #f5f7fa);
+}
+
+.node-badge {
+ position: absolute;
+ top: -10px;
+ left: 16px;
+ width: 24px;
+ height: 24px;
+ background: var(--el-color-primary, #409EFF);
+ color: #fff;
+ border-radius: 50%;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ font-size: 13px;
+ font-weight: 700;
+ box-shadow: 0 2px 8px rgba(64, 158, 255, 0.4);
+}
+
+.node-avatar-section {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ margin-bottom: 12px;
+ margin-top: 4px;
+}
+
+.node-avatar {
+ width: 56px;
+ height: 56px;
+ border-radius: 50%;
+ background: var(--el-fill-color, #f0f2f5);
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ margin-bottom: 8px;
+ color: var(--el-text-color-placeholder, #c0c4cc);
+ transition: all 0.3s ease;
+}
+
+.node-avatar.has-user {
+ color: #fff;
+ font-size: 22px;
+ font-weight: 600;
+ box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
+}
+
+.node-level {
+ font-size: 12px;
+ color: var(--el-text-color-secondary, #909399);
+ font-weight: 500;
+}
+
+.node-select-section {
+ margin-bottom: 12px;
+}
+
+.node-select-section :deep(.el-select) {
+ width: 100%;
+}
+
+.node-actions {
+ display: flex;
+ justify-content: center;
+ gap: 8px;
+ padding-top: 12px;
+ border-top: 1px solid var(--el-border-color-light, #ebeef5);
+}
+
+.action-btn {
+ transition: all 0.2s;
+}
+
+.action-btn:hover:not(:disabled) {
+ transform: scale(1.1);
+}
+
+.arrow-connector {
+ display: flex;
+ align-items: center;
+ width: 50px;
+ position: relative;
+}
+
+.arrow-line {
+ flex: 1;
+ height: 2px;
+ background: var(--el-border-color, #c0c4cc);
+}
+
+.arrow-icon {
+ color: var(--el-text-color-placeholder, #c0c4cc);
+ font-size: 14px;
+ margin-left: -2px;
+}
+
+/* 鏂板鑺傜偣鏍峰紡 */
+.add-node-item {
+ display: flex;
+ align-items: center;
+}
+
+.add-node-card {
+ width: 140px;
+ height: 200px;
+ border: 2px dashed var(--el-border-color, #c0c4cc);
+ border-radius: 12px;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ justify-content: center;
+ gap: 12px;
+ cursor: pointer;
+ transition: all 0.3s ease;
+ background: var(--el-fill-color-light, #fafbfc);
+ flex-shrink: 0;
+ margin-left: 0;
+}
+
+.add-node-card:hover {
+ border-color: var(--el-color-primary, #409EFF);
+ background: var(--el-color-primary-light-9, #f0f7ff);
+ transform: translateY(-2px);
+ box-shadow: 0 4px 16px rgba(64, 158, 255, 0.15);
+}
+
+.add-icon-wrapper {
+ width: 48px;
+ height: 48px;
+ border-radius: 50%;
+ background: var(--el-color-primary, #409EFF);
+ color: #fff;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ box-shadow: 0 4px 12px rgba(64, 158, 255, 0.3);
+ transition: all 0.3s ease;
+}
+
+.add-node-card:hover .add-icon-wrapper {
+ transform: scale(1.1);
+ box-shadow: 0 6px 16px rgba(64, 158, 255, 0.4);
+}
+
+.add-text {
+ font-size: 14px;
+ color: var(--el-text-color-regular, #606266);
+ font-weight: 500;
+}
+
+.add-node-card:hover .add-text {
+ color: var(--el-color-primary, #409EFF);
+}
+
+/* 绌虹姸鎬� */
+.empty-state {
+ padding: 50px 20px;
+}
+
+.empty-content {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ gap: 16px;
+}
+
+.empty-icon-wrapper {
+ width: 80px;
+ height: 80px;
+ border-radius: 50%;
+ background: var(--el-fill-color-light, #f5f7fa);
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ margin-bottom: 8px;
+}
+
+.empty-text {
+ font-size: 16px;
+ font-weight: 600;
+ color: var(--el-text-color-regular, #606266);
+}
+
+.empty-subtext {
+ font-size: 13px;
+ color: var(--el-text-color-secondary, #909399);
+}
+
+.empty-add-btn {
+ margin-top: 8px;
+ padding: 12px 28px;
+}
+
+/* 搴曢儴鎻愮ず */
+.bottom-tips {
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ gap: 8px;
+ padding: 12px 20px;
+ background: var(--el-fill-color-light, #f5f7fa);
+ border-radius: 8px;
+ color: var(--el-text-color-regular, #606266);
+ font-size: 13px;
+}
+
+.bottom-tips .el-icon {
+ color: var(--el-color-primary, #409EFF);
+ font-size: 16px;
+}
+
+@media (max-width: 768px) {
+ .type-tabs {
+ padding: 3px;
+ }
+
+ .type-tab {
+ padding: 6px 10px;
+ font-size: 12px;
+ }
+
+ .tab-name {
+ font-size: 12px;
+ }
+
+ .flow-container {
+ flex-wrap: wrap;
+ justify-content: center;
+ }
+
+ .arrow-connector {
+ width: 100%;
+ height: 30px;
+ flex-direction: row;
+ justify-content: center;
+ }
+
+ .arrow-line {
+ width: 2px;
+ height: 30px;
+ }
+
+ .arrow-icon {
+ right: auto;
+ top: auto;
+ bottom: -5px;
+ transform: rotate(90deg);
+ }
+
+ .add-node-item {
+ width: 100%;
+ justify-content: center;
+ margin-top: 10px;
+ }
+
+ .add-node-item .arrow-connector {
+ display: none;
+ }
+}
+</style>
diff --git a/src/views/collaborativeApproval/approvalProcess/components/approvalDia.vue b/src/views/collaborativeApproval/approvalProcess/components/approvalDia.vue
index d15d547..1269621 100644
--- a/src/views/collaborativeApproval/approvalProcess/components/approvalDia.vue
+++ b/src/views/collaborativeApproval/approvalProcess/components/approvalDia.vue
@@ -39,39 +39,6 @@
</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="閫夋嫨浜哄憳"
- disabled
- >
- <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%"
- disabled
- />
- </el-form-item>
- </el-col>
- </el-row>
</el-form>
<!-- 鎶ヤ环瀹℃壒锛氬睍绀烘姤浠疯鎯咃紙澶嶇敤閿�鍞姤浠�"鏌ョ湅璇︽儏瀵硅瘽妗�"鍐呭缁撴瀯锛� -->
@@ -116,19 +83,6 @@
<h4>澶囨敞</h4>
<p>{{ currentQuotation.remark }}</p>
</div>
-
- <div v-if="quotationAttachments.length > 0" style="margin-top: 20px;">
- <h4>闄勪欢</h4>
- <el-table :data="quotationAttachments" border style="width: 100%">
- <el-table-column prop="name" label="闄勪欢鍚嶇О" min-width="360" show-overflow-tooltip />
- <el-table-column label="鎿嶄綔" width="160" align="center">
- <template #default="{ row }">
- <el-button link type="primary" size="small" @click="downloadAttachment(row)">涓嬭浇</el-button>
- <el-button link type="primary" size="small" @click="previewAttachment(row)">棰勮</el-button>
- </template>
- </el-table-column>
- </el-table>
- </div>
</template>
</template>
</el-skeleton>
@@ -150,7 +104,7 @@
<el-descriptions-item label="閲囪喘鍚堝悓鍙�">{{ currentPurchase.purchaseContractNumber }}</el-descriptions-item>
<el-descriptions-item label="渚涘簲鍟嗗悕绉�">{{ currentPurchase.supplierName }}</el-descriptions-item>
<el-descriptions-item label="椤圭洰鍚嶇О">{{ currentPurchase.projectName }}</el-descriptions-item>
- <el-descriptions-item label="璁㈠崟缂栧彿">{{ currentPurchase.salesContractNo }}</el-descriptions-item>
+ <el-descriptions-item label="閿�鍞悎鍚屽彿">{{ currentPurchase.salesContractNo }}</el-descriptions-item>
<el-descriptions-item label="绛捐鏃ユ湡">{{ currentPurchase.executionDate }}</el-descriptions-item>
<el-descriptions-item label="褰曞叆鏃ユ湡">{{ currentPurchase.entryDate }}</el-descriptions-item>
<el-descriptions-item label="浠樻鏂瑰紡">{{ currentPurchase.paymentMethod }}</el-descriptions-item>
@@ -230,7 +184,6 @@
</div>
</template>
</el-dialog>
- <filePreview ref="filePreviewRef" />
</div>
</template>
@@ -242,11 +195,9 @@
updateApproveNode
} from "@/api/collaborativeApproval/approvalProcess.js";
import useUserStore from "@/store/modules/user.js";
-import {userListNoPageByTenantId} from "@/api/system/user.js";
import { WarningFilled, Edit, Check, MoreFilled } from '@element-plus/icons-vue'
-import { getQuotationDetail, getQuotationList } from "@/api/salesManagement/salesQuotation.js";
+import { getQuotationList } from "@/api/salesManagement/salesQuotation.js";
import { getPurchaseByCode } from "@/api/procurementManagement/procurementLedger.js";
-import filePreview from "@/components/filePreview/index.vue";
const emit = defineEmits(['close'])
const { proxy } = getCurrentInstance()
@@ -263,45 +214,16 @@
const formRef = ref(null);
const userStore = useUserStore()
const productOptions = ref([]);
-const userList = ref([])
const quotationLoading = ref(false)
const currentQuotation = ref({})
const purchaseLoading = ref(false)
const currentPurchase = ref({})
-const filePreviewRef = ref()
const isQuotationApproval = computed(() => Number(props.approveType) === 6)
const isPurchaseApproval = computed(() => Number(props.approveType) === 5)
-const normalizeQuotationFiles = (raw) => {
- const list =
- (raw && Array.isArray(raw.salesLedgerFiles) && raw.salesLedgerFiles) ||
- (raw && Array.isArray(raw.quotationFiles) && raw.quotationFiles) ||
- (raw && Array.isArray(raw.fileList) && raw.fileList) ||
- (raw && Array.isArray(raw.files) && raw.files) ||
- []
- return list
- .map((item) => ({
- id: item?.id,
- name: item?.fileName || item?.name || item?.originalName || item?.filename || "闄勪欢",
- url: item?.fileUrl || item?.url || item?.path || item?.tempPath,
- }))
- .filter((i) => i.url)
-}
-
-const quotationAttachments = computed(() => normalizeQuotationFiles(currentQuotation.value))
-
-const downloadAttachment = (row) => {
- proxy.$download.name(row.url)
-}
-const previewAttachment = (row) => {
- filePreviewRef.value?.open?.(row.url)
-}
-
const data = reactive({
form: {
- approveTime: "",
approveId: "",
- approveUser: "",
approveDeptId: "",
approveReason: "",
checkResult: "",
@@ -336,9 +258,6 @@
dialogFormVisible.value = true;
currentQuotation.value = {}
currentPurchase.value = {}
- userListNoPageByTenantId().then((res) => {
- userList.value = res.data;
- });
form.value = {...row}
// 绔嬪嵆娓呴櫎琛ㄥ崟楠岃瘉鐘舵�侊紙鍥犱负瀛楁鏄痙isabled鐨勶紝涓嶉渶瑕侀獙璇侊級
nextTick(() => {
@@ -371,18 +290,9 @@
const quotationNo = row?.approveReason;
if (quotationNo) {
quotationLoading.value = true
- getQuotationList({ quotationNo }).then(async (res) => {
+ getQuotationList({ quotationNo }).then((res) => {
const records = res?.data?.records || []
- const first = records[0] || {}
- currentQuotation.value = first
- if (first?.id && normalizeQuotationFiles(first).length === 0) {
- try {
- // const detailRes = await getQuotationDetail({ id: first.id })
- // const detail = detailRes?.data || detailRes || {}
- currentQuotation.value = { ...first }
- } catch (e) {
- }
- }
+ currentQuotation.value = records[0] || {}
}).finally(() => {
quotationLoading.value = false
})
@@ -495,4 +405,4 @@
width: 200px;
height: 60px;
}
-</style>
+</style>
\ No newline at end of file
diff --git a/src/views/collaborativeApproval/approvalProcess/components/infoFormDia.vue b/src/views/collaborativeApproval/approvalProcess/components/infoFormDia.vue
index df88ad8..8328ee6 100644
--- a/src/views/collaborativeApproval/approvalProcess/components/infoFormDia.vue
+++ b/src/views/collaborativeApproval/approvalProcess/components/infoFormDia.vue
@@ -46,10 +46,10 @@
<el-form-item label="璇峰亣寮�濮嬫椂闂达細" prop="startDate">
<el-date-picker
v-model="form.startDate"
- type="datetime"
- placeholder="璇烽�夋嫨寮�濮嬫椂闂�"
- value-format="YYYY-MM-DD HH:mm:ss"
- format="YYYY-MM-DD HH:mm:ss"
+ type="date"
+ placeholder="璇烽�夋嫨寮�濮嬫棩鏈�"
+ value-format="YYYY-MM-DD"
+ format="YYYY-MM-DD"
clearable
style="width: 100%"
/>
@@ -59,10 +59,10 @@
<el-form-item label="璇峰亣缁撴潫鏃堕棿锛�" prop="endDate">
<el-date-picker
v-model="form.endDate"
- type="datetime"
- placeholder="璇烽�夋嫨缁撴潫鏃堕棿"
- value-format="YYYY-MM-DD HH:mm:ss"
- format="YYYY-MM-DD HH:mm:ss"
+ type="date"
+ placeholder="璇烽�夋嫨缁撴潫鏃ユ湡"
+ value-format="YYYY-MM-DD"
+ format="YYYY-MM-DD"
clearable
style="width: 100%"
/>
@@ -97,82 +97,7 @@
</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">
@@ -211,13 +136,10 @@
import {
delLedgerFile,
} from "@/api/salesManagement/salesLedger.js";
-import {userListNoPageByTenantId} from "@/api/system/user.js";
import { getToken } from "@/utils/auth";
const { proxy } = getCurrentInstance()
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 dialogFormVisible = ref(false);
@@ -231,24 +153,19 @@
});
const data = reactive({
form: {
- approveTime: "",
approveId: "",
- approveUser: "",
- approveDeptId: "",
+ 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" }],
approveDeptName: [{ required: true, message: "璇疯緭鍏�", trigger: "blur" }],
approveReason: [{ required: true, message: "璇疯緭鍏�", trigger: "blur" }],
checkResult: [{ required: false, message: "璇疯緭鍏�", trigger: "blur" }],
@@ -268,18 +185,7 @@
}
})
-// 瀹℃壒浜鸿妭鐐圭浉鍏�
-const approverNodes = ref([
- { id: 1, userId: null }
-])
-let nextApproverId = 2
-const userList = ref([])
-function addApproverNode() {
- approverNodes.value.push({ id: nextApproverId++, userId: null })
-}
-function removeApproverNode(index) {
- approverNodes.value.splice(index, 1)
-}
+
// 澶勭悊閮ㄩ棬閫夋嫨鍙樺寲
const handleDeptChange = (deptId) => {
if (deptId) {
@@ -295,39 +201,19 @@
const openDialog = (type, row) => {
operationType.value = type;
dialogFormVisible.value = true;
- userListNoPageByTenantId().then((res) => {
- userList.value = res.data;
- });
- form.value = {}
- approverNodes.value = [
- { id: 1, userId: null }
- ]
- form.value.approveUser = userStore.id;
- form.value.approveTime = getCurrentDate();
-
+ form.value = {}
+
// 鑾峰彇褰撳墠鐢ㄦ埛淇℃伅骞惰缃儴闂↖D
form.value.approveDeptId = userStore.currentDeptId
-
+
// 鍔犺浇閮ㄩ棬閫夐」锛屽苟鍦ㄥ姞杞藉畬鎴愬悗璁剧疆閮ㄩ棬鍚嶇О
getProductOptions();
if (operationType.value === 'edit') {
fileList.value = row.commonFileList
form.value.tempFileIds = fileList.value.map(file => file.id)
- currentApproveStatus.value = row.approveStatus
+ 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
- }
+ form.value = {...res.data}
})
}
}
@@ -362,15 +248,7 @@
}
// 鎻愪氦浜у搧琛ㄥ崟
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) {
@@ -381,8 +259,9 @@
proxy.$modal.msgError("璇烽�夋嫨璇峰亣缁撴潫鏃堕棿锛�")
return
}
- if (new Date(form.value.startDate).getTime() >= new Date(form.value.endDate).getTime()) {
- proxy.$modal.msgError("璇峰亣寮�濮嬫椂闂村繀椤绘棭浜庣粨鏉熸椂闂达紒")
+ // 鏍¢獙缁撴潫鏃堕棿涓嶈兘鏃╀簬寮�濮嬫椂闂�
+ if (new Date(form.value.endDate) < new Date(form.value.startDate)) {
+ proxy.$modal.msgError("璇峰亣缁撴潫鏃堕棿涓嶈兘鏃╀簬寮�濮嬫椂闂达紒")
return
}
}
@@ -472,4 +351,4 @@
<style scoped>
-</style>
+</style>
\ No newline at end of file
diff --git a/src/views/collaborativeApproval/approvalProcess/fileList.vue b/src/views/collaborativeApproval/approvalProcess/fileList.vue
index 5cc65f1..498f474 100644
--- a/src/views/collaborativeApproval/approvalProcess/fileList.vue
+++ b/src/views/collaborativeApproval/approvalProcess/fileList.vue
@@ -4,9 +4,9 @@
<el-table-column label="闄勪欢鍚嶇О" prop="name" min-width="400" show-overflow-tooltip />
<el-table-column fixed="right" label="鎿嶄綔" width="150" align="center">
<template #default="scope">
- <el-button link type="primary" size="small" @click="downLoadFile(scope.row)">涓嬭浇</el-button>
- <el-button link type="primary" size="small" @click="lookFile(scope.row)">棰勮</el-button>
- <el-button link type="danger" size="small" @click="handleDelete(scope.row)">鍒犻櫎</el-button>
+ <el-button link type="primary" @click="downLoadFile(scope.row)">涓嬭浇</el-button>
+ <el-button link type="primary" @click="lookFile(scope.row)">棰勮</el-button>
+ <el-button link type="danger" @click="handleDelete(scope.row)">鍒犻櫎</el-button>
</template>
</el-table-column>
</el-table>
diff --git a/src/views/collaborativeApproval/approvalProcess/index.vue b/src/views/collaborativeApproval/approvalProcess/index.vue
index 33bde47..dba6bc1 100644
--- a/src/views/collaborativeApproval/approvalProcess/index.vue
+++ b/src/views/collaborativeApproval/approvalProcess/index.vue
@@ -1,67 +1,129 @@
<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-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>
- <el-tab-pane label="閲囪喘瀹℃壒" name="5"></el-tab-pane>
- <el-tab-pane label="鎶ヤ环瀹℃壒" name="6"></el-tab-pane>
- <el-tab-pane label="鍙戣揣瀹℃壒" name="7"></el-tab-pane>
- </el-tabs>
-
- <div class="search_form">
- <div>
- <span class="search_title">娴佺▼缂栧彿锛�</span>
- <el-input
- v-model="searchForm.approveId"
- style="width: 240px"
- placeholder="璇疯緭鍏ユ祦绋嬬紪鍙锋悳绱�"
- @change="handleQuery"
- clearable
- :prefix-icon="Search"
- />
- <span class="search_title ml10">瀹℃壒鐘舵�侊細</span>
- <el-select v-model="searchForm.approveStatus" clearable @change="handleQuery" style="width: 240px">
- <el-option label="寰呭鏍�" :value="0" />
- <el-option label="瀹℃牳涓�" :value="1" />
- <el-option label="瀹℃牳瀹屾垚" :value="2" />
- <el-option label="瀹℃牳鏈�氳繃" :value="3" />
- <el-option label="宸查噸鏂版彁浜�" :value="4" />
- </el-select>
- <el-button type="primary" @click="handleQuery" style="margin-left: 10px"
- >鎼滅储</el-button
- >
- </div>
- <div>
- <el-button
- type="primary"
- @click="openForm('add')"
- v-if="currentApproveType !== 5 && currentApproveType !== 6 && currentApproveType !== 7"
- >鏂板</el-button>
- <el-button @click="handleOut">瀵煎嚭</el-button>
- <el-button
- type="danger"
- plain
- @click="handleDelete"
- v-if="currentApproveType !== 5 && currentApproveType !== 6 && currentApproveType !== 7"
- >鍒犻櫎</el-button>
+ <!-- 瀹℃壒绫诲瀷鍒囨崲 - 绱у噾鏍囩寮� -->
+ <div class="type-tabs">
+ <div
+ v-for="type in approveTypes"
+ :key="type.value"
+ class="type-tab"
+ :class="{ active: activeTab === type.value }"
+ @click="activeTab = type.value; handleTabChange()"
+ >
+ <el-icon :size="14" :style="{ color: activeTab === type.value ? type.color : '#909399' }">
+ <component :is="type.icon" />
+ </el-icon>
+ <span class="tab-name">{{ type.label }}</span>
</div>
</div>
- <div class="table_list">
+
+ <!-- 鎼滅储鍜屾搷浣滃尯鍩� -->
+ <el-card class="search-card" shadow="never">
+ <div class="search-content">
+ <div class="search-filters">
+ <div class="filter-item">
+ <span class="filter-label">娴佺▼缂栧彿</span>
+ <el-input
+ v-model="searchForm.approveId"
+ placeholder="璇疯緭鍏ユ祦绋嬬紪鍙�"
+ clearable
+ :prefix-icon="Search"
+ @keyup.enter="handleQuery"
+ class="search-input"
+ />
+ </div>
+ <div class="filter-item">
+ <span class="filter-label">瀹℃壒鐘舵��</span>
+ <el-select
+ v-model="searchForm.approveStatus"
+ clearable
+ @change="handleQuery"
+ placeholder="璇烽�夋嫨鐘舵��"
+ class="search-select"
+ >
+ <el-option label="寰呭鏍�" :value="0">
+ <el-tag size="small" type="warning">寰呭鏍�</el-tag>
+ </el-option>
+ <el-option label="瀹℃牳涓�" :value="1">
+ <el-tag size="small" type="primary">瀹℃牳涓�</el-tag>
+ </el-option>
+ <el-option label="瀹℃牳瀹屾垚" :value="2">
+ <el-tag size="small" type="success">瀹℃牳瀹屾垚</el-tag>
+ </el-option>
+ <el-option label="瀹℃牳鏈�氳繃" :value="3">
+ <el-tag size="small" type="danger">瀹℃牳鏈�氳繃</el-tag>
+ </el-option>
+ <el-option label="宸查噸鏂版彁浜�" :value="4">
+ <el-tag size="small" type="info">宸查噸鏂版彁浜�</el-tag>
+ </el-option>
+ </el-select>
+ </div>
+ <el-button type="primary" @click="handleQuery" class="search-btn">
+ <el-icon><Search /></el-icon>
+ 鎼滅储
+ </el-button>
+ <el-button @click="resetQuery" class="reset-btn">
+ <el-icon><RefreshRight /></el-icon>
+ 閲嶇疆
+ </el-button>
+ </div>
+ <div class="search-actions">
+ <el-button
+ type="primary"
+ @click="openForm('add')"
+ v-if="currentApproveType !== 5 && currentApproveType !== 6 && currentApproveType !== 7"
+ class="action-btn primary"
+ >
+ <el-icon><Plus /></el-icon>
+ 鏂板
+ </el-button>
+ <el-button @click="handleOut" class="action-btn">
+ <el-icon><Download /></el-icon>
+ 瀵煎嚭
+ </el-button>
+ <el-button
+ type="danger"
+ plain
+ @click="handleDelete"
+ v-if="currentApproveType !== 5 && currentApproveType !== 6 && currentApproveType !== 7"
+ class="action-btn danger"
+ >
+ <el-icon><Delete /></el-icon>
+ 鍒犻櫎
+ </el-button>
+ </div>
+ </div>
+ </el-card>
+
+ <!-- 鏁版嵁琛ㄦ牸 -->
+ <el-card class="table-card" shadow="never" v-loading="tableLoading">
+ <template #header>
+ <div class="table-header">
+ <div class="table-title">
+ <div class="type-tag" :style="{ backgroundColor: currentTypeInfo.color }">
+ <el-icon color="#fff" :size="16"><component :is="currentTypeInfo.icon" /></el-icon>
+ </div>
+ <span>{{ currentTypeInfo.label }}鍒楄〃</span>
+ <el-tag type="info" size="small" effect="plain" class="count-tag">
+ 鍏� {{ page.total }} 鏉�
+ </el-tag>
+ </div>
+ </div>
+ </template>
<PIMTable
- rowKey="id"
- :column="tableColumnCopy"
- :tableData="tableData"
- :page="page"
- :isSelection="true"
- @selection-change="handleSelectionChange"
- :tableLoading="tableLoading"
- @pagination="pagination"
- :total="page.total"
+ rowKey="id"
+ :column="tableColumnCopy"
+ :tableData="tableData"
+ :page="page"
+ :isSelection="true"
+ @selection-change="handleSelectionChange"
+ :tableLoading="tableLoading"
+ @pagination="pagination"
+ :total="page.total"
+ class="custom-table"
></PIMTable>
- </div>
+ </el-card>
+
+ <!-- 寮圭獥缁勪欢 -->
<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" />
@@ -70,7 +132,7 @@
<script setup>
import FileList from "./fileList.vue";
-import { Search } from "@element-plus/icons-vue";
+import { Search, Plus, Delete, Download, RefreshRight, DocumentChecked } from "@element-plus/icons-vue";
import {onMounted, ref, computed, reactive, toRefs, nextTick, getCurrentInstance} from "vue";
import {ElMessageBox} from "element-plus";
import { useRoute } from 'vue-router';
@@ -85,13 +147,37 @@
// 褰撳墠閫変腑鐨勬爣绛鹃〉锛岄粯璁や负鍏嚭绠$悊
const activeTab = ref('1');
+// 鍚勭被鍨嬫暟閲忕粺璁�
+const typeCounts = ref({});
+
+// 瀹℃壒绫诲瀷閰嶇疆
+const approveTypes = [
+ { value: '1', label: '鍏嚭绠$悊', icon: 'Suitcase', color: '#409EFF' },
+ { value: '2', label: '璇峰亣绠$悊', icon: 'Calendar', color: '#67C23A' },
+ { value: '3', label: '鍑哄樊绠$悊', icon: 'Location', color: '#E6A23C' },
+ { value: '4', label: '鎶ラ攢绠$悊', icon: 'Money', color: '#F56C6C' },
+ { value: '5', label: '閲囪喘瀹℃壒', icon: 'ShoppingCart', color: '#909399' },
+ { value: '6', label: '鎶ヤ环瀹℃壒', icon: 'DocumentChecked', color: '#9B59B6' },
+ { value: '7', label: '鍙戣揣瀹℃壒', icon: 'Van', color: '#1ABC9C' },
+];
+
+// 褰撳墠瀹℃壒绫诲瀷淇℃伅
+const currentTypeInfo = computed(() => {
+ return approveTypes.find(t => t.value === activeTab.value) || approveTypes[0];
+});
+
+// 鑾峰彇绫诲瀷鏁伴噺
+const getTypeCount = (value) => {
+ return typeCounts.value[value] || 0;
+};
+
// 褰撳墠瀹℃壒绫诲瀷锛屾牴鎹�変腑鐨勬爣绛鹃〉璁$畻
const currentApproveType = computed(() => {
return Number(activeTab.value);
});
// 鏍囩椤靛垏鎹㈠鐞�
-const handleTabChange = (tabName) => {
+const handleTabChange = () => {
// 鍒囨崲鏍囩椤垫椂閲嶇疆鎼滅储鏉′欢鍜屽垎椤碉紝骞堕噸鏂板姞杞芥暟鎹�
searchForm.value.approveId = '';
searchForm.value.approveStatus = '';
@@ -102,11 +188,18 @@
const data = reactive({
searchForm: {
- approveId: "",
- approveStatus: "",
+ approveId: "",
+ approveStatus: "",
},
});
const { searchForm } = toRefs(data);
+
+// 閲嶇疆鎼滅储
+const resetQuery = () => {
+ searchForm.value.approveId = '';
+ searchForm.value.approveStatus = '';
+ handleQuery();
+};
// 鍔ㄦ�佽〃鏍煎垪閰嶇疆锛屾牴鎹鎵圭被鍨嬬敓鎴愬垪
const tableColumnCopy = computed(() => {
@@ -238,7 +331,7 @@
},
];
- // 鎶ヤ环瀹℃壒锛堢被鍨� 6锛変笉灞曠ず鈥滈檮浠垛�濇搷浣�
+ // 鎶ヤ环瀹℃壒锛堢被鍨� 6锛変笉灞曠ず"闄勪欢"鎿嶄綔
if (!isQuotationType) {
actionOperations.push({
name: "闄勪欢",
@@ -294,6 +387,8 @@
tableLoading.value = false;
tableData.value = res.data.records
page.total = res.data.total;
+ // 鏇存柊褰撳墠绫诲瀷鏁伴噺
+ typeCounts.value[activeTab.value] = res.data.total;
}).catch(err => {
tableLoading.value = false;
})
@@ -388,7 +483,256 @@
</script>
<style scoped>
-.approval-tabs {
- margin-bottom: 10px;
+.page-header {
+ margin-bottom: 20px;
+}
+
+.header-title {
+ display: flex;
+ align-items: center;
+ gap: 12px;
+}
+
+.title-icon {
+ font-size: 28px;
+ color: var(--el-color-primary, #409EFF);
+}
+
+.header-text {
+ display: flex;
+ flex-direction: column;
+ gap: 4px;
+}
+
+.main-title {
+ font-size: 20px;
+ font-weight: 600;
+ color: var(--el-text-color-primary, #303133);
+}
+
+.sub-title {
+ font-size: 13px;
+ color: var(--el-text-color-secondary, #909399);
+}
+
+/* 瀹℃壒绫诲瀷鍒囨崲 - 绱у噾鏍囩寮� */
+.type-tabs {
+ display: flex;
+ gap: 4px;
+ margin-bottom: 16px;
+ padding: 4px;
+ background: var(--el-fill-color-light, #f5f7fa);
+ border-radius: 8px;
+ overflow-x: auto;
+}
+
+.type-tab {
+ display: flex;
+ align-items: center;
+ gap: 6px;
+ padding: 8px 14px;
+ border-radius: 6px;
+ cursor: pointer;
+ transition: all 0.2s ease;
+ white-space: nowrap;
+ font-size: 13px;
+ color: var(--el-text-color-regular, #606266);
+}
+
+.type-tab:hover {
+ background: var(--el-color-primary-light-9, rgba(64, 158, 255, 0.1));
+ color: var(--el-color-primary, #409EFF);
+}
+
+.type-tab.active {
+ background: var(--el-bg-color, #fff);
+ color: var(--el-color-primary, #409EFF);
+ font-weight: 600;
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
+}
+
+.tab-name {
+ font-size: 13px;
+}
+
+.tab-count {
+ min-width: 16px;
+ height: 16px;
+ padding: 0 5px;
+ background: var(--el-color-success, #67C23A);
+ color: #fff;
+ border-radius: 8px;
+ font-size: 11px;
+ font-weight: 600;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+}
+
+/* 鎼滅储鍗$墖 */
+.search-card {
+ margin-bottom: 16px;
+ border-radius: 12px;
+}
+
+:deep(.el-card__body) {
+ padding: 20px;
+}
+
+.search-content {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ flex-wrap: wrap;
+ gap: 16px;
+}
+
+.search-filters {
+ display: flex;
+ align-items: center;
+ gap: 16px;
+ flex-wrap: wrap;
+}
+
+.filter-item {
+ display: flex;
+ align-items: center;
+ gap: 8px;
+}
+
+.filter-label {
+ font-size: 14px;
+ color: var(--el-text-color-regular, #606266);
+ font-weight: 500;
+ white-space: nowrap;
+}
+
+.search-input,
+.search-select {
+ width: 200px;
+}
+
+.search-btn {
+ display: flex;
+ align-items: center;
+ gap: 4px;
+}
+
+.reset-btn {
+ display: flex;
+ align-items: center;
+ gap: 4px;
+}
+
+.search-actions {
+ display: flex;
+ gap: 10px;
+}
+
+.action-btn {
+ display: flex;
+ align-items: center;
+ gap: 4px;
+}
+
+.action-btn.primary {
+ background: var(--el-color-primary, #409EFF);
+ border: none;
+}
+
+.action-btn.danger {
+ transition: all 0.3s;
+}
+
+.action-btn.danger:hover {
+ background: #f56c6c;
+ color: #fff;
+}
+
+/* 琛ㄦ牸鍗$墖 */
+.table-card {
+ border-radius: 12px;
+}
+
+:deep(.el-card__header) {
+ padding: 16px 20px;
+ border-bottom: 1px solid var(--el-border-color-light, #ebeef5);
+}
+
+.table-header {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+}
+
+.table-title {
+ display: flex;
+ align-items: center;
+ gap: 12px;
+ font-size: 16px;
+ font-weight: 600;
+ color: var(--el-text-color-primary, #303133);
+}
+
+.type-tag {
+ width: 32px;
+ height: 32px;
+ border-radius: 8px;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+}
+
+.count-tag {
+ margin-left: 8px;
+}
+
+.custom-table {
+ margin-top: 8px;
+}
+
+/* 鍝嶅簲寮� */
+@media (max-width: 1200px) {
+ .search-content {
+ flex-direction: column;
+ align-items: stretch;
+ }
+
+ .search-filters {
+ justify-content: flex-start;
+ }
+
+ .search-actions {
+ justify-content: flex-end;
+ }
+}
+
+@media (max-width: 768px) {
+ .type-tabs {
+ padding: 3px;
+ }
+
+ .type-tab {
+ padding: 6px 10px;
+ font-size: 12px;
+ }
+
+ .tab-name {
+ font-size: 12px;
+ }
+
+ .search-filters {
+ flex-direction: column;
+ align-items: stretch;
+ }
+
+ .filter-item {
+ width: 100%;
+ }
+
+ .search-input,
+ .search-select {
+ width: 100%;
+ }
}
</style>
diff --git a/src/views/procurementManagement/procurementLedger/index.vue b/src/views/procurementManagement/procurementLedger/index.vue
index 3d4686c..ed91559 100644
--- a/src/views/procurementManagement/procurementLedger/index.vue
+++ b/src/views/procurementManagement/procurementLedger/index.vue
@@ -295,50 +295,6 @@
</el-form-item>
</el-col>
</el-row>
- <el-row :gutter="30">
- <el-col :span="24">
- <el-form-item>
- <template #label>
- <div style="display: flex; align-items: center; justify-content: space-between; width: 100%;">
- <span>瀹℃壒浜洪�夋嫨锛�</span>
- <el-button type="primary" size="small" @click="addApproverNode" icon="Plus">鏂板鑺傜偣</el-button>
- </div>
- </template>
- <div class="approver-nodes-container">
- <div
- v-for="(node, index) in approverNodes"
- :key="node.id"
- class="approver-node-item"
- >
- <div class="approver-node-header">
- <span class="approver-node-label">瀹℃壒鑺傜偣 {{ index + 1 }}</span>
- <el-button
- v-if="approverNodes.length > 1"
- type="danger"
- size="small"
- text
- @click="removeApproverNode(index)"
- icon="Delete"
- >鍒犻櫎</el-button>
- </div>
- <el-select
- v-model="node.userId"
- placeholder="璇烽�夋嫨瀹℃壒浜�"
- filterable
- style="width: 100%;"
- >
- <el-option
- v-for="user in userList"
- :key="user.userId"
- :label="user.nickName"
- :value="user.userId"
- />
- </el-select>
- </div>
- </div>
- </el-form-item>
- </el-col>
- </el-row>
<el-row>
<el-form-item label="浜у搧淇℃伅锛�"
prop="entryDate">
@@ -760,16 +716,6 @@
const userStore = useUserStore();
- // 瀹℃壒浜鸿妭鐐癸紙浠块攢鍞彴璐﹀彂璐у鎵逛汉锛�
- const approverNodes = ref([{ id: 1, userId: null }]);
- let nextApproverId = 2;
- const addApproverNode = () => {
- approverNodes.value.push({ id: nextApproverId++, userId: null });
- };
- const removeApproverNode = (index) => {
- approverNodes.value.splice(index, 1);
- };
-
// 璁㈠崟瀹℃壒鐘舵�佹樉绀烘枃鏈�
const approvalStatusText = {
1: "寰呭鏍�",
@@ -919,9 +865,6 @@
rules: {
purchaseContractNumber: [
{ required: true, message: "璇疯緭鍏�", trigger: "blur" },
- ],
- approverId: [
- { required: true, message: "璇烽�夋嫨瀹℃壒浜�", trigger: "change" },
],
// projectName: [
// { required: true, message: "璇疯緭鍏ラ」鐩悕绉�", trigger: "blur" },
@@ -1121,19 +1064,12 @@
}
try {
- // 鑾峰彇瀹℃壒浜篒D瀛楃涓�
- const approveUserIds = approverNodes.value
- .filter(node => node.userId)
- .map(node => node.userId)
- .join(",");
-
let params = {
productData: proxy.HaveJson(productData.value),
supplierId: form.value.supplierId,
paymentMethod: form.value.paymentMethod,
recorderId: form.value.recorderId,
projectName: form.value.projectName,
- approveUserIds: approveUserIds,
templateName: templateName.value.trim(),
};
console.log("template params ===>", params, "currentTemplateId:", currentTemplateId.value);
@@ -1293,9 +1229,6 @@
templateName.value = "";
filterInputValue.value = "";
isTemplateNameDuplicate.value = false;
- // 閲嶇疆瀹℃壒浜鸿妭鐐癸紙榛樿涓�涓┖鑺傜偣锛�
- approverNodes.value = [{ id: 1, userId: null }];
- nextApproverId = 2;
try {
// 骞惰鍔犺浇鍩虹鏁版嵁
const [userRes, salesRes, supplierRes] = await Promise.all([
@@ -1334,15 +1267,6 @@
form.value = { ...purchaseRes };
productData.value = purchaseRes.productData || [];
fileList.value = purchaseRes.salesLedgerFiles || [];
- // 濡傛灉缂栬緫鏃舵湁瀹℃壒浜猴紝瑙f瀽瀹℃壒浜篒D瀛楃涓插苟璁剧疆鍒拌妭鐐逛腑
- if (purchaseRes.approveUserIds) {
- const approverIds = purchaseRes.approveUserIds.split(",");
- approverNodes.value = approverIds.map((id, index) => ({
- id: index + 1,
- userId: Number(id)
- }));
- nextApproverId = approverIds.length + 1;
- }
} catch (error) {
console.error("鍔犺浇閲囪喘鍙拌处鏁版嵁澶辫触:", error);
proxy.$modal.msgError("鍔犺浇鏁版嵁澶辫触");
@@ -1411,14 +1335,6 @@
const submitForm = () => {
proxy.$refs["formRef"].validate(valid => {
if (valid) {
- // 瀹℃壒浜哄繀濉牎楠岋紙鎵�鏈夎妭鐐归兘瑕侀�変汉锛�
- const hasEmptyApprover = approverNodes.value.some(node => !node.userId);
- if (hasEmptyApprover) {
- proxy.$modal.msgError("璇蜂负鎵�鏈夊鎵硅妭鐐归�夋嫨瀹℃壒浜猴紒");
- return;
- }
- const approveUserIds = approverNodes.value.map(node => node.userId).join(",");
-
if (productData.value.length > 0) {
// 鏂板鏃讹紝闇�瑕佷粠姣忎釜浜у搧瀵硅薄涓垹闄� id 瀛楁
let processedProductData = productData.value;
@@ -1439,7 +1355,6 @@
}
form.value.tempFileIds = tempFileIds;
form.value.type = 2;
- form.value.approveUserIds = approveUserIds;
// 濡傛灉salesLedgerId涓虹┖锛屽垯涓嶄紶閫抯alesContractNo
if (!form.value.salesLedgerId) {
@@ -1463,9 +1378,6 @@
// 鍏抽棴寮规
const closeDia = () => {
proxy.resetForm("formRef");
- // 閲嶇疆瀹℃壒浜鸿妭鐐癸紙榛樿涓�涓┖鑺傜偣锛�
- approverNodes.value = [{ id: 1, userId: null }];
- nextApproverId = 2;
dialogFormVisible.value = false;
};
// 鎵撳紑浜у搧寮规
@@ -1951,57 +1863,6 @@
.select-button-group {
display: flex;
align-items: center;
- }
-
- // 瀹℃壒浜鸿妭鐐瑰鍣ㄦ牱寮�
- .approver-nodes-container {
- display: flex;
- flex-wrap: wrap;
- gap: 16px;
- padding: 16px;
- background-color: #f8f9fa;
- border-radius: 4px;
- border: 1px solid #e4e7ed;
- }
-
- .approver-node-item {
- flex: 0 0 calc(33.333% - 12px);
- min-width: 200px;
- padding: 12px;
- background-color: #fff;
- border-radius: 4px;
- border: 1px solid #dcdfe6;
- transition: all 0.3s;
-
- &:hover {
- border-color: #409eff;
- box-shadow: 0 2px 8px rgba(64, 158, 255, 0.1);
- }
- }
-
- .approver-node-header {
- display: flex;
- justify-content: space-between;
- align-items: center;
- margin-bottom: 8px;
- }
-
- .approver-node-label {
- font-size: 13px;
- font-weight: 500;
- color: #606266;
- }
-
- @media (max-width: 1200px) {
- .approver-node-item {
- flex: 0 0 calc(50% - 8px);
- }
- }
-
- @media (max-width: 768px) {
- .approver-node-item {
- flex: 0 0 100%;
- }
}
// 鍒犻櫎鍥炬爣鏍峰紡
diff --git a/src/views/salesManagement/salesLedger/index.vue b/src/views/salesManagement/salesLedger/index.vue
index 66d387b..5b9e9e3 100644
--- a/src/views/salesManagement/salesLedger/index.vue
+++ b/src/views/salesManagement/salesLedger/index.vue
@@ -585,50 +585,6 @@
</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: 20px; text-align: center; margin-bottom: 10px;"
- >
- <div>
- <span>瀹℃壒浜�</span>
- 鈫�
- </div>
- <el-select
- v-model="node.userId"
- placeholder="閫夋嫨浜哄憳"
- filterable
- style="width: 140px; 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"
- @click="removeApproverNode(index)"
- v-if="approverNodes.length > 1"
- >鍒犻櫎</el-button>
- </div>
- </div>
- </div>
- </el-form-item>
- </el-col>
- </el-row>
</el-form>
<template #footer>
<div class="dialog-footer">
@@ -802,16 +758,6 @@
},
});
const { deliveryForm, deliveryRules } = toRefs(deliveryFormData);
-
-// 鍙戣揣瀹℃壒浜鸿妭鐐癸紙浠垮崗鍚屽鎵� infoFormDia.vue锛�
-const approverNodes = ref([{ id: 1, userId: null }]);
-let nextApproverId = 2;
-const addApproverNode = () => {
- approverNodes.value.push({ id: nextApproverId++, userId: null });
-};
-const removeApproverNode = (index) => {
- approverNodes.value.splice(index, 1);
-};
// 瀵煎叆鐩稿叧
const importUploadRef = ref(null);
@@ -2220,9 +2166,6 @@
deliveryForm.value = {
type: "璐ц溅",
};
- // 閲嶇疆瀹℃壒浜鸿妭鐐癸紙榛樿涓�涓┖鑺傜偣锛�
- approverNodes.value = [{ id: 1, userId: null }];
- nextApproverId = 2;
deliveryFormVisible.value = true;
};
@@ -2230,13 +2173,6 @@
const submitDelivery = () => {
proxy.$refs["deliveryFormRef"].validate((valid) => {
if (valid) {
- // 瀹℃壒浜哄繀濉牎楠岋紙鎵�鏈夎妭鐐归兘瑕侀�変汉锛�
- const hasEmptyApprover = approverNodes.value.some(node => !node.userId);
- if (hasEmptyApprover) {
- proxy.$modal.msgError("璇蜂负鎵�鏈夊鎵硅妭鐐归�夋嫨瀹℃壒浜猴紒");
- return;
- }
- const approveUserIds = approverNodes.value.map(node => node.userId).join(",");
// 淇濆瓨褰撳墠灞曞紑鐨勮ID锛屼互渚垮彂璐у悗閲嶆柊鍔犺浇瀛愯〃鏍兼暟鎹�
const currentExpandedKeys = [...expandedRowKeys.value];
const salesLedgerId = currentDeliveryRow.value.salesLedgerId;
@@ -2244,7 +2180,6 @@
salesLedgerId: salesLedgerId,
salesLedgerProductId: currentDeliveryRow.value.id,
type: deliveryForm.value.type,
- approveUserIds,
})
.then(() => {
proxy.$modal.msgSuccess("鍙戣揣鎴愬姛");
diff --git a/src/views/salesManagement/salesLedger/index2.vue b/src/views/salesManagement/salesLedger/index2.vue
index e29d79f..0718592 100644
--- a/src/views/salesManagement/salesLedger/index2.vue
+++ b/src/views/salesManagement/salesLedger/index2.vue
@@ -592,50 +592,6 @@
</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: 20px; text-align: center; margin-bottom: 10px;"
- >
- <div>
- <span>瀹℃壒浜�</span>
- 鈫�
- </div>
- <el-select
- v-model="node.userId"
- placeholder="閫夋嫨浜哄憳"
- filterable
- style="width: 140px; 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"
- @click="removeApproverNode(index)"
- v-if="approverNodes.length > 1"
- >鍒犻櫎</el-button>
- </div>
- </div>
- </div>
- </el-form-item>
- </el-col>
- </el-row>
</el-form>
<template #footer>
<div class="dialog-footer">
@@ -810,16 +766,6 @@
},
});
const { deliveryForm, deliveryRules } = toRefs(deliveryFormData);
-
-// 鍙戣揣瀹℃壒浜鸿妭鐐癸紙浠垮崗鍚屽鎵� infoFormDia.vue锛�
-const approverNodes = ref([{ id: 1, userId: null }]);
-let nextApproverId = 2;
-const addApproverNode = () => {
- approverNodes.value.push({ id: nextApproverId++, userId: null });
-};
-const removeApproverNode = (index) => {
- approverNodes.value.splice(index, 1);
-};
// 瀵煎叆鐩稿叧
const importUploadRef = ref(null);
@@ -2251,9 +2197,6 @@
deliveryForm.value = {
type: "璐ц溅",
};
- // 閲嶇疆瀹℃壒浜鸿妭鐐癸紙榛樿涓�涓┖鑺傜偣锛�
- approverNodes.value = [{ id: 1, userId: null }];
- nextApproverId = 2;
deliveryFormVisible.value = true;
};
@@ -2261,13 +2204,6 @@
const submitDelivery = () => {
proxy.$refs["deliveryFormRef"].validate((valid) => {
if (valid) {
- // 瀹℃壒浜哄繀濉牎楠岋紙鎵�鏈夎妭鐐归兘瑕侀�変汉锛�
- const hasEmptyApprover = approverNodes.value.some(node => !node.userId);
- if (hasEmptyApprover) {
- proxy.$modal.msgError("璇蜂负鎵�鏈夊鎵硅妭鐐归�夋嫨瀹℃壒浜猴紒");
- return;
- }
- const approveUserIds = approverNodes.value.map(node => node.userId).join(",");
// 淇濆瓨褰撳墠灞曞紑鐨勮ID锛屼互渚垮彂璐у悗閲嶆柊鍔犺浇瀛愯〃鏍兼暟鎹�
const currentExpandedKeys = [...expandedRowKeys.value];
const salesLedgerId = currentDeliveryRow.value.salesLedgerId;
@@ -2275,7 +2211,6 @@
salesLedgerId: salesLedgerId,
salesLedgerProductId: currentDeliveryRow.value.id,
type: deliveryForm.value.type,
- approveUserIds,
})
.then(() => {
proxy.$modal.msgSuccess("鍙戣揣鎴愬姛");
diff --git a/src/views/salesManagement/salesQuotation/index.vue b/src/views/salesManagement/salesQuotation/index.vue
index e25f111..dc4e2ca 100644
--- a/src/views/salesManagement/salesQuotation/index.vue
+++ b/src/views/salesManagement/salesQuotation/index.vue
@@ -155,63 +155,6 @@
</div>
</el-card>
- <!-- 瀹℃壒浜轰俊鎭� -->
- <el-card class="form-card" shadow="hover">
- <template #header>
- <div class="card-header-wrapper">
- <el-icon class="card-icon"><UserFilled /></el-icon>
- <span class="card-title">瀹℃壒浜洪�夋嫨</span>
- <el-button type="primary" size="small" @click="addApproverNode" class="header-btn">
- <el-icon><Plus /></el-icon>
- 鏂板鑺傜偣
- </el-button>
- </div>
- </template>
- <div class="form-content">
- <el-row>
- <el-col :span="24">
- <el-form-item>
- <div class="approver-nodes-container">
- <div
- v-for="(node, index) in approverNodes"
- :key="node.id"
- class="approver-node-item"
- >
- <div class="approver-node-label">
- <span class="node-step">{{ index + 1 }}</span>
- <span class="node-text">瀹℃壒浜�</span>
- <el-icon class="arrow-icon"><ArrowRight /></el-icon>
- </div>
- <el-select
- v-model="node.userId"
- placeholder="閫夋嫨浜哄憳"
- class="approver-select"
- filterable
- clearable
- >
- <el-option
- v-for="user in userList"
- :key="user.userId"
- :label="user.nickName"
- :value="user.userId"
- />
- </el-select>
- <el-button
- type="danger"
- size="small"
- :icon="Delete"
- @click="removeApproverNode(index)"
- v-if="approverNodes.length > 1"
- class="remove-btn"
- >鍒犻櫎</el-button>
- </div>
- </div>
- </el-form-item>
- </el-col>
- </el-row>
- </div>
- </el-card>
-
<!-- 浜у搧淇℃伅 -->
<el-card class="form-card" shadow="hover">
<template #header>
@@ -401,7 +344,7 @@
<script setup>
import { ref, reactive, computed, onMounted, markRaw, shallowRef, getCurrentInstance } from 'vue'
import { ElMessage, ElMessageBox } from 'element-plus'
-import { Search, Document, UserFilled, Box, EditPen, Plus, ArrowRight, Delete, Paperclip, View, Download } from '@element-plus/icons-vue'
+import { Search, Document, Box, EditPen, Plus, Delete, Paperclip, View, Download } from '@element-plus/icons-vue'
import Pagination from '@/components/PIMTable/Pagination.vue'
import FormDialog from '@/components/Dialog/FormDialog.vue'
import {getQuotationList,addQuotation,updateQuotation,deleteQuotation,deleteFile} from '@/api/salesManagement/salesQuotation.js'
@@ -487,26 +430,11 @@
const userList = ref([]);
const customerOption = ref([]);
-// 瀹℃壒浜鸿妭鐐圭浉鍏�
-const approverNodes = ref([
- { id: 1, userId: null }
-])
-let nextApproverId = 2
const isEdit = ref(false)
const editId = ref(null)
const currentQuotation = ref({})
const formRef = ref()
-
-// 娣诲姞瀹℃壒浜鸿妭鐐�
-function addApproverNode() {
- approverNodes.value.push({ id: nextApproverId++, userId: null })
-}
-
-// 鍒犻櫎瀹℃壒浜鸿妭鐐�
-function removeApproverNode(index) {
- approverNodes.value.splice(index, 1)
-}
// 璁$畻灞炴��
const filteredList = computed(() => {
@@ -556,9 +484,6 @@
isEdit.value = false
resetForm()
fileList.value = []
- // 閲嶇疆瀹℃壒浜鸿妭鐐�
- approverNodes.value = [{ id: 1, userId: null }]
- nextApproverId = 2
dialogVisible.value = true
let userLists = await userListNoPage();
// 鍙鍒堕渶瑕佺殑瀛楁锛岄伩鍏嶅皢缁勪欢寮曠敤鏀惧叆鍝嶅簲寮忓璞�
@@ -755,19 +680,6 @@
form.discountAmount = row.discountAmount || 0
form.totalAmount = row.totalAmount || 0
- // 鍙嶆樉瀹℃壒浜�
- if (row.approveUserIds) {
- const userIds = row.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
- }
-
// 鍔犺浇鐢ㄦ埛鍒楄〃
let userLists = await userListNoPage();
userList.value = (userLists.data || []).map(item => ({
@@ -926,16 +838,6 @@
return
}
- // 瀹℃壒浜哄繀濉牎楠�
- const hasEmptyApprover = approverNodes.value.some(node => !node.userId)
- if (hasEmptyApprover) {
- ElMessage.error('璇蜂负鎵�鏈夊鎵硅妭鐐归�夋嫨瀹℃壒浜猴紒')
- return
- }
-
- // 鏀堕泦鎵�鏈夎妭鐐圭殑瀹℃壒浜篿d
- form.approveUserIds = approverNodes.value.map(node => node.userId).join(',')
-
form.files = fileList.value.map(f => ({
id: f.id,
tempId: f.tempId,
@@ -1003,8 +905,6 @@
validDate: item.validDate || '',
paymentMethod: item.paymentMethod || '',
status: item.status || '鑽夌',
- // 瀹℃壒浜猴紙鐢ㄤ簬缂栬緫鏃跺弽鏄撅級
- approveUserIds: item.approveUserIds || '',
remark: item.remark || '',
salesLedgerFiles: normalizeQuotationFiles(item),
products: item.products ? item.products.map(product => ({
@@ -1125,71 +1025,6 @@
}
}
-.approver-nodes-container {
- display: flex;
- flex-wrap: wrap;
- gap: 24px;
- padding: 12px 0;
-}
-
-.approver-node-item {
- display: flex;
- flex-direction: column;
- align-items: center;
- gap: 12px;
- padding: 16px;
- background: #f8f9fa;
- border-radius: 8px;
- border: 1px solid #e4e7ed;
- transition: all 0.3s ease;
- min-width: 180px;
-
- &:hover {
- border-color: #409eff;
- background: #f0f7ff;
- box-shadow: 0 2px 8px rgba(64, 158, 255, 0.1);
- }
-}
-
-.approver-node-label {
- display: flex;
- align-items: center;
- gap: 8px;
- font-size: 14px;
- color: #606266;
-
- .node-step {
- display: inline-flex;
- align-items: center;
- justify-content: center;
- width: 24px;
- height: 24px;
- background: #409eff;
- color: #fff;
- border-radius: 50%;
- font-size: 12px;
- font-weight: 600;
- }
-
- .node-text {
- font-weight: 500;
- }
-
- .arrow-icon {
- color: #909399;
- font-size: 14px;
- }
-}
-
-.approver-select {
- width: 100%;
- min-width: 150px;
-}
-
-.remove-btn {
- margin-top: 4px;
-}
-
.product-table {
:deep(.el-table__header) {
background-color: #f5f7fa;
@@ -1217,13 +1052,4 @@
}
// 鍝嶅簲寮忎紭鍖�
-@media (max-width: 1200px) {
- .approver-nodes-container {
- gap: 16px;
- }
-
- .approver-node-item {
- min-width: 160px;
- }
-}
</style>
--
Gitblit v1.9.3